xref: /third_party/glfw/src/wgl_context.c (revision b877906b)
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//
37static 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//
65static 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
301static 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
326static 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
347static 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
371static 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
386static 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
395static 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//
406GLFWbool _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//
526void _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//
541GLFWbool _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
776GLFWAPI 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