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