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 }