eglcontext.c revision 3fd79dd9886f05f45f3dc94c028a38dd75b8ee1b
1/************************************************************************** 2 * 3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 4 * Copyright 2009-2010 Chia-I Wu <olvaffe@gmail.com> 5 * Copyright 2010-2011 LunarG, Inc. 6 * All Rights Reserved. 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sub license, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the 17 * next paragraph) shall be included in all copies or substantial portions 18 * of the Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 * 28 **************************************************************************/ 29 30 31#include <assert.h> 32#include <stdlib.h> 33#include <string.h> 34#include "eglconfig.h" 35#include "eglcontext.h" 36#include "egldisplay.h" 37#include "eglcurrent.h" 38#include "eglsurface.h" 39#include "egllog.h" 40 41 42/** 43 * Return the API bit (one of EGL_xxx_BIT) of the context. 44 */ 45static EGLint 46_eglGetContextAPIBit(_EGLContext *ctx) 47{ 48 EGLint bit = 0; 49 50 switch (ctx->ClientAPI) { 51 case EGL_OPENGL_ES_API: 52 switch (ctx->ClientMajorVersion) { 53 case 1: 54 bit = EGL_OPENGL_ES_BIT; 55 break; 56 case 2: 57 bit = EGL_OPENGL_ES2_BIT; 58 break; 59 default: 60 break; 61 } 62 break; 63 case EGL_OPENVG_API: 64 bit = EGL_OPENVG_BIT; 65 break; 66 case EGL_OPENGL_API: 67 bit = EGL_OPENGL_BIT; 68 break; 69 default: 70 break; 71 } 72 73 return bit; 74} 75 76 77/** 78 * Parse the list of context attributes and return the proper error code. 79 */ 80static EGLint 81_eglParseContextAttribList(_EGLContext *ctx, const EGLint *attrib_list) 82{ 83 EGLenum api = ctx->ClientAPI; 84 EGLint i, err = EGL_SUCCESS; 85 86 if (!attrib_list) 87 return EGL_SUCCESS; 88 89 for (i = 0; attrib_list[i] != EGL_NONE; i++) { 90 EGLint attr = attrib_list[i++]; 91 EGLint val = attrib_list[i]; 92 93 switch (attr) { 94 case EGL_CONTEXT_CLIENT_VERSION: 95 if (api != EGL_OPENGL_ES_API) { 96 err = EGL_BAD_ATTRIBUTE; 97 break; 98 } 99 if (val != 1 && val != 2) { 100 err = EGL_BAD_ATTRIBUTE; 101 break; 102 } 103 ctx->ClientMajorVersion = val; 104 break; 105 default: 106 err = EGL_BAD_ATTRIBUTE; 107 break; 108 } 109 110 if (err != EGL_SUCCESS) { 111 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr); 112 break; 113 } 114 } 115 116 return err; 117} 118 119 120/** 121 * Initialize the given _EGLContext object to defaults and/or the values 122 * in the attrib_list. 123 */ 124EGLBoolean 125_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf, 126 const EGLint *attrib_list) 127{ 128 const EGLenum api = eglQueryAPI(); 129 EGLint err; 130 131 if (api == EGL_NONE) { 132 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)"); 133 return EGL_FALSE; 134 } 135 136 _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy); 137 ctx->ClientAPI = api; 138 ctx->Config = conf; 139 ctx->WindowRenderBuffer = EGL_NONE; 140 141 ctx->ClientMajorVersion = 1; /* the default, per EGL spec */ 142 ctx->ClientMinorVersion = 0; 143 144 err = _eglParseContextAttribList(ctx, attrib_list); 145 if (err == EGL_SUCCESS && ctx->Config) { 146 EGLint api_bit; 147 148 api_bit = _eglGetContextAPIBit(ctx); 149 if (!(ctx->Config->RenderableType & api_bit)) { 150 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x", 151 api_bit, ctx->Config->RenderableType); 152 err = EGL_BAD_CONFIG; 153 } 154 } 155 if (err != EGL_SUCCESS) 156 return _eglError(err, "eglCreateContext"); 157 158 return EGL_TRUE; 159} 160 161 162static EGLint 163_eglQueryContextRenderBuffer(_EGLContext *ctx) 164{ 165 _EGLSurface *surf = ctx->DrawSurface; 166 EGLint rb; 167 168 if (!surf) 169 return EGL_NONE; 170 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE) 171 rb = ctx->WindowRenderBuffer; 172 else 173 rb = surf->RenderBuffer; 174 return rb; 175} 176 177 178EGLBoolean 179_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, 180 EGLint attribute, EGLint *value) 181{ 182 (void) drv; 183 (void) dpy; 184 185 if (!value) 186 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext"); 187 188 switch (attribute) { 189 case EGL_CONFIG_ID: 190 if (!c->Config) 191 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); 192 *value = c->Config->ConfigID; 193 break; 194 case EGL_CONTEXT_CLIENT_VERSION: 195 *value = c->ClientMajorVersion; 196 break; 197 case EGL_CONTEXT_CLIENT_TYPE: 198 *value = c->ClientAPI; 199 break; 200 case EGL_RENDER_BUFFER: 201 *value = _eglQueryContextRenderBuffer(c); 202 break; 203 default: 204 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); 205 } 206 207 return EGL_TRUE; 208} 209 210 211/** 212 * Bind the context to the thread and return the previous context. 213 * 214 * Note that the context may be NULL. 215 */ 216static _EGLContext * 217_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t) 218{ 219 EGLint apiIndex; 220 _EGLContext *oldCtx; 221 222 apiIndex = (ctx) ? 223 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex; 224 225 oldCtx = t->CurrentContexts[apiIndex]; 226 if (ctx != oldCtx) { 227 if (oldCtx) 228 oldCtx->Binding = NULL; 229 if (ctx) 230 ctx->Binding = t; 231 232 t->CurrentContexts[apiIndex] = ctx; 233 } 234 235 return oldCtx; 236} 237 238 239/** 240 * Return true if the given context and surfaces can be made current. 241 */ 242static EGLBoolean 243_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) 244{ 245 _EGLThreadInfo *t = _eglGetCurrentThread(); 246 _EGLDisplay *dpy; 247 EGLint conflict_api; 248 249 if (_eglIsCurrentThreadDummy()) 250 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent"); 251 252 /* this is easy */ 253 if (!ctx) { 254 if (draw || read) 255 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); 256 return EGL_TRUE; 257 } 258 259 dpy = ctx->Resource.Display; 260 if (!dpy->Extensions.KHR_surfaceless_context 261 && (draw == NULL || read == NULL)) 262 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); 263 264 /* 265 * The spec says 266 * 267 * "If ctx is current to some other thread, or if either draw or read are 268 * bound to contexts in another thread, an EGL_BAD_ACCESS error is 269 * generated." 270 * 271 * and 272 * 273 * "at most one context may be bound to a particular surface at a given 274 * time" 275 */ 276 if (ctx->Binding && ctx->Binding != t) 277 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 278 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) { 279 if (draw->CurrentContext->Binding != t || 280 draw->CurrentContext->ClientAPI != ctx->ClientAPI) 281 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 282 } 283 if (read && read->CurrentContext && read->CurrentContext != ctx) { 284 if (read->CurrentContext->Binding != t || 285 read->CurrentContext->ClientAPI != ctx->ClientAPI) 286 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 287 } 288 289 /* simply require the configs to be equal */ 290 if ((draw && draw->Config != ctx->Config) || 291 (read && read->Config != ctx->Config)) 292 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); 293 294 switch (ctx->ClientAPI) { 295 /* OpenGL and OpenGL ES are conflicting */ 296 case EGL_OPENGL_ES_API: 297 conflict_api = EGL_OPENGL_API; 298 break; 299 case EGL_OPENGL_API: 300 conflict_api = EGL_OPENGL_ES_API; 301 break; 302 default: 303 conflict_api = -1; 304 break; 305 } 306 307 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api)) 308 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 309 310 return EGL_TRUE; 311} 312 313 314/** 315 * Bind the context to the current thread and given surfaces. Return the 316 * previous bound context and surfaces. The caller should unreference the 317 * returned context and surfaces. 318 * 319 * Making a second call with the resources returned by the first call 320 * unsurprisingly undoes the first call, except for the resouce reference 321 * counts. 322 */ 323EGLBoolean 324_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read, 325 _EGLContext **old_ctx, 326 _EGLSurface **old_draw, _EGLSurface **old_read) 327{ 328 _EGLThreadInfo *t = _eglGetCurrentThread(); 329 _EGLContext *prev_ctx; 330 _EGLSurface *prev_draw, *prev_read; 331 332 if (!_eglCheckMakeCurrent(ctx, draw, read)) 333 return EGL_FALSE; 334 335 /* increment refcounts before binding */ 336 _eglGetContext(ctx); 337 _eglGetSurface(draw); 338 _eglGetSurface(read); 339 340 /* bind the new context */ 341 prev_ctx = _eglBindContextToThread(ctx, t); 342 343 /* break previous bindings */ 344 if (prev_ctx) { 345 prev_draw = prev_ctx->DrawSurface; 346 prev_read = prev_ctx->ReadSurface; 347 348 if (prev_draw) 349 prev_draw->CurrentContext = NULL; 350 if (prev_read) 351 prev_read->CurrentContext = NULL; 352 353 prev_ctx->DrawSurface = NULL; 354 prev_ctx->ReadSurface = NULL; 355 } 356 else { 357 prev_draw = prev_read = NULL; 358 } 359 360 /* establish new bindings */ 361 if (ctx) { 362 if (draw) 363 draw->CurrentContext = ctx; 364 if (read) 365 read->CurrentContext = ctx; 366 367 ctx->DrawSurface = draw; 368 ctx->ReadSurface = read; 369 } 370 371 assert(old_ctx && old_draw && old_read); 372 *old_ctx = prev_ctx; 373 *old_draw = prev_draw; 374 *old_read = prev_read; 375 376 return EGL_TRUE; 377} 378