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