Atlas - SDL_windowsopengl.c

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