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