SDL: wayland: Handle cases where the compositor does not scale the monitor viewport in its compositing space

From c270d151b004b3483226c32132e5f8a59de480c7 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Thu, 16 Mar 2023 12:59:24 -0400
Subject: [PATCH] wayland: Handle cases where the compositor does not scale the
 monitor viewport in its compositing space

The xdg-output spec was updated to clarify its usage rules, and what was previously thought to be a bug is actually valid behavior. Gnome, when not using 'scale-monitor-framebuffer', does not scale the viewport of the display in the global compositor space, and thus the physical and logical sizes of the display will match. This value still needs to be divided by the integer scale value to get the logical output dimensions in screen units though.
---
 src/video/wayland/SDL_waylandvideo.c | 39 +++++++++++-----------------
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 1f42324e0a56..bf487db5e3e0 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -302,24 +302,6 @@ static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xd
 {
     SDL_DisplayData *driverdata = (SDL_DisplayData *)data;
 
-    if (driverdata->screen_width != 0 && driverdata->screen_height != 0) {
-        /* FIXME: GNOME has a bug where the logical size does not account for
-         * scale, resulting in bogus viewport sizes.
-         *
-         * Until this is fixed, validate that _some_ kind of scaling is being
-         * done (we can't match exactly because fractional scaling can't be
-         * detected otherwise), then override if necessary.
-         * -flibit
-         */
-        const float scale = (float)driverdata->screen_width / (float)width;
-        if ((scale == 1.0f) && (driverdata->scale_factor != 1.0f)) {
-            SDL_LogWarn(
-                SDL_LOG_CATEGORY_VIDEO,
-                "xdg_output scale did not match, overriding with wl_output scale");
-            return;
-        }
-    }
-
     driverdata->screen_width = width;
     driverdata->screen_height = height;
     driverdata->has_logical_size = SDL_TRUE;
@@ -582,13 +564,22 @@ static void display_handle_done(void *data,
     native_mode.driverdata = driverdata->output;
 
     if (driverdata->has_logical_size) { /* If xdg-output is present... */
-        if (video->viewporter) {
-            /* ...and viewports are supported, calculate the true scale of the output. */
-            driverdata->scale_factor = (float)native_mode.pixel_w / (float)driverdata->screen_width;
+        if (native_mode.pixel_w != driverdata->screen_width || native_mode.pixel_h != driverdata->screen_height) {
+            /* ...and the compositor scales the logical viewport... */
+            if (video->viewporter) {
+                /* ...and viewports are supported, calculate the true scale of the output. */
+                driverdata->scale_factor = (float)native_mode.pixel_w / (float)driverdata->screen_width;
+            } else {
+                /* ...otherwise, the 'native' pixel values are a multiple of the logical screen size. */
+                driverdata->pixel_width = driverdata->screen_width * (int)driverdata->scale_factor;
+                driverdata->pixel_height = driverdata->screen_height * (int)driverdata->scale_factor;
+            }
         } else {
-            /* ...otherwise, the 'native' pixel values are a multiple of the logical screen size. */
-            driverdata->pixel_width = driverdata->screen_width * (int)driverdata->scale_factor;
-            driverdata->pixel_height = driverdata->screen_height * (int)driverdata->scale_factor;
+            /* ...and the output viewport is not scaled in the global compositing
+             * space, the output dimensions need to be divided by the scale factor.
+             */
+            driverdata->screen_width /= (int)driverdata->scale_factor;
+            driverdata->screen_height /= (int)driverdata->scale_factor;
         }
     } else {
         /* Calculate the screen coordinates from the pixel values, if xdg-output isn't present.