wgl_context.c 23.7 KB
Newer Older
Camilla Berglund's avatar
Camilla Berglund committed
1
//========================================================================
Camilla Berglund's avatar
Camilla Berglund committed
2
// GLFW 3.3 WGL - www.glfw.org
Camilla Berglund's avatar
Camilla Berglund committed
3
4
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
Camilla Löwy's avatar
Camilla Löwy committed
5
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
Camilla Berglund's avatar
Camilla Berglund committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
//    claim that you wrote the original software. If you use this software
//    in a product, an acknowledgment in the product documentation would
//    be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
//    be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
//    distribution.
//
//========================================================================

#include "internal.h"

Camilla Berglund's avatar
Camilla Berglund committed
30
#include <stdlib.h>
31
#include <malloc.h>
32
#include <assert.h>
Camilla Berglund's avatar
Camilla Berglund committed
33

Camilla Berglund's avatar
Camilla Berglund committed
34

35
36
37
38
39
40
// Returns the specified attribute of the specified pixel format
//
static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib)
{
    int value = 0;

Camilla Berglund's avatar
Camilla Berglund committed
41
    assert(_glfw.wgl.ARB_pixel_format);
42

43
    if (!_glfw.wgl.GetPixelFormatAttribivARB(window->context.wgl.dc,
Camilla Berglund's avatar
Camilla Berglund committed
44
45
                                             pixelFormat,
                                             0, 1, &attrib, &value))
46
    {
47
48
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to retrieve pixel format attribute");
49
50
51
52
53
54
55
56
        return 0;
    }

    return value;
}

// Return a list of available and usable framebuffer configs
//
57
58
59
static int choosePixelFormat(_GLFWwindow* window,
                             const _GLFWctxconfig* ctxconfig,
                             const _GLFWfbconfig* fbconfig)
60
61
62
{
    _GLFWfbconfig* usableConfigs;
    const _GLFWfbconfig* closest;
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
63
    int i, pixelFormat, nativeCount, usableCount;
64

Camilla Berglund's avatar
Camilla Berglund committed
65
    if (_glfw.wgl.ARB_pixel_format)
66
67
    {
        nativeCount = getPixelFormatAttrib(window,
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
68
69
                                           1,
                                           WGL_NUMBER_PIXEL_FORMATS_ARB);
70
71
72
    }
    else
    {
73
        nativeCount = DescribePixelFormat(window->context.wgl.dc,
74
75
76
77
78
                                          1,
                                          sizeof(PIXELFORMATDESCRIPTOR),
                                          NULL);
    }

79
    usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
80
81
82
83
84
85
86
    usableCount = 0;

    for (i = 0;  i < nativeCount;  i++)
    {
        const int n = i + 1;
        _GLFWfbconfig* u = usableConfigs + usableCount;

Camilla Berglund's avatar
Camilla Berglund committed
87
        if (_glfw.wgl.ARB_pixel_format)
88
        {
Camilla Berglund's avatar
Camilla Berglund committed
89
90
            // Get pixel format attributes through "modern" extension

91
            if (!getPixelFormatAttrib(window, n, WGL_SUPPORT_OPENGL_ARB) ||
Camilla Berglund's avatar
Camilla Berglund committed
92
                !getPixelFormatAttrib(window, n, WGL_DRAW_TO_WINDOW_ARB))
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
            {
                continue;
            }

            if (getPixelFormatAttrib(window, n, WGL_PIXEL_TYPE_ARB) !=
                WGL_TYPE_RGBA_ARB)
            {
                continue;
            }

            if (getPixelFormatAttrib(window, n, WGL_ACCELERATION_ARB) ==
                 WGL_NO_ACCELERATION_ARB)
            {
                continue;
            }

            u->redBits = getPixelFormatAttrib(window, n, WGL_RED_BITS_ARB);
            u->greenBits = getPixelFormatAttrib(window, n, WGL_GREEN_BITS_ARB);
            u->blueBits = getPixelFormatAttrib(window, n, WGL_BLUE_BITS_ARB);
            u->alphaBits = getPixelFormatAttrib(window, n, WGL_ALPHA_BITS_ARB);

            u->depthBits = getPixelFormatAttrib(window, n, WGL_DEPTH_BITS_ARB);
            u->stencilBits = getPixelFormatAttrib(window, n, WGL_STENCIL_BITS_ARB);

            u->accumRedBits = getPixelFormatAttrib(window, n, WGL_ACCUM_RED_BITS_ARB);
            u->accumGreenBits = getPixelFormatAttrib(window, n, WGL_ACCUM_GREEN_BITS_ARB);
            u->accumBlueBits = getPixelFormatAttrib(window, n, WGL_ACCUM_BLUE_BITS_ARB);
            u->accumAlphaBits = getPixelFormatAttrib(window, n, WGL_ACCUM_ALPHA_BITS_ARB);

            u->auxBuffers = getPixelFormatAttrib(window, n, WGL_AUX_BUFFERS_ARB);
Camilla Berglund's avatar
Camilla Berglund committed
123
124

            if (getPixelFormatAttrib(window, n, WGL_STEREO_ARB))
125
                u->stereo = GLFW_TRUE;
Camilla Berglund's avatar
Camilla Berglund committed
126
            if (getPixelFormatAttrib(window, n, WGL_DOUBLE_BUFFER_ARB))
127
                u->doublebuffer = GLFW_TRUE;
128

Camilla Berglund's avatar
Camilla Berglund committed
129
            if (_glfw.wgl.ARB_multisample)
130
131
                u->samples = getPixelFormatAttrib(window, n, WGL_SAMPLES_ARB);

132
            if (ctxconfig->client == GLFW_OPENGL_API)
Camilla Berglund's avatar
Camilla Berglund committed
133
            {
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
                if (_glfw.wgl.ARB_framebuffer_sRGB ||
                    _glfw.wgl.EXT_framebuffer_sRGB)
                {
                    if (getPixelFormatAttrib(window, n, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
                        u->sRGB = GLFW_TRUE;
                }
            }
            else
            {
                if (_glfw.wgl.EXT_colorspace)
                {
                    if (getPixelFormatAttrib(window, n, WGL_COLORSPACE_EXT) ==
                        WGL_COLORSPACE_SRGB_EXT)
                    {
                        u->sRGB = GLFW_TRUE;
                    }
                }
Camilla Berglund's avatar
Camilla Berglund committed
151
            }
152
153
154
155
156
        }
        else
        {
            PIXELFORMATDESCRIPTOR pfd;

Camilla Berglund's avatar
Camilla Berglund committed
157
            // Get pixel format attributes through legacy PFDs
158

159
            if (!DescribePixelFormat(window->context.wgl.dc,
160
161
162
163
164
165
166
167
                                     n,
                                     sizeof(PIXELFORMATDESCRIPTOR),
                                     &pfd))
            {
                continue;
            }

            if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
Camilla Berglund's avatar
Camilla Berglund committed
168
                !(pfd.dwFlags & PFD_SUPPORT_OPENGL))
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
            {
                continue;
            }

            if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) &&
                (pfd.dwFlags & PFD_GENERIC_FORMAT))
            {
                continue;
            }

            if (pfd.iPixelType != PFD_TYPE_RGBA)
                continue;

            u->redBits = pfd.cRedBits;
            u->greenBits = pfd.cGreenBits;
            u->blueBits = pfd.cBlueBits;
            u->alphaBits = pfd.cAlphaBits;

            u->depthBits = pfd.cDepthBits;
            u->stencilBits = pfd.cStencilBits;

            u->accumRedBits = pfd.cAccumRedBits;
            u->accumGreenBits = pfd.cAccumGreenBits;
            u->accumBlueBits = pfd.cAccumBlueBits;
            u->accumAlphaBits = pfd.cAccumAlphaBits;

            u->auxBuffers = pfd.cAuxBuffers;
Camilla Berglund's avatar
Camilla Berglund committed
196
197

            if (pfd.dwFlags & PFD_STEREO)
198
                u->stereo = GLFW_TRUE;
Camilla Berglund's avatar
Camilla Berglund committed
199
            if (pfd.dwFlags & PFD_DOUBLEBUFFER)
200
                u->doublebuffer = GLFW_TRUE;
201
202
        }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
203
        u->handle = n;
204
205
206
        usableCount++;
    }

207
208
209
210
211
212
    if (!usableCount)
    {
        _glfwInputError(GLFW_API_UNAVAILABLE,
                        "WGL: The driver does not appear to support OpenGL");

        free(usableConfigs);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
213
        return 0;
214
215
    }

216
    closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
217
218
    if (!closest)
    {
219
        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
220
221
                        "WGL: Failed to find a suitable pixel format");

222
        free(usableConfigs);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
223
        return 0;
224
    }
225

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
226
    pixelFormat = (int) closest->handle;
227
228
    free(usableConfigs);

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
229
    return pixelFormat;
230
231
}

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
// Returns whether desktop compositing is enabled
//
static GLFWbool isCompositionEnabled(void)
{
    BOOL enabled;

    if (!_glfw_DwmIsCompositionEnabled)
        return FALSE;

    if (_glfw_DwmIsCompositionEnabled(&enabled) != S_OK)
        return FALSE;

    return enabled;
}

247
static void makeContextCurrentWGL(_GLFWwindow* window)
248
249
250
251
{
    if (window)
    {
        if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
Camilla Löwy's avatar
Camilla Löwy committed
252
            _glfwPlatformSetTls(&_glfw.context, window);
253
254
        else
        {
255
256
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to make context current");
Camilla Löwy's avatar
Camilla Löwy committed
257
            _glfwPlatformSetTls(&_glfw.context, NULL);
258
259
260
261
262
263
        }
    }
    else
    {
        if (!wglMakeCurrent(NULL, NULL))
        {
264
265
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to clear current context");
266
267
        }

Camilla Löwy's avatar
Camilla Löwy committed
268
        _glfwPlatformSetTls(&_glfw.context, NULL);
269
270
271
    }
}

272
static void swapBuffersWGL(_GLFWwindow* window)
273
274
275
276
277
278
279
280
281
282
283
284
{
    // HACK: Use DwmFlush when desktop composition is enabled
    if (isCompositionEnabled() && !window->monitor)
    {
        int count = abs(window->context.wgl.interval);
        while (count--)
            _glfw_DwmFlush();
    }

    SwapBuffers(window->context.wgl.dc);
}

285
static void swapIntervalWGL(int interval)
286
{
Camilla Löwy's avatar
Camilla Löwy committed
287
    _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.context);
288
289
290
291
292
293
294
295
296
297
298
299

    window->context.wgl.interval = interval;

    // HACK: Disable WGL swap interval when desktop composition is enabled to
    //       avoid interfering with DWM vsync
    if (isCompositionEnabled() && !window->monitor)
        interval = 0;

    if (_glfw.wgl.EXT_swap_control)
        _glfw.wgl.SwapIntervalEXT(interval);
}

300
static int extensionSupportedWGL(const char* extension)
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
{
    const char* extensions;

    if (_glfw.wgl.GetExtensionsStringEXT)
    {
        extensions = _glfw.wgl.GetExtensionsStringEXT();
        if (extensions)
        {
            if (_glfwStringInExtensionString(extension, extensions))
                return GLFW_TRUE;
        }
    }

    if (_glfw.wgl.GetExtensionsStringARB)
    {
316
        extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
317
318
319
320
321
322
323
324
325
326
        if (extensions)
        {
            if (_glfwStringInExtensionString(extension, extensions))
                return GLFW_TRUE;
        }
    }

    return GLFW_FALSE;
}

327
static GLFWglproc getProcAddressWGL(const char* procname)
328
329
330
331
332
333
334
335
336
337
{
    const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
    if (proc)
        return proc;

    return (GLFWglproc) GetProcAddress(_glfw.wgl.instance, procname);
}

// Destroy the OpenGL context
//
338
static void destroyContextWGL(_GLFWwindow* window)
339
340
341
342
343
344
345
346
347
348
{
    if (window->context.wgl.handle)
    {
        wglDeleteContext(window->context.wgl.handle);
        window->context.wgl.handle = NULL;
    }
}

// Initialize WGL-specific extensions
//
349
static void loadWGLExtensions(void)
350
{
351
352
    PIXELFORMATDESCRIPTOR pfd;
    HGLRC rc;
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
353
    HDC dc = GetDC(_glfw.win32.helperWindowHandle);;
354
355
356

    _glfw.wgl.extensionsLoaded = GLFW_TRUE;

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
357
358
359
360
361
    // NOTE: A dummy context has to be created for opengl32.dll to load the
    //       OpenGL ICD, from which we can then query WGL extensions
    // NOTE: This code will accept the Microsoft GDI ICD; accelerated context
    //       creation failure occurs during manual pixel format enumeration

362
363
364
365
366
367
368
    ZeroMemory(&pfd, sizeof(pfd));
    pfd.nSize = sizeof(pfd);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
369
    if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
370
    {
371
372
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to set pixel format for dummy context");
373
374
375
376
377
378
        return;
    }

    rc = wglCreateContext(dc);
    if (!rc)
    {
379
380
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to create dummy context");
381
382
383
384
385
        return;
    }

    if (!wglMakeCurrent(dc, rc))
    {
386
387
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to make dummy context current");
388
        wglDeleteContext(rc);
389
390
391
        return;
    }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
392
393
    // NOTE: Functions must be loaded first as they're needed to retrieve the
    //       extension string that tells us whether the functions are supported
394
395
396
397
398
399
400
401
402
403
404
    _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
        wglGetProcAddress("wglGetExtensionsStringEXT");
    _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
        wglGetProcAddress("wglGetExtensionsStringARB");
    _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
        wglGetProcAddress("wglCreateContextAttribsARB");
    _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
        wglGetProcAddress("wglSwapIntervalEXT");
    _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
        wglGetProcAddress("wglGetPixelFormatAttribivARB");

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
405
406
    // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
    //       checked below as we are already using them
407
    _glfw.wgl.ARB_multisample =
408
        extensionSupportedWGL("WGL_ARB_multisample");
409
    _glfw.wgl.ARB_framebuffer_sRGB =
410
        extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
411
    _glfw.wgl.EXT_framebuffer_sRGB =
412
        extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
413
    _glfw.wgl.ARB_create_context =
414
        extensionSupportedWGL("WGL_ARB_create_context");
415
    _glfw.wgl.ARB_create_context_profile =
416
        extensionSupportedWGL("WGL_ARB_create_context_profile");
417
    _glfw.wgl.EXT_create_context_es2_profile =
418
        extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
419
    _glfw.wgl.ARB_create_context_robustness =
420
        extensionSupportedWGL("WGL_ARB_create_context_robustness");
421
    _glfw.wgl.EXT_swap_control =
422
        extensionSupportedWGL("WGL_EXT_swap_control");
423
424
    _glfw.wgl.EXT_colorspace =
        extensionSupportedWGL("WGL_EXT_colorspace");
425
    _glfw.wgl.ARB_pixel_format =
426
        extensionSupportedWGL("WGL_ARB_pixel_format");
427
    _glfw.wgl.ARB_context_flush_control =
428
        extensionSupportedWGL("WGL_ARB_context_flush_control");
429

430
431
    wglMakeCurrent(dc, NULL);
    wglDeleteContext(rc);
432
433
}

434

435
436
437
438
//////////////////////////////////////////////////////////////////////////
//////                       GLFW internal API                      //////
//////////////////////////////////////////////////////////////////////////

439
// Initialize WGL
440
//
Camilla Berglund's avatar
Camilla Berglund committed
441
GLFWbool _glfwInitWGL(void)
442
{
443
444
445
    if (_glfw.wgl.instance)
        return GLFW_TRUE;

Camilla Berglund's avatar
Camilla Berglund committed
446
447
    _glfw.wgl.instance = LoadLibraryA("opengl32.dll");
    if (!_glfw.wgl.instance)
448
    {
449
450
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to load opengl32.dll");
451
        return GLFW_FALSE;
452
453
    }

454
    _glfw.wgl.CreateContext = (PFN_wglCreateContext)
Camilla Berglund's avatar
Camilla Berglund committed
455
        GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
456
    _glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
Camilla Berglund's avatar
Camilla Berglund committed
457
        GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
458
    _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
Camilla Berglund's avatar
Camilla Berglund committed
459
        GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
460
    _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
461
        GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
462
    _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
Camilla Berglund's avatar
Camilla Berglund committed
463
        GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
464
    _glfw.wgl.ShareLists = (PFN_wglShareLists)
Camilla Berglund's avatar
Camilla Berglund committed
465
        GetProcAddress(_glfw.wgl.instance, "wglShareLists");
466

467
    return GLFW_TRUE;
468
469
470
}

// Terminate WGL
471
//
472
void _glfwTerminateWGL(void)
473
{
Camilla Berglund's avatar
Camilla Berglund committed
474
475
    if (_glfw.wgl.instance)
        FreeLibrary(_glfw.wgl.instance);
476
477
}

478
479
480
481
#define setWGLattrib(attribName, attribValue) \
{ \
    attribs[index++] = attribName; \
    attribs[index++] = attribValue; \
siavash's avatar
siavash committed
482
    assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
483
484
}

485
// Create the OpenGL or OpenGL ES context
486
//
Camilla Berglund's avatar
Camilla Berglund committed
487
488
489
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
490
{
491
    int attribs[40];
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
492
    int pixelFormat;
493
    PIXELFORMATDESCRIPTOR pfd;
494
    HGLRC share = NULL;
495

496
497
    if (!_glfw.wgl.extensionsLoaded)
        loadWGLExtensions();
498

499
    if (ctxconfig->share)
500
        share = ctxconfig->share->context.wgl.handle;
501

502
503
    window->context.wgl.dc = GetDC(window->win32.handle);
    if (!window->context.wgl.dc)
504
    {
505
        _glfwInputError(GLFW_PLATFORM_ERROR,
Camilla Berglund's avatar
Camilla Berglund committed
506
                        "WGL: Failed to retrieve DC for window");
507
        return GLFW_FALSE;
508
509
    }

510
    pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
511
    if (!pixelFormat)
512
        return GLFW_FALSE;
513

514
515
    if (!DescribePixelFormat(window->context.wgl.dc,
                             pixelFormat, sizeof(pfd), &pfd))
516
    {
517
518
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to retrieve PFD for selected pixel format");
519
        return GLFW_FALSE;
520
521
    }

522
    if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
523
    {
524
525
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to set selected pixel format");
526
        return GLFW_FALSE;
527
528
    }

529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
    if (ctxconfig->client == GLFW_OPENGL_API)
    {
        if (ctxconfig->forward)
        {
            if (!_glfw.wgl.ARB_create_context)
            {
                _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                "WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
                return GLFW_FALSE;
            }
        }

        if (ctxconfig->profile)
        {
            if (!_glfw.wgl.ARB_create_context_profile)
            {
                _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                "WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
                return GLFW_FALSE;
            }
        }
    }
    else
    {
        if (!_glfw.wgl.ARB_create_context ||
            !_glfw.wgl.ARB_create_context_profile ||
            !_glfw.wgl.EXT_create_context_es2_profile)
        {
            _glfwInputError(GLFW_API_UNAVAILABLE,
                            "WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
            return GLFW_FALSE;
        }
    }

Camilla Berglund's avatar
Camilla Berglund committed
563
    if (_glfw.wgl.ARB_create_context)
564
    {
565
        int index = 0, mask = 0, flags = 0;
566

567
        if (ctxconfig->client == GLFW_OPENGL_API)
568
        {
569
            if (ctxconfig->forward)
570
571
                flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;

572
573
574
575
            if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
                mask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
            else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
                mask |= WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
576
        }
Camilla Berglund's avatar
Camilla Berglund committed
577
578
        else
            mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
579

580
581
        if (ctxconfig->debug)
            flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
582
583
        if (ctxconfig->noerror)
            flags |= GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
584

585
        if (ctxconfig->robustness)
586
        {
Camilla Berglund's avatar
Camilla Berglund committed
587
            if (_glfw.wgl.ARB_create_context_robustness)
588
            {
589
                if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
590
591
592
593
                {
                    setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                                 WGL_NO_RESET_NOTIFICATION_ARB);
                }
594
                else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
595
596
597
598
                {
                    setWGLattrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                                 WGL_LOSE_CONTEXT_ON_RESET_ARB);
                }
599

Camilla Berglund's avatar
Camilla Berglund committed
600
601
                flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
            }
602
603
        }

604
605
        if (ctxconfig->release)
        {
Camilla Berglund's avatar
Camilla Berglund committed
606
            if (_glfw.wgl.ARB_context_flush_control)
607
608
609
610
611
612
613
614
615
616
617
618
619
620
            {
                if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
                {
                    setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                                 WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
                }
                else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
                {
                    setWGLattrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                                 WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
                }
            }
        }

Camilla Berglund's avatar
Camilla Berglund committed
621
622
623
        // NOTE: Only request an explicitly versioned context when necessary, as
        //       explicitly requesting version 1.0 does not always return the
        //       highest version supported by the driver
624
        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
625
        {
626
627
            setWGLattrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
            setWGLattrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
Camilla Berglund's avatar
Camilla Berglund committed
628
        }
629

Camilla Berglund's avatar
Camilla Berglund committed
630
631
        if (flags)
            setWGLattrib(WGL_CONTEXT_FLAGS_ARB, flags);
632

Camilla Berglund's avatar
Camilla Berglund committed
633
634
        if (mask)
            setWGLattrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
635

Camilla Berglund's avatar
Camilla Berglund committed
636
        setWGLattrib(0, 0);
637

638
639
640
641
        window->context.wgl.handle =
            _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
                                              share, attribs);
        if (!window->context.wgl.handle)
642
        {
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
            const DWORD error = GetLastError();

            if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
            {
                if (ctxconfig->client == GLFW_OPENGL_API)
                {
                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                    "WGL: Driver does not support OpenGL version %i.%i",
                                    ctxconfig->major,
                                    ctxconfig->minor);
                }
                else
                {
                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                    "WGL: Driver does not support OpenGL ES version %i.%i",
                                    ctxconfig->major,
                                    ctxconfig->minor);
                }
            }
            else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
            {
                _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                "WGL: Driver does not support the requested OpenGL profile");
            }
            else
            {
                if (ctxconfig->client == GLFW_OPENGL_API)
                {
                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                    "WGL: Failed to create OpenGL context");
                }
                else
                {
                    _glfwInputError(GLFW_VERSION_UNAVAILABLE,
                                    "WGL: Failed to create OpenGL ES context");
                }
            }

681
            return GLFW_FALSE;
682
683
684
685
        }
    }
    else
    {
686
        window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
687
        if (!window->context.wgl.handle)
688
        {
689
690
            _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
                                 "WGL: Failed to create OpenGL context");
691
            return GLFW_FALSE;
692
693
694
695
        }

        if (share)
        {
696
            if (!wglShareLists(share, window->context.wgl.handle))
697
            {
698
699
                _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                     "WGL: Failed to enable sharing with specified OpenGL context");
700
                return GLFW_FALSE;
701
702
703
704
            }
        }
    }

705
706
707
708
709
710
    window->context.makeCurrent = makeContextCurrentWGL;
    window->context.swapBuffers = swapBuffersWGL;
    window->context.swapInterval = swapIntervalWGL;
    window->context.extensionSupported = extensionSupportedWGL;
    window->context.getProcAddress = getProcAddressWGL;
    window->context.destroy = destroyContextWGL;
711

712
    return GLFW_TRUE;
713
714
}

Camilla Berglund's avatar
Camilla Berglund committed
715
716
717
#undef setWGLattrib


718
719
720
721
722
723
724
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
725
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
726

727
    if (window->context.client == GLFW_NO_API)
728
729
730
731
732
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return NULL;
    }

733
    return window->context.wgl.handle;
734
735
}