From d88e80464a96f19050f255560a67f13cdd7dc610 Mon Sep 17 00:00:00 2001 From: FarnaHerry Date: Mon, 10 Aug 2026 00:39:49 +0800 Subject: [PATCH] fix(sdl2): apply Linux desktop scaling to window size and UI scale What: On Linux, derive the desktop scaling factor from SDL display DPI (quantized to 0.25 steps, 1.25x minimum), enlarge newly created windows by that factor, and use it as the dpiScale fallback when the drawable-to-window ratio is 1.0. Why: SDL drawables on Linux (X11 and Wayland) never reflect desktop scaling, so the SDL2 backend computed a dpiScale of 1.0 and rendered unscaled, physically smaller UI than GLFW builds on HiDPI desktops. GLFW reads the desktop content scale directly; Windows was already handled via GetDpiForWindow; macOS reports a 2.0 drawable ratio. How: Add core::window::displayScaleEstimate() sharing the display-DPI quantization, multiply the SDL_CreateWindow size by it on Linux, and fall back to it in the app entry point's dpiScale() so logical layout size, rendering scale, and pointer mapping stay consistent. --- core/app/sdl2_app_main.cpp | 8 +++++++- core/window/window_backend.cpp | 34 ++++++++++++++++++++++++++++++++-- core/window/window_backend.h | 6 ++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/core/app/sdl2_app_main.cpp b/core/app/sdl2_app_main.cpp index e9cb0a83..7e1b50af 100644 --- a/core/app/sdl2_app_main.cpp +++ b/core/app/sdl2_app_main.cpp @@ -121,7 +121,13 @@ float dpiScale(SDL_Window* window) { } } #endif - return pointerScale(window); + const float drawableRatio = pointerScale(window); + if (drawableRatio > 1.0f) { + return drawableRatio; + } + // On Linux the drawable-to-window ratio does not reflect desktop scaling, + // so fall back to the display DPI reported by SDL. + return core::window::displayScaleEstimate(SDL_GetWindowDisplayIndex(window)); } void attachNativeChildWindow(SDL_Window* parentWindow, SDL_Window* childWindow) { diff --git a/core/window/window_backend.cpp b/core/window/window_backend.cpp index c40c4616..93d6bd92 100644 --- a/core/window/window_backend.cpp +++ b/core/window/window_backend.cpp @@ -2,6 +2,7 @@ #include "core/platform/native_bridge.h" #include +#include #if defined(EUI_WINDOW_BACKEND_SDL2) @@ -201,14 +202,43 @@ void uninstallSdlImeFilter(SDL_Window* window) { } // namespace +float displayScaleEstimate(int displayIndex) { +#if defined(_WIN32) || defined(__APPLE__) + (void)displayIndex; + return 1.0f; +#else + if (displayIndex < 0) { + displayIndex = 0; + } + float diagonalDpi = 0.0f; + if (SDL_GetDisplayDPI(displayIndex, &diagonalDpi, nullptr, nullptr) != 0 || + diagonalDpi < 120.0f) { + return 1.0f; + } + return std::round((diagonalDpi / 96.0f) * 4.0f) / 4.0f; +#endif +} + Handle createWindow(const WindowCreateRequest& request) { if (request.renderApi == RenderApi::OpenGL) { configureOpenGLWindowAttributes(); } Uint32 flags = 0; + int width = request.width; + int height = request.height; if (request.highDpi) { flags |= SDL_WINDOW_ALLOW_HIGHDPI; +#if !defined(_WIN32) && !defined(__APPLE__) + // On Linux the SDL drawable size never reflects desktop scaling, so + // the drawable-to-window ratio stays 1.0 and the UI would render at a + // physically smaller size than on other backends. Enlarge the window + // by the desktop scale so its buffer covers the same physical area; + // dpiScale() derives the matching scale from the display DPI. + const float displayScale = displayScaleEstimate(0); + width = static_cast(std::lround(width * displayScale)); + height = static_cast(std::lround(height * displayScale)); +#endif } if (request.resizable) { flags |= SDL_WINDOW_RESIZABLE; @@ -219,8 +249,8 @@ Handle createWindow(const WindowCreateRequest& request) { request.title != nullptr ? request.title : "", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - request.width, - request.height, + width, + height, flags); #if defined(_WIN32) installSdlImeFilter(window); diff --git a/core/window/window_backend.h b/core/window/window_backend.h index a39ca0f5..9e2f19e1 100644 --- a/core/window/window_backend.h +++ b/core/window/window_backend.h @@ -10,6 +10,12 @@ Handle createWindow(const WindowCreateRequest& request); void destroyWindow(Handle window); NativeWindowInfo nativeWindowInfo(Handle window); +// SDL2 only: estimates the desktop scaling factor for a display via +// SDL_GetDisplayDPI, quantized to 0.25 steps. Returns 1.0f when the scale +// cannot be determined or is below 1.25x, and on platforms where SDL already +// reports high-density drawable sizes (Windows, macOS). +float displayScaleEstimate(int displayIndex); + ContextKey currentContextKey(); double timeSeconds(); void postEmptyEvent();