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