context.c (25670B)
1 //======================================================================== 2 // GLFW 3.4 - www.glfw.org 3 //------------------------------------------------------------------------ 4 // Copyright (c) 2002-2006 Marcus Geelnard 5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> 6 // 7 // This software is provided 'as-is', without any express or implied 8 // warranty. In no event will the authors be held liable for any damages 9 // arising from the use of this software. 10 // 11 // Permission is granted to anyone to use this software for any purpose, 12 // including commercial applications, and to alter it and redistribute it 13 // freely, subject to the following restrictions: 14 // 15 // 1. The origin of this software must not be misrepresented; you must not 16 // claim that you wrote the original software. If you use this software 17 // in a product, an acknowledgment in the product documentation would 18 // be appreciated but is not required. 19 // 20 // 2. Altered source versions must be plainly marked as such, and must not 21 // be misrepresented as being the original software. 22 // 23 // 3. This notice may not be removed or altered from any source 24 // distribution. 25 // 26 //======================================================================== 27 28 #include "internal.h" 29 30 #include <assert.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <limits.h> 34 #include <stdio.h> 35 36 37 ////////////////////////////////////////////////////////////////////////// 38 ////// GLFW internal API ////// 39 ////////////////////////////////////////////////////////////////////////// 40 41 // Checks whether the desired context attributes are valid 42 // 43 // This function checks things like whether the specified client API version 44 // exists and whether all relevant options have supported and non-conflicting 45 // values 46 // 47 GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig) 48 { 49 if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API && 50 ctxconfig->source != GLFW_EGL_CONTEXT_API && 51 ctxconfig->source != GLFW_OSMESA_CONTEXT_API) 52 { 53 _glfwInputError(GLFW_INVALID_ENUM, 54 "Invalid context creation API 0x%08X", 55 ctxconfig->source); 56 return GLFW_FALSE; 57 } 58 59 if (ctxconfig->client != GLFW_NO_API && 60 ctxconfig->client != GLFW_OPENGL_API && 61 ctxconfig->client != GLFW_OPENGL_ES_API) 62 { 63 _glfwInputError(GLFW_INVALID_ENUM, 64 "Invalid client API 0x%08X", 65 ctxconfig->client); 66 return GLFW_FALSE; 67 } 68 69 if (ctxconfig->share) 70 { 71 if (ctxconfig->client == GLFW_NO_API || 72 ctxconfig->share->context.client == GLFW_NO_API) 73 { 74 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); 75 return GLFW_FALSE; 76 } 77 78 if (ctxconfig->source != ctxconfig->share->context.source) 79 { 80 _glfwInputError(GLFW_INVALID_ENUM, 81 "Context creation APIs do not match between contexts"); 82 return GLFW_FALSE; 83 } 84 } 85 86 if (ctxconfig->client == GLFW_OPENGL_API) 87 { 88 if ((ctxconfig->major < 1 || ctxconfig->minor < 0) || 89 (ctxconfig->major == 1 && ctxconfig->minor > 5) || 90 (ctxconfig->major == 2 && ctxconfig->minor > 1) || 91 (ctxconfig->major == 3 && ctxconfig->minor > 3)) 92 { 93 // OpenGL 1.0 is the smallest valid version 94 // OpenGL 1.x series ended with version 1.5 95 // OpenGL 2.x series ended with version 2.1 96 // OpenGL 3.x series ended with version 3.3 97 // For now, let everything else through 98 99 _glfwInputError(GLFW_INVALID_VALUE, 100 "Invalid OpenGL version %i.%i", 101 ctxconfig->major, ctxconfig->minor); 102 return GLFW_FALSE; 103 } 104 105 if (ctxconfig->profile) 106 { 107 if (ctxconfig->profile != GLFW_OPENGL_CORE_PROFILE && 108 ctxconfig->profile != GLFW_OPENGL_COMPAT_PROFILE) 109 { 110 _glfwInputError(GLFW_INVALID_ENUM, 111 "Invalid OpenGL profile 0x%08X", 112 ctxconfig->profile); 113 return GLFW_FALSE; 114 } 115 116 if (ctxconfig->major <= 2 || 117 (ctxconfig->major == 3 && ctxconfig->minor < 2)) 118 { 119 // Desktop OpenGL context profiles are only defined for version 3.2 120 // and above 121 122 _glfwInputError(GLFW_INVALID_VALUE, 123 "Context profiles are only defined for OpenGL version 3.2 and above"); 124 return GLFW_FALSE; 125 } 126 } 127 128 if (ctxconfig->forward && ctxconfig->major <= 2) 129 { 130 // Forward-compatible contexts are only defined for OpenGL version 3.0 and above 131 _glfwInputError(GLFW_INVALID_VALUE, 132 "Forward-compatibility is only defined for OpenGL version 3.0 and above"); 133 return GLFW_FALSE; 134 } 135 } 136 else if (ctxconfig->client == GLFW_OPENGL_ES_API) 137 { 138 if (ctxconfig->major < 1 || ctxconfig->minor < 0 || 139 (ctxconfig->major == 1 && ctxconfig->minor > 1) || 140 (ctxconfig->major == 2 && ctxconfig->minor > 0)) 141 { 142 // OpenGL ES 1.0 is the smallest valid version 143 // OpenGL ES 1.x series ended with version 1.1 144 // OpenGL ES 2.x series ended with version 2.0 145 // For now, let everything else through 146 147 _glfwInputError(GLFW_INVALID_VALUE, 148 "Invalid OpenGL ES version %i.%i", 149 ctxconfig->major, ctxconfig->minor); 150 return GLFW_FALSE; 151 } 152 } 153 154 if (ctxconfig->robustness) 155 { 156 if (ctxconfig->robustness != GLFW_NO_RESET_NOTIFICATION && 157 ctxconfig->robustness != GLFW_LOSE_CONTEXT_ON_RESET) 158 { 159 _glfwInputError(GLFW_INVALID_ENUM, 160 "Invalid context robustness mode 0x%08X", 161 ctxconfig->robustness); 162 return GLFW_FALSE; 163 } 164 } 165 166 if (ctxconfig->release) 167 { 168 if (ctxconfig->release != GLFW_RELEASE_BEHAVIOR_NONE && 169 ctxconfig->release != GLFW_RELEASE_BEHAVIOR_FLUSH) 170 { 171 _glfwInputError(GLFW_INVALID_ENUM, 172 "Invalid context release behavior 0x%08X", 173 ctxconfig->release); 174 return GLFW_FALSE; 175 } 176 } 177 178 return GLFW_TRUE; 179 } 180 181 // Chooses the framebuffer config that best matches the desired one 182 // 183 const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, 184 const _GLFWfbconfig* alternatives, 185 unsigned int count) 186 { 187 unsigned int i; 188 unsigned int missing, leastMissing = UINT_MAX; 189 unsigned int colorDiff, leastColorDiff = UINT_MAX; 190 unsigned int extraDiff, leastExtraDiff = UINT_MAX; 191 const _GLFWfbconfig* current; 192 const _GLFWfbconfig* closest = NULL; 193 194 for (i = 0; i < count; i++) 195 { 196 current = alternatives + i; 197 198 if (desired->stereo > 0 && current->stereo == 0) 199 { 200 // Stereo is a hard constraint 201 continue; 202 } 203 204 // Count number of missing buffers 205 { 206 missing = 0; 207 208 if (desired->alphaBits > 0 && current->alphaBits == 0) 209 missing++; 210 211 if (desired->depthBits > 0 && current->depthBits == 0) 212 missing++; 213 214 if (desired->stencilBits > 0 && current->stencilBits == 0) 215 missing++; 216 217 if (desired->auxBuffers > 0 && 218 current->auxBuffers < desired->auxBuffers) 219 { 220 missing += desired->auxBuffers - current->auxBuffers; 221 } 222 223 if (desired->samples > 0 && current->samples == 0) 224 { 225 // Technically, several multisampling buffers could be 226 // involved, but that's a lower level implementation detail and 227 // not important to us here, so we count them as one 228 missing++; 229 } 230 231 if (desired->transparent != current->transparent) 232 missing++; 233 } 234 235 // These polynomials make many small channel size differences matter 236 // less than one large channel size difference 237 238 // Calculate color channel size difference value 239 { 240 colorDiff = 0; 241 242 if (desired->redBits != GLFW_DONT_CARE) 243 { 244 colorDiff += (desired->redBits - current->redBits) * 245 (desired->redBits - current->redBits); 246 } 247 248 if (desired->greenBits != GLFW_DONT_CARE) 249 { 250 colorDiff += (desired->greenBits - current->greenBits) * 251 (desired->greenBits - current->greenBits); 252 } 253 254 if (desired->blueBits != GLFW_DONT_CARE) 255 { 256 colorDiff += (desired->blueBits - current->blueBits) * 257 (desired->blueBits - current->blueBits); 258 } 259 } 260 261 // Calculate non-color channel size difference value 262 { 263 extraDiff = 0; 264 265 if (desired->alphaBits != GLFW_DONT_CARE) 266 { 267 extraDiff += (desired->alphaBits - current->alphaBits) * 268 (desired->alphaBits - current->alphaBits); 269 } 270 271 if (desired->depthBits != GLFW_DONT_CARE) 272 { 273 extraDiff += (desired->depthBits - current->depthBits) * 274 (desired->depthBits - current->depthBits); 275 } 276 277 if (desired->stencilBits != GLFW_DONT_CARE) 278 { 279 extraDiff += (desired->stencilBits - current->stencilBits) * 280 (desired->stencilBits - current->stencilBits); 281 } 282 283 if (desired->accumRedBits != GLFW_DONT_CARE) 284 { 285 extraDiff += (desired->accumRedBits - current->accumRedBits) * 286 (desired->accumRedBits - current->accumRedBits); 287 } 288 289 if (desired->accumGreenBits != GLFW_DONT_CARE) 290 { 291 extraDiff += (desired->accumGreenBits - current->accumGreenBits) * 292 (desired->accumGreenBits - current->accumGreenBits); 293 } 294 295 if (desired->accumBlueBits != GLFW_DONT_CARE) 296 { 297 extraDiff += (desired->accumBlueBits - current->accumBlueBits) * 298 (desired->accumBlueBits - current->accumBlueBits); 299 } 300 301 if (desired->accumAlphaBits != GLFW_DONT_CARE) 302 { 303 extraDiff += (desired->accumAlphaBits - current->accumAlphaBits) * 304 (desired->accumAlphaBits - current->accumAlphaBits); 305 } 306 307 if (desired->samples != GLFW_DONT_CARE) 308 { 309 extraDiff += (desired->samples - current->samples) * 310 (desired->samples - current->samples); 311 } 312 313 if (desired->sRGB && !current->sRGB) 314 extraDiff++; 315 } 316 317 // Figure out if the current one is better than the best one found so far 318 // Least number of missing buffers is the most important heuristic, 319 // then color buffer size match and lastly size match for other buffers 320 321 if (missing < leastMissing) 322 closest = current; 323 else if (missing == leastMissing) 324 { 325 if ((colorDiff < leastColorDiff) || 326 (colorDiff == leastColorDiff && extraDiff < leastExtraDiff)) 327 { 328 closest = current; 329 } 330 } 331 332 if (current == closest) 333 { 334 leastMissing = missing; 335 leastColorDiff = colorDiff; 336 leastExtraDiff = extraDiff; 337 } 338 } 339 340 return closest; 341 } 342 343 // Retrieves the attributes of the current context 344 // 345 GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, 346 const _GLFWctxconfig* ctxconfig) 347 { 348 int i; 349 _GLFWwindow* previous; 350 const char* version; 351 const char* prefixes[] = 352 { 353 "OpenGL ES-CM ", 354 "OpenGL ES-CL ", 355 "OpenGL ES ", 356 NULL 357 }; 358 359 window->context.source = ctxconfig->source; 360 window->context.client = GLFW_OPENGL_API; 361 362 previous = _glfwPlatformGetTls(&_glfw.contextSlot); 363 glfwMakeContextCurrent((GLFWwindow*) window); 364 if (_glfwPlatformGetTls(&_glfw.contextSlot) != window) 365 return GLFW_FALSE; 366 367 window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) 368 window->context.getProcAddress("glGetIntegerv"); 369 window->context.GetString = (PFNGLGETSTRINGPROC) 370 window->context.getProcAddress("glGetString"); 371 if (!window->context.GetIntegerv || !window->context.GetString) 372 { 373 _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); 374 glfwMakeContextCurrent((GLFWwindow*) previous); 375 return GLFW_FALSE; 376 } 377 378 version = (const char*) window->context.GetString(GL_VERSION); 379 if (!version) 380 { 381 if (ctxconfig->client == GLFW_OPENGL_API) 382 { 383 _glfwInputError(GLFW_PLATFORM_ERROR, 384 "OpenGL version string retrieval is broken"); 385 } 386 else 387 { 388 _glfwInputError(GLFW_PLATFORM_ERROR, 389 "OpenGL ES version string retrieval is broken"); 390 } 391 392 glfwMakeContextCurrent((GLFWwindow*) previous); 393 return GLFW_FALSE; 394 } 395 396 for (i = 0; prefixes[i]; i++) 397 { 398 const size_t length = strlen(prefixes[i]); 399 400 if (strncmp(version, prefixes[i], length) == 0) 401 { 402 version += length; 403 window->context.client = GLFW_OPENGL_ES_API; 404 break; 405 } 406 } 407 408 if (!sscanf(version, "%d.%d.%d", 409 &window->context.major, 410 &window->context.minor, 411 &window->context.revision)) 412 { 413 if (window->context.client == GLFW_OPENGL_API) 414 { 415 _glfwInputError(GLFW_PLATFORM_ERROR, 416 "No version found in OpenGL version string"); 417 } 418 else 419 { 420 _glfwInputError(GLFW_PLATFORM_ERROR, 421 "No version found in OpenGL ES version string"); 422 } 423 424 glfwMakeContextCurrent((GLFWwindow*) previous); 425 return GLFW_FALSE; 426 } 427 428 if (window->context.major < ctxconfig->major || 429 (window->context.major == ctxconfig->major && 430 window->context.minor < ctxconfig->minor)) 431 { 432 // The desired OpenGL version is greater than the actual version 433 // This only happens if the machine lacks {GLX|WGL}_ARB_create_context 434 // /and/ the user has requested an OpenGL version greater than 1.0 435 436 // For API consistency, we emulate the behavior of the 437 // {GLX|WGL}_ARB_create_context extension and fail here 438 439 if (window->context.client == GLFW_OPENGL_API) 440 { 441 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 442 "Requested OpenGL version %i.%i, got version %i.%i", 443 ctxconfig->major, ctxconfig->minor, 444 window->context.major, window->context.minor); 445 } 446 else 447 { 448 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 449 "Requested OpenGL ES version %i.%i, got version %i.%i", 450 ctxconfig->major, ctxconfig->minor, 451 window->context.major, window->context.minor); 452 } 453 454 glfwMakeContextCurrent((GLFWwindow*) previous); 455 return GLFW_FALSE; 456 } 457 458 if (window->context.major >= 3) 459 { 460 // OpenGL 3.0+ uses a different function for extension string retrieval 461 // We cache it here instead of in glfwExtensionSupported mostly to alert 462 // users as early as possible that their build may be broken 463 464 window->context.GetStringi = (PFNGLGETSTRINGIPROC) 465 window->context.getProcAddress("glGetStringi"); 466 if (!window->context.GetStringi) 467 { 468 _glfwInputError(GLFW_PLATFORM_ERROR, 469 "Entry point retrieval is broken"); 470 glfwMakeContextCurrent((GLFWwindow*) previous); 471 return GLFW_FALSE; 472 } 473 } 474 475 if (window->context.client == GLFW_OPENGL_API) 476 { 477 // Read back context flags (OpenGL 3.0 and above) 478 if (window->context.major >= 3) 479 { 480 GLint flags; 481 window->context.GetIntegerv(GL_CONTEXT_FLAGS, &flags); 482 483 if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) 484 window->context.forward = GLFW_TRUE; 485 486 if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) 487 window->context.debug = GLFW_TRUE; 488 else if (glfwExtensionSupported("GL_ARB_debug_output") && 489 ctxconfig->debug) 490 { 491 // HACK: This is a workaround for older drivers (pre KHR_debug) 492 // not setting the debug bit in the context flags for 493 // debug contexts 494 window->context.debug = GLFW_TRUE; 495 } 496 497 if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR) 498 window->context.noerror = GLFW_TRUE; 499 } 500 501 // Read back OpenGL context profile (OpenGL 3.2 and above) 502 if (window->context.major >= 4 || 503 (window->context.major == 3 && window->context.minor >= 2)) 504 { 505 GLint mask; 506 window->context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); 507 508 if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) 509 window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; 510 else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) 511 window->context.profile = GLFW_OPENGL_CORE_PROFILE; 512 else if (glfwExtensionSupported("GL_ARB_compatibility")) 513 { 514 // HACK: This is a workaround for the compatibility profile bit 515 // not being set in the context flags if an OpenGL 3.2+ 516 // context was created without having requested a specific 517 // version 518 window->context.profile = GLFW_OPENGL_COMPAT_PROFILE; 519 } 520 } 521 522 // Read back robustness strategy 523 if (glfwExtensionSupported("GL_ARB_robustness")) 524 { 525 // NOTE: We avoid using the context flags for detection, as they are 526 // only present from 3.0 while the extension applies from 1.1 527 528 GLint strategy; 529 window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, 530 &strategy); 531 532 if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) 533 window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; 534 else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) 535 window->context.robustness = GLFW_NO_RESET_NOTIFICATION; 536 } 537 } 538 else 539 { 540 // Read back robustness strategy 541 if (glfwExtensionSupported("GL_EXT_robustness")) 542 { 543 // NOTE: The values of these constants match those of the OpenGL ARB 544 // one, so we can reuse them here 545 546 GLint strategy; 547 window->context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, 548 &strategy); 549 550 if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) 551 window->context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; 552 else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) 553 window->context.robustness = GLFW_NO_RESET_NOTIFICATION; 554 } 555 } 556 557 if (glfwExtensionSupported("GL_KHR_context_flush_control")) 558 { 559 GLint behavior; 560 window->context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); 561 562 if (behavior == GL_NONE) 563 window->context.release = GLFW_RELEASE_BEHAVIOR_NONE; 564 else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) 565 window->context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; 566 } 567 568 // Clearing the front buffer to black to avoid garbage pixels left over from 569 // previous uses of our bit of VRAM 570 { 571 PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) 572 window->context.getProcAddress("glClear"); 573 glClear(GL_COLOR_BUFFER_BIT); 574 575 if (window->doublebuffer) 576 window->context.swapBuffers(window); 577 } 578 579 glfwMakeContextCurrent((GLFWwindow*) previous); 580 return GLFW_TRUE; 581 } 582 583 // Searches an extension string for the specified extension 584 // 585 GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions) 586 { 587 const char* start = extensions; 588 589 for (;;) 590 { 591 const char* where; 592 const char* terminator; 593 594 where = strstr(start, string); 595 if (!where) 596 return GLFW_FALSE; 597 598 terminator = where + strlen(string); 599 if (where == start || *(where - 1) == ' ') 600 { 601 if (*terminator == ' ' || *terminator == '\0') 602 break; 603 } 604 605 start = terminator; 606 } 607 608 return GLFW_TRUE; 609 } 610 611 612 ////////////////////////////////////////////////////////////////////////// 613 ////// GLFW public API ////// 614 ////////////////////////////////////////////////////////////////////////// 615 616 GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle) 617 { 618 _GLFWwindow* window = (_GLFWwindow*) handle; 619 _GLFWwindow* previous; 620 621 _GLFW_REQUIRE_INIT(); 622 623 previous = _glfwPlatformGetTls(&_glfw.contextSlot); 624 625 if (window && window->context.client == GLFW_NO_API) 626 { 627 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, 628 "Cannot make current with a window that has no OpenGL or OpenGL ES context"); 629 return; 630 } 631 632 if (previous) 633 { 634 if (!window || window->context.source != previous->context.source) 635 previous->context.makeCurrent(NULL); 636 } 637 638 if (window) 639 window->context.makeCurrent(window); 640 } 641 642 GLFWAPI GLFWwindow* glfwGetCurrentContext(void) 643 { 644 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 645 return _glfwPlatformGetTls(&_glfw.contextSlot); 646 } 647 648 GLFWAPI void glfwSwapBuffers(GLFWwindow* handle) 649 { 650 _GLFWwindow* window = (_GLFWwindow*) handle; 651 assert(window != NULL); 652 653 _GLFW_REQUIRE_INIT(); 654 655 if (window->context.client == GLFW_NO_API) 656 { 657 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, 658 "Cannot swap buffers of a window that has no OpenGL or OpenGL ES context"); 659 return; 660 } 661 662 window->context.swapBuffers(window); 663 } 664 665 GLFWAPI void glfwSwapInterval(int interval) 666 { 667 _GLFWwindow* window; 668 669 _GLFW_REQUIRE_INIT(); 670 671 window = _glfwPlatformGetTls(&_glfw.contextSlot); 672 if (!window) 673 { 674 _glfwInputError(GLFW_NO_CURRENT_CONTEXT, 675 "Cannot set swap interval without a current OpenGL or OpenGL ES context"); 676 return; 677 } 678 679 window->context.swapInterval(interval); 680 } 681 682 GLFWAPI int glfwExtensionSupported(const char* extension) 683 { 684 _GLFWwindow* window; 685 assert(extension != NULL); 686 687 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 688 689 window = _glfwPlatformGetTls(&_glfw.contextSlot); 690 if (!window) 691 { 692 _glfwInputError(GLFW_NO_CURRENT_CONTEXT, 693 "Cannot query extension without a current OpenGL or OpenGL ES context"); 694 return GLFW_FALSE; 695 } 696 697 if (*extension == '\0') 698 { 699 _glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string"); 700 return GLFW_FALSE; 701 } 702 703 if (window->context.major >= 3) 704 { 705 int i; 706 GLint count; 707 708 // Check if extension is in the modern OpenGL extensions string list 709 710 window->context.GetIntegerv(GL_NUM_EXTENSIONS, &count); 711 712 for (i = 0; i < count; i++) 713 { 714 const char* en = (const char*) 715 window->context.GetStringi(GL_EXTENSIONS, i); 716 if (!en) 717 { 718 _glfwInputError(GLFW_PLATFORM_ERROR, 719 "Extension string retrieval is broken"); 720 return GLFW_FALSE; 721 } 722 723 if (strcmp(en, extension) == 0) 724 return GLFW_TRUE; 725 } 726 } 727 else 728 { 729 // Check if extension is in the old style OpenGL extensions string 730 731 const char* extensions = (const char*) 732 window->context.GetString(GL_EXTENSIONS); 733 if (!extensions) 734 { 735 _glfwInputError(GLFW_PLATFORM_ERROR, 736 "Extension string retrieval is broken"); 737 return GLFW_FALSE; 738 } 739 740 if (_glfwStringInExtensionString(extension, extensions)) 741 return GLFW_TRUE; 742 } 743 744 // Check if extension is in the platform-specific string 745 return window->context.extensionSupported(extension); 746 } 747 748 GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname) 749 { 750 _GLFWwindow* window; 751 assert(procname != NULL); 752 753 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 754 755 window = _glfwPlatformGetTls(&_glfw.contextSlot); 756 if (!window) 757 { 758 _glfwInputError(GLFW_NO_CURRENT_CONTEXT, 759 "Cannot query entry point without a current OpenGL or OpenGL ES context"); 760 return NULL; 761 } 762 763 return window->context.getProcAddress(procname); 764 } 765