eglcontext.c revision 63beb3df98147f34fd0965cb0afbb97444206d0c
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, _EGLDisplay *dpy, 82 const EGLint *attrib_list) 83{ 84 EGLenum api = ctx->ClientAPI; 85 EGLint i, err = EGL_SUCCESS; 86 87 if (!attrib_list) 88 return EGL_SUCCESS; 89 90 if (api == EGL_OPENVG_API && attrib_list[0] != EGL_NONE) { 91 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attrib_list[0]); 92 return EGL_BAD_ATTRIBUTE; 93 } 94 95 for (i = 0; attrib_list[i] != EGL_NONE; i++) { 96 EGLint attr = attrib_list[i++]; 97 EGLint val = attrib_list[i]; 98 99 switch (attr) { 100 case EGL_CONTEXT_CLIENT_VERSION: 101 ctx->ClientMajorVersion = val; 102 break; 103 104 case EGL_CONTEXT_MINOR_VERSION_KHR: 105 if (!dpy->Extensions.KHR_create_context) { 106 err = EGL_BAD_ATTRIBUTE; 107 break; 108 } 109 110 ctx->ClientMinorVersion = val; 111 break; 112 113 case EGL_CONTEXT_FLAGS_KHR: 114 if (!dpy->Extensions.KHR_create_context) { 115 err = EGL_BAD_ATTRIBUTE; 116 break; 117 } 118 119 /* The EGL_KHR_create_context spec says: 120 * 121 * "Flags are only defined for OpenGL context creation, and 122 * specifying a flags value other than zero for other types of 123 * contexts, including OpenGL ES contexts, will generate an 124 * error." 125 */ 126 if (api != EGL_OPENGL_API && val != 0) { 127 err = EGL_BAD_ATTRIBUTE; 128 break; 129 } 130 131 ctx->Flags = val; 132 break; 133 134 case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR: 135 if (!dpy->Extensions.KHR_create_context) { 136 err = EGL_BAD_ATTRIBUTE; 137 break; 138 } 139 140 /* The EGL_KHR_create_context spec says: 141 * 142 * "[EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR] is only meaningful for 143 * OpenGL contexts, and specifying it for other types of 144 * contexts, including OpenGL ES contexts, will generate an 145 * error." 146 */ 147 if (api != EGL_OPENGL_API) { 148 err = EGL_BAD_ATTRIBUTE; 149 break; 150 } 151 152 ctx->Profile = val; 153 break; 154 155 case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR: 156 /* The EGL_KHR_create_context spec says: 157 * 158 * "[EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR] is only 159 * meaningful for OpenGL contexts, and specifying it for other 160 * types of contexts, including OpenGL ES contexts, will generate 161 * an error." 162 */ 163 if (!dpy->Extensions.KHR_create_context 164 || api != EGL_OPENGL_API) { 165 err = EGL_BAD_ATTRIBUTE; 166 break; 167 } 168 169 ctx->ResetNotificationStrategy = val; 170 break; 171 172 default: 173 err = EGL_BAD_ATTRIBUTE; 174 break; 175 } 176 177 if (err != EGL_SUCCESS) { 178 _eglLog(_EGL_DEBUG, "bad context attribute 0x%04x", attr); 179 break; 180 } 181 } 182 183 if (api == EGL_OPENGL_API) { 184 /* The EGL_KHR_create_context spec says: 185 * 186 * "If the requested OpenGL version is less than 3.2, 187 * EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR is ignored and the 188 * functionality of the context is determined solely by the 189 * requested version." 190 * 191 * Since the value is ignored, only validate the setting if the version 192 * is >= 3.2. 193 */ 194 if (ctx->ClientMajorVersion >= 4 195 || (ctx->ClientMajorVersion == 3 && ctx->ClientMinorVersion >= 2)) { 196 switch (ctx->Profile) { 197 case EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR: 198 case EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR: 199 break; 200 201 default: 202 /* The EGL_KHR_create_context spec says: 203 * 204 * "* If an OpenGL context is requested, the requested version 205 * is greater than 3.2, and the value for attribute 206 * EGL_CONTEXT_PROFILE_MASK_KHR has no bits set; has any 207 * bits set other than EGL_CONTEXT_CORE_PROFILE_BIT_KHR and 208 * EGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_KHR; has more than 209 * one of these bits set; or if the implementation does not 210 * support the requested profile, then an 211 * EGL_BAD_PROFILE_KHR error is generated." 212 * 213 * However, it does not define EGL_BAD_PROFILE_KHR. For now use 214 * EGL_BAD_ATTRIBUTE. 215 */ 216 err = EGL_BAD_ATTRIBUTE; 217 break; 218 } 219 } 220 221 /* The EGL_KHR_create_context spec says: 222 * 223 * "* If an OpenGL context is requested and the values for 224 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and 225 * EGL_CONTEXT_MINOR_VERSION_KHR, when considered together with 226 * the value for attribute 227 * EGL_CONTEXT_FORWARD_COMPATIBLE_BIT_KHR, specify an OpenGL 228 * version and feature set that are not defined, than an 229 * EGL_BAD_MATCH error is generated. 230 * 231 * ... Thus, examples of invalid combinations of attributes 232 * include: 233 * 234 * - Major version < 1 or > 4 235 * - Major version == 1 and minor version < 0 or > 5 236 * - Major version == 2 and minor version < 0 or > 1 237 * - Major version == 3 and minor version < 0 or > 2 238 * - Major version == 4 and minor version < 0 or > 2 239 * - Forward-compatible flag set and major version < 3" 240 */ 241 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0) 242 err = EGL_BAD_MATCH; 243 244 switch (ctx->ClientMajorVersion) { 245 case 1: 246 if (ctx->ClientMinorVersion > 5 247 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0) 248 err = EGL_BAD_MATCH; 249 break; 250 251 case 2: 252 if (ctx->ClientMinorVersion > 1 253 || (ctx->Flags & EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR) != 0) 254 err = EGL_BAD_MATCH; 255 break; 256 257 case 3: 258 /* Note: The text above is incorrect. There *is* an OpenGL 3.3! 259 */ 260 if (ctx->ClientMinorVersion > 3) 261 err = EGL_BAD_MATCH; 262 break; 263 264 case 4: 265 default: 266 /* Don't put additional version checks here. We don't know that 267 * there won't be versions > 4.2. 268 */ 269 break; 270 } 271 } else if (api == EGL_OPENGL_ES_API) { 272 /* The EGL_KHR_create_context spec says: 273 * 274 * "* If an OpenGL ES context is requested and the values for 275 * attributes EGL_CONTEXT_MAJOR_VERSION_KHR and 276 * EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that 277 * is not defined, than an EGL_BAD_MATCH error is generated. 278 * 279 * ... Examples of invalid combinations of attributes include: 280 * 281 * - Major version < 1 or > 2 282 * - Major version == 1 and minor version < 0 or > 1 283 * - Major version == 2 and minor version != 0 284 */ 285 if (ctx->ClientMajorVersion < 1 || ctx->ClientMinorVersion < 0) 286 err = EGL_BAD_MATCH; 287 288 switch (ctx->ClientMajorVersion) { 289 case 1: 290 if (ctx->ClientMinorVersion > 1) 291 err = EGL_BAD_MATCH; 292 break; 293 294 case 2: 295 default: 296 /* Don't put additional version checks here. We don't know that 297 * there won't be versions > 2.0. 298 */ 299 break; 300 } 301 } 302 303 switch (ctx->ResetNotificationStrategy) { 304 case EGL_NO_RESET_NOTIFICATION_KHR: 305 case EGL_LOSE_CONTEXT_ON_RESET_KHR: 306 break; 307 308 default: 309 err = EGL_BAD_ATTRIBUTE; 310 break; 311 } 312 313 if ((ctx->Flags & (EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 314 | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 315 | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) != 0) { 316 err = EGL_BAD_ATTRIBUTE; 317 } 318 319 return err; 320} 321 322 323/** 324 * Initialize the given _EGLContext object to defaults and/or the values 325 * in the attrib_list. 326 */ 327EGLBoolean 328_eglInitContext(_EGLContext *ctx, _EGLDisplay *dpy, _EGLConfig *conf, 329 const EGLint *attrib_list) 330{ 331 const EGLenum api = eglQueryAPI(); 332 EGLint err; 333 334 if (api == EGL_NONE) { 335 _eglError(EGL_BAD_MATCH, "eglCreateContext(no client API)"); 336 return EGL_FALSE; 337 } 338 339 _eglInitResource(&ctx->Resource, sizeof(*ctx), dpy); 340 ctx->ClientAPI = api; 341 ctx->Config = conf; 342 ctx->WindowRenderBuffer = EGL_NONE; 343 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; 344 345 ctx->ClientMajorVersion = 1; /* the default, per EGL spec */ 346 ctx->ClientMinorVersion = 0; 347 ctx->Flags = 0; 348 ctx->Profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; 349 ctx->ResetNotificationStrategy = EGL_NO_RESET_NOTIFICATION_KHR; 350 351 err = _eglParseContextAttribList(ctx, dpy, attrib_list); 352 if (err == EGL_SUCCESS && ctx->Config) { 353 EGLint api_bit; 354 355 api_bit = _eglGetContextAPIBit(ctx); 356 if (!(ctx->Config->RenderableType & api_bit)) { 357 _eglLog(_EGL_DEBUG, "context api is 0x%x while config supports 0x%x", 358 api_bit, ctx->Config->RenderableType); 359 err = EGL_BAD_CONFIG; 360 } 361 } 362 if (err != EGL_SUCCESS) 363 return _eglError(err, "eglCreateContext"); 364 365 return EGL_TRUE; 366} 367 368 369static EGLint 370_eglQueryContextRenderBuffer(_EGLContext *ctx) 371{ 372 _EGLSurface *surf = ctx->DrawSurface; 373 EGLint rb; 374 375 if (!surf) 376 return EGL_NONE; 377 if (surf->Type == EGL_WINDOW_BIT && ctx->WindowRenderBuffer != EGL_NONE) 378 rb = ctx->WindowRenderBuffer; 379 else 380 rb = surf->RenderBuffer; 381 return rb; 382} 383 384 385EGLBoolean 386_eglQueryContext(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *c, 387 EGLint attribute, EGLint *value) 388{ 389 (void) drv; 390 (void) dpy; 391 392 if (!value) 393 return _eglError(EGL_BAD_PARAMETER, "eglQueryContext"); 394 395 switch (attribute) { 396 case EGL_CONFIG_ID: 397 if (!c->Config) 398 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); 399 *value = c->Config->ConfigID; 400 break; 401 case EGL_CONTEXT_CLIENT_VERSION: 402 *value = c->ClientMajorVersion; 403 break; 404 case EGL_CONTEXT_CLIENT_TYPE: 405 *value = c->ClientAPI; 406 break; 407 case EGL_RENDER_BUFFER: 408 *value = _eglQueryContextRenderBuffer(c); 409 break; 410 default: 411 return _eglError(EGL_BAD_ATTRIBUTE, "eglQueryContext"); 412 } 413 414 return EGL_TRUE; 415} 416 417 418/** 419 * Bind the context to the thread and return the previous context. 420 * 421 * Note that the context may be NULL. 422 */ 423static _EGLContext * 424_eglBindContextToThread(_EGLContext *ctx, _EGLThreadInfo *t) 425{ 426 EGLint apiIndex; 427 _EGLContext *oldCtx; 428 429 apiIndex = (ctx) ? 430 _eglConvertApiToIndex(ctx->ClientAPI) : t->CurrentAPIIndex; 431 432 oldCtx = t->CurrentContexts[apiIndex]; 433 if (ctx != oldCtx) { 434 if (oldCtx) 435 oldCtx->Binding = NULL; 436 if (ctx) 437 ctx->Binding = t; 438 439 t->CurrentContexts[apiIndex] = ctx; 440 } 441 442 return oldCtx; 443} 444 445 446/** 447 * Return true if the given context and surfaces can be made current. 448 */ 449static EGLBoolean 450_eglCheckMakeCurrent(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read) 451{ 452 _EGLThreadInfo *t = _eglGetCurrentThread(); 453 _EGLDisplay *dpy; 454 EGLint conflict_api; 455 456 if (_eglIsCurrentThreadDummy()) 457 return _eglError(EGL_BAD_ALLOC, "eglMakeCurrent"); 458 459 /* this is easy */ 460 if (!ctx) { 461 if (draw || read) 462 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); 463 return EGL_TRUE; 464 } 465 466 dpy = ctx->Resource.Display; 467 if (!dpy->Extensions.KHR_surfaceless_context 468 && (draw == NULL || read == NULL)) 469 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); 470 471 /* 472 * The spec says 473 * 474 * "If ctx is current to some other thread, or if either draw or read are 475 * bound to contexts in another thread, an EGL_BAD_ACCESS error is 476 * generated." 477 * 478 * and 479 * 480 * "at most one context may be bound to a particular surface at a given 481 * time" 482 */ 483 if (ctx->Binding && ctx->Binding != t) 484 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 485 if (draw && draw->CurrentContext && draw->CurrentContext != ctx) { 486 if (draw->CurrentContext->Binding != t || 487 draw->CurrentContext->ClientAPI != ctx->ClientAPI) 488 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 489 } 490 if (read && read->CurrentContext && read->CurrentContext != ctx) { 491 if (read->CurrentContext->Binding != t || 492 read->CurrentContext->ClientAPI != ctx->ClientAPI) 493 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 494 } 495 496 /* simply require the configs to be equal */ 497 if ((draw && draw->Config != ctx->Config) || 498 (read && read->Config != ctx->Config)) 499 return _eglError(EGL_BAD_MATCH, "eglMakeCurrent"); 500 501 switch (ctx->ClientAPI) { 502 /* OpenGL and OpenGL ES are conflicting */ 503 case EGL_OPENGL_ES_API: 504 conflict_api = EGL_OPENGL_API; 505 break; 506 case EGL_OPENGL_API: 507 conflict_api = EGL_OPENGL_ES_API; 508 break; 509 default: 510 conflict_api = -1; 511 break; 512 } 513 514 if (conflict_api >= 0 && _eglGetAPIContext(conflict_api)) 515 return _eglError(EGL_BAD_ACCESS, "eglMakeCurrent"); 516 517 return EGL_TRUE; 518} 519 520 521/** 522 * Bind the context to the current thread and given surfaces. Return the 523 * previous bound context and surfaces. The caller should unreference the 524 * returned context and surfaces. 525 * 526 * Making a second call with the resources returned by the first call 527 * unsurprisingly undoes the first call, except for the resouce reference 528 * counts. 529 */ 530EGLBoolean 531_eglBindContext(_EGLContext *ctx, _EGLSurface *draw, _EGLSurface *read, 532 _EGLContext **old_ctx, 533 _EGLSurface **old_draw, _EGLSurface **old_read) 534{ 535 _EGLThreadInfo *t = _eglGetCurrentThread(); 536 _EGLContext *prev_ctx; 537 _EGLSurface *prev_draw, *prev_read; 538 539 if (!_eglCheckMakeCurrent(ctx, draw, read)) 540 return EGL_FALSE; 541 542 /* increment refcounts before binding */ 543 _eglGetContext(ctx); 544 _eglGetSurface(draw); 545 _eglGetSurface(read); 546 547 /* bind the new context */ 548 prev_ctx = _eglBindContextToThread(ctx, t); 549 550 /* break previous bindings */ 551 if (prev_ctx) { 552 prev_draw = prev_ctx->DrawSurface; 553 prev_read = prev_ctx->ReadSurface; 554 555 if (prev_draw) 556 prev_draw->CurrentContext = NULL; 557 if (prev_read) 558 prev_read->CurrentContext = NULL; 559 560 prev_ctx->DrawSurface = NULL; 561 prev_ctx->ReadSurface = NULL; 562 } 563 else { 564 prev_draw = prev_read = NULL; 565 } 566 567 /* establish new bindings */ 568 if (ctx) { 569 if (draw) 570 draw->CurrentContext = ctx; 571 if (read) 572 read->CurrentContext = ctx; 573 574 ctx->DrawSurface = draw; 575 ctx->ReadSurface = read; 576 } 577 578 assert(old_ctx && old_draw && old_read); 579 *old_ctx = prev_ctx; 580 *old_draw = prev_draw; 581 *old_read = prev_read; 582 583 return EGL_TRUE; 584} 585