mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-12 03:21:08 +00:00
fix(gamescope): keep Fill scaling and magnification visible (#1634)
* fix(gamescope): preserve signed plane positions * fix(gamescope): pin validated scaling component
This commit is contained in:
1 parent
aa17b0553d
commit
73daaf7adc
4 files changed
+131
-3
No files matched your search
@@ -99,3 +99,25 @@ The patch can keep the result for `DROIDDECK_WSI_BYPASS_CHECK_MS` milliseconds.
|
||||
or 0 keeps the per-present check; the app sets 100 only in Performance mode and 0
|
||||
otherwise. With 100, a window resize or a flip/obscure change is seen up to 100 ms
|
||||
later than before; surface creation and capability queries still check every time.
|
||||
|
||||
## 0118 Wayland: preserve signed plane positions
|
||||
|
||||
Fill scaling and Steam magnification can place the image at negative x/y coordinates.
|
||||
The Wayland backend converted these signed positions through an unsigned size helper:
|
||||
at host scale 120, -120 became 35791275 and the image moved off-screen while overlays
|
||||
could remain visible. A separate signed conversion uses a 64-bit intermediate and
|
||||
retains the existing ceiling convention; viewport sizes keep their original helper.
|
||||
|
||||
The component build runs `wayland_scaling` for negative crop offsets, positive/zero
|
||||
positions, fractional host scales and wide intermediates. This patch may be worth
|
||||
upstreaming: the same unsigned position calls were present in ValveSoftware/gamescope
|
||||
3.16.29 and master `d175688ad4ec490dc7b0695c5c62f8807684a1f1` when checked on
|
||||
2026-10-26. Carry it here until an upstream release containing the fix is adopted.
|
||||
|
||||
Device validation on AYN Thor (1280x720 session, 1920x1080 Android output):
|
||||
800x600 and 1600x600 source windows retained their image through Auto, Fit,
|
||||
Stretch, Fill, Integer and 2x Steam magnification, including returning to Fit.
|
||||
The old component lost the image in Fill and magnification. The tested executable
|
||||
matches the pinned p14 archive and the locally assembled APK. Hardware checks used
|
||||
native Gamescope properties; the physical Back+LB shortcut was not independently
|
||||
confirmed. The original APK and runtime were restored after validation.
|
||||
@@ -39,7 +39,7 @@ else
|
||||
fi
|
||||
PREP
|
||||
makepkg -A -s --noconfirm --skipchecksums --skippgpcheck
|
||||
meson test -C src/build --no-rebuild --print-errorlogs cursor_routing
|
||||
meson test -C src/build --no-rebuild --print-errorlogs cursor_routing wayland_scaling
|
||||
ls -l *.pkg.tar.*
|
||||
"
|
||||
cd "$WORK"
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp
|
||||
index d00644f..40164ba 100644
|
||||
--- a/src/Backends/WaylandBackend.cpp
|
||||
+++ b/src/Backends/WaylandBackend.cpp
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "waitable.h"
|
||||
#include "Utils/TempFiles.h"
|
||||
#include "Utils/CursorRouting.h"
|
||||
+#include "Utils/WaylandScaling.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <unordered_map>
|
||||
@@ -1618,8 +1619,8 @@ namespace gamescope
|
||||
{
|
||||
wl_subsurface_set_position(
|
||||
m_pSubsurface,
|
||||
- WaylandScaleToLogical( oState->nDestX, uScale ),
|
||||
- WaylandScaleToLogical( oState->nDestY, uScale ) );
|
||||
+ gamescope::WaylandPositionToLogical( oState->nDestX, uScale ),
|
||||
+ gamescope::WaylandPositionToLogical( oState->nDestY, uScale ) );
|
||||
}
|
||||
// The x/y here does nothing? Why? What is it for...
|
||||
// Use the subsurface set_position thing instead.
|
||||
diff --git a/src/Utils/WaylandScaling.h b/src/Utils/WaylandScaling.h
|
||||
new file mode 100644
|
||||
index 0000000..d488e39
|
||||
--- /dev/null
|
||||
+++ b/src/Utils/WaylandScaling.h
|
||||
@@ -0,0 +1,12 @@
|
||||
+#pragma once
|
||||
+
|
||||
+#include <cstdint>
|
||||
+
|
||||
+namespace gamescope
|
||||
+{
|
||||
+ constexpr int32_t WaylandPositionToLogical( int32_t nValue, uint32_t uFactor )
|
||||
+ {
|
||||
+ const int64_t nScaled = int64_t( nValue ) * 120;
|
||||
+ return int32_t( nScaled / uFactor + ( nScaled % uFactor > 0 ) );
|
||||
+ }
|
||||
+}
|
||||
diff --git a/tests/meson.build b/tests/meson.build
|
||||
index 1ccdf7d..d86bf9e 100644
|
||||
--- a/tests/meson.build
|
||||
+++ b/tests/meson.build
|
||||
@@ -8,7 +8,7 @@ endforeach
|
||||
|
||||
gamescope_tests = executable(
|
||||
'gamescope_tests',
|
||||
- unittest_src + ['test_convar.cpp', 'test_cursor_routing.cpp', 'test_focus_placement.cpp', 'test_mangoapp_config.cpp', 'test_mangoapp_control.cpp', 'test_process.cpp', 'test_upscale.cpp', 'test_utils_parsers.cpp', 'test_utils_string.cpp', 'test_vrclient_detect.cpp'],
|
||||
+ unittest_src + ['test_convar.cpp', 'test_cursor_routing.cpp', 'test_focus_placement.cpp', 'test_mangoapp_config.cpp', 'test_mangoapp_control.cpp', 'test_process.cpp', 'test_upscale.cpp', 'test_utils_parsers.cpp', 'test_utils_string.cpp', 'test_vrclient_detect.cpp', 'test_wayland_scaling.cpp'],
|
||||
include_directories: [srcdir, sol2_include],
|
||||
dependencies: [catch2_dep, luajit_dep, cap_dep, drm_dep, glm_dep, wlroots_dep],
|
||||
cpp_args: gamescope_cpp_args,
|
||||
@@ -18,6 +18,7 @@ reaper_test_helper = executable('reaper_test_helper', 'reaper_test_helper.cpp')
|
||||
|
||||
test('convar', gamescope_tests, args: ['[convar]'])
|
||||
test('cursor_routing', gamescope_tests, args: ['[cursor_routing]'])
|
||||
+test('wayland_scaling', gamescope_tests, args: ['[wayland_scaling]'])
|
||||
test('focus_placement', gamescope_tests, args: ['[focus_placement]'])
|
||||
test('mangoapp_config', gamescope_tests, args: ['[mangoapp_config]'])
|
||||
test('mangoapp_control', gamescope_tests, args: ['[mangoapp_control]'])
|
||||
diff --git a/tests/test_wayland_scaling.cpp b/tests/test_wayland_scaling.cpp
|
||||
new file mode 100644
|
||||
index 0000000..498f55b
|
||||
--- /dev/null
|
||||
+++ b/tests/test_wayland_scaling.cpp
|
||||
@@ -0,0 +1,38 @@
|
||||
+#include <catch2/catch_test_macros.hpp>
|
||||
+
|
||||
+#include "Utils/WaylandScaling.h"
|
||||
+
|
||||
+#include <cmath>
|
||||
+#include <limits>
|
||||
+
|
||||
+using namespace gamescope;
|
||||
+
|
||||
+TEST_CASE("cropped Wayland planes retain negative positions", "[wayland_scaling]")
|
||||
+{
|
||||
+ REQUIRE( WaylandPositionToLogical( -120, 120 ) == -120 );
|
||||
+ REQUIRE( WaylandPositionToLogical( -640, 120 ) == -640 );
|
||||
+ REQUIRE( WaylandPositionToLogical( -360, 120 ) == -360 );
|
||||
+ REQUIRE( WaylandPositionToLogical( 0, 120 ) == 0 );
|
||||
+ REQUIRE( WaylandPositionToLogical( 160, 120 ) == 160 );
|
||||
+}
|
||||
+
|
||||
+TEST_CASE("Wayland positions round up at fractional host scales", "[wayland_scaling]")
|
||||
+{
|
||||
+ const int32_t positions[] = { -100000000, -1000000, -640, -120, -1, 0, 1, 120, 640, 1000000, 100000000 };
|
||||
+ const uint32_t scales[] = { 120, 150, 180, 240, 360, 480 };
|
||||
+ for ( uint32_t uScale : scales )
|
||||
+ {
|
||||
+ for ( int32_t nPosition : positions )
|
||||
+ {
|
||||
+ CAPTURE( nPosition, uScale );
|
||||
+ const int32_t nExpected = int32_t( std::ceil( (long double)( nPosition ) * 120 / uScale ) );
|
||||
+ REQUIRE( WaylandPositionToLogical( nPosition, uScale ) == nExpected );
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+TEST_CASE("Wayland position conversion widens before multiplying", "[wayland_scaling]")
|
||||
+{
|
||||
+ REQUIRE( WaylandPositionToLogical( std::numeric_limits<int32_t>::min(), 120 ) == std::numeric_limits<int32_t>::min() );
|
||||
+ REQUIRE( WaylandPositionToLogical( std::numeric_limits<int32_t>::max(), 120 ) == std::numeric_limits<int32_t>::max() );
|
||||
+}
|
||||
@@ -1,3 +1,3 @@
|
||||
GAMESCOPE_REPO=Droid-Deck/DroidDeck-Components
|
||||
GAMESCOPE_TAG=gamescope-3.16.29-p13
|
||||
GAMESCOPE_SHA256=93c789dc9e08828496f1caa2849d56acdf205838de723a24b296547a29c0b6af
|
||||
GAMESCOPE_TAG=gamescope-3.16.29-p14
|
||||
GAMESCOPE_SHA256=f0f2f33767c883bcfe66f28c303fddc1564f91a915fb7cedd31eb823570b254c
|
||||
Reference in new issue
Block a user