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