Atlas - SDL_windowsopengl.c

Home / ext / SDL / src / video / windows Lines: 1 | Size: 33008 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 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 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_PumpEventsForHWND(_this, hwnd); 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 // see if we can get at OpenGL ES profiles even if EGL isn't available. 493 _this->gl_data->HAS_WGL_EXT_create_context_es2_profile = HasExtension("WGL_EXT_create_context_es2_profile", extensions); 494 if (_this->gl_data->HAS_WGL_EXT_create_context_es2_profile) { 495 SDL_GL_DeduceMaxSupportedESProfile( 496 &_this->gl_data->es_profile_max_supported_version.major, 497 &_this->gl_data->es_profile_max_supported_version.minor); 498 } 499 500 // Check for WGL_ARB_context_flush_control 501 if (HasExtension("WGL_ARB_context_flush_control", extensions)) { 502 _this->gl_data->HAS_WGL_ARB_context_flush_control = true; 503 } 504 505 // Check for WGL_ARB_create_context_robustness 506 if (HasExtension("WGL_ARB_create_context_robustness", extensions)) { 507 _this->gl_data->HAS_WGL_ARB_create_context_robustness = true; 508 } 509 510 // Check for WGL_ARB_create_context_no_error 511 if (HasExtension("WGL_ARB_create_context_no_error", extensions)) { 512 _this->gl_data->HAS_WGL_ARB_create_context_no_error = true; 513 } 514 515 // Check for WGL_ARB_framebuffer_sRGB 516 if (HasExtension("WGL_ARB_framebuffer_sRGB", extensions)) { 517 _this->gl_data->HAS_WGL_ARB_framebuffer_sRGB = true; 518 } else if (HasExtension("WGL_EXT_framebuffer_sRGB", extensions)) { // same thing. 519 _this->gl_data->HAS_WGL_ARB_framebuffer_sRGB = true; 520 } 521 522 /* Check for WGL_ARB_pixel_format_float */ 523 _this->gl_data->HAS_WGL_ARB_pixel_format_float = 524 HasExtension("WGL_ARB_pixel_format_float", extensions); 525 526 _this->gl_data->wglMakeCurrent(hdc, NULL); 527 _this->gl_data->wglDeleteContext(hglrc); 528 ReleaseDC(hwnd, hdc); 529 DestroyWindow(hwnd); 530 WIN_PumpEventsForHWND(_this, hwnd); 531} 532 533static int WIN_GL_ChoosePixelFormatARB(SDL_VideoDevice *_this, int *iAttribs, float *fAttribs) 534{ 535 HWND hwnd; 536 HDC hdc; 537 PIXELFORMATDESCRIPTOR pfd; 538 HGLRC hglrc; 539 int pixel_format = 0; 540 unsigned int matching; 541 542 hwnd = 543 CreateWindow(SDL_Appname, SDL_Appname, (WS_POPUP | WS_DISABLED), 0, 0, 544 10, 10, NULL, NULL, SDL_Instance, NULL); 545 WIN_PumpEventsForHWND(_this, hwnd); 546 547 hdc = GetDC(hwnd); 548 549 WIN_GL_SetupPixelFormat(_this, &pfd); 550 551 SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd); 552 553 hglrc = _this->gl_data->wglCreateContext(hdc); 554 if (hglrc) { 555 _this->gl_data->wglMakeCurrent(hdc, hglrc); 556 557 if (_this->gl_data->HAS_WGL_ARB_pixel_format) { 558 _this->gl_data->wglChoosePixelFormatARB(hdc, iAttribs, fAttribs, 559 1, &pixel_format, 560 &matching); 561 562 // Check whether we actually got an SRGB capable buffer 563 int srgb = 0; 564 if (_this->gl_data->HAS_WGL_ARB_framebuffer_sRGB) { 565 int qAttrib = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; 566 _this->gl_data->wglGetPixelFormatAttribivARB(hdc, pixel_format, 0, 1, &qAttrib, &srgb); 567 } 568 _this->gl_config.framebuffer_srgb_capable = srgb; 569 } 570 571 _this->gl_data->wglMakeCurrent(hdc, NULL); 572 _this->gl_data->wglDeleteContext(hglrc); 573 } 574 ReleaseDC(hwnd, hdc); 575 DestroyWindow(hwnd); 576 WIN_PumpEventsForHWND(_this, hwnd); 577 578 return pixel_format; 579} 580 581// actual work of WIN_GL_SetupWindow() happens here. 582static bool WIN_GL_SetupWindowInternal(SDL_VideoDevice *_this, SDL_Window *window) 583{ 584 HDC hdc = window->internal->hdc; 585 PIXELFORMATDESCRIPTOR pfd; 586 int pixel_format = 0; 587 int iAttribs[64]; 588 int *iAttr; 589 int *iAccelAttr; 590 float fAttribs[1] = { 0 }; 591 592 WIN_GL_SetupPixelFormat(_this, &pfd); 593 594 // setup WGL_ARB_pixel_format attribs 595 iAttr = &iAttribs[0]; 596 597 *iAttr++ = WGL_DRAW_TO_WINDOW_ARB; 598 *iAttr++ = GL_TRUE; 599 *iAttr++ = WGL_RED_BITS_ARB; 600 *iAttr++ = _this->gl_config.red_size; 601 *iAttr++ = WGL_GREEN_BITS_ARB; 602 *iAttr++ = _this->gl_config.green_size; 603 *iAttr++ = WGL_BLUE_BITS_ARB; 604 *iAttr++ = _this->gl_config.blue_size; 605 606 if (_this->gl_config.alpha_size) { 607 *iAttr++ = WGL_ALPHA_BITS_ARB; 608 *iAttr++ = _this->gl_config.alpha_size; 609 } 610 611 *iAttr++ = WGL_DOUBLE_BUFFER_ARB; 612 *iAttr++ = _this->gl_config.double_buffer; 613 614 *iAttr++ = WGL_DEPTH_BITS_ARB; 615 *iAttr++ = _this->gl_config.depth_size; 616 617 if (_this->gl_config.stencil_size) { 618 *iAttr++ = WGL_STENCIL_BITS_ARB; 619 *iAttr++ = _this->gl_config.stencil_size; 620 } 621 622 if (_this->gl_config.accum_red_size) { 623 *iAttr++ = WGL_ACCUM_RED_BITS_ARB; 624 *iAttr++ = _this->gl_config.accum_red_size; 625 } 626 627 if (_this->gl_config.accum_green_size) { 628 *iAttr++ = WGL_ACCUM_GREEN_BITS_ARB; 629 *iAttr++ = _this->gl_config.accum_green_size; 630 } 631 632 if (_this->gl_config.accum_blue_size) { 633 *iAttr++ = WGL_ACCUM_BLUE_BITS_ARB; 634 *iAttr++ = _this->gl_config.accum_blue_size; 635 } 636 637 if (_this->gl_config.accum_alpha_size) { 638 *iAttr++ = WGL_ACCUM_ALPHA_BITS_ARB; 639 *iAttr++ = _this->gl_config.accum_alpha_size; 640 } 641 642 if (_this->gl_config.stereo) { 643 *iAttr++ = WGL_STEREO_ARB; 644 *iAttr++ = GL_TRUE; 645 } 646 647 if (_this->gl_config.multisamplebuffers) { 648 *iAttr++ = WGL_SAMPLE_BUFFERS_ARB; 649 *iAttr++ = _this->gl_config.multisamplebuffers; 650 } 651 652 if (_this->gl_config.multisamplesamples) { 653 *iAttr++ = WGL_SAMPLES_ARB; 654 *iAttr++ = _this->gl_config.multisamplesamples; 655 } 656 657 if (_this->gl_data->HAS_WGL_ARB_pixel_format_float && _this->gl_config.floatbuffers) { 658 *iAttr++ = WGL_PIXEL_TYPE_ARB; 659 *iAttr++ = WGL_TYPE_RGBA_FLOAT_ARB; 660 } 661 662 if (_this->gl_data->HAS_WGL_ARB_framebuffer_sRGB) { 663 *iAttr++ = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; 664 *iAttr++ = (_this->gl_config.framebuffer_srgb_capable > 0) ? GL_TRUE : GL_FALSE; 665 } 666 667 /* We always choose either FULL or NO accel on Windows, because of flaky 668 drivers. If the app didn't specify, we use FULL, because that's 669 probably what they wanted (and if you didn't care and got FULL, that's 670 a perfectly valid result in any case). */ 671 *iAttr++ = WGL_ACCELERATION_ARB; 672 iAccelAttr = iAttr; 673 if (_this->gl_config.accelerated) { 674 *iAttr++ = WGL_FULL_ACCELERATION_ARB; 675 } else { 676 *iAttr++ = WGL_NO_ACCELERATION_ARB; 677 } 678 679 *iAttr = 0; 680 681 // Choose and set the closest available pixel format 682 pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs); 683 684 // App said "don't care about accel" and FULL accel failed. Try NO. 685 if ((!pixel_format) && (_this->gl_config.accelerated < 0)) { 686 *iAccelAttr = WGL_NO_ACCELERATION_ARB; 687 pixel_format = WIN_GL_ChoosePixelFormatARB(_this, iAttribs, fAttribs); 688 *iAccelAttr = WGL_FULL_ACCELERATION_ARB; // if we try again. 689 } 690 if (!pixel_format) { 691 pixel_format = WIN_GL_ChoosePixelFormat(_this, hdc, &pfd); 692 } 693 if (!pixel_format) { 694 return SDL_SetError("No matching GL pixel format available"); 695 } 696 if (!SetPixelFormat(hdc, pixel_format, &pfd)) { 697 return WIN_SetError("SetPixelFormat()"); 698 } 699 return true; 700} 701 702bool WIN_GL_SetupWindow(SDL_VideoDevice *_this, SDL_Window *window) 703{ 704 // The current context is lost in here; save it and reset it. 705 SDL_Window *current_win = SDL_GL_GetCurrentWindow(); 706 SDL_GLContext current_ctx = SDL_GL_GetCurrentContext(); 707 const int result = WIN_GL_SetupWindowInternal(_this, window); 708 WIN_GL_MakeCurrent(_this, current_win, current_ctx); 709 return result; 710} 711 712bool WIN_GL_UseEGL(SDL_VideoDevice *_this) 713{ 714 SDL_assert(_this->gl_data != NULL); 715 SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES); 716 717 // (we don't need EGL to do OpenGL ES if HAS_WGL_EXT_create_context_es2_profile exists.) 718 return !_this->gl_data->HAS_WGL_EXT_create_context_es2_profile || 719 SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, false) || 720 _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major || 721 (_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); 722} 723 724SDL_GLContext WIN_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) 725{ 726 HDC hdc = window->internal->hdc; 727 HGLRC context, share_context; 728 729 if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES && WIN_GL_UseEGL(_this)) { 730#ifdef SDL_VIDEO_OPENGL_EGL 731 // Switch to EGL based functions 732 WIN_GL_UnloadLibrary(_this); 733 _this->GL_LoadLibrary = WIN_GLES_LoadLibrary; 734 _this->GL_GetProcAddress = WIN_GLES_GetProcAddress; 735 _this->GL_UnloadLibrary = WIN_GLES_UnloadLibrary; 736 _this->GL_CreateContext = WIN_GLES_CreateContext; 737 _this->GL_MakeCurrent = WIN_GLES_MakeCurrent; 738 _this->GL_SetSwapInterval = WIN_GLES_SetSwapInterval; 739 _this->GL_GetSwapInterval = WIN_GLES_GetSwapInterval; 740 _this->GL_SwapWindow = WIN_GLES_SwapWindow; 741 _this->GL_DestroyContext = WIN_GLES_DestroyContext; 742 _this->GL_GetEGLSurface = WIN_GLES_GetEGLSurface; 743 744 if (!WIN_GLES_LoadLibrary(_this, NULL)) { 745 return NULL; 746 } 747 748 return WIN_GLES_CreateContext(_this, window); 749#else 750 SDL_SetError("SDL not configured with EGL support"); 751 return NULL; 752#endif 753 } 754 755 if (_this->gl_config.share_with_current_context) { 756 share_context = (HGLRC)SDL_GL_GetCurrentContext(); 757 } else { 758 share_context = 0; 759 } 760 761 if (_this->gl_config.major_version < 3 && 762 _this->gl_config.profile_mask == 0 && 763 _this->gl_config.flags == 0) { 764 // Create legacy context 765 context = _this->gl_data->wglCreateContext(hdc); 766 if (share_context != 0) { 767 _this->gl_data->wglShareLists(share_context, context); 768 } 769 } else { 770 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; 771 HGLRC temp_context = _this->gl_data->wglCreateContext(hdc); 772 if (!temp_context) { 773 SDL_SetError("Could not create GL context"); 774 return NULL; 775 } 776 777 // Make the context current 778 if (!WIN_GL_MakeCurrent(_this, window, (SDL_GLContext)temp_context)) { 779 WIN_GL_DestroyContext(_this, (SDL_GLContext)temp_context); 780 return NULL; 781 } 782 783 wglCreateContextAttribsARB = 784 (PFNWGLCREATECONTEXTATTRIBSARBPROC)_this->gl_data->wglGetProcAddress("wglCreateContextAttribsARB"); 785 if (!wglCreateContextAttribsARB) { 786 SDL_SetError("GL 3.x is not supported"); 787 context = temp_context; 788 } else { 789 int attribs[15]; // max 14 attributes plus terminator 790 int iattr = 0; 791 792 attribs[iattr++] = WGL_CONTEXT_MAJOR_VERSION_ARB; 793 attribs[iattr++] = _this->gl_config.major_version; 794 attribs[iattr++] = WGL_CONTEXT_MINOR_VERSION_ARB; 795 attribs[iattr++] = _this->gl_config.minor_version; 796 797 // SDL profile bits match WGL profile bits 798 if (_this->gl_config.profile_mask != 0) { 799 attribs[iattr++] = WGL_CONTEXT_PROFILE_MASK_ARB; 800 attribs[iattr++] = _this->gl_config.profile_mask; 801 } 802 803 // SDL flags match WGL flags 804 if (_this->gl_config.flags != 0) { 805 attribs[iattr++] = WGL_CONTEXT_FLAGS_ARB; 806 attribs[iattr++] = _this->gl_config.flags; 807 } 808 809 // only set if wgl extension is available and not the default setting 810 if ((_this->gl_data->HAS_WGL_ARB_context_flush_control) && (_this->gl_config.release_behavior == 0)) { 811 attribs[iattr++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB; 812 attribs[iattr++] = _this->gl_config.release_behavior ? WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB; 813 } 814 815 // only set if wgl extension is available and not the default setting 816 if ((_this->gl_data->HAS_WGL_ARB_create_context_robustness) && (_this->gl_config.reset_notification != 0)) { 817 attribs[iattr++] = WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB; 818 attribs[iattr++] = _this->gl_config.reset_notification ? WGL_LOSE_CONTEXT_ON_RESET_ARB : WGL_NO_RESET_NOTIFICATION_ARB; 819 } 820 821 // only set if wgl extension is available and not the default setting 822 if ((_this->gl_data->HAS_WGL_ARB_create_context_no_error) && (_this->gl_config.no_error != 0)) { 823 attribs[iattr++] = WGL_CONTEXT_OPENGL_NO_ERROR_ARB; 824 attribs[iattr++] = _this->gl_config.no_error; 825 } 826 827 attribs[iattr++] = 0; 828 829 // Create the GL 3.x context 830 context = wglCreateContextAttribsARB(hdc, share_context, attribs); 831 // Delete the GL 2.x context 832 _this->gl_data->wglDeleteContext(temp_context); 833 } 834 } 835 836 if (!context) { 837 WIN_SetError("Could not create GL context"); 838 return NULL; 839 } 840 841 if (!WIN_GL_MakeCurrent(_this, window, (SDL_GLContext)context)) { 842 WIN_GL_DestroyContext(_this, (SDL_GLContext)context); 843 return NULL; 844 } 845 846 _this->gl_config.HAS_GL_ARB_color_buffer_float = 847 SDL_GL_ExtensionSupported("GL_ARB_color_buffer_float"); 848 849 return (SDL_GLContext)context; 850} 851 852bool WIN_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) 853{ 854 HDC hdc; 855 856 if (!_this->gl_data) { 857 return SDL_SetError("OpenGL not initialized"); 858 } 859 860 // sanity check that higher level handled this. 861 SDL_assert(window || (window == NULL && !context)); 862 863 /* Some Windows drivers freak out if hdc is NULL, even when context is 864 NULL, against spec. Since hdc is _supposed_ to be ignored if context 865 is NULL, we either use the current GL window, or do nothing if we 866 already have no current context. */ 867 if (!window) { 868 window = SDL_GL_GetCurrentWindow(); 869 if (!window) { 870 SDL_assert(SDL_GL_GetCurrentContext() == NULL); 871 return true; // already done. 872 } 873 } 874 875 hdc = window->internal->hdc; 876 if (!_this->gl_data->wglMakeCurrent(hdc, (HGLRC)context)) { 877 return WIN_SetError("wglMakeCurrent()"); 878 } 879 return true; 880} 881 882bool WIN_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval) 883{ 884 if ((interval < 0) && (!_this->gl_data->HAS_WGL_EXT_swap_control_tear)) { 885 return SDL_SetError("Negative swap interval unsupported in this GL"); 886 } else if (_this->gl_data->wglSwapIntervalEXT) { 887 if (!_this->gl_data->wglSwapIntervalEXT(interval)) { 888 return WIN_SetError("wglSwapIntervalEXT()"); 889 } 890 } else { 891 return SDL_Unsupported(); 892 } 893 return true; 894} 895 896bool WIN_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval) 897{ 898 if (_this->gl_data->wglGetSwapIntervalEXT) { 899 *interval = _this->gl_data->wglGetSwapIntervalEXT(); 900 return true; 901 } else { 902 return false; 903 } 904} 905 906bool WIN_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) 907{ 908 HDC hdc = window->internal->hdc; 909 910 if (!SwapBuffers(hdc)) { 911 return WIN_SetError("SwapBuffers()"); 912 } 913 return true; 914} 915 916bool WIN_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context) 917{ 918 if (!_this->gl_data) { 919 return true; 920 } 921 _this->gl_data->wglDeleteContext((HGLRC)context); 922 return true; 923} 924 925#endif // SDL_VIDEO_OPENGL_WGL 926 927#endif // SDL_VIDEO_DRIVER_WINDOWS 928
[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.