1 //========================================================================
2 // GLFW 3.5 WGL - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2019 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 #if defined(_GLFW_WIN32)
31
32 #include <stdlib.h>
33 #include <assert.h>
34
35 // Return the value corresponding to the specified attribute
36 //
findPixelFormatAttribValueWGL(const int * attribs,int attribCount,const int * values,int attrib)37 static int findPixelFormatAttribValueWGL(const int* attribs,
38 int attribCount,
39 const int* values,
40 int attrib)
41 {
42 int i;
43
44 for (i = 0; i < attribCount; i++)
45 {
46 if (attribs[i] == attrib)
47 return values[i];
48 }
49
50 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
51 "WGL: Unknown pixel format attribute requested");
52 return 0;
53 }
54
55 #define ADD_ATTRIB(a) \
56 { \
57 assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \
58 attribs[attribCount++] = a; \
59 }
60 #define FIND_ATTRIB_VALUE(a) \
61 findPixelFormatAttribValueWGL(attribs, attribCount, values, a)
62
63 // Return a list of available and usable framebuffer configs
64 //
choosePixelFormatWGL(_GLFWwindow * window,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)65 static int choosePixelFormatWGL(_GLFWwindow* window,
66 const _GLFWctxconfig* ctxconfig,
67 const _GLFWfbconfig* fbconfig)
68 {
69 _GLFWfbconfig* usableConfigs;
70 const _GLFWfbconfig* closest;
71 int i, pixelFormat, nativeCount, usableCount = 0, attribCount = 0;
72 int attribs[40];
73 int values[sizeof(attribs) / sizeof(attribs[0])];
74
75 nativeCount = DescribePixelFormat(window->context.wgl.dc,
76 1,
77 sizeof(PIXELFORMATDESCRIPTOR),
78 NULL);
79
80 if (_glfw.wgl.ARB_pixel_format)
81 {
82 ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB);
83 ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB);
84 ADD_ATTRIB(WGL_PIXEL_TYPE_ARB);
85 ADD_ATTRIB(WGL_ACCELERATION_ARB);
86 ADD_ATTRIB(WGL_RED_BITS_ARB);
87 ADD_ATTRIB(WGL_RED_SHIFT_ARB);
88 ADD_ATTRIB(WGL_GREEN_BITS_ARB);
89 ADD_ATTRIB(WGL_GREEN_SHIFT_ARB);
90 ADD_ATTRIB(WGL_BLUE_BITS_ARB);
91 ADD_ATTRIB(WGL_BLUE_SHIFT_ARB);
92 ADD_ATTRIB(WGL_ALPHA_BITS_ARB);
93 ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB);
94 ADD_ATTRIB(WGL_DEPTH_BITS_ARB);
95 ADD_ATTRIB(WGL_STENCIL_BITS_ARB);
96 ADD_ATTRIB(WGL_ACCUM_BITS_ARB);
97 ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB);
98 ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB);
99 ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB);
100 ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB);
101 ADD_ATTRIB(WGL_AUX_BUFFERS_ARB);
102 ADD_ATTRIB(WGL_STEREO_ARB);
103 ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB);
104
105 if (_glfw.wgl.ARB_multisample)
106 ADD_ATTRIB(WGL_SAMPLES_ARB);
107
108 if (ctxconfig->client == GLFW_OPENGL_API)
109 {
110 if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB)
111 ADD_ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
112 }
113 else
114 {
115 if (_glfw.wgl.EXT_colorspace)
116 ADD_ATTRIB(WGL_COLORSPACE_EXT);
117 }
118
119 // NOTE: In a Parallels VM WGL_ARB_pixel_format returns fewer pixel formats than
120 // DescribePixelFormat, violating the guarantees of the extension spec
121 // HACK: Iterate through the minimum of both counts
122
123 const int attrib = WGL_NUMBER_PIXEL_FORMATS_ARB;
124 int extensionCount;
125
126 if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
127 1, 0, 1, &attrib, &extensionCount))
128 {
129 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
130 "WGL: Failed to retrieve pixel format attribute");
131 return 0;
132 }
133
134 nativeCount = _glfw_min(nativeCount, extensionCount);
135 }
136
137 usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
138
139 for (i = 0; i < nativeCount; i++)
140 {
141 _GLFWfbconfig* u = usableConfigs + usableCount;
142 pixelFormat = i + 1;
143
144 if (_glfw.wgl.ARB_pixel_format)
145 {
146 // Get pixel format attributes through "modern" extension
147
148 if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
149 pixelFormat, 0,
150 attribCount,
151 attribs, values))
152 {
153 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
154 "WGL: Failed to retrieve pixel format attributes");
155
156 _glfw_free(usableConfigs);
157 return 0;
158 }
159
160 if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) ||
161 !FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB))
162 {
163 continue;
164 }
165
166 if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
167 continue;
168
169 if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
170 continue;
171
172 if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
173 continue;
174
175 u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB);
176 u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB);
177 u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB);
178 u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB);
179
180 u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB);
181 u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB);
182
183 u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB);
184 u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB);
185 u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_BITS_ARB);
186 u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB);
187
188 u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB);
189
190 if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB))
191 u->stereo = GLFW_TRUE;
192
193 if (_glfw.wgl.ARB_multisample)
194 u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB);
195
196 if (ctxconfig->client == GLFW_OPENGL_API)
197 {
198 if (_glfw.wgl.ARB_framebuffer_sRGB ||
199 _glfw.wgl.EXT_framebuffer_sRGB)
200 {
201 if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
202 u->sRGB = GLFW_TRUE;
203 }
204 }
205 else
206 {
207 if (_glfw.wgl.EXT_colorspace)
208 {
209 if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
210 u->sRGB = GLFW_TRUE;
211 }
212 }
213 }
214 else
215 {
216 // Get pixel format attributes through legacy PFDs
217
218 PIXELFORMATDESCRIPTOR pfd;
219
220 if (!DescribePixelFormat(window->context.wgl.dc,
221 pixelFormat,
222 sizeof(PIXELFORMATDESCRIPTOR),
223 &pfd))
224 {
225 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
226 "WGL: Failed to describe pixel format");
227
228 _glfw_free(usableConfigs);
229 return 0;
230 }
231
232 if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
233 !(pfd.dwFlags & PFD_SUPPORT_OPENGL))
234 {
235 continue;
236 }
237
238 if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
239 (pfd.dwFlags & PFD_GENERIC_FORMAT))
240 {
241 continue;
242 }
243
244 if (pfd.iPixelType != PFD_TYPE_RGBA)
245 continue;
246
247 if (!!(pfd.dwFlags & PFD_DOUBLEBUFFER) != fbconfig->doublebuffer)
248 continue;
249
250 u->redBits = pfd.cRedBits;
251 u->greenBits = pfd.cGreenBits;
252 u->blueBits = pfd.cBlueBits;
253 u->alphaBits = pfd.cAlphaBits;
254
255 u->depthBits = pfd.cDepthBits;
256 u->stencilBits = pfd.cStencilBits;
257
258 u->accumRedBits = pfd.cAccumRedBits;
259 u->accumGreenBits = pfd.cAccumGreenBits;
260 u->accumBlueBits = pfd.cAccumBlueBits;
261 u->accumAlphaBits = pfd.cAccumAlphaBits;
262
263 u->auxBuffers = pfd.cAuxBuffers;
264
265 if (pfd.dwFlags & PFD_STEREO)
266 u->stereo = GLFW_TRUE;
267 }
268
269 u->handle = pixelFormat;
270 usableCount++;
271 }
272
273 if (!usableCount)
274 {
275 _glfwInputError(GLFW_API_UNAVAILABLE,
276 "WGL: The driver does not appear to support OpenGL");
277
278 _glfw_free(usableConfigs);
279 return 0;
280 }
281
282 closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
283 if (!closest)
284 {
285 _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
286 "WGL: Failed to find a suitable pixel format");
287
288 _glfw_free(usableConfigs);
289 return 0;
290 }
291
292 pixelFormat = (int) closest->handle;
293 _glfw_free(usableConfigs);
294
295 return pixelFormat;
296 }
297
298 #undef ADD_ATTRIB
299 #undef FIND_ATTRIB_VALUE
300
makeContextCurrentWGL(_GLFWwindow * window)301 static void makeContextCurrentWGL(_GLFWwindow* window)
302 {
303 if (window)
304 {
305 if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
306 _glfwPlatformSetTls(&_glfw.contextSlot, window);
307 else
308 {
309 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
310 "WGL: Failed to make context current");
311 _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
312 }
313 }
314 else
315 {
316 if (!wglMakeCurrent(NULL, NULL))
317 {
318 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
319 "WGL: Failed to clear current context");
320 }
321
322 _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
323 }
324 }
325
swapBuffersWGL(_GLFWwindow * window)326 static void swapBuffersWGL(_GLFWwindow* window)
327 {
328 if (!window->monitor)
329 {
330 // HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7
331 if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater())
332 {
333 BOOL enabled = FALSE;
334
335 if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
336 {
337 int count = abs(window->context.wgl.interval);
338 while (count--)
339 DwmFlush();
340 }
341 }
342 }
343
344 SwapBuffers(window->context.wgl.dc);
345 }
346
swapIntervalWGL(int interval)347 static void swapIntervalWGL(int interval)
348 {
349 _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
350 assert(window != NULL);
351
352 window->context.wgl.interval = interval;
353
354 if (!window->monitor)
355 {
356 // HACK: Disable WGL swap interval when desktop composition is enabled on Windows
357 // Vista and 7 to avoid interfering with DWM vsync
358 if (!IsWindows8OrGreater() && IsWindowsVistaOrGreater())
359 {
360 BOOL enabled = FALSE;
361
362 if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
363 interval = 0;
364 }
365 }
366
367 if (_glfw.wgl.EXT_swap_control)
368 wglSwapIntervalEXT(interval);
369 }
370
extensionSupportedWGL(const char * extension)371 static int extensionSupportedWGL(const char* extension)
372 {
373 const char* extensions = NULL;
374
375 if (_glfw.wgl.GetExtensionsStringARB)
376 extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
377 else if (_glfw.wgl.GetExtensionsStringEXT)
378 extensions = wglGetExtensionsStringEXT();
379
380 if (!extensions)
381 return GLFW_FALSE;
382
383 return _glfwStringInExtensionString(extension, extensions);
384 }
385
getProcAddressWGL(const char * procname)386 static GLFWglproc getProcAddressWGL(const char* procname)
387 {
388 const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
389 if (proc)
390 return proc;
391
392 return (GLFWglproc) _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, procname);
393 }
394
destroyContextWGL(_GLFWwindow * window)395 static void destroyContextWGL(_GLFWwindow* window)
396 {
397 if (window->context.wgl.handle)
398 {
399 wglDeleteContext(window->context.wgl.handle);
400 window->context.wgl.handle = NULL;
401 }
402 }
403
404 // Initialize WGL
405 //
_glfwInitWGL(void)406 GLFWbool _glfwInitWGL(void)
407 {
408 PIXELFORMATDESCRIPTOR pfd;
409 HGLRC prc, rc;
410 HDC pdc, dc;
411
412 if (_glfw.wgl.instance)
413 return GLFW_TRUE;
414
415 _glfw.wgl.instance = _glfwPlatformLoadModule("opengl32.dll");
416 if (!_glfw.wgl.instance)
417 {
418 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
419 "WGL: Failed to load opengl32.dll");
420 return GLFW_FALSE;
421 }
422
423 _glfw.wgl.CreateContext = (PFN_wglCreateContext)
424 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglCreateContext");
425 _glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
426 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglDeleteContext");
427 _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
428 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetProcAddress");
429 _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
430 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentDC");
431 _glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext)
432 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglGetCurrentContext");
433 _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
434 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglMakeCurrent");
435 _glfw.wgl.ShareLists = (PFN_wglShareLists)
436 _glfwPlatformGetModuleSymbol(_glfw.wgl.instance, "wglShareLists");
437
438 // NOTE: A dummy context has to be created for opengl32.dll to load the
439 // OpenGL ICD, from which we can then query WGL extensions
440 // NOTE: This code will accept the Microsoft GDI ICD; accelerated context
441 // creation failure occurs during manual pixel format enumeration
442
443 dc = GetDC(_glfw.win32.helperWindowHandle);
444
445 ZeroMemory(&pfd, sizeof(pfd));
446 pfd.nSize = sizeof(pfd);
447 pfd.nVersion = 1;
448 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
449 pfd.iPixelType = PFD_TYPE_RGBA;
450 pfd.cColorBits = 24;
451
452 if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
453 {
454 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
455 "WGL: Failed to set pixel format for dummy context");
456 return GLFW_FALSE;
457 }
458
459 rc = wglCreateContext(dc);
460 if (!rc)
461 {
462 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
463 "WGL: Failed to create dummy context");
464 return GLFW_FALSE;
465 }
466
467 pdc = wglGetCurrentDC();
468 prc = wglGetCurrentContext();
469
470 if (!wglMakeCurrent(dc, rc))
471 {
472 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
473 "WGL: Failed to make dummy context current");
474 wglMakeCurrent(pdc, prc);
475 wglDeleteContext(rc);
476 return GLFW_FALSE;
477 }
478
479 // NOTE: Functions must be loaded first as they're needed to retrieve the
480 // extension string that tells us whether the functions are supported
481 _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
482 wglGetProcAddress("wglGetExtensionsStringEXT");
483 _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
484 wglGetProcAddress("wglGetExtensionsStringARB");
485 _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
486 wglGetProcAddress("wglCreateContextAttribsARB");
487 _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
488 wglGetProcAddress("wglSwapIntervalEXT");
489 _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
490 wglGetProcAddress("wglGetPixelFormatAttribivARB");
491
492 // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
493 // checked below as we are already using them
494 _glfw.wgl.ARB_multisample =
495 extensionSupportedWGL("WGL_ARB_multisample");
496 _glfw.wgl.ARB_framebuffer_sRGB =
497 extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
498 _glfw.wgl.EXT_framebuffer_sRGB =
499 extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
500 _glfw.wgl.ARB_create_context =
501 extensionSupportedWGL("WGL_ARB_create_context");
502 _glfw.wgl.ARB_create_context_profile =
503 extensionSupportedWGL("WGL_ARB_create_context_profile");
504 _glfw.wgl.EXT_create_context_es2_profile =
505 extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
506 _glfw.wgl.ARB_create_context_robustness =
507 extensionSupportedWGL("WGL_ARB_create_context_robustness");
508 _glfw.wgl.ARB_create_context_no_error =
509 extensionSupportedWGL("WGL_ARB_create_context_no_error");
510 _glfw.wgl.EXT_swap_control =
511 extensionSupportedWGL("WGL_EXT_swap_control");
512 _glfw.wgl.EXT_colorspace =
513 extensionSupportedWGL("WGL_EXT_colorspace");
514 _glfw.wgl.ARB_pixel_format =
515 extensionSupportedWGL("WGL_ARB_pixel_format");
516 _glfw.wgl.ARB_context_flush_control =
517 extensionSupportedWGL("WGL_ARB_context_flush_control");
518
519 wglMakeCurrent(pdc, prc);
520 wglDeleteContext(rc);
521 return GLFW_TRUE;
522 }
523
524 // Terminate WGL
525 //
_glfwTerminateWGL(void)526 void _glfwTerminateWGL(void)
527 {
528 if (_glfw.wgl.instance)
529 _glfwPlatformFreeModule(_glfw.wgl.instance);
530 }
531
532 #define SET_ATTRIB(a, v) \
533 { \
534 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
535 attribs[index++] = a; \
536 attribs[index++] = v; \
537 }
538
539 // Create the OpenGL or OpenGL ES context
540 //
_glfwCreateContextWGL(_GLFWwindow * window,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)541 GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
542 const _GLFWctxconfig* ctxconfig,
543 const _GLFWfbconfig* fbconfig)
544 {
545 int attribs[40];
546 int pixelFormat;
547 PIXELFORMATDESCRIPTOR pfd;
548 HGLRC share = NULL;
549
550 if (ctxconfig->share)
551 share = ctxconfig->share->context.wgl.handle;
552
553 window->context.wgl.dc = GetDC(window->win32.handle);
554 if (!window->context.wgl.dc)
555 {
556 _glfwInputError(GLFW_PLATFORM_ERROR,
557 "WGL: Failed to retrieve DC for window");
558 return GLFW_FALSE;
559 }
560
561 pixelFormat = choosePixelFormatWGL(window, ctxconfig, fbconfig);
562 if (!pixelFormat)
563 return GLFW_FALSE;
564
565 if (!DescribePixelFormat(window->context.wgl.dc,
566 pixelFormat, sizeof(pfd), &pfd))
567 {
568 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
569 "WGL: Failed to retrieve PFD for selected pixel format");
570 return GLFW_FALSE;
571 }
572
573 if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
574 {
575 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
576 "WGL: Failed to set selected pixel format");
577 return GLFW_FALSE;
578 }
579
580 if (ctxconfig->client == GLFW_OPENGL_API)
581 {
582 if (ctxconfig->forward)
583 {
584 if (!_glfw.wgl.ARB_create_context)
585 {
586 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
587 "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
588 return GLFW_FALSE;
589 }
590 }
591
592 if (ctxconfig->profile)
593 {
594 if (!_glfw.wgl.ARB_create_context_profile)
595 {
596 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
597 "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
598 return GLFW_FALSE;
599 }
600 }
601 }
602 else
603 {
604 if (!_glfw.wgl.ARB_create_context ||
605 !_glfw.wgl.ARB_create_context_profile ||
606 !_glfw.wgl.EXT_create_context_es2_profile)
607 {
608 _glfwInputError(GLFW_API_UNAVAILABLE,
609 "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
610 return GLFW_FALSE;
611 }
612 }
613
614 if (_glfw.wgl.ARB_create_context)
615 {
616 int index = 0, mask = 0, flags = 0;
617
618 if (ctxconfig->client == GLFW_OPENGL_API)
619 {
620 if (ctxconfig->forward)
621 flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
622
623 if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
624 mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
625 else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
626 mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
627 }
628 else
629 mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
630
631 if (ctxconfig->debug)
632 flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
633
634 if (ctxconfig->robustness)
635 {
636 if (_glfw.wgl.ARB_create_context_robustness)
637 {
638 if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
639 {
640 SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
641 WGL_NO_RESET_NOTIFICATION_ARB);
642 }
643 else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
644 {
645 SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
646 WGL_LOSE_CONTEXT_ON_RESET_ARB);
647 }
648
649 flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
650 }
651 }
652
653 if (ctxconfig->release)
654 {
655 if (_glfw.wgl.ARB_context_flush_control)
656 {
657 if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
658 {
659 SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
660 WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
661 }
662 else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
663 {
664 SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
665 WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
666 }
667 }
668 }
669
670 if (ctxconfig->noerror)
671 {
672 if (_glfw.wgl.ARB_create_context_no_error)
673 SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
674 }
675
676 // NOTE: Only request an explicitly versioned context when necessary, as
677 // explicitly requesting version 1.0 does not always return the
678 // highest version supported by the driver
679 if (ctxconfig->major != 1 || ctxconfig->minor != 0)
680 {
681 SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
682 SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
683 }
684
685 if (flags)
686 SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags);
687
688 if (mask)
689 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
690
691 SET_ATTRIB(0, 0);
692
693 window->context.wgl.handle =
694 wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
695 if (!window->context.wgl.handle)
696 {
697 const DWORD error = GetLastError();
698
699 if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
700 {
701 if (ctxconfig->client == GLFW_OPENGL_API)
702 {
703 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
704 "WGL: Driver does not support OpenGL version %i.%i",
705 ctxconfig->major,
706 ctxconfig->minor);
707 }
708 else
709 {
710 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
711 "WGL: Driver does not support OpenGL ES version %i.%i",
712 ctxconfig->major,
713 ctxconfig->minor);
714 }
715 }
716 else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
717 {
718 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
719 "WGL: Driver does not support the requested OpenGL profile");
720 }
721 else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
722 {
723 _glfwInputError(GLFW_INVALID_VALUE,
724 "WGL: The share context is not compatible with the requested context");
725 }
726 else
727 {
728 if (ctxconfig->client == GLFW_OPENGL_API)
729 {
730 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
731 "WGL: Failed to create OpenGL context");
732 }
733 else
734 {
735 _glfwInputError(GLFW_VERSION_UNAVAILABLE,
736 "WGL: Failed to create OpenGL ES context");
737 }
738 }
739
740 return GLFW_FALSE;
741 }
742 }
743 else
744 {
745 window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
746 if (!window->context.wgl.handle)
747 {
748 _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
749 "WGL: Failed to create OpenGL context");
750 return GLFW_FALSE;
751 }
752
753 if (share)
754 {
755 if (!wglShareLists(share, window->context.wgl.handle))
756 {
757 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
758 "WGL: Failed to enable sharing with specified OpenGL context");
759 return GLFW_FALSE;
760 }
761 }
762 }
763
764 window->context.makeCurrent = makeContextCurrentWGL;
765 window->context.swapBuffers = swapBuffersWGL;
766 window->context.swapInterval = swapIntervalWGL;
767 window->context.extensionSupported = extensionSupportedWGL;
768 window->context.getProcAddress = getProcAddressWGL;
769 window->context.destroy = destroyContextWGL;
770
771 return GLFW_TRUE;
772 }
773
774 #undef SET_ATTRIB
775
glfwGetWGLContext(GLFWwindow * handle)776 GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
777 {
778 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
779
780 if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
781 {
782 _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
783 "WGL: Platform not initialized");
784 return NULL;
785 }
786
787 _GLFWwindow* window = (_GLFWwindow*) handle;
788 assert(window != NULL);
789
790 if (window->context.source != GLFW_NATIVE_CONTEXT_API)
791 {
792 _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
793 return NULL;
794 }
795
796 return window->context.wgl.handle;
797 }
798
799 #endif // _GLFW_WIN32
800
801