From 705a007c22955e633054a085e83d43ae010cfeb4 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 25 Oct 2025 10:59:38 +0100 Subject: [PATCH] SDL3: Fix nearest-neighbor scaling For some reason, setting the scaling on just `texture` still results in bluriness. However, setting the default scaling mode on the renderer fixes it. Also, does a few more things the SDL3 way. --- Source/engine/dx.cpp | 22 ++++----------------- Source/hwcursor.cpp | 2 +- Source/utils/display.cpp | 41 +++++++++++++++++++++++++-------------- Source/utils/sdl_compat.h | 2 +- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/Source/engine/dx.cpp b/Source/engine/dx.cpp index e7e60b65f..60c792ec8 100644 --- a/Source/engine/dx.cpp +++ b/Source/engine/dx.cpp @@ -242,29 +242,15 @@ void RenderPresent() #ifndef USE_SDL1 if (renderer != nullptr) { -#ifdef USE_SDL3 - if (!SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch)) ErrSdl(); -#else - if (SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch) <= -1) ErrSdl(); -#endif - - // Clear buffer to avoid artifacts in case the window was resized - // TODO only do this if window was resized #ifdef USE_SDL3 if (!SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)) ErrSdl(); -#else - if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255) <= -1) ErrSdl(); -#endif - -#ifdef USE_SDL3 if (!SDL_RenderClear(renderer)) ErrSdl(); -#else - if (SDL_RenderClear(renderer) <= -1) ErrSdl(); -#endif - -#ifdef USE_SDL3 + if (!SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch)) ErrSdl(); if (!SDL_RenderTexture(renderer, texture.get(), nullptr, nullptr)) ErrSdl(); #else + if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255) <= -1) ErrSdl(); + if (SDL_RenderClear(renderer) <= -1) ErrSdl(); + if (SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch) <= -1) ErrSdl(); if (SDL_RenderCopy(renderer, texture.get(), nullptr, nullptr) <= -1) ErrSdl(); #endif diff --git a/Source/hwcursor.cpp b/Source/hwcursor.cpp index 72c295a2c..bb18e9629 100644 --- a/Source/hwcursor.cpp +++ b/Source/hwcursor.cpp @@ -144,7 +144,7 @@ bool SetHardwareCursorFromSurface(SDL_Surface *surface, HotpointPosition hotpoin size.width, size.height, scaledSize.width, scaledSize.height); #endif #ifdef USE_SDL3 - SDL_BlitSurfaceScaled(converted.get(), nullptr, scaledSurface.get(), nullptr, SDL_SCALEMODE_NEAREST); + SDL_BlitSurfaceScaled(converted.get(), nullptr, scaledSurface.get(), nullptr, SDL_SCALEMODE_PIXELART); #else SDL_BlitScaled(converted.get(), nullptr, scaledSurface.get(), nullptr); #endif diff --git a/Source/utils/display.cpp b/Source/utils/display.cpp index d69e3b8d1..8a802244f 100644 --- a/Source/utils/display.cpp +++ b/Source/utils/display.cpp @@ -432,19 +432,21 @@ void AdjustToScreenGeometry(Size windowSize) float GetDpiScalingFactor() { -#ifdef USE_SDL1 - return 1.0F; -#else +#ifdef USE_SDL3 + const float dispScale = SDL_GetWindowDisplayScale(ghMainWnd); + if (dispScale == 0.0F) { + LogError("SDL_GetWindowDisplayScale: {}", SDL_GetError()); + SDL_ClearError(); + return 1.0F; + } + return dispScale; +#elif !defined(USE_SDL1) if (renderer == nullptr) return 1.0F; int renderWidth; int renderHeight; -#ifdef USE_SDL3 - SDL_GetCurrentRenderOutputSize(renderer, &renderWidth, &renderHeight); -#else SDL_GetRendererOutputSize(renderer, &renderWidth, &renderHeight); -#endif int windowWidth; int windowHeight; @@ -454,6 +456,8 @@ float GetDpiScalingFactor() const float vhfactor = static_cast(renderHeight) / windowHeight; return std::min(hfactor, vhfactor); +#else + return 1.0F; #endif } @@ -616,7 +620,11 @@ bool SpawnWindow(const char *lpWindowName) } #ifdef USE_SDL3 - ghMainWnd = SDL_CreateWindow(lpWindowName, windowSize.width, windowSize.height, flags); + if (*GetOptions().Graphics.upscale) { + if (!SDL_CreateWindowAndRenderer(lpWindowName, windowSize.width, windowSize.height, flags, &ghMainWnd, &renderer)) ErrSdl(); + } else { + ghMainWnd = SDL_CreateWindow(lpWindowName, windowSize.width, windowSize.height, flags); + } #else ghMainWnd = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowSize.width, windowSize.height, flags); #endif @@ -687,14 +695,17 @@ void ReinitializeTexture() if (renderer == nullptr) return; - auto quality = StrCat(static_cast(*GetOptions().Graphics.scaleQuality)); - #ifdef USE_SDL3 - texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight); - if (quality == "nearest") { - SDL_SetTextureScaleMode(texture.get(), SDL_SCALEMODE_NEAREST); + if (!SDL_SetDefaultTextureScaleMode(renderer, + *GetOptions().Graphics.scaleQuality == ScalingQuality::NearestPixel + ? SDL_SCALEMODE_PIXELART + : SDL_SCALEMODE_LINEAR)) { + Log("SDL_SetDefaultTextureScaleMode: {}", SDL_GetError()); + SDL_ClearError(); } + texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight); #else + auto quality = StrCat(static_cast(*GetOptions().Graphics.scaleQuality)); SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, quality.c_str()); texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight); #endif @@ -756,8 +767,6 @@ void ReinitializeRenderer() SDL_RenderSetVSync(renderer, *GetOptions().Graphics.frameRateControl == FrameRateControl::VerticalSync ? 1 : 0); #endif - ReinitializeTexture(); - #ifdef USE_SDL3 if (!SDL_SetRenderLogicalPresentation(renderer, gnScreenWidth, gnScreenHeight, *GetOptions().Graphics.integerScaling @@ -775,6 +784,8 @@ void ReinitializeRenderer() } #endif + ReinitializeTexture(); + #ifdef USE_SDL3 RendererTextureSurface = SDLSurfaceUniquePtr { SDL_CreateSurface(gnScreenWidth, gnScreenHeight, texture->format) }; if (RendererTextureSurface == nullptr) ErrSdl(); diff --git a/Source/utils/sdl_compat.h b/Source/utils/sdl_compat.h index fed7e2e08..898a151e5 100644 --- a/Source/utils/sdl_compat.h +++ b/Source/utils/sdl_compat.h @@ -236,7 +236,7 @@ inline const SDL_GamepadDeviceEvent &SDLC_EventGamepadDevice(const SDL_Event &ev #define SDLC_SURFACE_BITSPERPIXEL(surface) surface->format->BitsPerPixel -inline bool SDLC_PushEvent(SDL_Event *event) { return SDL_PushEvent(event) == 0; } +inline bool SDLC_PushEvent(SDL_Event *event) { return SDL_PushEvent(event) == 1; } inline #ifdef USE_SDL1