wgl_context.c 24.1 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
        }
        else
        {
Camilla Berglund's avatar
Camilla Berglund committed
155
            // Get pixel format attributes through legacy PFDs
156

157
158
159
            PIXELFORMATDESCRIPTOR pfd;

            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
static void makeContextCurrentWGL(_GLFWwindow* window)
233
234
235
236
{
    if (window)
    {
        if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
237
            _glfwPlatformSetTls(&_glfw.contextSlot, window);
238
239
        else
        {
240
241
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to make context current");
242
            _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
243
244
245
246
247
248
        }
    }
    else
    {
        if (!wglMakeCurrent(NULL, NULL))
        {
249
250
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to clear current context");
251
252
        }

253
        _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
254
255
256
    }
}

257
static void swapBuffersWGL(_GLFWwindow* window)
258
{
Camilla Löwy's avatar
Camilla Löwy committed
259
    if (!window->monitor)
260
    {
Camilla Löwy's avatar
Camilla Löwy committed
261
262
263
264
265
266
267
268
269
270
271
272
        if (IsWindowsVistaOrGreater())
        {
            BOOL enabled;

            // HACK: Use DwmFlush when desktop composition is enabled
            if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
            {
                int count = abs(window->context.wgl.interval);
                while (count--)
                    DwmFlush();
            }
        }
273
274
275
276
277
    }

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

278
static void swapIntervalWGL(int interval)
279
{
280
    _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
281
282
283

    window->context.wgl.interval = interval;

Camilla Löwy's avatar
Camilla Löwy committed
284
285
286
287
288
289
290
291
292
293
294
295
    if (!window->monitor)
    {
        if (IsWindowsVistaOrGreater())
        {
            BOOL enabled;

            // HACK: Disable WGL swap interval when desktop composition is enabled to
            //       avoid interfering with DWM vsync
            if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled)
                interval = 0;
        }
    }
296
297
298
299
300

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

301
static int extensionSupportedWGL(const char* extension)
302
{
Camilla Löwy's avatar
Camilla Löwy committed
303
    const char* extensions = NULL;
304
305

    if (_glfw.wgl.GetExtensionsStringARB)
306
        extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
Camilla Löwy's avatar
Camilla Löwy committed
307
308
309
310
311
    else if (_glfw.wgl.GetExtensionsStringEXT)
        extensions = _glfw.wgl.GetExtensionsStringEXT();

    if (!extensions)
        return GLFW_FALSE;
312

Camilla Löwy's avatar
Camilla Löwy committed
313
    return _glfwStringInExtensionString(extension, extensions);
314
315
}

316
static GLFWglproc getProcAddressWGL(const char* procname)
317
318
319
320
321
322
323
324
325
326
{
    const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
    if (proc)
        return proc;

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

// Destroy the OpenGL context
//
327
static void destroyContextWGL(_GLFWwindow* window)
328
329
330
331
332
333
334
335
{
    if (window->context.wgl.handle)
    {
        wglDeleteContext(window->context.wgl.handle);
        window->context.wgl.handle = NULL;
    }
}

336
337
338
339
340
341

//////////////////////////////////////////////////////////////////////////
//////                       GLFW internal API                      //////
//////////////////////////////////////////////////////////////////////////

// Initialize WGL
342
//
343
GLFWbool _glfwInitWGL(void)
344
{
345
    PIXELFORMATDESCRIPTOR pfd;
346
347
348
349
350
351
352
353
354
355
356
357
358
    HGLRC prc, rc;
    HDC pdc, dc;

    if (_glfw.wgl.instance)
        return GLFW_TRUE;

    _glfw.wgl.instance = LoadLibraryA("opengl32.dll");
    if (!_glfw.wgl.instance)
    {
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to load opengl32.dll");
        return GLFW_FALSE;
    }
359

360
361
362
363
364
365
366
367
368
369
370
371
372
373
    _glfw.wgl.CreateContext = (PFN_wglCreateContext)
        GetProcAddress(_glfw.wgl.instance, "wglCreateContext");
    _glfw.wgl.DeleteContext = (PFN_wglDeleteContext)
        GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
    _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress)
        GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
    _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC)
        GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
    _glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext)
        GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext");
    _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent)
        GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
    _glfw.wgl.ShareLists = (PFN_wglShareLists)
        GetProcAddress(_glfw.wgl.instance, "wglShareLists");
374

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
375
376
377
378
379
    // 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

380
381
    dc = GetDC(_glfw.win32.helperWindowHandle);;

382
383
384
385
386
387
388
    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
389
    if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
390
    {
391
392
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to set pixel format for dummy context");
393
        return GLFW_FALSE;
394
395
396
397
398
    }

    rc = wglCreateContext(dc);
    if (!rc)
    {
399
400
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to create dummy context");
401
        return GLFW_FALSE;
402
403
    }

404
405
406
    pdc = wglGetCurrentDC();
    prc = wglGetCurrentContext();

407
408
    if (!wglMakeCurrent(dc, rc))
    {
409
410
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to make dummy context current");
411
        wglMakeCurrent(pdc, prc);
412
        wglDeleteContext(rc);
413
        return GLFW_FALSE;
414
415
    }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
416
417
    // NOTE: Functions must be loaded first as they're needed to retrieve the
    //       extension string that tells us whether the functions are supported
418
419
420
421
422
423
424
425
426
427
428
    _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
429
430
    // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
    //       checked below as we are already using them
431
    _glfw.wgl.ARB_multisample =
432
        extensionSupportedWGL("WGL_ARB_multisample");
433
    _glfw.wgl.ARB_framebuffer_sRGB =
434
        extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
435
    _glfw.wgl.EXT_framebuffer_sRGB =
436
        extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
437
    _glfw.wgl.ARB_create_context =
438
        extensionSupportedWGL("WGL_ARB_create_context");
439
    _glfw.wgl.ARB_create_context_profile =
440
        extensionSupportedWGL("WGL_ARB_create_context_profile");
441
    _glfw.wgl.EXT_create_context_es2_profile =
442
        extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
443
    _glfw.wgl.ARB_create_context_robustness =
444
        extensionSupportedWGL("WGL_ARB_create_context_robustness");
445
446
    _glfw.wgl.ARB_create_context_no_error =
        extensionSupportedWGL("WGL_ARB_create_context_no_error");
447
    _glfw.wgl.EXT_swap_control =
448
        extensionSupportedWGL("WGL_EXT_swap_control");
449
450
    _glfw.wgl.EXT_colorspace =
        extensionSupportedWGL("WGL_EXT_colorspace");
451
    _glfw.wgl.ARB_pixel_format =
452
        extensionSupportedWGL("WGL_ARB_pixel_format");
453
    _glfw.wgl.ARB_context_flush_control =
454
        extensionSupportedWGL("WGL_ARB_context_flush_control");
455

456
    wglMakeCurrent(pdc, prc);
457
    wglDeleteContext(rc);
458
    return GLFW_TRUE;
459
460
461
}

// Terminate WGL
462
//
463
void _glfwTerminateWGL(void)
464
{
Camilla Berglund's avatar
Camilla Berglund committed
465
466
    if (_glfw.wgl.instance)
        FreeLibrary(_glfw.wgl.instance);
467
468
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
469
#define setAttrib(a, v) \
470
{ \
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
471
472
473
    assert((size_t) (index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
    attribs[index++] = a; \
    attribs[index++] = v; \
474
475
}

476
// Create the OpenGL or OpenGL ES context
477
//
Camilla Berglund's avatar
Camilla Berglund committed
478
479
480
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
481
{
482
    int attribs[40];
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
483
    int pixelFormat;
484
    PIXELFORMATDESCRIPTOR pfd;
485
    HGLRC share = NULL;
486

487
    if (ctxconfig->share)
488
        share = ctxconfig->share->context.wgl.handle;
489

490
491
    window->context.wgl.dc = GetDC(window->win32.handle);
    if (!window->context.wgl.dc)
492
    {
493
        _glfwInputError(GLFW_PLATFORM_ERROR,
Camilla Berglund's avatar
Camilla Berglund committed
494
                        "WGL: Failed to retrieve DC for window");
495
        return GLFW_FALSE;
496
497
    }

498
    pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
499
    if (!pixelFormat)
500
        return GLFW_FALSE;
501

502
503
    if (!DescribePixelFormat(window->context.wgl.dc,
                             pixelFormat, sizeof(pfd), &pfd))
504
    {
505
506
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to retrieve PFD for selected pixel format");
507
        return GLFW_FALSE;
508
509
    }

510
    if (!SetPixelFormat(window->context.wgl.dc, pixelFormat, &pfd))
511
    {
512
513
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to set selected pixel format");
514
        return GLFW_FALSE;
515
516
    }

517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
    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
551
    if (_glfw.wgl.ARB_create_context)
552
    {
553
        int index = 0, mask = 0, flags = 0;
554

555
        if (ctxconfig->client == GLFW_OPENGL_API)
556
        {
557
            if (ctxconfig->forward)
558
559
                flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;

560
561
562
563
            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;
564
        }
Camilla Berglund's avatar
Camilla Berglund committed
565
566
        else
            mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
567

568
569
570
        if (ctxconfig->debug)
            flags |= WGL_CONTEXT_DEBUG_BIT_ARB;

571
        if (ctxconfig->robustness)
572
        {
Camilla Berglund's avatar
Camilla Berglund committed
573
            if (_glfw.wgl.ARB_create_context_robustness)
574
            {
575
                if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
576
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
577
578
                    setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              WGL_NO_RESET_NOTIFICATION_ARB);
579
                }
580
                else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
581
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
582
583
                    setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              WGL_LOSE_CONTEXT_ON_RESET_ARB);
584
                }
585

Camilla Berglund's avatar
Camilla Berglund committed
586
587
                flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
            }
588
589
        }

590
591
        if (ctxconfig->release)
        {
Camilla Berglund's avatar
Camilla Berglund committed
592
            if (_glfw.wgl.ARB_context_flush_control)
593
594
595
            {
                if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
596
597
                    setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
598
599
600
                }
                else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
601
602
                    setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
603
604
605
606
                }
            }
        }

607
608
609
        if (ctxconfig->noerror)
        {
            if (_glfw.wgl.ARB_create_context_no_error)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
610
                setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
611
612
        }

Camilla Berglund's avatar
Camilla Berglund committed
613
614
615
        // 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
616
        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
617
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
618
619
            setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
            setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
Camilla Berglund's avatar
Camilla Berglund committed
620
        }
621

Camilla Berglund's avatar
Camilla Berglund committed
622
        if (flags)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
623
            setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
624

Camilla Berglund's avatar
Camilla Berglund committed
625
        if (mask)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
626
            setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
627

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
628
        setAttrib(0, 0);
629

630
631
632
633
        window->context.wgl.handle =
            _glfw.wgl.CreateContextAttribsARB(window->context.wgl.dc,
                                              share, attribs);
        if (!window->context.wgl.handle)
634
        {
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
            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");
            }
659
660
661
662
663
            else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
            {
                _glfwInputError(GLFW_INVALID_VALUE,
                                "WGL: The share context is not compatible with the requested context");
            }
664
665
666
667
668
669
670
671
672
673
674
675
676
677
            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");
                }
            }

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

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

702
703
704
705
706
707
    window->context.makeCurrent = makeContextCurrentWGL;
    window->context.swapBuffers = swapBuffersWGL;
    window->context.swapInterval = swapIntervalWGL;
    window->context.extensionSupported = extensionSupportedWGL;
    window->context.getProcAddress = getProcAddressWGL;
    window->context.destroy = destroyContextWGL;
708

709
    return GLFW_TRUE;
710
711
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
712
#undef setAttrib
Camilla Berglund's avatar
Camilla Berglund committed
713
714


715
716
717
718
719
720
721
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
722
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
723

724
    if (window->context.client == GLFW_NO_API)
725
726
727
728
729
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return NULL;
    }

730
    return window->context.wgl.handle;
731
732
}