wgl_context.c 27.9 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
542
//
Camilla Berglund's avatar
Camilla Berglund committed
543
544
545
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
546
{
547
    int attribs[40];
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
548
    int pixelFormat;
549
    PIXELFORMATDESCRIPTOR pfd;
550
    HGLRC share = NULL;
551

552
    if (ctxconfig->share)
553
        share = ctxconfig->share->context.wgl.handle;
554

555
556
    window->context.wgl.dc = GetDC(window->win32.handle);
    if (!window->context.wgl.dc)
557
    {
558
        _glfwInputError(GLFW_PLATFORM_ERROR,
Camilla Berglund's avatar
Camilla Berglund committed
559
                        "WGL: Failed to retrieve DC for window");
560
        return GLFW_FALSE;
561
562
    }

563
    pixelFormat = choosePixelFormat(window, ctxconfig, fbconfig);
Camilla Berglund's avatar
Cleanup    
Camilla Berglund committed
564
    if (!pixelFormat)
565
        return GLFW_FALSE;
566

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

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

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
    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
616
    if (_glfw.wgl.ARB_create_context)
617
    {
618
        int index = 0, mask = 0, flags = 0;
619

620
        if (ctxconfig->client == GLFW_OPENGL_API)
621
        {
622
            if (ctxconfig->forward)
623
624
                flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;

625
626
627
628
            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;
629
        }
Camilla Berglund's avatar
Camilla Berglund committed
630
631
        else
            mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
632

633
634
635
        if (ctxconfig->debug)
            flags |= WGL_CONTEXT_DEBUG_BIT_ARB;

636
        if (ctxconfig->robustness)
637
        {
Camilla Berglund's avatar
Camilla Berglund committed
638
            if (_glfw.wgl.ARB_create_context_robustness)
639
            {
640
                if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
641
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
642
643
                    setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              WGL_NO_RESET_NOTIFICATION_ARB);
644
                }
645
                else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
646
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
647
648
                    setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
                              WGL_LOSE_CONTEXT_ON_RESET_ARB);
649
                }
650

Camilla Berglund's avatar
Camilla Berglund committed
651
652
                flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
            }
653
654
        }

655
656
        if (ctxconfig->release)
        {
Camilla Berglund's avatar
Camilla Berglund committed
657
            if (_glfw.wgl.ARB_context_flush_control)
658
659
660
            {
                if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
661
662
                    setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
663
664
665
                }
                else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
                {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
666
667
                    setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
                              WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
668
669
670
671
                }
            }
        }

672
673
674
        if (ctxconfig->noerror)
        {
            if (_glfw.wgl.ARB_create_context_no_error)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
675
                setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
676
677
        }

Camilla Berglund's avatar
Camilla Berglund committed
678
679
680
        // 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
681
        if (ctxconfig->major != 1 || ctxconfig->minor != 0)
682
        {
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
683
684
            setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
            setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
Camilla Berglund's avatar
Camilla Berglund committed
685
        }
686

Camilla Berglund's avatar
Camilla Berglund committed
687
        if (flags)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
688
            setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
689

Camilla Berglund's avatar
Camilla Berglund committed
690
        if (mask)
Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
691
            setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
692

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
693
        setAttrib(0, 0);
694

695
        window->context.wgl.handle =
696
            wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
697
        if (!window->context.wgl.handle)
698
        {
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
            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");
            }
723
724
725
726
727
            else if (error == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB))
            {
                _glfwInputError(GLFW_INVALID_VALUE,
                                "WGL: The share context is not compatible with the requested context");
            }
728
729
730
731
732
733
734
735
736
737
738
739
740
741
            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");
                }
            }

742
            return GLFW_FALSE;
743
744
745
746
        }
    }
    else
    {
747
        window->context.wgl.handle = wglCreateContext(window->context.wgl.dc);
748
        if (!window->context.wgl.handle)
749
        {
750
751
            _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
                                 "WGL: Failed to create OpenGL context");
752
            return GLFW_FALSE;
753
754
755
756
        }

        if (share)
        {
757
            if (!wglShareLists(share, window->context.wgl.handle))
758
            {
759
760
                _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                     "WGL: Failed to enable sharing with specified OpenGL context");
761
                return GLFW_FALSE;
762
763
764
765
            }
        }
    }

766
767
768
769
770
771
    window->context.makeCurrent = makeContextCurrentWGL;
    window->context.swapBuffers = swapBuffersWGL;
    window->context.swapInterval = swapIntervalWGL;
    window->context.extensionSupported = extensionSupportedWGL;
    window->context.getProcAddress = getProcAddressWGL;
    window->context.destroy = destroyContextWGL;
772

773
    return GLFW_TRUE;
774
775
}

Camilla Löwy's avatar
Cleanup    
Camilla Löwy committed
776
#undef setAttrib
Camilla Berglund's avatar
Camilla Berglund committed
777
778


779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
//////////////////////////////////////////////////////////////////////////
//////                       GLFW platform API                      //////
//////////////////////////////////////////////////////////////////////////

_GLFWusercontext* _glfwPlatformCreateUserContext(_GLFWwindow* window)
{
    _GLFWusercontext* context;
    context = calloc(1, sizeof(_GLFWusercontext));

    context->handle = wglCreateContext(window->context.wgl.dc);
    context->window = window;
    if (!context->handle)
    {
        _glfwInputErrorWin32(GLFW_VERSION_UNAVAILABLE,
                                "WGL: Failed to create user OpenGL context");
        free(context);
        return GLFW_FALSE;
    }

    if (!wglShareLists(window->context.wgl.handle,context->handle))
    {
        _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                "WGL: Failed to enable sharing with window OpenGL context and user context");
        free(context);
        return GLFW_FALSE;
    }
    return context;
}

void _glfwPlatformDestroyUserContext(_GLFWusercontext* context)
{
    wglDeleteContext(context->handle);
    free(context);
}

void _glfwPlatformMakeUserContextCurrent(_GLFWusercontext* context)
{
    if(context)
    {
        if(!wglMakeCurrent(context->window->context.wgl.dc,context->handle))
        {
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to set current user context");
        }
    }
    else
    {
        if (!wglMakeCurrent(NULL, NULL))
        {
            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
                                 "WGL: Failed to clear current context");
        }
    }
}


835
836
837
838
839
840
841
//////////////////////////////////////////////////////////////////////////
//////                        GLFW native API                       //////
//////////////////////////////////////////////////////////////////////////

GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
842
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
843

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

850
    return window->context.wgl.handle;
851
852
}