Skip to content

Commit aaa4113

Browse files
committed
GPU Display: Render also text in X11 and GLFW at correct size taking into accound HiDPI settings
1 parent 8482661 commit aaa4113

4 files changed

Lines changed: 69 additions & 9 deletions

File tree

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.cxx‎

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -227,11 +227,17 @@ void GPUDisplayFrontendGlfw::scroll_callback(GLFWwindow* window, double x, doubl
227227

228228
void GPUDisplayFrontendGlfw::cursorPos_callback(GLFWwindow* window, double x, double y)
229229
{
230-
me->mMouseMvX = x;
231-
me->mMouseMvY = y;
230+
me->mMouseMvX = x * me->mPixelRatio; // Window coordinates to framebuffer pixels
231+
me->mMouseMvY = y * me->mPixelRatio;
232232
}
233233

234-
void GPUDisplayFrontendGlfw::resize_callback(GLFWwindow* window, int32_t width, int32_t height) { me->ResizeScene(width, height); }
234+
void GPUDisplayFrontendGlfw::resize_callback(GLFWwindow* window, int32_t width, int32_t height) // Framebuffer size in pixels
235+
{
236+
int32_t windowWidth, windowHeight;
237+
glfwGetWindowSize(window, &windowWidth, &windowHeight);
238+
me->mPixelRatio = windowWidth ? (double)width / windowWidth : 1.;
239+
me->ResizeScene(width, height);
240+
}
235241

236242
void GPUDisplayFrontendGlfw::focus_callback(GLFWwindow* window, int32_t focused)
237243
{
@@ -240,7 +246,22 @@ void GPUDisplayFrontendGlfw::focus_callback(GLFWwindow* window, int32_t focused)
240246
}
241247
}
242248

243-
void GPUDisplayFrontendGlfw::maximize_callback(GLFWwindow* window, int32_t maximized) { me->setWindowState(glfwGetWindowMonitor(window) != nullptr, maximized); }
249+
void GPUDisplayFrontendGlfw::contentScale_callback(GLFWwindow* window, float xscale, float yscale)
250+
{
251+
me->mScale = xscale;
252+
}
253+
254+
void GPUDisplayFrontendGlfw::maximize_callback(GLFWwindow* window, int32_t maximized)
255+
{
256+
me->setWindowState(glfwGetWindowMonitor(window) != nullptr, maximized);
257+
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) { // Called before the resize. GLFW keeps the maximized size if the compositor leaves the size to the client when unmaximizing, so restore the last windowed size
258+
if (maximized) {
259+
glfwGetWindowSize(window, &me->mWindowedWidth, &me->mWindowedHeight);
260+
} else {
261+
me->mRestoreWindowedSize = true; // Must be applied after GLFW has processed the configure event, otherwise GLFW resizes to the pending maximized size again
262+
}
263+
}
264+
}
244265

245266
#ifndef GPUCA_STANDALONE
246267
void GPUDisplayFrontendGlfw::DisplayLoop()
@@ -273,6 +294,7 @@ int32_t GPUDisplayFrontendGlfw::FrontendMain()
273294
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 0);
274295
glfwWindowHint(GLFW_OPENGL_PROFILE, mBackend->CoreProfile() ? GLFW_OPENGL_CORE_PROFILE : GLFW_OPENGL_COMPAT_PROFILE);
275296
}
297+
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Initial size scaled by the content scale on X11 / Win32
276298
mWindow = glfwCreateWindow(INIT_WIDTH, INIT_HEIGHT, DISPLAY_WINDOW_NAME, nullptr, nullptr);
277299
if (!mWindow) {
278300
fprintf(stderr, "Error creating glfw window\n");
@@ -288,10 +310,19 @@ int32_t GPUDisplayFrontendGlfw::FrontendMain()
288310
glfwSetMouseButtonCallback(mWindow, mouseButton_callback);
289311
glfwSetScrollCallback(mWindow, scroll_callback);
290312
glfwSetCursorPosCallback(mWindow, cursorPos_callback);
291-
glfwSetWindowSizeCallback(mWindow, resize_callback);
313+
glfwSetFramebufferSizeCallback(mWindow, resize_callback);
292314
glfwSetWindowMaximizeCallback(mWindow, maximize_callback);
293315
glfwSetWindowFocusCallback(mWindow, focus_callback);
294-
glfwSetWindowSizeLimits(mWindow, MIN_WIDTH, MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE);
316+
float xscale, yscale;
317+
glfwGetWindowContentScale(mWindow, &xscale, &yscale);
318+
contentScale_callback(mWindow, xscale, yscale);
319+
glfwSetWindowContentScaleCallback(mWindow, contentScale_callback);
320+
const float limitScale = (glfwGetPlatform() == GLFW_PLATFORM_X11 || glfwGetPlatform() == GLFW_PLATFORM_WIN32) ? mScale : 1.f; // Window coordinates are pixels on X11 / Win32, logical on Wayland / macOS
321+
glfwSetWindowSizeLimits(mWindow, MIN_WIDTH * limitScale, MIN_HEIGHT * limitScale, GLFW_DONT_CARE, GLFW_DONT_CARE);
322+
int32_t fbWidth, fbHeight, windowWidth, windowHeight;
323+
glfwGetFramebufferSize(mWindow, &fbWidth, &fbHeight);
324+
glfwGetWindowSize(mWindow, &windowWidth, &windowHeight);
325+
mPixelRatio = windowWidth ? (double)fbWidth / windowWidth : 1.; // Updated in resize_callback, which must not be called before InitDisplay
295326
applyInitialWindowState();
296327
if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
297328
glfwSwapInterval(1);
@@ -322,6 +353,12 @@ int32_t GPUDisplayFrontendGlfw::FrontendMain()
322353
}
323354
waitForFPSLimit();
324355
glfwPollEvents();
356+
if (mRestoreWindowedSize) {
357+
mRestoreWindowedSize = false;
358+
if (mWindowedWidth > 0 && mWindowedHeight > 0 && !glfwGetWindowAttrib(mWindow, GLFW_MAXIMIZED)) {
359+
glfwSetWindowSize(mWindow, mWindowedWidth, mWindowedHeight);
360+
}
361+
}
325362
}
326363

327364
ExitDisplay();

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendGlfw.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class GPUDisplayFrontendGlfw : public GPUDisplayFrontend
3535
void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override;
3636
bool EnableSendKey() override;
3737
void getSize(int32_t& width, int32_t& height) override;
38+
float getDisplayScale() const override { return mScale; }
3839
int32_t getVulkanSurface(void* instance, void* surface) override;
3940
uint32_t getReqVulkanExtensions(const char**& p) override;
4041

@@ -51,10 +52,16 @@ class GPUDisplayFrontendGlfw : public GPUDisplayFrontend
5152
static void resize_callback(GLFWwindow* mWindow, int32_t width, int32_t height);
5253
static void maximize_callback(GLFWwindow* mWindow, int32_t maximized);
5354
static void focus_callback(GLFWwindow* mWindow, int32_t focused);
55+
static void contentScale_callback(GLFWwindow* mWindow, float xscale, float yscale);
5456
static int32_t GetKey(int32_t key);
5557
static void GetKey(int32_t keyin, int32_t scancode, int32_t mods, int32_t& keyOut, int32_t& keyPressOut);
5658

5759
GLFWwindow* mWindow;
60+
float mScale = 1.f; // Content scale for text / UI
61+
int32_t mWindowedWidth = 0; // Window size before maximizing (Wayland)
62+
int32_t mWindowedHeight = 0;
63+
bool mRestoreWindowedSize = false;
64+
double mPixelRatio = 1.; // Framebuffer pixels per window coordinate (1 on X11 / Win32, scale on Wayland / macOS)
5865

5966
pthread_mutex_t mSemLockExit = PTHREAD_MUTEX_INITIALIZER;
6067
int32_t mWindowX = 0;

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.cxx‎

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <unistd.h>
2626
#include <X11/Xatom.h>
27+
#include <X11/Xresource.h>
2728

2829
#ifdef GPUCA_BUILD_EVENT_DISPLAY_VULKAN
2930
#include <vulkan/vulkan.h>
@@ -202,6 +203,19 @@ int32_t GPUDisplayFrontendX11::FrontendMain()
202203
return (-1);
203204
}
204205

206+
XrmInitialize();
207+
if (const char* resources = XResourceManagerString(mXDisplay)) {
208+
XrmDatabase db = XrmGetStringDatabase(resources);
209+
char* type = nullptr;
210+
XrmValue value;
211+
if (db && XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && value.addr && atof(value.addr) > 0) {
212+
mScale = atof(value.addr) / 96.;
213+
}
214+
if (db) {
215+
XrmDestroyDatabase(db);
216+
}
217+
}
218+
205219
// Make sure OpenGL's GLX extension supported
206220
if (!glXQueryExtension(mXDisplay, &errorBase, &eventBase)) {
207221
GPUError("X server has no OpenGL GLX extension");
@@ -264,13 +278,13 @@ int32_t GPUDisplayFrontendX11::FrontendMain()
264278
windowAttributes.event_mask = ExposureMask | VisibilityChangeMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask | PropertyChangeMask;
265279

266280
// Create an X window with the selected visual
267-
mWindow = XCreateWindow(mXDisplay, win, 50, 50, INIT_WIDTH, INIT_HEIGHT, // Position / Width and height of window
281+
mWindow = XCreateWindow(mXDisplay, win, 50, 50, INIT_WIDTH * mScale, INIT_HEIGHT * mScale, // Position / Width and height of window
268282
0, visualInfo->depth, InputOutput, visualInfo->visual, CWBorderPixel | CWColormap | CWEventMask, &windowAttributes);
269283
XSetStandardProperties(mXDisplay, mWindow, DISPLAY_WINDOW_NAME, DISPLAY_WINDOW_NAME, None, nullptr, 0, nullptr);
270284
XSizeHints sizeHints{};
271285
sizeHints.flags = PMinSize;
272-
sizeHints.min_width = MIN_WIDTH;
273-
sizeHints.min_height = MIN_HEIGHT;
286+
sizeHints.min_width = MIN_WIDTH * mScale;
287+
sizeHints.min_height = MIN_HEIGHT * mScale;
274288
XSetWMNormalHints(mXDisplay, mWindow, &sizeHints);
275289
if (backend()->backendType() == GPUDisplayBackend::TYPE_OPENGL) {
276290
glXMakeCurrent(mXDisplay, mWindow, glxContext);

‎GPU/GPUTracking/display/frontend/GPUDisplayFrontendX11.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class GPUDisplayFrontendX11 : public GPUDisplayFrontend
3636
void SetVSync(bool enable) override;
3737
void OpenGLPrint(const char* s, float x, float y, float r, float g, float b, float a, bool fromBotton = true) override;
3838
void getSize(int32_t& width, int32_t& height) override;
39+
float getDisplayScale() const override { return mScale; }
3940
int32_t getVulkanSurface(void* instance, void* surface) override;
4041
uint32_t getReqVulkanExtensions(const char**& p) override;
4142

@@ -51,6 +52,7 @@ class GPUDisplayFrontendX11 : public GPUDisplayFrontend
5152
Display* mXDisplay = nullptr;
5253
Window mWindow;
5354
void updateWindowState();
55+
float mScale = 1.f; // From the Xft.dpi X resource (desktop scaling, e.g. KDE with "Apply scaling themselves" for X11 apps)
5456

5557
PFNGLXSWAPINTERVALEXTPROC mGlXSwapIntervalEXT = nullptr;
5658
bool vsync_supported = false;

0 commit comments

Comments
 (0)