From 37a348be43f6a30821e8799f14d319f6969aed82 Mon Sep 17 00:00:00 2001 From: Colin Kinloch Date: Sat, 23 Nov 2024 16:41:46 +0000 Subject: [PATCH] WaylandBackend: Fix scale equation and unscale libdecor frame commit This fixes the issue where in a scaled wayland sessions the window buffer is the correct size with window decorations that are too large. It also fixes gamescope being having a couple of pixels smaller when fullscreen. --- src/Backends/WaylandBackend.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp index c53bf14df1..8f45a00b3b 100644 --- a/src/Backends/WaylandBackend.cpp +++ b/src/Backends/WaylandBackend.cpp @@ -38,6 +38,8 @@ #include "drm_include.h" +#define WL_FRACTIONAL_SCALE_DENOMINATOR 120 + extern int g_nPreferredOutputWidth; extern int g_nPreferredOutputHeight; extern bool g_bForceHDR10OutputDebug; @@ -63,6 +65,13 @@ auto CallWithAllButLast(Func pFunc, Args&&... args) return Forwarder(std::forward_as_tuple(args...), std::make_index_sequence()); } +static inline uint32_t WaylandScaleToPhysical( uint32_t pValue, uint32_t pFactor ) { + return pValue * pFactor / WL_FRACTIONAL_SCALE_DENOMINATOR; +} +static inline uint32_t WaylandScaleToLogical( uint32_t pValue, uint32_t pFactor ) { + return div_roundup( pValue * WL_FRACTIONAL_SCALE_DENOMINATOR, pFactor ); +} + #define WAYLAND_NULL() [] ( void *pData, Args... args ) { } #define WAYLAND_USERDATA_TO_THIS(type, name) [] ( void *pData, Args... args ) { type *pThing = (type *)pData; pThing->name( std::forward(args)... ); } @@ -1016,14 +1025,15 @@ namespace gamescope wl_fixed_from_double( oState->flSrcHeight ) ); wp_viewport_set_destination( m_pViewport, - oState->nDstWidth * 120 / uScale, - oState->nDstHeight * 120 / uScale); + WaylandScaleToLogical( oState->nDstWidth, uScale ), + WaylandScaleToLogical( oState->nDstHeight, uScale ) ); + if ( m_pSubsurface ) { wl_subsurface_set_position( m_pSubsurface, - oState->nDestX * 120 / uScale, - oState->nDestY * 120 / uScale ); + WaylandScaleToLogical( oState->nDestX, uScale ), + WaylandScaleToLogical( oState->nDestY, uScale ) ); } // The x/y here does nothing? Why? What is it for... // Use the subsurface set_position thing instead. @@ -1041,7 +1051,10 @@ namespace gamescope void CWaylandPlane::CommitLibDecor( libdecor_configuration *pConfiguration ) { - libdecor_state *pState = libdecor_state_new( g_nOutputWidth, g_nOutputHeight ); + int32_t uScale = GetScale(); + libdecor_state *pState = libdecor_state_new( + WaylandScaleToLogical( g_nOutputWidth, uScale ), + WaylandScaleToLogical( g_nOutputHeight, uScale ) ); libdecor_frame_commit( m_pFrame, pState, pConfiguration ); libdecor_state_free( pState ); } @@ -1148,11 +1161,11 @@ namespace gamescope int nWidth, nHeight; if ( !libdecor_configuration_get_content_size( pConfiguration, m_pFrame, &nWidth, &nHeight ) ) { - nWidth = g_nOutputWidth * 120 / uScale; - nHeight = g_nOutputHeight * 120 / uScale; + nWidth = WaylandScaleToLogical( g_nOutputWidth, uScale ); + nHeight = WaylandScaleToLogical( g_nOutputHeight, uScale ); } - g_nOutputWidth = nWidth * uScale / 120; - g_nOutputHeight = nHeight * uScale / 120; + g_nOutputWidth = WaylandScaleToPhysical( nWidth, uScale ); + g_nOutputHeight = WaylandScaleToPhysical( nHeight, uScale ); CommitLibDecor( pConfiguration );