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