1 /// Translated from C to D 2 module context; 3 4 extern(C): @nogc: nothrow: __gshared: 5 //======================================================================== 6 // GLFW 3.3 - www.glfw.org 7 //------------------------------------------------------------------------ 8 // Copyright (c) 2002-2006 Marcus Geelnard 9 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org> 10 // 11 // This software is provided 'as-is', without any express or implied 12 // warranty. In no event will the authors be held liable for any damages 13 // arising from the use of this software. 14 // 15 // Permission is granted to anyone to use this software for any purpose, 16 // including commercial applications, and to alter it and redistribute it 17 // freely, subject to the following restrictions: 18 // 19 // 1. The origin of this software must not be misrepresented; you must not 20 // claim that you wrote the original software. If you use this software 21 // in a product, an acknowledgment in the product documentation would 22 // be appreciated but is not required. 23 // 24 // 2. Altered source versions must be plainly marked as such, and must not 25 // be misrepresented as being the original software. 26 // 27 // 3. This notice may not be removed or altered from any source 28 // distribution. 29 // 30 //======================================================================== 31 // Please use C89 style variable declarations in this file because VS 2010 32 //======================================================================== 33 34 import glfw3.internal; 35 36 import core.stdc.assert_; 37 import core.stdc.stdio; 38 import core.stdc.string; 39 import core.stdc.limits; 40 import core.stdc.stdio; 41 42 ////////////////////////////////////////////////////////////////////////// 43 ////// GLFW internal API ////// 44 ////////////////////////////////////////////////////////////////////////// 45 46 // Checks whether the desired context attributes are valid 47 // 48 // This function checks things like whether the specified client API version 49 // exists and whether all relevant options have supported and non-conflicting 50 // values 51 // 52 GLFWbool _glfwIsValidContextConfig(const(_GLFWctxconfig)* ctxconfig) { 53 if (ctxconfig.share) 54 { 55 if (ctxconfig.client == GLFW_NO_API || 56 ctxconfig.share.context.client == GLFW_NO_API) 57 { 58 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, null); 59 return GLFW_FALSE; 60 } 61 } 62 63 if (ctxconfig.source != GLFW_NATIVE_CONTEXT_API && 64 ctxconfig.source != GLFW_EGL_CONTEXT_API && 65 ctxconfig.source != GLFW_OSMESA_CONTEXT_API) 66 { 67 _glfwInputError(GLFW_INVALID_ENUM, 68 "Invalid context creation API 0x%08X", 69 ctxconfig.source); 70 return GLFW_FALSE; 71 } 72 73 if (ctxconfig.client != GLFW_NO_API && 74 ctxconfig.client != GLFW_OPENGL_API && 75 ctxconfig.client != GLFW_OPENGL_ES_API) 76 { 77 _glfwInputError(GLFW_INVALID_ENUM, 78 "Invalid client API 0x%08X", 79 ctxconfig.client); 80 return GLFW_FALSE; 81 } 82 83 if (ctxconfig.client == GLFW_OPENGL_API) 84 { 85 if ((ctxconfig.major < 1 || ctxconfig.minor < 0) || 86 (ctxconfig.major == 1 && ctxconfig.minor > 5) || 87 (ctxconfig.major == 2 && ctxconfig.minor > 1) || 88 (ctxconfig.major == 3 && ctxconfig.minor > 3)) 89 { 90 // OpenGL 1.0 is the smallest valid version 91 // OpenGL 1.x series ended with version 1.5 92 // OpenGL 2.x series ended with version 2.1 93 // OpenGL 3.x series ended with version 3.3 94 // For now, let everything else through 95 96 _glfwInputError(GLFW_INVALID_VALUE, 97 "Invalid OpenGL version %i.%i", 98 ctxconfig.major, ctxconfig.minor); 99 return GLFW_FALSE; 100 } 101 102 if (ctxconfig.profile) 103 { 104 if (ctxconfig.profile != GLFW_OPENGL_CORE_PROFILE && 105 ctxconfig.profile != GLFW_OPENGL_COMPAT_PROFILE) 106 { 107 _glfwInputError(GLFW_INVALID_ENUM, 108 "Invalid OpenGL profile 0x%08X", 109 ctxconfig.profile); 110 return GLFW_FALSE; 111 } 112 113 if (ctxconfig.major <= 2 || 114 (ctxconfig.major == 3 && ctxconfig.minor < 2)) 115 { 116 // Desktop OpenGL context profiles are only defined for version 3.2 117 // and above 118 119 _glfwInputError(GLFW_INVALID_VALUE, 120 "Context profiles are only defined for OpenGL version 3.2 and above"); 121 return GLFW_FALSE; 122 } 123 } 124 125 if (ctxconfig.forward && ctxconfig.major <= 2) 126 { 127 // Forward-compatible contexts are only defined for OpenGL version 3.0 and above 128 _glfwInputError(GLFW_INVALID_VALUE, 129 "Forward-compatibility is only defined for OpenGL version 3.0 and above"); 130 return GLFW_FALSE; 131 } 132 } 133 else if (ctxconfig.client == GLFW_OPENGL_ES_API) 134 { 135 if (ctxconfig.major < 1 || ctxconfig.minor < 0 || 136 (ctxconfig.major == 1 && ctxconfig.minor > 1) || 137 (ctxconfig.major == 2 && ctxconfig.minor > 0)) 138 { 139 // OpenGL ES 1.0 is the smallest valid version 140 // OpenGL ES 1.x series ended with version 1.1 141 // OpenGL ES 2.x series ended with version 2.0 142 // For now, let everything else through 143 144 _glfwInputError(GLFW_INVALID_VALUE, 145 "Invalid OpenGL ES version %i.%i", 146 ctxconfig.major, ctxconfig.minor); 147 return GLFW_FALSE; 148 } 149 } 150 151 if (ctxconfig.robustness) 152 { 153 if (ctxconfig.robustness != GLFW_NO_RESET_NOTIFICATION && 154 ctxconfig.robustness != GLFW_LOSE_CONTEXT_ON_RESET) 155 { 156 _glfwInputError(GLFW_INVALID_ENUM, 157 "Invalid context robustness mode 0x%08X", 158 ctxconfig.robustness); 159 return GLFW_FALSE; 160 } 161 } 162 163 if (ctxconfig.release) 164 { 165 if (ctxconfig.release != GLFW_RELEASE_BEHAVIOR_NONE && 166 ctxconfig.release != GLFW_RELEASE_BEHAVIOR_FLUSH) 167 { 168 _glfwInputError(GLFW_INVALID_ENUM, 169 "Invalid context release behavior 0x%08X", 170 ctxconfig.release); 171 return GLFW_FALSE; 172 } 173 } 174 175 return GLFW_TRUE; 176 } 177 178 // Chooses the framebuffer config that best matches the desired one 179 // 180 const(_GLFWfbconfig)* _glfwChooseFBConfig(const(_GLFWfbconfig)* desired, const(_GLFWfbconfig)* alternatives, uint count) { 181 uint i; 182 uint missing;uint leastMissing = UINT_MAX; 183 uint colorDiff;uint leastColorDiff = UINT_MAX; 184 uint extraDiff;uint leastExtraDiff = UINT_MAX; 185 const(_GLFWfbconfig)* current; 186 const(_GLFWfbconfig)* closest = null; 187 188 for (i = 0; i < count; i++) 189 { 190 current = alternatives + i; 191 192 if (desired.stereo > 0 && current.stereo == 0) 193 { 194 // Stereo is a hard constraint 195 continue; 196 } 197 198 if (desired.doublebuffer != current.doublebuffer) 199 { 200 // Double buffering 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, const(_GLFWctxconfig)* ctxconfig) { 346 int i; 347 _GLFWwindow* previous; 348 const(char)* version_; 349 static immutable char*[4] prefixes = [ 350 "OpenGL ES-CM ", 351 "OpenGL ES-CL ", 352 "OpenGL ES ", 353 null 354 ]; 355 356 window.context.source = ctxconfig.source; 357 window.context.client = GLFW_OPENGL_API; 358 359 previous = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); 360 glfwMakeContextCurrent(cast(GLFWwindow*) window); 361 362 window.context.GetIntegerv = cast(PFNGLGETINTEGERVPROC) 363 window.context.getProcAddress("glGetIntegerv"); 364 window.context.GetString = cast(PFNGLGETSTRINGPROC) 365 window.context.getProcAddress("glGetString"); 366 if (!window.context.GetIntegerv || !window.context.GetString) 367 { 368 _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); 369 glfwMakeContextCurrent(cast(GLFWwindow*) previous); 370 return GLFW_FALSE; 371 } 372 373 version_ = cast(const(char)*) window.context.GetString(GL_VERSION); 374 if (!version_) 375 { 376 if (ctxconfig.client == GLFW_OPENGL_API) 377 { 378 _glfwInputError(GLFW_PLATFORM_ERROR, 379 "OpenGL version string retrieval is broken"); 380 } 381 else 382 { 383 _glfwInputError(GLFW_PLATFORM_ERROR, 384 "OpenGL ES version string retrieval is broken"); 385 } 386 387 glfwMakeContextCurrent(cast(GLFWwindow*) previous); 388 return GLFW_FALSE; 389 } 390 391 for (i = 0; prefixes[i]; i++) 392 { 393 const(size_t) length = strlen(prefixes[i]); 394 395 if (strncmp(version_, prefixes[i], length) == 0) 396 { 397 version_ += length; 398 window.context.client = GLFW_OPENGL_ES_API; 399 break; 400 } 401 } 402 403 if (!sscanf(version_, "%d.%d.%d", 404 &window.context.major, 405 &window.context.minor, 406 &window.context.revision)) 407 { 408 if (window.context.client == GLFW_OPENGL_API) 409 { 410 _glfwInputError(GLFW_PLATFORM_ERROR, 411 "No version found in OpenGL version string"); 412 } 413 else 414 { 415 _glfwInputError(GLFW_PLATFORM_ERROR, 416 "No version found in OpenGL ES version string"); 417 } 418 419 glfwMakeContextCurrent(cast(GLFWwindow*) previous); 420 return GLFW_FALSE; 421 } 422 423 if (window.context.major < ctxconfig.major || 424 (window.context.major == ctxconfig.major && 425 window.context.minor < ctxconfig.minor)) 426 { 427 // The desired OpenGL version is greater than the actual version 428 // This only happens if the machine lacks {GLX|WGL}_ARB_create_context 429 // /and/ the user has requested an OpenGL version greater than 1.0 430 431 // For API consistency, we emulate the behavior of the 432 // {GLX|WGL}_ARB_create_context extension and fail here 433 434 if (window.context.client == GLFW_OPENGL_API) 435 { 436 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 437 "Requested OpenGL version %i.%i, got version %i.%i", 438 ctxconfig.major, ctxconfig.minor, 439 window.context.major, window.context.minor); 440 } 441 else 442 { 443 _glfwInputError(GLFW_VERSION_UNAVAILABLE, 444 "Requested OpenGL ES version %i.%i, got version %i.%i", 445 ctxconfig.major, ctxconfig.minor, 446 window.context.major, window.context.minor); 447 } 448 449 glfwMakeContextCurrent(cast(GLFWwindow*) previous); 450 return GLFW_FALSE; 451 } 452 453 if (window.context.major >= 3) 454 { 455 // OpenGL 3.0+ uses a different function for extension string retrieval 456 // We cache it here instead of in glfwExtensionSupported mostly to alert 457 // users as early as possible that their build may be broken 458 459 window.context.GetStringi = cast(PFNGLGETSTRINGIPROC) 460 window.context.getProcAddress("glGetStringi"); 461 if (!window.context.GetStringi) 462 { 463 _glfwInputError(GLFW_PLATFORM_ERROR, 464 "Entry point retrieval is broken"); 465 glfwMakeContextCurrent(cast(GLFWwindow*) previous); 466 return GLFW_FALSE; 467 } 468 } 469 470 if (window.context.client == GLFW_OPENGL_API) 471 { 472 // Read back context flags (OpenGL 3.0 and above) 473 if (window.context.major >= 3) 474 { 475 GLint flags; 476 window.context.GetIntegerv(GL_CONTEXT_FLAGS, &flags); 477 478 if (flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT) 479 window.context.forward = GLFW_TRUE; 480 481 if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) 482 window.context.debug_ = GLFW_TRUE; 483 else if (glfwExtensionSupported("GL_ARB_debug_output") && 484 ctxconfig.debug_) 485 { 486 // HACK: This is a workaround for older drivers (pre KHR_debug) 487 // not setting the debug bit in the context flags for 488 // debug contexts 489 window.context.debug_ = GLFW_TRUE; 490 } 491 492 if (flags & GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR) 493 window.context.noerror = GLFW_TRUE; 494 } 495 496 // Read back OpenGL context profile (OpenGL 3.2 and above) 497 if (window.context.major >= 4 || 498 (window.context.major == 3 && window.context.minor >= 2)) 499 { 500 GLint mask; 501 window.context.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &mask); 502 503 if (mask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) 504 window.context.profile = GLFW_OPENGL_COMPAT_PROFILE; 505 else if (mask & GL_CONTEXT_CORE_PROFILE_BIT) 506 window.context.profile = GLFW_OPENGL_CORE_PROFILE; 507 else if (glfwExtensionSupported("GL_ARB_compatibility")) 508 { 509 // HACK: This is a workaround for the compatibility profile bit 510 // not being set in the context flags if an OpenGL 3.2+ 511 // context was created without having requested a specific 512 // version 513 window.context.profile = GLFW_OPENGL_COMPAT_PROFILE; 514 } 515 } 516 517 // Read back robustness strategy 518 if (glfwExtensionSupported("GL_ARB_robustness")) 519 { 520 // NOTE: We avoid using the context flags for detection, as they are 521 // only present from 3.0 while the extension applies from 1.1 522 523 GLint strategy; 524 window.context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, 525 &strategy); 526 527 if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) 528 window.context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; 529 else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) 530 window.context.robustness = GLFW_NO_RESET_NOTIFICATION; 531 } 532 } 533 else 534 { 535 // Read back robustness strategy 536 if (glfwExtensionSupported("GL_EXT_robustness")) 537 { 538 // NOTE: The values of these constants match those of the OpenGL ARB 539 // one, so we can reuse them here 540 541 GLint strategy; 542 window.context.GetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB, 543 &strategy); 544 545 if (strategy == GL_LOSE_CONTEXT_ON_RESET_ARB) 546 window.context.robustness = GLFW_LOSE_CONTEXT_ON_RESET; 547 else if (strategy == GL_NO_RESET_NOTIFICATION_ARB) 548 window.context.robustness = GLFW_NO_RESET_NOTIFICATION; 549 } 550 } 551 552 if (glfwExtensionSupported("GL_KHR_context_flush_control")) 553 { 554 GLint behavior; 555 window.context.GetIntegerv(GL_CONTEXT_RELEASE_BEHAVIOR, &behavior); 556 557 if (behavior == GL_NONE) 558 window.context.release = GLFW_RELEASE_BEHAVIOR_NONE; 559 else if (behavior == GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH) 560 window.context.release = GLFW_RELEASE_BEHAVIOR_FLUSH; 561 } 562 563 // Clearing the front buffer to black to avoid garbage pixels left over from 564 // previous uses of our bit of VRAM 565 { 566 PFNGLCLEARPROC glClear = cast(PFNGLCLEARPROC) 567 window.context.getProcAddress("glClear"); 568 glClear(GL_COLOR_BUFFER_BIT); 569 window.context.swapBuffers(window); 570 } 571 572 glfwMakeContextCurrent(cast(GLFWwindow*) previous); 573 return GLFW_TRUE; 574 } 575 576 // Searches an extension string for the specified extension 577 // 578 GLFWbool _glfwStringInExtensionString(const(char)* string, const(char)* extensions) { 579 const(char)* start = extensions; 580 581 for (;;) 582 { 583 const(char)* where; 584 const(char)* terminator; 585 586 where = strstr(start, string); 587 if (!where) 588 return GLFW_FALSE; 589 590 terminator = where + strlen(string); 591 if (where == start || *(where - 1) == ' ') 592 { 593 if (*terminator == ' ' || *terminator == '\0') 594 break; 595 } 596 597 start = terminator; 598 } 599 600 return GLFW_TRUE; 601 } 602 603 604 ////////////////////////////////////////////////////////////////////////// 605 ////// GLFW public API ////// 606 ////////////////////////////////////////////////////////////////////////// 607 608 void glfwMakeContextCurrent(GLFWwindow* handle) { 609 _GLFWwindow* window = cast(_GLFWwindow*) handle; 610 _GLFWwindow* previous = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); 611 612 mixin(_GLFW_REQUIRE_INIT); 613 614 if (window && window.context.client == GLFW_NO_API) 615 { 616 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, 617 "Cannot make current with a window that has no OpenGL or OpenGL ES context"); 618 return; 619 } 620 621 if (previous) 622 { 623 if (!window || window.context.source != previous.context.source) 624 previous.context.makeCurrent(null); 625 } 626 627 if (window) 628 window.context.makeCurrent(window); 629 } 630 631 GLFWwindow* glfwGetCurrentContext() { 632 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 633 return cast(GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); 634 } 635 636 void glfwSwapBuffers(GLFWwindow* handle) { 637 _GLFWwindow* window = cast(_GLFWwindow*) handle; 638 assert(window != null); 639 640 mixin(_GLFW_REQUIRE_INIT); 641 642 if (window.context.client == GLFW_NO_API) 643 { 644 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, 645 "Cannot swap buffers of a window that has no OpenGL or OpenGL ES context"); 646 return; 647 } 648 649 window.context.swapBuffers(window); 650 } 651 652 void glfwSwapInterval(int interval) { 653 _GLFWwindow* window; 654 655 mixin(_GLFW_REQUIRE_INIT); 656 657 window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); 658 if (!window) 659 { 660 _glfwInputError(GLFW_NO_CURRENT_CONTEXT, 661 "Cannot set swap interval without a current OpenGL or OpenGL ES context"); 662 return; 663 } 664 665 window.context.swapInterval(interval); 666 } 667 668 int glfwExtensionSupported(const(char)* extension) { 669 _GLFWwindow* window; 670 assert(extension != null); 671 672 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); 673 674 window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); 675 if (!window) 676 { 677 _glfwInputError(GLFW_NO_CURRENT_CONTEXT, 678 "Cannot query extension without a current OpenGL or OpenGL ES context"); 679 return GLFW_FALSE; 680 } 681 682 if (*extension == '\0') 683 { 684 _glfwInputError(GLFW_INVALID_VALUE, "Extension name cannot be an empty string"); 685 return GLFW_FALSE; 686 } 687 688 if (window.context.major >= 3) 689 { 690 int i; 691 GLint count; 692 693 // Check if extension is in the modern OpenGL extensions string list 694 695 window.context.GetIntegerv(GL_NUM_EXTENSIONS, &count); 696 697 for (i = 0; i < count; i++) 698 { 699 const(char)* en = cast(const(char)*) 700 window.context.GetStringi(GL_EXTENSIONS, i); 701 if (!en) 702 { 703 _glfwInputError(GLFW_PLATFORM_ERROR, 704 "Extension string retrieval is broken"); 705 return GLFW_FALSE; 706 } 707 708 if (strcmp(en, extension) == 0) 709 return GLFW_TRUE; 710 } 711 } 712 else 713 { 714 // Check if extension is in the old style OpenGL extensions string 715 716 const(char)* extensions = cast(const(char)*) 717 window.context.GetString(GL_EXTENSIONS); 718 if (!extensions) 719 { 720 _glfwInputError(GLFW_PLATFORM_ERROR, 721 "Extension string retrieval is broken"); 722 return GLFW_FALSE; 723 } 724 725 if (_glfwStringInExtensionString(extension, extensions)) 726 return GLFW_TRUE; 727 } 728 729 // Check if extension is in the platform-specific string 730 return window.context.extensionSupported(extension); 731 } 732 733 GLFWglproc glfwGetProcAddress(const(char)* procname) { 734 _GLFWwindow* window; 735 assert(procname != null); 736 737 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 738 739 window = cast(_GLFWwindow*) _glfwPlatformGetTls(&_glfw.contextSlot); 740 if (!window) 741 { 742 _glfwInputError(GLFW_NO_CURRENT_CONTEXT, 743 "Cannot query entry point without a current OpenGL or OpenGL ES context"); 744 return null; 745 } 746 747 return window.context.getProcAddress(procname); 748 }