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