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