diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index 9958b49f6..3e16de124 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -87,6 +87,47 @@ void CalculatePreferredWindowSize(int &width, int &height) height = mode.h * width / mode.w; } } + +void FreeRenderer() +{ +#ifdef _WIN32 + bool wasD3D9 = false; + bool wasD3D11 = false; + if (renderer != nullptr) { + SDL_RendererInfo previousRendererInfo; + SDL_GetRendererInfo(renderer, &previousRendererInfo); + wasD3D9 = (std::string_view(previousRendererInfo.name) == "direct3d"); + wasD3D11 = (std::string_view(previousRendererInfo.name) == "direct3d11"); + } +#endif + + if (renderer != nullptr) { + SDL_DestroyRenderer(renderer); + renderer = nullptr; + } + +#ifdef _WIN32 + // On Windows 11 the directx9 VSYNC timer doesn't get recreated properly, see https://github.com/libsdl-org/SDL/issues/5099 + // Furthermore, the direct3d11 driver "poisons" the window so it can't be used by another renderer + if ((wasD3D9 && *sgOptions.Graphics.upscale && *sgOptions.Graphics.vSync) || (wasD3D11 && !*sgOptions.Graphics.upscale)) { + std::string title = SDL_GetWindowTitle(ghMainWnd); + Uint32 flags = SDL_GetWindowFlags(ghMainWnd); + Rectangle dimensions; + + SDL_GetWindowPosition(ghMainWnd, &dimensions.position.x, &dimensions.position.y); + SDL_GetWindowSize(ghMainWnd, &dimensions.size.width, &dimensions.size.height); + SDL_DestroyWindow(ghMainWnd); + + ghMainWnd = SDL_CreateWindow( + title.c_str(), + dimensions.position.x, + dimensions.position.y, + dimensions.size.width, + dimensions.size.height, + flags); + } +#endif +} #endif void AdjustToScreenGeometry(Size windowSize) @@ -309,10 +350,7 @@ void ReinitializeRenderer() if (texture) texture.reset(); - if (renderer != nullptr) { - SDL_DestroyRenderer(renderer); - renderer = nullptr; - } + FreeRenderer(); if (*sgOptions.Graphics.upscale) { Uint32 rendererFlags = 0; @@ -321,25 +359,11 @@ void ReinitializeRenderer() rendererFlags |= SDL_RENDERER_PRESENTVSYNC; } -#ifdef _WIN32 - // On Windows 11 the directx9 VSYNC timer doesn't get recreated properly, see https://github.com/libsdl-org/SDL/issues/5099 - // Attempt to use the directx11 driver instead if we have vsync active. - const char *const renderHint = SDL_GetHint(SDL_HINT_RENDER_DRIVER); - if ((rendererFlags & SDL_RENDERER_PRESENTVSYNC) != 0 && SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d11") != SDL_TRUE) { - Log("Error when trying to set hint for direct3d11, using default render driver"); - } -#endif - renderer = SDL_CreateRenderer(ghMainWnd, -1, rendererFlags); if (renderer == nullptr) { ErrSdl(); } -#ifdef _WIN32 - // Restore any system/user defined hint just in case they turn off upscale/vsync. - SDL_SetHint(SDL_HINT_RENDER_DRIVER, renderHint); -#endif - ReinitializeTexture(); if (SDL_RenderSetIntegerScale(renderer, *sgOptions.Graphics.integerScaling ? SDL_TRUE : SDL_FALSE) < 0) {