wgl_context.c 27.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-2019 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
//
// 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.
//
//========================================================================
27
28
// Please use C89 style variable declarations in this file because VS 2010
//========================================================================
Camilla Berglund's avatar
Camilla Berglund committed
29
30
31

#include "internal.h"

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

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
36
37
38
39
40
41
// Return the value corresponding to the specified attribute
//
static int findPixelFormatAttribValue(const int* attribs,
                                      int attribCount,
                                      const int* values,
                                      int attrib)
42
43
{
    int i;
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
44
45

    for (i = 0;  i < attribCount;  i++)
46
    {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
47
        if (attribs[i] == attrib)
48
49
50
51
            return values[i];
    }

    _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
52
                         "WGL: Unknown pixel format attribute requested");
53
54
    return 0;
}
Camilla Berglund's avatar
Camilla Berglund committed
55

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
56
57
58
59
#define addAttrib(a) \
{ \
    assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \
    attribs[attribCount++] = a; \
60
}
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
61
62
#define findAttribValue(a) \
    findPixelFormatAttribValue(attribs, attribCount, values, a)
63
64
65

// Return a list of available and usable framebuffer configs
//
66
67
68
static int choosePixelFormat(_GLFWwindow* window,
                             const _GLFWctxconfig* ctxconfig,
                             const _GLFWfbconfig* fbconfig)
69
70
71
{
    _GLFWfbconfig* usableConfigs;
    const _GLFWfbconfig* closest;
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
72
    int i, pixelFormat, nativeCount, usableCount = 0, attribCount = 0;
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
73
74
    int attribs[40];
    int values[sizeof(attribs) / sizeof(attribs[0])];
75

Camilla Berglund's avatar
Camilla Berglund committed
76
    if (_glfw.wgl.ARB_pixel_format)
77
    {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
78
79
        const int attrib = WGL_NUMBER_PIXEL_FORMATS_ARB;

80
81
        if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
                                          1, 0, 1, &attrib, &nativeCount))
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
82
83
84
85
86
87
88
89
90
91
92
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
123
        {
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to retrieve pixel format attribute");
            return 0;
        }

        addAttrib(WGL_SUPPORT_OPENGL_ARB);
        addAttrib(WGL_DRAW_TO_WINDOW_ARB);
        addAttrib(WGL_PIXEL_TYPE_ARB);
        addAttrib(WGL_ACCELERATION_ARB);
        addAttrib(WGL_RED_BITS_ARB);
        addAttrib(WGL_RED_SHIFT_ARB);
        addAttrib(WGL_GREEN_BITS_ARB);
        addAttrib(WGL_GREEN_SHIFT_ARB);
        addAttrib(WGL_BLUE_BITS_ARB);
        addAttrib(WGL_BLUE_SHIFT_ARB);
        addAttrib(WGL_ALPHA_BITS_ARB);
        addAttrib(WGL_ALPHA_SHIFT_ARB);
        addAttrib(WGL_DEPTH_BITS_ARB);
        addAttrib(WGL_STENCIL_BITS_ARB);
        addAttrib(WGL_ACCUM_BITS_ARB);
        addAttrib(WGL_ACCUM_RED_BITS_ARB);
        addAttrib(WGL_ACCUM_GREEN_BITS_ARB);
        addAttrib(WGL_ACCUM_BLUE_BITS_ARB);
        addAttrib(WGL_ACCUM_ALPHA_BITS_ARB);
        addAttrib(WGL_AUX_BUFFERS_ARB);
        addAttrib(WGL_STEREO_ARB);
        addAttrib(WGL_DOUBLE_BUFFER_ARB);

        if (_glfw.wgl.ARB_multisample)
            addAttrib(WGL_SAMPLES_ARB);

        if (ctxconfig->client == GLFW_OPENGL_API)
        {
            if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB)
                addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
        }
        else
        {
            if (_glfw.wgl.EXT_colorspace)
                addAttrib(WGL_COLORSPACE_EXT);
        }
124
125
126
    }
    else
    {
127
        nativeCount = DescribePixelFormat(window->context.wgl.dc,
128
129
130
131
132
                                          1,
                                          sizeof(PIXELFORMATDESCRIPTOR),
                                          NULL);
    }

133
    usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
134
135
136
137

    for (i = 0;  i < nativeCount;  i++)
    {
        _GLFWfbconfig* u = usableConfigs + usableCount;
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
138
        pixelFormat = i + 1;
139

Camilla Berglund's avatar
Camilla Berglund committed
140
        if (_glfw.wgl.ARB_pixel_format)
141
        {
Camilla Berglund's avatar
Camilla Berglund committed
142
143
            // Get pixel format attributes through "modern" extension

144
145
146
147
            if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
                                              pixelFormat, 0,
                                              attribCount,
                                              attribs, values))
148
            {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
149
150
                _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                    "WGL: Failed to retrieve pixel format attributes");
151
152

                free(usableConfigs);
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
153
                return 0;
154
155
            }

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
156
157
            if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) ||
                !findAttribValue(WGL_DRAW_TO_WINDOW_ARB))
158
159
160
161
            {
                continue;
            }

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
162
            if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
163
164
                continue;

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
165
166
167
168
169
170
171
            if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
                continue;

            u->redBits = findAttribValue(WGL_RED_BITS_ARB);
            u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB);
            u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB);
            u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB);
172

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
173
174
            u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB);
            u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB);
175

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
176
177
178
179
            u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB);
            u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB);
            u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB);
            u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB);
180

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
181
            u->auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB);
Camilla Berglund's avatar
Camilla Berglund committed
182

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
183
            if (findAttribValue(WGL_STEREO_ARB))
184
                u->stereo = GLFW_TRUE;
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
185
            if (findAttribValue(WGL_DOUBLE_BUFFER_ARB))
186
                u->doublebuffer = GLFW_TRUE;
187

Camilla Berglund's avatar
Camilla Berglund committed
188
            if (_glfw.wgl.ARB_multisample)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
189
                u->samples = findAttribValue(WGL_SAMPLES_ARB);
190

191
            if (ctxconfig->client == GLFW_OPENGL_API)
Camilla Berglund's avatar
Camilla Berglund committed
192
            {
193
194
195
                if (_glfw.wgl.ARB_framebuffer_sRGB ||
                    _glfw.wgl.EXT_framebuffer_sRGB)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
196
                    if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
197
198
199
200
201
202
203
                        u->sRGB = GLFW_TRUE;
                }
            }
            else
            {
                if (_glfw.wgl.EXT_colorspace)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
204
                    if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
205
206
                        u->sRGB = GLFW_TRUE;
                }
Camilla Berglund's avatar
Camilla Berglund committed
207
            }
208
209
210
        }
        else
        {
Camilla Berglund's avatar
Camilla Berglund committed
211
            // Get pixel format attributes through legacy PFDs
212

213
214
215
            PIXELFORMATDESCRIPTOR pfd;

            if (!DescribePixelFormat(window->context.wgl.dc,
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
216
                                     pixelFormat,
217
218
219
                                     sizeof(PIXELFORMATDESCRIPTOR),
                                     &pfd))
            {
220
221
222
223
224
                _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                    "WGL: Failed to describe pixel format");

                free(usableConfigs);
                return 0;
225
226
227
            }

            if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
Camilla Berglund's avatar
Camilla Berglund committed
228
                !(pfd.dwFlags & PFD_SUPPORT_OPENGL))
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
            {
                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
256
257

            if (pfd.dwFlags & PFD_STEREO)
258
                u->stereo = GLFW_TRUE;
Camilla Berglund's avatar
Camilla Berglund committed
259
            if (pfd.dwFlags & PFD_DOUBLEBUFFER)
260
                u->doublebuffer = GLFW_TRUE;
261
262
        }

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
263
        u->handle = pixelFormat;
264
265
266
        usableCount++;
    }

267
268
269
270
271
272
    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
273
        return 0;
274
275
    }

276
    closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
277
278
    if (!closest)
    {
279
        _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
280
281
                        "WGL: Failed to find a suitable pixel format");

282
        free(usableConfigs);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
283
        return 0;
284
    }
285

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
286
    pixelFormat = (int) closest->handle;
287
288
    free(usableConfigs);

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
289
    return pixelFormat;
290
291
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
292
293
294
#undef addAttrib
#undef findAttribValue

295
static void makeContextCurrentWGL(_GLFWwindow* window)
296
297
298
299
{
    if (window)
    {
        if (wglMakeCurrent(window->context.wgl.dc, window->context.wgl.handle))
300
            _glfwPlatformSetTls(&_glfw.contextSlot, window);
301
302
        else
        {
303
304
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to make context current");
305
            _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
306
307
308
309
310
311
        }
    }
    else
    {
        if (!wglMakeCurrent(NULL, NULL))
        {
312
313
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to clear current context");
314
315
        }

316
        _glfwPlatformSetTls(&_glfw.contextSlot, NULL);
317
318
319
    }
}

320
static void swapBuffersWGL(_GLFWwindow* window)
321
{
Camilla Löwy's avatar
Camilla Löwy committed
322
    if (!window->monitor)
323
    {
Camilla Löwy's avatar
Camilla Löwy committed
324
325
        if (IsWindowsVistaOrGreater())
        {
326
327
            // DWM Composition is always enabled on Win8+
            BOOL enabled = IsWindows8OrGreater();
Camilla Löwy's avatar
Camilla Löwy committed
328
329

            // HACK: Use DwmFlush when desktop composition is enabled
330
331
            if (enabled ||
                (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled))
Camilla Löwy's avatar
Camilla Löwy committed
332
333
334
335
336
337
            {
                int count = abs(window->context.wgl.interval);
                while (count--)
                    DwmFlush();
            }
        }
338
339
340
341
342
    }

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

343
static void swapIntervalWGL(int interval)
344
{
345
    _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
346
347
348

    window->context.wgl.interval = interval;

Camilla Löwy's avatar
Camilla Löwy committed
349
350
351
352
    if (!window->monitor)
    {
        if (IsWindowsVistaOrGreater())
        {
353
354
            // DWM Composition is always enabled on Win8+
            BOOL enabled = IsWindows8OrGreater();
Camilla Löwy's avatar
Camilla Löwy committed
355
356
357

            // HACK: Disable WGL swap interval when desktop composition is enabled to
            //       avoid interfering with DWM vsync
358
359
            if (enabled ||
                (SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled))
Camilla Löwy's avatar
Camilla Löwy committed
360
361
362
                interval = 0;
        }
    }
363
364

    if (_glfw.wgl.EXT_swap_control)
365
        wglSwapIntervalEXT(interval);
366
367
}

368
static int extensionSupportedWGL(const char* extension)
369
{
Camilla Löwy's avatar
Camilla Löwy committed
370
    const char* extensions = NULL;
371
372

    if (_glfw.wgl.GetExtensionsStringARB)
373
        extensions = wglGetExtensionsStringARB(wglGetCurrentDC());
Camilla Löwy's avatar
Camilla Löwy committed
374
    else if (_glfw.wgl.GetExtensionsStringEXT)
375
        extensions = wglGetExtensionsStringEXT();
Camilla Löwy's avatar
Camilla Löwy committed
376
377
378

    if (!extensions)
        return GLFW_FALSE;
379

Camilla Löwy's avatar
Camilla Löwy committed
380
    return _glfwStringInExtensionString(extension, extensions);
381
382
}

383
static GLFWglproc getProcAddressWGL(const char* procname)
384
385
386
387
388
389
390
391
{
    const GLFWglproc proc = (GLFWglproc) wglGetProcAddress(procname);
    if (proc)
        return proc;

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

392
static void destroyContextWGL(_GLFWwindow* window)
393
394
395
396
397
398
399
400
{
    if (window->context.wgl.handle)
    {
        wglDeleteContext(window->context.wgl.handle);
        window->context.wgl.handle = NULL;
    }
}

401
402
403
404
405
406

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

// Initialize WGL
407
//
408
GLFWbool _glfwInitWGL(void)
409
{
410
    PIXELFORMATDESCRIPTOR pfd;
411
412
413
414
415
416
417
418
419
420
421
422
423
    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;
    }
424

425
426
427
428
429
430
431
432
433
434
435
436
437
438
    _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");
439

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
440
441
442
443
444
    // 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

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
445
    dc = GetDC(_glfw.win32.helperWindowHandle);
446

447
448
449
450
451
452
453
    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
454
    if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
455
    {
456
457
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to set pixel format for dummy context");
458
        return GLFW_FALSE;
459
460
461
462
463
    }

    rc = wglCreateContext(dc);
    if (!rc)
    {
464
465
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to create dummy context");
466
        return GLFW_FALSE;
467
468
    }

469
470
471
    pdc = wglGetCurrentDC();
    prc = wglGetCurrentContext();

472
473
    if (!wglMakeCurrent(dc, rc))
    {
474
475
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to make dummy context current");
476
        wglMakeCurrent(pdc, prc);
477
        wglDeleteContext(rc);
478
        return GLFW_FALSE;
479
480
    }

Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
481
482
    // NOTE: Functions must be loaded first as they're needed to retrieve the
    //       extension string that tells us whether the functions are supported
483
484
485
486
487
488
489
490
491
492
493
    _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
494
495
    // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
    //       checked below as we are already using them
496
    _glfw.wgl.ARB_multisample =
497
        extensionSupportedWGL("WGL_ARB_multisample");
498
    _glfw.wgl.ARB_framebuffer_sRGB =
499
        extensionSupportedWGL("WGL_ARB_framebuffer_sRGB");
500
    _glfw.wgl.EXT_framebuffer_sRGB =
501
        extensionSupportedWGL("WGL_EXT_framebuffer_sRGB");
502
    _glfw.wgl.ARB_create_context =
503
        extensionSupportedWGL("WGL_ARB_create_context");
504
    _glfw.wgl.ARB_create_context_profile =
505
        extensionSupportedWGL("WGL_ARB_create_context_profile");
506
    _glfw.wgl.EXT_create_context_es2_profile =
507
        extensionSupportedWGL("WGL_EXT_create_context_es2_profile");
508
    _glfw.wgl.ARB_create_context_robustness =
509
        extensionSupportedWGL("WGL_ARB_create_context_robustness");
510
511
    _glfw.wgl.ARB_create_context_no_error =
        extensionSupportedWGL("WGL_ARB_create_context_no_error");
512
    _glfw.wgl.EXT_swap_control =
513
        extensionSupportedWGL("WGL_EXT_swap_control");
514
515
    _glfw.wgl.EXT_colorspace =
        extensionSupportedWGL("WGL_EXT_colorspace");
516
    _glfw.wgl.ARB_pixel_format =
517
        extensionSupportedWGL("WGL_ARB_pixel_format");
518
    _glfw.wgl.ARB_context_flush_control =
519
        extensionSupportedWGL("WGL_ARB_context_flush_control");
520

521
    wglMakeCurrent(pdc, prc);
522
    wglDeleteContext(rc);
523
    return GLFW_TRUE;
524
525
526
}

// Terminate WGL
527
//
528
void _glfwTerminateWGL(void)
529
{
Camilla Berglund's avatar
Camilla Berglund committed
530
531
    if (_glfw.wgl.instance)
        FreeLibrary(_glfw.wgl.instance);
532
533
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
534
#define setAttrib(a, v) \
535
{ \
536
    assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
537
538
    attribs[index++] = a; \
    attribs[index++] = v; \
539
540
}

541
// Create the OpenGL or OpenGL ES context for the given HDC
542
//
543
GLFWbool _glfwCreateContextForDCWGL(HDC dc, const _GLFWctxconfig* ctxconfig, HGLRC* context)
544
{
545
546
    int attribs[40];
    HGLRC share = NULL;
547

548
    *context = NULL;
549
    if (ctxconfig->share)
550
        share = ctxconfig->share->context.wgl.handle;
551
552


553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
    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
587
    if (_glfw.wgl.ARB_create_context)
588
    {
589
        int index = 0, mask = 0, flags = 0;
590

591
        if (ctxconfig->client == GLFW_OPENGL_API)
592
        {
593
            if (ctxconfig->forward)
594
595
                flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;

596
597
598
599
            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;
600
        }
Camilla Berglund's avatar
Camilla Berglund committed
601
602
        else
            mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
603

604
605
606
        if (ctxconfig->debug)
            flags |= WGL_CONTEXT_DEBUG_BIT_ARB;

607
        if (ctxconfig->robustness)
608
        {
Camilla Berglund's avatar
Camilla Berglund committed
609
            if (_glfw.wgl.ARB_create_context_robustness)
610
            {
611
                if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
612
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
613
614
                    setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              WGL_NO_RESET_NOTIFICATION_ARB);
615
                }
616
                else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
617
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
618
619
                    setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              WGL_LOSE_CONTEXT_ON_RESET_ARB);
620
                }
621

Camilla Berglund's avatar
Camilla Berglund committed
622
623
                flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
            }
624
625
        }

626
627
        if (ctxconfig->release)
        {
Camilla Berglund's avatar
Camilla Berglund committed
628
            if (_glfw.wgl.ARB_context_flush_control)
629
630
631
            {
                if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
632
633
                    setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
634
635
636
                }
                else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
637
638
                    setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
639
640
641
642
                }
            }
        }

643
644
645
        if (ctxconfig->noerror)
        {
            if (_glfw.wgl.ARB_create_context_no_error)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
646
                setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
647
648
        }

Camilla Berglund's avatar
Camilla Berglund committed
649
650
651
        // 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
652
        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
653
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
654
655
            setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
            setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
Camilla Berglund's avatar
Camilla Berglund committed
656
        }
657

Camilla Berglund's avatar
Camilla Berglund committed
658
        if (flags)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
659
            setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
660

Camilla Berglund's avatar
Camilla Berglund committed
661
        if (mask)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
662
            setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
663

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
664
        setAttrib(0, 0);
665

666
667
668
        *context =
            wglCreateContextAttribsARB(dc, share, attribs);
        if (!(*context))
669
        {
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
            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");
            }
694
695
696
697
698
            else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
            {
                _glfwInputError(GLFW_INVALID_VALUE,
                                "WGL: The share context is not compatible with the requested context");
            }
699
700
701
702
703
704
705
706
707
708
709
710
711
712
            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");
                }
            }

713
            return GLFW_FALSE;
714
715
716
717
        }
    }
    else
    {
718
719
        *context = wglCreateContext(dc);
        if (!(*context) )
720
        {
721
722
            _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
                                 "WGL: Failed to create OpenGL context");
723
            return GLFW_FALSE;
724
725
726
727
        }

        if (share)
        {
728
            if (!wglShareLists(share, *context))
729
            {
730
731
                _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                     "WGL: Failed to enable sharing with specified OpenGL context");
732
                return GLFW_FALSE;
733
734
735
736
            }
        }
    }

737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
    return GLFW_TRUE;
}

// Create the OpenGL or OpenGL ES context
//
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
{
    int pixelFormat;
    PIXELFORMATDESCRIPTOR pfd;

    window->context.wgl.dc = GetDC(window->win32.handle);
    if (!window->context.wgl.dc)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "WGL: Failed to retrieve DC for window");
        return GLFW_FALSE;
    }

    pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
    if (!pixelFormat)
        return GLFW_FALSE;

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

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

    if(!_glfwCreateContextForDCWGL( window->context.wgl.dc, ctxconfig, &window->context.wgl.handle ))
    {
        return GLFW_FALSE;
    }

781
782
783
784
785
786
    window->context.makeCurrent = makeContextCurrentWGL;
    window->context.swapBuffers = swapBuffersWGL;
    window->context.swapInterval = swapIntervalWGL;
    window->context.extensionSupported = extensionSupportedWGL;
    window->context.getProcAddress = getProcAddressWGL;
    window->context.destroy = destroyContextWGL;
787

788
    return GLFW_TRUE;
789
790
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
791
#undef setAttrib
Camilla Berglund's avatar
Camilla Berglund committed
792

793
794
static void _glfwMakeUserContextCurrentWGL(_GLFWusercontext* context)
{
795
    if(!wglMakeCurrent(context->window->context.wgl.dc,context->wgl.handle))
796
    {
797
798
799
800
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                             "WGL: Failed to make user context current");
        _glfwPlatformSetTls(&_glfw.usercontextSlot, NULL);
        return;
801
    }
802
    _glfwPlatformSetTls(&_glfw.usercontextSlot, context);
803
}
Camilla Berglund's avatar
Camilla Berglund committed
804

805
806
807
808
809
static void _glfwDestroyUserContextWGL(_GLFWusercontext* context)
{
    wglDeleteContext(context->wgl.handle);
    free(context);
}
810

811
_GLFWusercontext* _glfwCreateUserContextWGL(_GLFWwindow* window)
812
813
{
    _GLFWusercontext* context;
814
    _GLFWctxconfig ctxconfig;
815

816
    context = calloc(1, sizeof(_GLFWusercontext));
817
818
    context->window = window;

819
820
821
    ctxconfig = _glfw.hints.context;
    ctxconfig.share = window;

822
    if (!_glfwCreateContextForDCWGL(window->context.wgl.dc, &ctxconfig, &context->wgl.handle))
823
824
    {
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
825
                                "WGL: Failed to create user OpenGL context");
826
        free(context);
827
        return NULL;
828
    }
829

830
831
    context->makeCurrent = _glfwMakeUserContextCurrentWGL;
    context->destroy = _glfwDestroyUserContextWGL;
832

833
    return context;
834
835
836
}


837
838
839
840
841
842
843
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
844
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
845

846
    if (window->context.client == GLFW_NO_API)
847
848
849
850
851
    {
        _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
        return NULL;
    }

852
    return window->context.wgl.handle;
853
854
}