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