• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
WIN_GL_LoadLibrary(_THIS,const char * path)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 *
WIN_GL_GetProcAddress(_THIS,const char * proc)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
WIN_GL_UnloadLibrary(_THIS)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
WIN_GL_SetupPixelFormat(_THIS,PIXELFORMATDESCRIPTOR * pfd)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
WIN_GL_ChoosePixelFormat(HDC hdc,PIXELFORMATDESCRIPTOR * target)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
HasExtension(const char * extension,const char * extensions)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
WIN_GL_InitExtensions(_THIS)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
WIN_GL_ChoosePixelFormatARB(_THIS,int * iAttribs,float * fAttribs)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
WIN_GL_SetupWindowInternal(_THIS,SDL_Window * window)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
WIN_GL_SetupWindow(_THIS,SDL_Window * window)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
WIN_GL_CreateContext(_THIS,SDL_Window * window)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
WIN_GL_MakeCurrent(_THIS,SDL_Window * window,SDL_GLContext context)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
WIN_GL_SetSwapInterval(_THIS,int interval)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
WIN_GL_GetSwapInterval(_THIS)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
WIN_GL_SwapWindow(_THIS,SDL_Window * window)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
WIN_GL_DeleteContext(_THIS,SDL_GLContext context)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
WIN_GL_SetPixelFormatFrom(_THIS,SDL_Window * fromWindow,SDL_Window * toWindow)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: */
811