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