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