d30d838fdcc5a403ebffd285a3b7be26be875e24
[platform/upstream/SDL.git] / src / video / windows / SDL_windowsopengl.c
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if SDL_VIDEO_DRIVER_WINDOWS
24
25 #include "SDL_assert.h"
26 #include "SDL_loadso.h"
27 #include "SDL_windowsvideo.h"
28 #include "SDL_windowsopengles.h"
29
30 /* WGL implementation of SDL OpenGL support */
31
32 #if SDL_VIDEO_OPENGL_WGL
33 #include "SDL_opengl.h"
34
35 #define DEFAULT_OPENGL "OPENGL32.DLL"
36
37 #ifndef WGL_ARB_create_context
38 #define WGL_ARB_create_context
39 #define WGL_CONTEXT_MAJOR_VERSION_ARB   0x2091
40 #define WGL_CONTEXT_MINOR_VERSION_ARB   0x2092
41 #define WGL_CONTEXT_LAYER_PLANE_ARB     0x2093
42 #define WGL_CONTEXT_FLAGS_ARB           0x2094
43 #define WGL_CONTEXT_DEBUG_BIT_ARB       0x0001
44 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB  0x0002
45
46 #ifndef WGL_ARB_create_context_profile
47 #define WGL_ARB_create_context_profile
48 #define WGL_CONTEXT_PROFILE_MASK_ARB              0x9126
49 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB          0x00000001
50 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
51 #endif
52
53 #ifndef WGL_ARB_create_context_robustness
54 #define WGL_ARB_create_context_robustness
55 #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB         0x00000004
56 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB     0x8256
57 #define WGL_NO_RESET_NOTIFICATION_ARB                   0x8261
58 #define WGL_LOSE_CONTEXT_ON_RESET_ARB                   0x8252
59 #endif
60 #endif
61
62 #ifndef WGL_EXT_create_context_es2_profile
63 #define WGL_EXT_create_context_es2_profile
64 #define WGL_CONTEXT_ES2_PROFILE_BIT_EXT           0x00000004
65 #endif
66
67 #ifndef WGL_EXT_create_context_es_profile
68 #define WGL_EXT_create_context_es_profile
69 #define WGL_CONTEXT_ES_PROFILE_BIT_EXT            0x00000004
70 #endif
71
72 #ifndef WGL_ARB_framebuffer_sRGB
73 #define WGL_ARB_framebuffer_sRGB
74 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB                0x20A9
75 #endif
76
77 #ifndef WGL_ARB_context_flush_control
78 #define WGL_ARB_context_flush_control
79 #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB   0x2097
80 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB           0x0000
81 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB          0x2098
82 #endif
83
84 typedef HGLRC(APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC,
85                                                             HGLRC
86                                                             hShareContext,
87                                                             const int
88                                                             *attribList);
89
90 int
91 WIN_GL_LoadLibrary(_THIS, const char *path)
92 {
93     void *handle;
94
95     if (path == NULL) {
96         path = SDL_getenv("SDL_OPENGL_LIBRARY");
97     }
98     if (path == NULL) {
99         path = DEFAULT_OPENGL;
100     }
101     _this->gl_config.dll_handle = SDL_LoadObject(path);
102     if (!_this->gl_config.dll_handle) {
103         return -1;
104     }
105     SDL_strlcpy(_this->gl_config.driver_path, path,
106                 SDL_arraysize(_this->gl_config.driver_path));
107
108     /* Allocate OpenGL memory */
109     _this->gl_data = (struct SDL_GLDriverData *) SDL_calloc(1, sizeof(struct SDL_GLDriverData));
110     if (!_this->gl_data) {
111         return SDL_OutOfMemory();
112     }
113
114     /* Load function pointers */
115     handle = _this->gl_config.dll_handle;
116     _this->gl_data->wglGetProcAddress = (void *(WINAPI *) (const char *))
117         SDL_LoadFunction(handle, "wglGetProcAddress");
118     _this->gl_data->wglCreateContext = (HGLRC(WINAPI *) (HDC))
119         SDL_LoadFunction(handle, "wglCreateContext");
120     _this->gl_data->wglDeleteContext = (BOOL(WINAPI *) (HGLRC))
121         SDL_LoadFunction(handle, "wglDeleteContext");
122     _this->gl_data->wglMakeCurrent = (BOOL(WINAPI *) (HDC, HGLRC))
123         SDL_LoadFunction(handle, "wglMakeCurrent");
124     _this->gl_data->wglShareLists = (BOOL(WINAPI *) (HGLRC, HGLRC))
125         SDL_LoadFunction(handle, "wglShareLists");
126
127     if (!_this->gl_data->wglGetProcAddress ||
128         !_this->gl_data->wglCreateContext ||
129         !_this->gl_data->wglDeleteContext ||
130         !_this->gl_data->wglMakeCurrent) {
131         return SDL_SetError("Could not retrieve OpenGL functions");
132     }
133
134     return 0;
135 }
136
137 void *
138 WIN_GL_GetProcAddress(_THIS, const char *proc)
139 {
140     void *func;
141
142     /* This is to pick up extensions */
143     func = _this->gl_data->wglGetProcAddress(proc);
144     if (!func) {
145         /* This is probably a normal GL function */
146         func = GetProcAddress(_this->gl_config.dll_handle, proc);
147     }
148     return func;
149 }
150
151 void
152 WIN_GL_UnloadLibrary(_THIS)
153 {
154     SDL_UnloadObject(_this->gl_config.dll_handle);
155     _this->gl_config.dll_handle = NULL;
156
157     /* Free OpenGL memory */
158     SDL_free(_this->gl_data);
159     _this->gl_data = NULL;
160 }
161
162 static void
163 WIN_GL_SetupPixelFormat(_THIS, PIXELFORMATDESCRIPTOR * pfd)
164 {
165     SDL_zerop(pfd);
166     pfd->nSize = sizeof(*pfd);
167     pfd->nVersion = 1;
168     pfd->dwFlags = (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL);
169     if (_this->gl_config.double_buffer) {
170         pfd->dwFlags |= PFD_DOUBLEBUFFER;
171     }
172     if (_this->gl_config.stereo) {
173         pfd->dwFlags |= PFD_STEREO;
174     }
175     pfd->iLayerType = PFD_MAIN_PLANE;
176     pfd->iPixelType = PFD_TYPE_RGBA;
177     pfd->cRedBits = _this->gl_config.red_size;
178     pfd->cGreenBits = _this->gl_config.green_size;
179     pfd->cBlueBits = _this->gl_config.blue_size;
180     pfd->cAlphaBits = _this->gl_config.alpha_size;
181     if (_this->gl_config.buffer_size) {
182         pfd->cColorBits =
183             _this->gl_config.buffer_size - _this->gl_config.alpha_size;
184     } else {
185         pfd->cColorBits = (pfd->cRedBits + pfd->cGreenBits + pfd->cBlueBits);
186     }
187     pfd->cAccumRedBits = _this->gl_config.accum_red_size;
188     pfd->cAccumGreenBits = _this->gl_config.accum_green_size;
189     pfd->cAccumBlueBits = _this->gl_config.accum_blue_size;
190     pfd->cAccumAlphaBits = _this->gl_config.accum_alpha_size;
191     pfd->cAccumBits =
192         (pfd->cAccumRedBits + pfd->cAccumGreenBits + pfd->cAccumBlueBits +
193          pfd->cAccumAlphaBits);
194     pfd->cDepthBits = _this->gl_config.depth_size;
195     pfd->cStencilBits = _this->gl_config.stencil_size;
196 }
197
198 /* Choose the closest pixel format that meets or exceeds the target.
199    FIXME: Should we weight any particular attribute over any other?
200 */
201 static int
202 WIN_GL_ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR * target)
203 {
204     PIXELFORMATDESCRIPTOR pfd;
205     int count, index, best = 0;
206     unsigned int dist, best_dist = ~0U;
207
208     count = DescribePixelFormat(hdc, 1, sizeof(pfd), NULL);
209
210     for (index = 1; index <= count; index++) {
211
212         if (!DescribePixelFormat(hdc, index, sizeof(pfd), &pfd)) {
213             continue;
214         }
215
216         if ((pfd.dwFlags & target->dwFlags) != target->dwFlags) {
217             continue;
218         }
219
220         if (pfd.iLayerType != target->iLayerType) {
221             continue;
222         }
223         if (pfd.iPixelType != target->iPixelType) {
224             continue;
225         }
226
227         dist = 0;
228
229         if (pfd.cColorBits < target->cColorBits) {
230             continue;
231         } else {
232             dist += (pfd.cColorBits - target->cColorBits);
233         }
234         if (pfd.cRedBits < target->cRedBits) {
235             continue;
236         } else {
237             dist += (pfd.cRedBits - target->cRedBits);
238         }
239         if (pfd.cGreenBits < target->cGreenBits) {
240             continue;
241         } else {
242             dist += (pfd.cGreenBits - target->cGreenBits);
243         }
244         if (pfd.cBlueBits < target->cBlueBits) {
245             continue;
246         } else {
247             dist += (pfd.cBlueBits - target->cBlueBits);
248         }
249         if (pfd.cAlphaBits < target->cAlphaBits) {
250             continue;
251         } else {
252             dist += (pfd.cAlphaBits - target->cAlphaBits);
253         }
254         if (pfd.cAccumBits < target->cAccumBits) {
255             continue;
256         } else {
257             dist += (pfd.cAccumBits - target->cAccumBits);
258         }
259         if (pfd.cAccumRedBits < target->cAccumRedBits) {
260             continue;
261         } else {
262             dist += (pfd.cAccumRedBits - target->cAccumRedBits);
263         }
264         if (pfd.cAccumGreenBits < target->cAccumGreenBits) {
265             continue;
266         } else {
267             dist += (pfd.cAccumGreenBits - target->cAccumGreenBits);
268         }
269         if (pfd.cAccumBlueBits < target->cAccumBlueBits) {
270             continue;
271         } else {
272             dist += (pfd.cAccumBlueBits - target->cAccumBlueBits);
273         }
274         if (pfd.cAccumAlphaBits < target->cAccumAlphaBits) {
275             continue;
276         } else {
277             dist += (pfd.cAccumAlphaBits - target->cAccumAlphaBits);
278         }
279         if (pfd.cDepthBits < target->cDepthBits) {
280             continue;
281         } else {
282             dist += (pfd.cDepthBits - target->cDepthBits);
283         }
284         if (pfd.cStencilBits < target->cStencilBits) {
285             continue;
286         } else {
287             dist += (pfd.cStencilBits - target->cStencilBits);
288         }
289
290         if (dist < best_dist) {
291             best = index;
292             best_dist = dist;
293         }
294     }
295
296     return best;
297 }
298
299 static SDL_bool
300 HasExtension(const char *extension, const char *extensions)
301 {
302     const char *start;
303     const char *where, *terminator;
304
305     /* Extension names should not have spaces. */
306     where = SDL_strchr(extension, ' ');
307     if (where || *extension == '\0')
308         return SDL_FALSE;
309
310     if (!extensions)
311         return SDL_FALSE;
312
313     /* It takes a bit of care to be fool-proof about parsing the
314      * OpenGL extensions string. Don't be fooled by sub-strings,
315      * etc. */
316
317     start = extensions;
318
319     for (;;) {
320         where = SDL_strstr(start, extension);
321         if (!where)
322             break;
323
324         terminator = where + SDL_strlen(extension);
325         if (where == start || *(where - 1) == ' ')
326             if (*terminator == ' ' || *terminator == '\0')
327                 return SDL_TRUE;
328
329         start = terminator;
330     }
331     return SDL_FALSE;
332 }
333
334 void
335 WIN_GL_InitExtensions(_THIS)
336 {
337     const char *(WINAPI * wglGetExtensionsStringARB) (HDC) = 0;
338     const char *extensions;
339     HWND hwnd;
340     HDC hdc;
341     HGLRC hglrc;
342     PIXELFORMATDESCRIPTOR pfd;
343
344     if (!_this->gl_data) {
345         return;
346     }
347
348     hwnd =
349         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
350         10, 10, NULL, NULL, SDL_Instance, NULL);
351     if (!hwnd) {
352         return;
353     }
354     WIN_PumpEvents(_this);
355
356     hdc = GetDC(hwnd);
357
358     WIN_GL_SetupPixelFormat(_this, &pfd);
359
360     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
361
362     hglrc = _this->gl_data->wglCreateContext(hdc);
363     if (!hglrc) {
364         return;
365     }
366     _this->gl_data->wglMakeCurrent(hdc, hglrc);
367
368     wglGetExtensionsStringARB = (const char *(WINAPI *) (HDC))
369         _this->gl_data->wglGetProcAddress("wglGetExtensionsStringARB");
370     if (wglGetExtensionsStringARB) {
371         extensions = wglGetExtensionsStringARB(hdc);
372     } else {
373         extensions = NULL;
374     }
375
376     /* Check for WGL_ARB_pixel_format */
377     _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_FALSE;
378     if (HasExtension("WGL_ARB_pixel_format", extensions)) {
379         _this->gl_data->wglChoosePixelFormatARB = (BOOL(WINAPI *)
380                                                    (HDC, const int *,
381                                                     const FLOAT *, UINT,
382                                                     int *, UINT *))
383             WIN_GL_GetProcAddress(_this, "wglChoosePixelFormatARB");
384         _this->gl_data->wglGetPixelFormatAttribivARB =
385             (BOOL(WINAPI *) (HDC, int, int, UINT, const int *, int *))
386             WIN_GL_GetProcAddress(_this, "wglGetPixelFormatAttribivARB");
387
388         if ((_this->gl_data->wglChoosePixelFormatARB != NULL) &&
389             (_this->gl_data->wglGetPixelFormatAttribivARB != NULL)) {
390             _this->gl_data->HAS_WGL_ARB_pixel_format = SDL_TRUE;
391         }
392     }
393
394     /* Check for WGL_EXT_swap_control */
395     _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_FALSE;
396     if (HasExtension("WGL_EXT_swap_control", extensions)) {
397         _this->gl_data->wglSwapIntervalEXT =
398             WIN_GL_GetProcAddress(_this, "wglSwapIntervalEXT");
399         _this->gl_data->wglGetSwapIntervalEXT =
400             WIN_GL_GetProcAddress(_this, "wglGetSwapIntervalEXT");
401         if (HasExtension("WGL_EXT_swap_control_tear", extensions)) {
402             _this->gl_data->HAS_WGL_EXT_swap_control_tear = SDL_TRUE;
403         }
404     } else {
405         _this->gl_data->wglSwapIntervalEXT = NULL;
406         _this->gl_data->wglGetSwapIntervalEXT = NULL;
407     }
408
409     /* Check for WGL_EXT_create_context_es2_profile */
410     _this->gl_data->HAS_WGL_EXT_create_context_es2_profile = SDL_FALSE;
411     if (HasExtension("WGL_EXT_create_context_es2_profile", extensions)) {
412         _this->gl_data->HAS_WGL_EXT_create_context_es2_profile = SDL_TRUE;
413     }
414
415     /* Check for GLX_ARB_context_flush_control */
416     if (HasExtension("WGL_ARB_context_flush_control", extensions)) {
417         _this->gl_data->HAS_WGL_ARB_context_flush_control = SDL_TRUE;
418     }
419
420     _this->gl_data->wglMakeCurrent(hdc, NULL);
421     _this->gl_data->wglDeleteContext(hglrc);
422     ReleaseDC(hwnd, hdc);
423     DestroyWindow(hwnd);
424     WIN_PumpEvents(_this);
425 }
426
427 static int
428 WIN_GL_ChoosePixelFormatARB(_THIS, int *iAttribs, float *fAttribs)
429 {
430     HWND hwnd;
431     HDC hdc;
432     PIXELFORMATDESCRIPTOR pfd;
433     HGLRC hglrc;
434     int pixel_format = 0;
435     unsigned int matching;
436
437     hwnd =
438         CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0,
439                      10, 10, NULL, NULL, SDL_Instance, NULL);
440     WIN_PumpEvents(_this);
441
442     hdc = GetDC(hwnd);
443
444     WIN_GL_SetupPixelFormat(_this, &pfd);
445
446     SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd);
447
448     hglrc = _this->gl_data->wglCreateContext(hdc);
449     if (hglrc) {
450         _this->gl_data->wglMakeCurrent(hdc, hglrc);
451
452         if (_this->gl_data->HAS_WGL_ARB_pixel_format) {
453             _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs,
454                                                     1, &pixel_format,
455                                                     &matching);
456         }
457
458         _this->gl_data->wglMakeCurrent(hdc, NULL);
459         _this->gl_data->wglDeleteContext(hglrc);
460     }
461     ReleaseDC(hwnd, hdc);
462     DestroyWindow(hwnd);
463     WIN_PumpEvents(_this);
464
465     return pixel_format;
466 }
467
468 /* actual work of WIN_GL_SetupWindow() happens here. */
469 static int
470 WIN_GL_SetupWindowInternal(_THIS, SDL_Window * window)
471 {
472     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
473     PIXELFORMATDESCRIPTOR pfd;
474     int pixel_format = 0;
475     int iAttribs[64];
476     int *iAttr;
477     int *iAccelAttr;
478     float fAttribs[1] = { 0 };
479
480     WIN_GL_SetupPixelFormat(_this, &pfd);
481
482     /* setup WGL_ARB_pixel_format attribs */
483     iAttr = &iAttribs[0];
484
485     *iAttr++ = WGL_DRAW_TO_WINDOW_ARB;
486     *iAttr++ = GL_TRUE;
487     *iAttr++ = WGL_RED_BITS_ARB;
488     *iAttr++ = _this->gl_config.red_size;
489     *iAttr++ = WGL_GREEN_BITS_ARB;
490     *iAttr++ = _this->gl_config.green_size;
491     *iAttr++ = WGL_BLUE_BITS_ARB;
492     *iAttr++ = _this->gl_config.blue_size;
493
494     if (_this->gl_config.alpha_size) {
495         *iAttr++ = WGL_ALPHA_BITS_ARB;
496         *iAttr++ = _this->gl_config.alpha_size;
497     }
498
499     *iAttr++ = WGL_DOUBLE_BUFFER_ARB;
500     *iAttr++ = _this->gl_config.double_buffer;
501
502     *iAttr++ = WGL_DEPTH_BITS_ARB;
503     *iAttr++ = _this->gl_config.depth_size;
504
505     if (_this->gl_config.stencil_size) {
506         *iAttr++ = WGL_STENCIL_BITS_ARB;
507         *iAttr++ = _this->gl_config.stencil_size;
508     }
509
510     if (_this->gl_config.accum_red_size) {
511         *iAttr++ = WGL_ACCUM_RED_BITS_ARB;
512         *iAttr++ = _this->gl_config.accum_red_size;
513     }
514
515     if (_this->gl_config.accum_green_size) {
516         *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB;
517         *iAttr++ = _this->gl_config.accum_green_size;
518     }
519
520     if (_this->gl_config.accum_blue_size) {
521         *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB;
522         *iAttr++ = _this->gl_config.accum_blue_size;
523     }
524
525     if (_this->gl_config.accum_alpha_size) {
526         *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB;
527         *iAttr++ = _this->gl_config.accum_alpha_size;
528     }
529
530     if (_this->gl_config.stereo) {
531         *iAttr++ = WGL_STEREO_ARB;
532         *iAttr++ = GL_TRUE;
533     }
534
535     if (_this->gl_config.multisamplebuffers) {
536         *iAttr++ = WGL_SAMPLE_BUFFERS_ARB;
537         *iAttr++ = _this->gl_config.multisamplebuffers;
538     }
539
540     if (_this->gl_config.multisamplesamples) {
541         *iAttr++ = WGL_SAMPLES_ARB;
542         *iAttr++ = _this->gl_config.multisamplesamples;
543     }
544
545     if (_this->gl_config.framebuffer_srgb_capable) {
546         *iAttr++ = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
547         *iAttr++ = _this->gl_config.framebuffer_srgb_capable;
548     }
549
550     /* We always choose either FULL or NO accel on Windows, because of flaky
551        drivers. If the app didn't specify, we use FULL, because that's
552        probably what they wanted (and if you didn't care and got FULL, that's
553        a perfectly valid result in any case). */
554     *iAttr++ = WGL_ACCELERATION_ARB;
555     iAccelAttr = iAttr;
556     if (_this->gl_config.accelerated) {
557         *iAttr++ = WGL_FULL_ACCELERATION_ARB;
558     } else {
559         *iAttr++ = WGL_NO_ACCELERATION_ARB;
560     }
561
562     *iAttr = 0;
563
564     /* Choose and set the closest available pixel format */
565     pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
566
567     /* App said "don't care about accel" and FULL accel failed. Try NO. */
568     if ( ( !pixel_format ) && ( _this->gl_config.accelerated < 0 ) ) {
569         *iAccelAttr = WGL_NO_ACCELERATION_ARB;
570         pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs);
571         *iAccelAttr = WGL_FULL_ACCELERATION_ARB;  /* if we try again. */
572     }
573     if (!pixel_format) {
574         pixel_format = WIN_GL_ChoosePixelFormat(hdc, &pfd);
575     }
576     if (!pixel_format) {
577         return SDL_SetError("No matching GL pixel format available");
578     }
579     if (!SetPixelFormat(hdc, pixel_format, &pfd)) {
580         return WIN_SetError("SetPixelFormat()");
581     }
582     return 0;
583 }
584
585 int
586 WIN_GL_SetupWindow(_THIS, SDL_Window * window)
587 {
588     /* The current context is lost in here; save it and reset it. */
589     SDL_Window *current_win = SDL_GL_GetCurrentWindow();
590     SDL_GLContext current_ctx = SDL_GL_GetCurrentContext();
591     const int retval = WIN_GL_SetupWindowInternal(_this, window);
592     WIN_GL_MakeCurrent(_this, current_win, current_ctx);
593     return retval;
594 }
595
596 SDL_GLContext
597 WIN_GL_CreateContext(_THIS, SDL_Window * window)
598 {
599     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
600     HGLRC context, share_context;
601
602     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES &&
603         !_this->gl_data->HAS_WGL_EXT_create_context_es2_profile) {
604 #if SDL_VIDEO_OPENGL_EGL        
605         /* Switch to EGL based functions */
606         WIN_GL_UnloadLibrary(_this);
607         _this->GL_LoadLibrary = WIN_GLES_LoadLibrary;
608         _this->GL_GetProcAddress = WIN_GLES_GetProcAddress;
609         _this->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
610         _this->GL_CreateContext = WIN_GLES_CreateContext;
611         _this->GL_MakeCurrent = WIN_GLES_MakeCurrent;
612         _this->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
613         _this->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
614         _this->GL_SwapWindow = WIN_GLES_SwapWindow;
615         _this->GL_DeleteContext = WIN_GLES_DeleteContext;
616         
617         if (WIN_GLES_LoadLibrary(_this, NULL) != 0) {
618             return NULL;
619         }
620         
621         return WIN_GLES_CreateContext(_this, window);
622 #else
623         SDL_SetError("SDL not configured with EGL support");
624         return NULL;
625 #endif
626     }
627
628     if (_this->gl_config.share_with_current_context) {
629         share_context = (HGLRC)SDL_GL_GetCurrentContext();
630     } else {
631         share_context = 0;
632     }
633
634     if (_this->gl_config.major_version < 3 &&
635         _this->gl_config.profile_mask == 0 &&
636         _this->gl_config.flags == 0) {
637         /* Create legacy context */
638         context = _this->gl_data->wglCreateContext(hdc);
639         if( share_context != 0 ) {
640             _this->gl_data->wglShareLists(share_context, context);
641         }
642     } else {
643         PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
644         HGLRC temp_context = _this->gl_data->wglCreateContext(hdc);
645         if (!temp_context) {
646             SDL_SetError("Could not create GL context");
647             return NULL;
648         }
649
650         /* Make the context current */
651         if (WIN_GL_MakeCurrent(_this, window, temp_context) < 0) {
652             WIN_GL_DeleteContext(_this, temp_context);
653             return NULL;
654         }
655
656         wglCreateContextAttribsARB =
657             (PFNWGLCREATECONTEXTATTRIBSARBPROC) _this->gl_data->
658             wglGetProcAddress("wglCreateContextAttribsARB");
659         if (!wglCreateContextAttribsARB) {
660             SDL_SetError("GL 3.x is not supported");
661             context = temp_context;
662         } else {
663         /* max 10 attributes plus terminator */
664             int attribs[11] = {
665                 WGL_CONTEXT_MAJOR_VERSION_ARB, _this->gl_config.major_version,
666                 WGL_CONTEXT_MINOR_VERSION_ARB, _this->gl_config.minor_version,
667                 0
668             };
669             int iattr = 4;
670
671             /* SDL profile bits match WGL profile bits */
672             if (_this->gl_config.profile_mask != 0) {
673                 attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB;
674                 attribs[iattr++] = _this->gl_config.profile_mask;
675             }
676
677             /* SDL flags match WGL flags */
678             if (_this->gl_config.flags != 0) {
679                 attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB;
680                 attribs[iattr++] = _this->gl_config.flags;
681             }
682
683             /* only set if wgl extension is available */
684             if (_this->gl_data->HAS_WGL_ARB_context_flush_control) {
685                 attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB;
686                 attribs[iattr++] = _this->gl_config.release_behavior ?
687                                     WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :
688                                     WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
689             }
690
691             attribs[iattr++] = 0;
692
693             /* Create the GL 3.x context */
694             context = wglCreateContextAttribsARB(hdc, share_context, attribs);
695             /* Delete the GL 2.x context */
696             _this->gl_data->wglDeleteContext(temp_context);
697         }
698     }
699
700     if (!context) {
701         WIN_SetError("Could not create GL context");
702         return NULL;
703     }
704
705     if (WIN_GL_MakeCurrent(_this, window, context) < 0) {
706         WIN_GL_DeleteContext(_this, context);
707         return NULL;
708     }
709
710     return context;
711 }
712
713 int
714 WIN_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
715 {
716     HDC hdc;
717
718     if (!_this->gl_data) {
719         return SDL_SetError("OpenGL not initialized");
720     }
721
722     /* sanity check that higher level handled this. */
723     SDL_assert(window || (!window && !context));
724
725     /* Some Windows drivers freak out if hdc is NULL, even when context is
726        NULL, against spec. Since hdc is _supposed_ to be ignored if context
727        is NULL, we either use the current GL window, or do nothing if we
728        already have no current context. */
729     if (!window) {
730         window = SDL_GL_GetCurrentWindow();
731         if (!window) {
732             SDL_assert(SDL_GL_GetCurrentContext() == NULL);
733             return 0;  /* already done. */
734         }
735     }
736
737     hdc = ((SDL_WindowData *) window->driverdata)->hdc;
738     if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC) context)) {
739         return WIN_SetError("wglMakeCurrent()");
740     }
741     return 0;
742 }
743
744 int
745 WIN_GL_SetSwapInterval(_THIS, int interval)
746 {
747     if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) {
748         return SDL_SetError("Negative swap interval unsupported in this GL");
749     } else if (_this->gl_data->wglSwapIntervalEXT) {
750         if (_this->gl_data->wglSwapIntervalEXT(interval) != TRUE) {
751             return WIN_SetError("wglSwapIntervalEXT()");
752         }
753     } else {
754         return SDL_Unsupported();
755     }
756     return 0;
757 }
758
759 int
760 WIN_GL_GetSwapInterval(_THIS)
761 {
762     int retval = 0;
763     if (_this->gl_data->wglGetSwapIntervalEXT) {
764         retval = _this->gl_data->wglGetSwapIntervalEXT();
765     }
766     return retval;
767 }
768
769 void
770 WIN_GL_SwapWindow(_THIS, SDL_Window * window)
771 {
772     HDC hdc = ((SDL_WindowData *) window->driverdata)->hdc;
773
774     SwapBuffers(hdc);
775 }
776
777 void
778 WIN_GL_DeleteContext(_THIS, SDL_GLContext context)
779 {
780     if (!_this->gl_data) {
781         return;
782     }
783     _this->gl_data->wglDeleteContext((HGLRC) context);
784 }
785
786
787 SDL_bool
788 WIN_GL_SetPixelFormatFrom(_THIS, SDL_Window * fromWindow, SDL_Window * toWindow)
789 {
790     HDC hfromdc = ((SDL_WindowData *) fromWindow->driverdata)->hdc;
791     HDC htodc = ((SDL_WindowData *) toWindow->driverdata)->hdc;
792     BOOL result;
793
794     /* get the pixel format of the fromWindow */
795     int pixel_format = GetPixelFormat(hfromdc);
796     PIXELFORMATDESCRIPTOR pfd;
797     SDL_memset(&pfd, 0, sizeof(pfd));
798     DescribePixelFormat(hfromdc, pixel_format, sizeof(pfd), &pfd);
799
800     /* set the pixel format of the toWindow */
801     result = SetPixelFormat(htodc, pixel_format, &pfd);
802
803     return result ? SDL_TRUE : SDL_FALSE;
804 }
805
806 #endif /* SDL_VIDEO_OPENGL_WGL */
807
808 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
809
810 /* vi: set ts=4 sw=4 expandtab: */