diff --git a/anda/games/terra-gamescope/0002-wlroots-libinput-switch-keypad-slide.patch b/anda/games/terra-gamescope/0002-wlroots-libinput-switch-keypad-slide.patch new file mode 100644 index 0000000000..4910d582cf --- /dev/null +++ b/anda/games/terra-gamescope/0002-wlroots-libinput-switch-keypad-slide.patch @@ -0,0 +1,18 @@ +From: porkloin +Subject: [PATCH] wlroots: handle LIBINPUT_SWITCH_KEYPAD_SLIDE enum in switch.c + +libinput added LIBINPUT_SWITCH_KEYPAD_SLIDE and GCC 16 on Fedora 44 +treats the unhandled enum value as -Werror=switch, breaking the build. + +diff --git a/subprojects/wlroots/backend/libinput/switch.c b/subprojects/wlroots/backend/libinput/switch.c +--- a/subprojects/wlroots/backend/libinput/switch.c ++++ b/subprojects/wlroots/backend/libinput/switch.c +@@ -34,6 +34,8 @@ void handle_switch_toggle(struct libinput_event *event, + case LIBINPUT_SWITCH_TABLET_MODE: + wlr_event.switch_type = WLR_SWITCH_TYPE_TABLET_MODE; + break; ++ case LIBINPUT_SWITCH_KEYPAD_SLIDE: ++ break; + } + switch (libinput_event_switch_get_switch_state(sevent)) { + case LIBINPUT_SWITCH_STATE_OFF: diff --git a/anda/games/terra-gamescope/Use-system-stb-glm.patch b/anda/games/terra-gamescope/Use-system-stb-glm.patch new file mode 100644 index 0000000000..f0addb676b --- /dev/null +++ b/anda/games/terra-gamescope/Use-system-stb-glm.patch @@ -0,0 +1,28 @@ +From 1a37d7113ed29ede9dcd30be16898b10464cd76e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Franti=C5=A1ek=20Zatloukal?= +Date: Wed, 28 May 2025 12:19:05 +0200 +Subject: [PATCH] Use system stb/glm + +--- + meson.build | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/meson.build b/meson.build +index c300b07..3044e54 100644 +--- a/meson.build ++++ b/meson.build +@@ -47,10 +47,8 @@ dep_x11 = dependency('x11') + dep_wayland = dependency('wayland-client') + vulkan_dep = dependency('vulkan') + +-glm_proj = subproject('glm') +-glm_dep = glm_proj.get_variable('glm_dep') +-stb_proj = subproject('stb') +-stb_dep = stb_proj.get_variable('stb_dep') ++glm_dep = dependency('glm') ++stb_dep = dependency('stb') + + if get_option('enable_openvr_support') + openvr_dep = dependency('openvr', version: '>= 2.7', required : false) +-- +2.49.0 diff --git a/anda/games/terra-gamescope/handheld.patch b/anda/games/terra-gamescope/handheld.patch deleted file mode 100755 index fcd7cb87f3..0000000000 --- a/anda/games/terra-gamescope/handheld.patch +++ /dev/null @@ -1,2050 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 22 Nov 2024 01:37:48 +0100 -Subject: [NA] add dev script - ---- - sync.sh | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - create mode 100755 sync.sh - -diff --git a/sync.sh b/sync.sh -new file mode 100755 -index 000000000000..8dd5815d4aeb ---- /dev/null -+++ b/sync.sh -@@ -0,0 +1,21 @@ -+if [ -z "$1" ]; then -+ echo "Usage: $0 " -+ exit 1 -+fi -+ -+HOST=$1 -+RSYNC="rsync -rv --exclude .git --exclude venv --exclude __pycache__'" -+USER=${USER:-bazzite} -+ -+set -e -+ -+meson build/ -Dforce_fallback_for=stb,libdisplay-info,libliftoff,wlroots,vkroots -Denable_openvr_support=false -+ninja -C build/ -+scp build/src/gamescope ${HOST}:gamescope -+ -+ssh $HOST /bin/bash << EOF -+ sudo rpm-ostree usroverlay --hotfix -+ sudo mv ~/gamescope /usr/bin/gamescope -+ bazzite-session-select gamescope -+ # sudo reboot -+EOF --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Matthew Anderson -Date: Fri, 17 May 2024 21:56:55 -0500 -Subject: feat: add --custom-refresh-rates option (+ fixes) - -Commit originally by Matthew, external fixes by Kyle, and new system check -move by Antheas. - -Co-authored-by: Kyle Gospodnetich -Co-authored-by: Antheas Kapenekakis ---- - src/Backends/DRMBackend.cpp | 4 +++- - src/main.cpp | 31 +++++++++++++++++++++++++++++++ - src/main.hpp | 2 ++ - 3 files changed, 36 insertions(+), 1 deletion(-) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 1ec2699821f0..c8e821314dc4 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -2342,8 +2342,10 @@ namespace gamescope - } - else - { -+ if ( g_customRefreshRates.size() > 0 && GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL ) -+ m_Mutable.ValidDynamicRefreshRates = g_customRefreshRates; - // Unknown display, see if there are any other refresh rates in the EDID we can get. -- if ( GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL || cv_drm_allow_dynamic_modes_for_external_display ) -+ else if ( GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL || cv_drm_allow_dynamic_modes_for_external_display ) - { - const drmModeModeInfo *pPreferredMode = find_mode( m_pConnector.get(), 0, 0, 0 ); - -diff --git a/src/main.cpp b/src/main.cpp -index cdb35c3b2518..d63b1fe50cc6 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -133,6 +133,7 @@ const struct option *gamescope_options = (struct option[]){ - { "fade-out-duration", required_argument, nullptr, 0 }, - { "force-orientation", required_argument, nullptr, 0 }, - { "force-windows-fullscreen", no_argument, nullptr, 0 }, -+ { "custom-refresh-rates", required_argument, nullptr, 0 }, - - { "disable-color-management", no_argument, nullptr, 0 }, - { "sdr-gamut-wideness", required_argument, nullptr, 0 }, -@@ -207,6 +208,7 @@ const char usage[] = - " --hdr-itm-target-nits set the target luminace of the inverse tone mapping process.\n" - " Default: 1000 nits, Max: 10000 nits\n" - " --framerate-limit Set a simple framerate limit. Used as a divisor of the refresh rate, rounds down eg 60 / 59 -> 60fps, 60 / 25 -> 30fps. Default: 0, disabled.\n" -+ " --custom-refresh-rates Set custom refresh rates for the output. eg: 60,90,110-120\n" - " --mangoapp Launch with the mangoapp (mangohud) performance overlay enabled. You should use this instead of using mangohud on the game or gamescope.\n" - " --adaptive-sync Enable adaptive sync if available (variable rate refresh)\n" - "\n" -@@ -460,6 +462,33 @@ static float parse_float(const char *str, const char *optionName) - } - } - -+std::vector g_customRefreshRates; -+// eg: 60,60,90,110-120 -+static std::vector parse_custom_refresh_rates( const char *str ) -+{ -+ std::vector rates; -+ char *token = strtok( strdup(str), ","); -+ while (token) -+ { -+ char *dash = strchr(token, '-'); -+ if (dash) -+ { -+ uint32_t start = atoi(token); -+ uint32_t end = atoi(dash + 1); -+ for (uint32_t i = start; i <= end; i++) -+ { -+ rates.push_back(i); -+ } -+ } -+ else -+ { -+ rates.push_back(atoi(token)); -+ } -+ token = strtok(nullptr, ","); -+ } -+ return rates; -+} -+ - struct sigaction handle_signal_action = {}; - - void ShutdownGamescope() -@@ -783,6 +812,8 @@ int main(int argc, char **argv) - g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); - } else if (strcmp(opt_name, "force-orientation") == 0) { - g_DesiredInternalOrientation = force_orientation( optarg ); -+ } else if (strcmp(opt_name, "custom-refresh-rates") == 0) { -+ g_customRefreshRates = parse_custom_refresh_rates( optarg ); - } else if (strcmp(opt_name, "sharpness") == 0 || - strcmp(opt_name, "fsr-sharpness") == 0) { - g_upscaleFilterSharpness = parse_integer( optarg, opt_name ); -diff --git a/src/main.hpp b/src/main.hpp -index 2e6fb833af12..390c04a63ecd 100644 ---- a/src/main.hpp -+++ b/src/main.hpp -@@ -3,6 +3,7 @@ - #include - - #include -+#include - - extern const char *gamescope_optstring; - extern const struct option *gamescope_options; -@@ -28,6 +29,7 @@ extern bool g_bGrabbed; - - extern float g_mouseSensitivity; - extern const char *g_sOutputName; -+extern std::vector g_customRefreshRates; - - enum class GamescopeUpscaleFilter : uint32_t - { --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Renn <8340896+AkazaRenn@users.noreply.github.com> -Date: Fri, 11 Oct 2024 17:48:26 +0200 -Subject: fix(deck): Use super + 1/2 for Overlay/QAM - -Replaces the patch for CTRL + 1/2 for Overlay/QAM with Super + 1/2 and -allows for CTRL for a smooth transition. - -Suggested-by: Antheas Kapenekakis ---- - src/wlserver.cpp | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 4d8546eed51f..56a9f25cd03a 100644 ---- a/src/wlserver.cpp -+++ b/src/wlserver.cpp -@@ -296,6 +296,9 @@ static void wlserver_handle_modifiers(struct wl_listener *listener, void *data) - bump_input_counter(); - } - -+// false if GS_ENABLE_CTRL_12 exists and is 0, true otherwise -+bool env_gs_enable_ctrl_12 = getenv("GS_ENABLE_CTRL_12") ? (getenv("GS_ENABLE_CTRL_12")[0] != '0') : true; -+ - static void wlserver_handle_key(struct wl_listener *listener, void *data) - { - struct wlr_keyboard *keyboard = &wlserver.keyboard_group->keyboard; -@@ -319,7 +322,14 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) - keysym == XKB_KEY_XF86AudioLowerVolume || - keysym == XKB_KEY_XF86AudioRaiseVolume || - keysym == XKB_KEY_XF86PowerOff; -- if ( ( event->state == WL_KEYBOARD_KEY_STATE_PRESSED || event->state == WL_KEYBOARD_KEY_STATE_RELEASED ) && forbidden_key ) -+ -+ // Check for steam overlay key (ctrl/super + 1/2) -+ bool is_steamshortcut = -+ ((env_gs_enable_ctrl_12 && (keyboard->modifiers.depressed & WLR_MODIFIER_CTRL)) || -+ (keyboard->modifiers.depressed & WLR_MODIFIER_LOGO)) && -+ (keysym == XKB_KEY_1 || keysym == XKB_KEY_2); -+ -+ if ( ( event->state == WL_KEYBOARD_KEY_STATE_PRESSED || event->state == WL_KEYBOARD_KEY_STATE_RELEASED ) && (forbidden_key || is_steamshortcut) ) - { - // Always send volume+/- to root server only, to avoid it reaching the game. - struct wlr_surface *old_kb_surf = wlserver.kb_focus_surface; -@@ -328,6 +338,17 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) - { - wlserver_keyboardfocus( new_kb_surf, false ); - wlr_seat_set_keyboard( wlserver.wlr.seat, keyboard ); -+ -+ if (is_steamshortcut) -+ { -+ // send ctrl down modifier to trigger the overlay -+ wlr_keyboard_modifiers ctrl_down_modifier; -+ ctrl_down_modifier.depressed = WLR_MODIFIER_CTRL; -+ ctrl_down_modifier.latched = WLR_MODIFIER_CTRL; -+ ctrl_down_modifier.locked = WLR_MODIFIER_CTRL; -+ wlr_seat_keyboard_notify_modifiers(wlserver.wlr.seat, &ctrl_down_modifier); -+ } -+ - wlr_seat_keyboard_notify_key( wlserver.wlr.seat, event->time_msec, event->keycode, event->state ); - wlserver_keyboardfocus( old_kb_surf, false ); - return; --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: honjow -Date: Wed, 16 Oct 2024 00:23:58 +0800 -Subject: fix(external): fix crash when using external touchscreens - ---- - src/wlserver.cpp | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 56a9f25cd03a..4d6e8de55ba4 100644 ---- a/src/wlserver.cpp -+++ b/src/wlserver.cpp -@@ -2766,8 +2766,12 @@ static void apply_touchscreen_orientation(double *x, double *y ) - double tx = 0; - double ty = 0; - -- // Use internal screen always for orientation purposes. -- switch ( GetBackend()->GetConnector( gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL )->GetCurrentOrientation() ) -+ auto orientation = GAMESCOPE_PANEL_ORIENTATION_AUTO; -+ if ( GetBackend() && GetBackend()->GetCurrentConnector( ) ) -+ { -+ orientation = GetBackend()->GetCurrentConnector()->GetCurrentOrientation(); -+ } -+ switch ( orientation ) - { - default: - case GAMESCOPE_PANEL_ORIENTATION_AUTO: --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Mon, 14 Oct 2024 22:42:20 +0200 -Subject: fix(display-config): always fill in mutable refresh rates - -Assume the user is not lying to us when they fill in dynamic_refresh_rates -and that gamescope will work with e.g., CVT, so accept it even if no -custom modeline generation has been provided. ---- - src/Backends/DRMBackend.cpp | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index c8e821314dc4..a919c61f9f8d 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -2258,7 +2258,9 @@ namespace gamescope - sol::optional otDynamicRefreshRates = tTable["dynamic_refresh_rates"]; - sol::optional ofnDynamicModegen = tTable["dynamic_modegen"]; - -- if ( otDynamicRefreshRates && ofnDynamicModegen ) -+ if ( otDynamicRefreshRates && !ofnDynamicModegen ) -+ m_Mutable.ValidDynamicRefreshRates = TableToVector( *otDynamicRefreshRates ); -+ else if ( otDynamicRefreshRates && ofnDynamicModegen ) - { - m_Mutable.ValidDynamicRefreshRates = TableToVector( *otDynamicRefreshRates ); - --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Wed, 30 Oct 2024 00:39:03 +0100 -Subject: fix(battery): run at half hz while at steamUI with atom - ---- - src/steamcompmgr.cpp | 53 +++++++++++++++++++++++++++++++++++--------- - src/xwayland_ctx.hpp | 2 ++ - 2 files changed, 45 insertions(+), 10 deletions(-) - -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index b0cf080e0642..07e45b19fc61 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -172,6 +172,8 @@ uint32_t g_reshade_technique_idx = 0; - - bool g_bSteamIsActiveWindow = false; - bool g_bForceInternal = false; -+bool b_bForceFrameLimit = false; -+bool g_bRefreshHalveEnable = false; - - namespace gamescope - { -@@ -928,6 +930,7 @@ uint64_t g_uCurrentBasePlaneCommitID = 0; - bool g_bCurrentBasePlaneIsFifo = false; - - static int g_nSteamCompMgrTargetFPS = 0; -+static int g_nSteamCompMgrTargetFPSreq = 0; - static uint64_t g_uDynamicRefreshEqualityTime = 0; - static int g_nDynamicRefreshRate[gamescope::GAMESCOPE_SCREEN_TYPE_COUNT] = { 0, 0 }; - // Delay to stop modes flickering back and forth. -@@ -947,7 +950,7 @@ static void _update_app_target_refresh_cycle() - int target_fps = g_nCombinedAppRefreshCycleOverride[type]; - - g_nDynamicRefreshRate[ type ] = 0; -- g_nSteamCompMgrTargetFPS = 0; -+ g_nSteamCompMgrTargetFPSreq = 0; - - if ( !target_fps ) - { -@@ -956,7 +959,7 @@ static void _update_app_target_refresh_cycle() - - if ( g_nCombinedAppRefreshCycleChangeFPS[ type ] ) - { -- g_nSteamCompMgrTargetFPS = target_fps; -+ g_nSteamCompMgrTargetFPSreq = target_fps; - } - - if ( g_nCombinedAppRefreshCycleChangeRefresh[ type ] ) -@@ -977,9 +980,9 @@ static void _update_app_target_refresh_cycle() - - static void update_app_target_refresh_cycle() - { -- int nPrevFPSLimit = g_nSteamCompMgrTargetFPS; -+ int nPrevFPSLimit = g_nSteamCompMgrTargetFPSreq; - _update_app_target_refresh_cycle(); -- if ( !!g_nSteamCompMgrTargetFPS != !!nPrevFPSLimit ) -+ if ( !!g_nSteamCompMgrTargetFPSreq != !!nPrevFPSLimit ) - update_runtime_info(); - } - -@@ -5316,7 +5319,7 @@ update_runtime_info() - if ( g_nRuntimeInfoFd < 0 ) - return; - -- uint32_t limiter_enabled = g_nSteamCompMgrTargetFPS != 0 ? 1 : 0; -+ uint32_t limiter_enabled = g_nSteamCompMgrTargetFPSreq != 0 ? 1 : 0; - pwrite( g_nRuntimeInfoFd, &limiter_enabled, sizeof( limiter_enabled ), 0 ); - } - -@@ -5379,7 +5382,7 @@ static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vb - { - bool bCloseEnough = std::abs( g_nSteamCompMgrTargetFPS - nRefreshHz ) < 2; - -- if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && w && !bCloseEnough ) -+ if ( g_nSteamCompMgrTargetFPS && (bShouldLimitFPS || b_bForceFrameLimit) && w && !bCloseEnough ) - { - uint64_t schedule = w->last_commit_first_latch_time + g_SteamCompMgrLimitedAppRefreshCycle; - -@@ -5397,7 +5400,7 @@ static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vb - } - else - { -- if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && nRefreshHz > nTargetFPS ) -+ if ( g_nSteamCompMgrTargetFPS && (bShouldLimitFPS || b_bForceFrameLimit) && nRefreshHz > nTargetFPS ) - { - int nVblankDivisor = nRefreshHz / nTargetFPS; - -@@ -5796,7 +5799,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - } - if ( ev->atom == ctx->atoms.gamescopeFPSLimit ) - { -- g_nSteamCompMgrTargetFPS = get_prop( ctx, ctx->root, ctx->atoms.gamescopeFPSLimit, 0 ); -+ g_nSteamCompMgrTargetFPSreq = get_prop( ctx, ctx->root, ctx->atoms.gamescopeFPSLimit, 0 ); - update_runtime_info(); - } - for (int i = 0; i < gamescope::GAMESCOPE_SCREEN_TYPE_COUNT; i++) -@@ -6227,6 +6230,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - MakeFocusDirty(); - } - } -+ if ( ev->atom == ctx->atoms.gamescopeFrameHalveAtom ) -+ { -+ g_bRefreshHalveEnable = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeFrameHalveAtom, 0 ); -+ } - } - - static int -@@ -6603,7 +6610,7 @@ void handle_presented_for_window( steamcompmgr_win_t* w ) - - uint64_t next_refresh_time = g_SteamCompMgrVBlankTime.schedule.ulTargetVBlank; - -- uint64_t refresh_cycle = g_nSteamCompMgrTargetFPS && steamcompmgr_window_should_limit_fps( w ) -+ uint64_t refresh_cycle = g_nSteamCompMgrTargetFPS && (steamcompmgr_window_should_limit_fps( w ) || b_bForceFrameLimit) - ? g_SteamCompMgrLimitedAppRefreshCycle - : g_SteamCompMgrAppRefreshCycle; - -@@ -7462,6 +7469,8 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ - ctx->atoms.primarySelection = XInternAtom(ctx->dpy, "PRIMARY", false); - ctx->atoms.targets = XInternAtom(ctx->dpy, "TARGETS", false); - -+ ctx->atoms.gamescopeFrameHalveAtom = XInternAtom( ctx->dpy, "GAMESCOPE_STEAMUI_HALFHZ", false );; -+ - ctx->root_width = DisplayWidth(ctx->dpy, ctx->scr); - ctx->root_height = DisplayHeight(ctx->dpy, ctx->scr); - -@@ -7883,7 +7892,7 @@ steamcompmgr_main(int argc, char **argv) - } else if (strcmp(opt_name, "hdr-itm-target-nits") == 0) { - g_flHDRItmTargetNits = atof(optarg); - } else if (strcmp(opt_name, "framerate-limit") == 0) { -- g_nSteamCompMgrTargetFPS = atoi(optarg); -+ g_nSteamCompMgrTargetFPSreq = atoi(optarg); - } else if (strcmp(opt_name, "reshade-effect") == 0) { - g_reshade_effect = optarg; - } else if (strcmp(opt_name, "reshade-technique-idx") == 0) { -@@ -8051,6 +8060,30 @@ steamcompmgr_main(int argc, char **argv) - // as a question. - const bool bIsVBlankFromTimer = vblank; - -+ // Halve refresh rate on SteamUI -+ bool isSteam = false; -+ for (auto &iter : g_VirtualConnectorFocuses) -+ { -+ global_focus_t *pFocus = &iter.second; -+ if (window_is_steam( pFocus->focusWindow )) { -+ isSteam = true; -+ break; -+ } -+ } -+ if ( g_bRefreshHalveEnable && isSteam ) { -+ int nRealRefreshHz = gamescope::ConvertmHzToHz( g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh ); -+ if (nRealRefreshHz > 100 && (g_nSteamCompMgrTargetFPSreq > 50 || !g_nSteamCompMgrTargetFPSreq)) { -+ g_nSteamCompMgrTargetFPS = nRealRefreshHz / 2; -+ b_bForceFrameLimit = true; -+ } else { -+ g_nSteamCompMgrTargetFPS = g_nSteamCompMgrTargetFPSreq; -+ b_bForceFrameLimit = false; -+ } -+ } else { -+ g_nSteamCompMgrTargetFPS = g_nSteamCompMgrTargetFPSreq; -+ b_bForceFrameLimit = false; -+ } -+ - // We can always vblank if VRR. - const bool bVRR = GetBackend()->GetCurrentConnector() && GetBackend()->GetCurrentConnector()->IsVRRActive(); - if ( bVRR ) -diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp -index df2af70d19ae..e4eec9fa0c48 100644 ---- a/src/xwayland_ctx.hpp -+++ b/src/xwayland_ctx.hpp -@@ -246,6 +246,8 @@ struct xwayland_ctx_t final : public gamescope::IWaitable - Atom clipboard; - Atom primarySelection; - Atom targets; -+ -+ Atom gamescopeFrameHalveAtom; - } atoms; - - bool HasQueuedEvents(); --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Joshua Tam <297250+joshuatam@users.noreply.github.com> -Date: Fri, 6 Dec 2024 16:51:02 +0800 -Subject: feat(intel): add rotation shader for rotating output - ---- - src/Backends/DRMBackend.cpp | 35 +++++++++- - src/main.cpp | 7 ++ - src/main.hpp | 2 + - src/meson.build | 1 + - src/rendervulkan.cpp | 126 ++++++++++++++++++++++++++++++----- - src/rendervulkan.hpp | 6 +- - src/shaders/cs_rotation.comp | 53 +++++++++++++++ - src/wlserver.cpp | 5 ++ - 8 files changed, 216 insertions(+), 19 deletions(-) - create mode 100644 src/shaders/cs_rotation.comp - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index a919c61f9f8d..a099185e7cdc 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -1609,6 +1609,10 @@ static void update_drm_effective_orientations( struct drm_t *drm, const drmModeM - if ( pDRMInternalConnector != drm->pConnector ) - pInternalMode = find_mode( pDRMInternalConnector->GetModeConnector(), 0, 0, 0 ); - -+ if ( g_bUseRotationShader ) { -+ g_bEnableDRMRotationShader = true; -+ } -+ - pDRMInternalConnector->UpdateEffectiveOrientation( pInternalMode ); - } - -@@ -1620,6 +1624,10 @@ static void update_drm_effective_orientations( struct drm_t *drm, const drmModeM - if ( pDRMExternalConnector != drm->pConnector ) - pExternalMode = find_mode( pDRMExternalConnector->GetModeConnector(), 0, 0, 0 ); - -+ if ( g_bUseRotationShader ) { -+ g_bEnableDRMRotationShader = false; -+ } -+ - pDRMExternalConnector->UpdateEffectiveOrientation( pExternalMode ); - } - } -@@ -1835,7 +1843,7 @@ LiftoffStateCacheEntry FrameInfoToLiftoffStateCacheEntry( struct drm_t *drm, con - uint64_t crtcW = srcWidth / frameInfo->layers[ i ].scale.x; - uint64_t crtcH = srcHeight / frameInfo->layers[ i ].scale.y; - -- if (g_bRotated) -+ if (g_bRotated && !g_bEnableDRMRotationShader) - { - int64_t imageH = frameInfo->layers[ i ].tex->contentHeight() / frameInfo->layers[ i ].scale.y; - -@@ -2136,6 +2144,17 @@ namespace gamescope - - void CDRMConnector::UpdateEffectiveOrientation( const drmModeModeInfo *pMode ) - { -+ if (g_bEnableDRMRotationShader) -+ { -+ drm_log.infof("Using rotation shader"); -+ if (g_DesiredInternalOrientation == GAMESCOPE_PANEL_ORIENTATION_270) { -+ m_ChosenOrientation = GAMESCOPE_PANEL_ORIENTATION_180; -+ } else { -+ m_ChosenOrientation = GAMESCOPE_PANEL_ORIENTATION_0; -+ } -+ return; -+ } -+ - if ( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL && g_DesiredInternalOrientation != GAMESCOPE_PANEL_ORIENTATION_AUTO ) - { - m_ChosenOrientation = g_DesiredInternalOrientation; -@@ -3185,6 +3204,13 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) - g_bRotated = false; - g_nOutputWidth = mode->hdisplay; - g_nOutputHeight = mode->vdisplay; -+ -+ if (g_bEnableDRMRotationShader) { -+ g_bRotated = true; -+ g_nOutputWidth = mode->vdisplay; -+ g_nOutputHeight = mode->hdisplay; -+ } -+ - break; - case GAMESCOPE_PANEL_ORIENTATION_90: - case GAMESCOPE_PANEL_ORIENTATION_270: -@@ -3449,6 +3475,11 @@ namespace gamescope - - bNeedsFullComposite |= !!(g_uCompositeDebug & CompositeDebugFlag::Heatmap); - -+ if (g_bEnableDRMRotationShader) -+ { -+ bNeedsFullComposite = true; -+ } -+ - bool bDoComposite = true; - if ( !bNeedsFullComposite && !bWantsPartialComposite ) - { -@@ -3539,7 +3570,7 @@ namespace gamescope - if ( bDefer && !!( g_uCompositeDebug & CompositeDebugFlag::Markers ) ) - g_uCompositeDebug |= CompositeDebugFlag::Markers_Partial; - -- std::optional oCompositeResult = vulkan_composite( &compositeFrameInfo, nullptr, !bNeedsFullComposite ); -+ std::optional oCompositeResult = vulkan_composite( &compositeFrameInfo, nullptr, !bNeedsFullComposite, nullptr, true, nullptr, g_bEnableDRMRotationShader ); - - m_bWasCompositing = true; - -diff --git a/src/main.cpp b/src/main.cpp -index d63b1fe50cc6..cfd4cc11d179 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -131,6 +131,7 @@ const struct option *gamescope_options = (struct option[]){ - { "composite-debug", no_argument, nullptr, 0 }, - { "disable-xres", no_argument, nullptr, 'x' }, - { "fade-out-duration", required_argument, nullptr, 0 }, -+ { "use-rotation-shader", required_argument, nullptr, 0 }, - { "force-orientation", required_argument, nullptr, 0 }, - { "force-windows-fullscreen", no_argument, nullptr, 0 }, - { "custom-refresh-rates", required_argument, nullptr, 0 }, -@@ -194,6 +195,7 @@ const char usage[] = - " -e, --steam enable Steam integration\n" - " --xwayland-count create N xwayland servers\n" - " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" -+ " --use-rotation-shader use rotation shader for rotating the screen\n" - " --force-orientation rotate the internal display (left, right, normal, upsidedown)\n" - " --force-windows-fullscreen force windows inside of gamescope to be the size of the nested display (fullscreen)\n" - " --cursor-scale-height if specified, sets a base output height to linearly scale the cursor against.\n" -@@ -355,6 +357,9 @@ static gamescope::GamescopeModeGeneration parse_gamescope_mode_generation( const - } - } - -+bool g_bUseRotationShader = false; -+bool g_bEnableDRMRotationShader = false; -+ - GamescopePanelOrientation g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_AUTO; - static GamescopePanelOrientation force_orientation(const char *str) - { -@@ -812,6 +817,8 @@ int main(int argc, char **argv) - g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); - } else if (strcmp(opt_name, "force-orientation") == 0) { - g_DesiredInternalOrientation = force_orientation( optarg ); -+ } else if (strcmp(opt_name, "use-rotation-shader") == 0) { -+ g_bUseRotationShader = true; - } else if (strcmp(opt_name, "custom-refresh-rates") == 0) { - g_customRefreshRates = parse_custom_refresh_rates( optarg ); - } else if (strcmp(opt_name, "sharpness") == 0 || -diff --git a/src/main.hpp b/src/main.hpp -index 390c04a63ecd..e7b857d44b0d 100644 ---- a/src/main.hpp -+++ b/src/main.hpp -@@ -22,6 +22,8 @@ extern bool g_bForceRelativeMouse; - extern int g_nOutputRefresh; // mHz - extern bool g_bOutputHDREnabled; - extern bool g_bForceInternal; -+extern bool g_bUseRotationShader; -+extern bool g_bEnableDRMRotationShader; - - extern bool g_bFullscreen; - -diff --git a/src/meson.build b/src/meson.build -index a3dfdabd7366..36c073ec214e 100644 ---- a/src/meson.build -+++ b/src/meson.build -@@ -70,6 +70,7 @@ shader_src = [ - 'shaders/cs_nis.comp', - 'shaders/cs_nis_fp16.comp', - 'shaders/cs_rgb_to_nv12.comp', -+ 'shaders/cs_rotation.comp', - ] - - spirv_shaders = glsl_generator.process(shader_src) -diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp -index f79d26e0c139..b19f9bf101b4 100644 ---- a/src/rendervulkan.cpp -+++ b/src/rendervulkan.cpp -@@ -48,6 +48,7 @@ - #include "cs_nis.h" - #include "cs_nis_fp16.h" - #include "cs_rgb_to_nv12.h" -+#include "cs_rotation.h" - - #define A_CPU - #include "shaders/ffx_a.h" -@@ -923,6 +924,7 @@ bool CVulkanDevice::createShaders() - SHADER(NIS, cs_nis); - } - SHADER(RGB_TO_NV12, cs_rgb_to_nv12); -+ SHADER(ROTATION, cs_rotation); - #undef SHADER - - for (uint32_t i = 0; i < shaderInfos.size(); i++) -@@ -1153,6 +1155,7 @@ void CVulkanDevice::compileAllPipelines() - SHADER(EASU, 1, 1, 1); - SHADER(NIS, 1, 1, 1); - SHADER(RGB_TO_NV12, 1, 1, 1); -+ SHADER(ROTATION, k_nMaxLayers, k_nMaxYcbcrMask_ToPreCompile, k_nMaxBlurLayers); - #undef SHADER - - for (auto& info : pipelineInfos) { -@@ -3249,8 +3252,16 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) - - uint32_t uDRMFormat = pOutput->uOutputFormat; - -+ uint32_t l_nOutputWidth = g_nOutputWidth; -+ uint32_t l_nOutputHeight = g_nOutputHeight; -+ -+ if (g_bEnableDRMRotationShader) { -+ l_nOutputWidth = g_nOutputHeight; -+ l_nOutputHeight = g_nOutputWidth; -+ } -+ - pOutput->outputImages[0] = new CVulkanTexture(); -- bool bSuccess = pOutput->outputImages[0]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uDRMFormat, outputImageflags ); -+ bool bSuccess = pOutput->outputImages[0]->BInit( l_nOutputWidth, l_nOutputHeight, 1u, uDRMFormat, outputImageflags ); - if ( bSuccess != true ) - { - vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3258,7 +3269,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) - } - - pOutput->outputImages[1] = new CVulkanTexture(); -- bSuccess = pOutput->outputImages[1]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uDRMFormat, outputImageflags ); -+ bSuccess = pOutput->outputImages[1]->BInit( l_nOutputWidth, l_nOutputHeight, 1u, uDRMFormat, outputImageflags ); - if ( bSuccess != true ) - { - vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3266,7 +3277,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) - } - - pOutput->outputImages[2] = new CVulkanTexture(); -- bSuccess = pOutput->outputImages[2]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uDRMFormat, outputImageflags ); -+ bSuccess = pOutput->outputImages[2]->BInit( l_nOutputWidth, l_nOutputHeight, 1u, uDRMFormat, outputImageflags ); - if ( bSuccess != true ) - { - vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3281,7 +3292,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) - uint32_t uPartialDRMFormat = pOutput->uOutputFormatOverlay; - - pOutput->outputImagesPartialOverlay[0] = new CVulkanTexture(); -- bool bSuccess = pOutput->outputImagesPartialOverlay[0]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[0].get() ); -+ bool bSuccess = pOutput->outputImagesPartialOverlay[0]->BInit( l_nOutputWidth, l_nOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[0].get() ); - if ( bSuccess != true ) - { - vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3289,7 +3300,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) - } - - pOutput->outputImagesPartialOverlay[1] = new CVulkanTexture(); -- bSuccess = pOutput->outputImagesPartialOverlay[1]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[1].get() ); -+ bSuccess = pOutput->outputImagesPartialOverlay[1]->BInit( l_nOutputWidth, l_nOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[1].get() ); - if ( bSuccess != true ) - { - vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3297,7 +3308,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) - } - - pOutput->outputImagesPartialOverlay[2] = new CVulkanTexture(); -- bSuccess = pOutput->outputImagesPartialOverlay[2]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[2].get() ); -+ bSuccess = pOutput->outputImagesPartialOverlay[2]->BInit( l_nOutputWidth, l_nOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[2].get() ); - if ( bSuccess != true ) - { - vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3427,6 +3438,28 @@ static void update_tmp_images( uint32_t width, uint32_t height ) - } - } - -+static void update_rotated_images( uint32_t width, uint32_t height ) -+{ -+ if ( g_output.rotatedOutput != nullptr -+ && width == g_output.rotatedOutput->width() -+ && height == g_output.rotatedOutput->height() ) -+ { -+ return; -+ } -+ -+ CVulkanTexture::createFlags createFlags; -+ createFlags.bSampled = true; -+ createFlags.bStorage = true; -+ -+ g_output.rotatedOutput = new CVulkanTexture(); -+ bool bSuccess = g_output.rotatedOutput->BInit( width, height, 1u, DRM_FORMAT_ARGB8888, createFlags, nullptr ); -+ -+ if ( !bSuccess ) -+ { -+ vk_log.errorf( "failed to create rotated output" ); -+ return; -+ } -+} - - static bool init_nis_data() - { -@@ -3903,7 +3936,7 @@ extern uint32_t g_reshade_technique_idx; - - ReshadeEffectPipeline *g_pLastReshadeEffect = nullptr; - --std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc pPipewireTexture, bool partial, gamescope::Rc pOutputOverride, bool increment, std::unique_ptr pInCommandBuffer ) -+std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc pPipewireTexture, bool partial, gamescope::Rc pOutputOverride, bool increment, std::unique_ptr pInCommandBuffer, bool applyRotation ) - { - EOTF outputTF = frameInfo->outputEncodingEOTF; - if (!frameInfo->applyOutputColorMgmt) -@@ -3978,7 +4011,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco - cmdBuffer->setTextureSrgb(0, true); - cmdBuffer->setSamplerUnnormalized(0, false); - cmdBuffer->setSamplerNearest(0, false); -- cmdBuffer->bindTarget(compositeImage); -+ -+ if (applyRotation) { -+ // Make a rotatedOutput with normal dimensions -+ update_rotated_images(currentOutputWidth, currentOutputHeight); // 2560x1600 -+ cmdBuffer->bindTarget(g_output.rotatedOutput); -+ } else { -+ cmdBuffer->bindTarget(compositeImage); -+ } -+ - cmdBuffer->uploadConstants(frameInfo, g_upscaleFilterSharpness / 10.0f); - - cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -@@ -4021,7 +4062,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco - - cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, nisFrameInfo.layerCount, nisFrameInfo.ycbcrMask(), 0u, nisFrameInfo.colorspaceMask(), outputTF )); - bind_all_layers(cmdBuffer.get(), &nisFrameInfo); -- cmdBuffer->bindTarget(compositeImage); -+ -+ if (applyRotation) { -+ // Make a rotatedOutput with normal dimensions -+ update_rotated_images(currentOutputWidth, currentOutputHeight); // 2560x1600 -+ cmdBuffer->bindTarget(g_output.rotatedOutput); -+ } else { -+ cmdBuffer->bindTarget(compositeImage); -+ } -+ - cmdBuffer->uploadConstants(&nisFrameInfo); - - int pixelsPerGroup = 8; -@@ -4059,7 +4108,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco - type = frameInfo->blurLayer0 == BLUR_MODE_COND ? SHADER_TYPE_BLUR_COND : SHADER_TYPE_BLUR; - cmdBuffer->bindPipeline(g_device.pipeline(type, frameInfo->layerCount, frameInfo->ycbcrMask(), blur_layer_count, frameInfo->colorspaceMask(), outputTF )); - bind_all_layers(cmdBuffer.get(), frameInfo); -- cmdBuffer->bindTarget(compositeImage); -+ -+ if (applyRotation) { -+ // Make a rotatedOutput with normal dimensions -+ update_rotated_images(currentOutputWidth, currentOutputHeight); // 2560x1600 -+ cmdBuffer->bindTarget(g_output.rotatedOutput); -+ } else { -+ cmdBuffer->bindTarget(compositeImage); -+ } -+ - cmdBuffer->bindTexture(VKR_BLUR_EXTRA_SLOT, g_output.tmpOutput); - cmdBuffer->setTextureSrgb(VKR_BLUR_EXTRA_SLOT, !useSrgbView); // Inverted because it chooses whether to view as linear (sRGB view) or sRGB (raw view). It's horrible. I need to change it. - cmdBuffer->setSamplerUnnormalized(VKR_BLUR_EXTRA_SLOT, true); -@@ -4069,14 +4126,51 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco - } - else - { -- cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, frameInfo->layerCount, frameInfo->ycbcrMask(), 0u, frameInfo->colorspaceMask(), outputTF )); -- bind_all_layers(cmdBuffer.get(), frameInfo); -- cmdBuffer->bindTarget(compositeImage); -- cmdBuffer->uploadConstants(frameInfo); -+ if (applyRotation) { -+ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_ROTATION, frameInfo->layerCount, frameInfo->ycbcrMask(), 0u, frameInfo->colorspaceMask(), outputTF )); -+ bind_all_layers(cmdBuffer.get(), frameInfo); -+ cmdBuffer->bindTarget(compositeImage); -+ cmdBuffer->uploadConstants(frameInfo); - -- const int pixelsPerGroup = 8; -+ const int pixelsPerGroup = 8; - -- cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -+ cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -+ } else { -+ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, frameInfo->layerCount, frameInfo->ycbcrMask(), 0u, frameInfo->colorspaceMask(), outputTF )); -+ bind_all_layers(cmdBuffer.get(), frameInfo); -+ cmdBuffer->bindTarget(compositeImage); -+ cmdBuffer->uploadConstants(frameInfo); -+ -+ const int pixelsPerGroup = 8; -+ -+ cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -+ } -+ } -+ -+ if (applyRotation) -+ { -+ if (g_output.rotatedOutput != nullptr) { -+ // Rotate the final output -+ // TODO: may need rework with another rotation shader for blur, fsr and nis -+ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_ROTATION, frameInfo->layerCount, frameInfo->ycbcrMask(), 0u, frameInfo->colorspaceMask(), outputTF)); -+ bind_all_layers(cmdBuffer.get(), frameInfo); -+ -+ // if (frameInfo->blurLayer0) { -+ // bool useSrgbView = frameInfo->layers[0].colorspace == GAMESCOPE_APP_TEXTURE_COLORSPACE_LINEAR; -+ // -+ // cmdBuffer->bindTexture(VKR_BLUR_EXTRA_SLOT, g_output.rotatedOutput); -+ // cmdBuffer->setTextureSrgb(VKR_BLUR_EXTRA_SLOT, !useSrgbView); -+ // cmdBuffer->setSamplerUnnormalized(VKR_BLUR_EXTRA_SLOT, true); -+ // cmdBuffer->setSamplerNearest(VKR_BLUR_EXTRA_SLOT, false); -+ // } -+ -+ cmdBuffer->bindTarget(compositeImage); -+ cmdBuffer->uploadConstants(frameInfo); -+ -+ const int pixelsPerGroup = 8; -+ -+ cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -+ } - } - - if ( pPipewireTexture != nullptr ) -diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp -index 63cc6029ac5f..93a4a6027f55 100644 ---- a/src/rendervulkan.hpp -+++ b/src/rendervulkan.hpp -@@ -408,7 +408,7 @@ gamescope::OwningRc vulkan_create_texture_from_dmabuf( struct wl - gamescope::OwningRc vulkan_create_texture_from_bits( uint32_t width, uint32_t height, uint32_t contentWidth, uint32_t contentHeight, uint32_t drmFormat, CVulkanTexture::createFlags texCreateFlags, void *bits ); - gamescope::OwningRc vulkan_create_texture_from_wlr_buffer( struct wlr_buffer *buf, gamescope::OwningRc pBackendFb ); - --std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc pScreenshotTexture, bool partial, gamescope::Rc pOutputOverride = nullptr, bool increment = true, std::unique_ptr pInCommandBuffer = nullptr ); -+std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc pScreenshotTexture, bool partial, gamescope::Rc pOutputOverride = nullptr, bool increment = true, std::unique_ptr pInCommandBuffer = nullptr, bool applyRotation = false ); - void vulkan_wait( uint64_t ulSeqNo, bool bReset ); - gamescope::Rc vulkan_get_last_output_image( bool partial, bool defer ); - gamescope::Rc vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, bool exportable, uint32_t drmFormat, EStreamColorspace colorspace = k_EStreamColorspace_Unknown); -@@ -545,6 +545,9 @@ struct VulkanOutput_t - // NIS - gamescope::OwningRc nisScalerImage; - gamescope::OwningRc nisUsmImage; -+ -+ // Rotated -+ gamescope::OwningRc rotatedOutput; - }; - - -@@ -557,6 +560,7 @@ enum ShaderType { - SHADER_TYPE_RCAS, - SHADER_TYPE_NIS, - SHADER_TYPE_RGB_TO_NV12, -+ SHADER_TYPE_ROTATION, - - SHADER_TYPE_COUNT - }; -diff --git a/src/shaders/cs_rotation.comp b/src/shaders/cs_rotation.comp -new file mode 100644 -index 000000000000..1a47fd505748 ---- /dev/null -+++ b/src/shaders/cs_rotation.comp -@@ -0,0 +1,53 @@ -+#version 450 -+ -+#extension GL_GOOGLE_include_directive : require -+#extension GL_EXT_scalar_block_layout : require -+ -+#include "descriptor_set.h" -+ -+layout( -+ local_size_x = 8, -+ local_size_y = 8, -+ local_size_z = 1) in; -+ -+#include "blit_push_data.h" -+#include "composite.h" -+ -+vec4 sampleLayer(uint layerIdx, vec2 uv) { -+ if ((c_ycbcrMask & (1 << layerIdx)) != 0) -+ return sampleLayer(s_ycbcr_samplers[layerIdx], layerIdx, uv, false); -+ return sampleLayer(s_samplers[layerIdx], layerIdx, uv, true); -+} -+ -+void main() { -+ uvec2 coord = uvec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); -+ uvec2 outSize = imageSize(dst); -+ float outWidth = outSize.y; -+ float outHeight = outSize.x; -+ -+ vec2 uv = vec2(coord); -+ vec4 outputValue = vec4(255.0f); -+ -+ if (c_layerCount > 0) { -+ outputValue = sampleLayer(0, uv) * u_opacity[0]; -+ } -+ -+ for (int i = 1; i < c_layerCount; i++) { -+ vec4 layerColor = sampleLayer(i, uv); -+ // wl_surfaces come with premultiplied alpha, so that's them being -+ // premultiplied by layerColor.a. -+ // We need to then multiply that by the layer's opacity to get to our -+ // final premultiplied state. -+ // For the other side of things, we need to multiply by (1.0f - (layerColor.a * opacity)) -+ float opacity = u_opacity[i]; -+ float layerAlpha = opacity * layerColor.a; -+ outputValue = layerColor * opacity + outputValue * (1.0f - layerAlpha); -+ } -+ -+ outputValue.rgb = encodeOutputColor(outputValue.rgb); -+ -+ // Rotate the pixel coordinates counter-clockwise by 90 degrees -+ ivec2 rotatedCoord = ivec2(coord.y, outWidth - coord.x - 1); -+ -+ imageStore(dst, rotatedCoord, outputValue); -+} -diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 4d6e8de55ba4..a694b5245a97 100644 ---- a/src/wlserver.cpp -+++ b/src/wlserver.cpp -@@ -2793,6 +2793,11 @@ static void apply_touchscreen_orientation(double *x, double *y ) - break; - } - -+ if (g_bEnableDRMRotationShader) { -+ tx = 1.0 - *y; -+ ty = *x; -+ } -+ - *x = tx; - *y = ty; - } --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: brainantifreeze -Date: Thu, 19 Dec 2024 09:16:15 +0000 -Subject: feat(nvidia): fix crash with current driver - -add layer env var to hide present wait ext - -see: https://github.com/ValveSoftware/gamescope/pull/1671 ---- - layer/VkLayer_FROG_gamescope_wsi.cpp | 20 +++++++++++++++++++- - 1 file changed, 19 insertions(+), 1 deletion(-) - -diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp -index af0c2009930b..263cbc37bd88 100644 ---- a/layer/VkLayer_FROG_gamescope_wsi.cpp -+++ b/layer/VkLayer_FROG_gamescope_wsi.cpp -@@ -183,6 +183,16 @@ namespace GamescopeWSILayer { - return s_ensureMinImageCount; - } - -+ static bool getHidePresentWait() { -+ static bool s_hidePresentWait = []() -> bool { -+ if (auto hide = parseEnv("GAMESCOPE_WSI_HIDE_PRESENT_WAIT_EXT")) { -+ return *hide; -+ } -+ return false; -+ }(); -+ return s_hidePresentWait; -+ } -+ - // Taken from Mesa, licensed under MIT. - // - // No real reason to rewrite this code, -@@ -589,7 +599,11 @@ namespace GamescopeWSILayer { - createInfo.ppEnabledExtensionNames = enabledExts.data(); - - setenv("vk_xwayland_wait_ready", "false", 0); -- setenv("vk_khr_present_wait", "true", 0); -+ if (getHidePresentWait()) { -+ setenv("vk_khr_present_wait", "false", 0); -+ } else { -+ setenv("vk_khr_present_wait", "true", 0); -+ } - - VkResult result = pfnCreateInstanceProc(&createInfo, pAllocator, pInstance); - if (result != VK_SUCCESS) -@@ -899,6 +913,10 @@ namespace GamescopeWSILayer { - const vkroots::VkInstanceDispatch* pDispatch, - VkPhysicalDevice physicalDevice, - VkPhysicalDeviceFeatures2* pFeatures) { -+ if (getHidePresentWait()) { -+ fprintf(stderr, "[Gamescope WSI] Removing VkPhysicalDevicePresentWaitFeaturesKHR because GAMESCOPE_WSI_HIDE_PRESENT_WAIT_EXT is set\n"); -+ vkroots::RemoveFromChain(pFeatures); -+ } - pDispatch->GetPhysicalDeviceFeatures2(physicalDevice, pFeatures); - } - --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Sun, 23 Feb 2025 02:16:55 +0100 -Subject: feat(display): add asus z13 - ---- - .../00-gamescope/displays/asus.z13.lcd.lua | 57 +++++++++++++++++++ - 1 file changed, 57 insertions(+) - create mode 100644 scripts/00-gamescope/displays/asus.z13.lcd.lua - -diff --git a/scripts/00-gamescope/displays/asus.z13.lcd.lua b/scripts/00-gamescope/displays/asus.z13.lcd.lua -new file mode 100644 -index 000000000000..891f1ea9ca6f ---- /dev/null -+++ b/scripts/00-gamescope/displays/asus.z13.lcd.lua -@@ -0,0 +1,57 @@ -+gamescope.config.known_displays.asusz13_lcd = { -+ pretty_name = "Asus Z13 LCD", -+ dynamic_refresh_rates = { -+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, -+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, -+ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, -+ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, -+ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, -+ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, -+ 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, -+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, -+ 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180 -+ }, -+ -+ -- Detailed Timing Descriptors: -+ -- DTD 1: 1920x1200 120.002 Hz 8:5 151.683 kHz 315.500 MHz (172 mm x 107 mm) -+ -- Modeline "1920x1200_120.00" 315.500 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync -+ -- DTD 2: 1920x1200 60.001 Hz 8:5 75.841 kHz 157.750 MHz (172 mm x 107 mm) -+ -- Modeline "1920x1200_60.00" 157.750 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync -+ dynamic_modegen = function(base_mode, refresh) -+ debug("Generating mode "..refresh.."Hz with fixed pixel clock") -+ local vfps = { -+ 4886, 4751, 4620, 4495, 4375, 4259, 4147, 4040, 3936, 3836, 3739, 3646, -+ 3556, 3468, 3384, 3302, 3223, 3146, 3072, 2999, 2929, 2861, 2795, 2731, -+ 2668, 2608, 2548, 2491, 2435, 2380, 2327, 2275, 2225, 2175, 2127, 2080, -+ 2035, 1990, 1946, 1903, 1862, 1821, 1781, 1742, 1704, 1667, 1630, 1594, -+ 1559, 1525, 1491, 1458, 1426, 1395, 1364, 1333, 1303, 1274, 1245, 1217, -+ 1190, 1162, 1136, 1110, 1084, 1059, 1034, 1010, 986, 962, 939, 916, 894, -+ 872, 850, 829, 808, 787, 767, 747, 727, 708, 689, 670, 652, 634, 616, -+ 598, 581, 563, 547, 530, 513, 497, 481, 466, 450, 435, 420, 405, 390, -+ 376, 361, 347, 333, 320, 306, 293, 279, 266, 254, 241, 228, 216, 204, -+ 192, 180, 168, 156, 145, 133, 122, 111, 100, 89, 78, 68, 57, 47, 36, -+ 26, 16, 6 -+ } -+ local vfp = vfps[zero_index(refresh - 48)] -+ if vfp == nil then -+ warn("Couldn't do refresh "..refresh.." on ROG Ally") -+ return base_mode -+ end -+ -+ local mode = base_mode -+ -+ gamescope.modegen.adjust_front_porch(mode, vfp) -+ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) -+ -+ --debug(inspect(mode)) -+ return mode -+ end, -+ matches = function(display) -+ if display.vendor == "TMA" and display.model == "TL134ADXP03" then -+ debug("[z13] Matched vendor: "..display.vendor.." model: "..display.model.." product:"..display.product) -+ return 5000 -+ end -+ return -1 -+ end -+} -+debug("Registered Lenovo Legion Go S LCD as a known display") -\ No newline at end of file --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Wed, 23 Apr 2025 22:51:54 +0200 -Subject: feat(display): consider vporch to avoid timing issues - ---- - src/Backends/DRMBackend.cpp | 8 ++++++++ - src/main.cpp | 1 + - src/main.hpp | 1 + - src/vblankmanager.cpp | 6 +----- - 4 files changed, 11 insertions(+), 5 deletions(-) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index a099185e7cdc..d09030e0cf5e 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -213,6 +213,11 @@ namespace gamescope - return nRefresh; - } - -+ static int32_t GetVblankNs(const drmModeModeInfo *mode) -+ { -+ return (mode->vsync_start - mode->vdisplay) * 1'000'000'000ll / mode->vrefresh / mode->vtotal; -+ } -+ - template - using CAutoDeletePtr = std::unique_ptr; - -@@ -3194,6 +3199,9 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) - g_nOutputRefresh = gamescope::GetModeRefresh( mode ); - g_nDynamicRefreshHz = 0; - -+ g_nsVsync = gamescope::GetVblankNs( mode ); -+ drm_log.infof("Vblank ns: %lu", g_nsVsync); -+ - update_drm_effective_orientations(drm, mode); - - switch ( drm->pConnector->GetCurrentOrientation() ) -diff --git a/src/main.cpp b/src/main.cpp -index cfd4cc11d179..0d88e3a2cded 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -291,6 +291,7 @@ int g_nNestedDisplayIndex = 0; - uint32_t g_nOutputWidth = 0; - uint32_t g_nOutputHeight = 0; - int g_nOutputRefresh = 0; -+long g_nsVsync = 0; - bool g_bOutputHDREnabled = false; - - bool g_bFullscreen = false; -diff --git a/src/main.hpp b/src/main.hpp -index e7b857d44b0d..e6f8ff133689 100644 ---- a/src/main.hpp -+++ b/src/main.hpp -@@ -20,6 +20,7 @@ extern uint32_t g_nOutputWidth; - extern uint32_t g_nOutputHeight; - extern bool g_bForceRelativeMouse; - extern int g_nOutputRefresh; // mHz -+extern long g_nsVsync; // ns - extern bool g_bOutputHDREnabled; - extern bool g_bForceInternal; - extern bool g_bUseRotationShader; -diff --git a/src/vblankmanager.cpp b/src/vblankmanager.cpp -index f036d000a8e2..e388374c98ba 100644 ---- a/src/vblankmanager.cpp -+++ b/src/vblankmanager.cpp -@@ -95,8 +95,6 @@ namespace gamescope - - VBlankScheduleTime CVBlankTimer::CalcNextWakeupTime( bool bPreemptive ) - { -- const GamescopeScreenType eScreenType = GetBackend()->GetScreenType(); -- - const int nRefreshRate = GetRefresh(); - const uint64_t ulRefreshInterval = mHzToRefreshCycle( nRefreshRate ); - -@@ -113,9 +111,7 @@ namespace gamescope - // to not account for vertical front porch when dealing with the vblank - // drm_commit is going to target? - // Need to re-test that. -- const uint64_t ulRedZone = eScreenType == GAMESCOPE_SCREEN_TYPE_INTERNAL -- ? m_ulVBlankDrawBufferRedZone -- : std::min( m_ulVBlankDrawBufferRedZone, ( m_ulVBlankDrawBufferRedZone * 60'000 * nRefreshRate ) / 60'000 ); -+ const uint64_t ulRedZone = m_ulVBlankDrawBufferRedZone + g_nsVsync; - - const uint64_t ulDecayAlpha = m_ulVBlankRateOfDecayPercentage; // eg. 980 = 98% - --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Sun, 22 Jun 2025 15:18:19 +0200 -Subject: feat: add Legion Go S display with all framerates - ---- - .../displays/lenovo.legiongos.lcd.lua | 71 +++++++++++-------- - 1 file changed, 42 insertions(+), 29 deletions(-) - -diff --git a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua -index 32f776c17f3d..057850f374f8 100644 ---- a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua -+++ b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua -@@ -1,44 +1,58 @@ --local legiongos_lcd_refresh_rates = { -- 52, 53, 54, 56, 57, 58, 59, -- 60, 61, 62, 63, 64, 65, 67, 68, 69, -- 70, -- 102, 103, 104, 105, 106, 107, 108, 109, -- 111, 112, 113, 114, 115, 116, 117, 118, 119, -- 120 --} -- - gamescope.config.known_displays.legiongos_lcd = { - pretty_name = "Lenovo Legion Go S LCD", - hdr = { -- -- The Legion Go S panel does not support HDR. -+ -- Setup some fallbacks for undocking with HDR, meant -+ -- for the internal panel. It does not support HDR. - supported = false, - force_enabled = false, -- eotf = gamescope.eotf.gamma22, -- max_content_light_level = 500, -- max_frame_average_luminance = 500, -- min_content_light_level = 0.5 -+ eotf = gamescope.eotf.gamma22, -+ max_content_light_level = 500, -+ max_frame_average_luminance = 500, -+ min_content_light_level = 0.5 - }, -- -- 60Hz has a different pixel clock than 120Hz in the EDID with VRR disabled, -- -- and the panel is not responsive to tuning VFPs. To cover the non-VRR -- -- limiter, an LCD Deck-style dynamic modegen method works best. -- dynamic_refresh_rates = legiongos_lcd_refresh_rates, -+ -+ dynamic_refresh_rates = { -+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, -+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, -+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, -+ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, -+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, -+ 118, 119, 120 -+ }, -+ -+ -- Detailed Timing Descriptors: -+ -- DTD 1: 1920x1200 120.002 Hz 8:5 151.683 kHz 315.500 MHz (172 mm x 107 mm) -+ -- Modeline "1920x1200_120.00" 315.500 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync -+ -- DTD 2: 1920x1200 60.001 Hz 8:5 75.841 kHz 157.750 MHz (172 mm x 107 mm) -+ -- Modeline "1920x1200_60.00" 157.750 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync - dynamic_modegen = function(base_mode, refresh) -- debug("Generating mode "..refresh.."Hz for Lenovo Legion Go S LCD") -- local mode = base_mode -+ debug("Generating mode "..refresh.."Hz with fixed pixel clock") -+ local vfps = { -+ 1950, 1885, 1824, 1764, 1707, 1652, 1599, 1548, 1499, 1451, 1405, -+ 1361, 1318, 1277, 1237, 1198, 1160, 1124, 1088, 1054, 1021, 988, -+ 957, 927, 897, 868, 840, 813, 786, 760, 735, 710, 686, 663, 640, -+ 618, 596, 575, 554, 534, 514, 495, 476, 457, 439, 421, 404, 387, -+ 370, 354, 338, 322, 307, 292, 277, 263, 249, 235, 221, 208, 195, -+ 182, 169, 157, 145, 133, 121, 109, 98, 87, 76, 65, 54 -+ } -+ local vfp = vfps[zero_index(refresh - 48)] -+ if vfp == nil then -+ warn("Couldn't do refresh "..refresh.." on ROG Ally") -+ return base_mode -+ end - -- -- These are only tuned for 1920x1200. -- gamescope.modegen.set_resolution(mode, 1920, 1200) -+ local mode = base_mode - -- -- hfp, hsync, hbp -- gamescope.modegen.set_h_timings(mode, 48, 36, 80) -- -- vfp, vsync, vbp -- gamescope.modegen.set_v_timings(mode, 54, 6, 4) -- mode.clock = gamescope.modegen.calc_max_clock(mode, refresh) -+ gamescope.modegen.adjust_front_porch(mode, vfp) - mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) - - --debug(inspect(mode)) - return mode - end, -+ -+ - matches = function(display) - local lcd_types = { - { vendor = "CSW", model = "PN8007QB1-1", product = 0x0800 }, -@@ -56,5 +70,4 @@ gamescope.config.known_displays.legiongos_lcd = { - return -1 - end - } --debug("Registered Lenovo Legion Go S LCD as a known display") ----debug(inspect(gamescope.config.known_displays.legiongos_lcd)) -+debug("Registered Lenovo Legion Go S LCD as a known display") -\ No newline at end of file --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 29 Aug 2025 16:45:39 +0200 -Subject: feat: add DPMS support through an Atom - ---- - src/Backends/DRMBackend.cpp | 15 ++++++++++++++- - src/rendervulkan.hpp | 2 ++ - src/steamcompmgr.cpp | 18 +++++++++++++++--- - src/xwayland_ctx.hpp | 1 + - 4 files changed, 32 insertions(+), 4 deletions(-) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index d09030e0cf5e..2861f30aaf66 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -2827,6 +2827,9 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI - drm->needs_modeset = true; - } - -+ if (drm->pCRTC && drm->pCRTC->GetProperties().ACTIVE->GetCurrentValue() != !frameInfo->dpms) -+ drm->needs_modeset = true; -+ - drm_colorspace uColorimetry = DRM_MODE_COLORIMETRY_DEFAULT; - - const bool bWantsHDR10 = g_bOutputHDREnabled && frameInfo->outputEncodingEOTF == EOTF_PQ; -@@ -2894,6 +2897,9 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI - needs_modeset = true; - } - -+ if ( frameInfo->dpms ) -+ bSleep = true; -+ - if ( !bSleep ) - { - if ( drm->pCRTC != nullptr ) -@@ -2973,7 +2979,13 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI - - if ( drm->pCRTC && !bSleep ) - { -- drm->pCRTC->GetProperties().ACTIVE->SetPendingValue( drm->req, 1u, true ); -+ if ( frameInfo->dpms ) { -+ // We can't disable a CRTC if it's already disabled -+ if (drm->pCRTC->GetProperties().ACTIVE->GetCurrentValue() != 0) -+ drm->pCRTC->GetProperties().ACTIVE->SetPendingValue(drm->req, 0, true); -+ } -+ else -+ drm->pCRTC->GetProperties().ACTIVE->SetPendingValue( drm->req, 1u, true ); - drm->pCRTC->GetProperties().MODE_ID->SetPendingValue( drm->req, drm->pending.mode_id ? drm->pending.mode_id->GetBlobValue() : 0lu, true ); - - if ( drm->pCRTC->GetProperties().VRR_ENABLED ) -@@ -3594,6 +3606,7 @@ namespace gamescope - - FrameInfo_t presentCompFrameInfo = {}; - presentCompFrameInfo.allowVRR = pFrameInfo->allowVRR; -+ presentCompFrameInfo.dpms = pFrameInfo->dpms; - presentCompFrameInfo.outputEncodingEOTF = pFrameInfo->outputEncodingEOTF; - - if ( bNeedsFullComposite ) -diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp -index 93a4a6027f55..0833fc46ffd7 100644 ---- a/src/rendervulkan.hpp -+++ b/src/rendervulkan.hpp -@@ -292,6 +292,8 @@ struct FrameInfo_t - bool applyOutputColorMgmt; // drm only - EOTF outputEncodingEOTF; - -+ bool dpms; -+ - int layerCount; - struct Layer_t - { -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 07e45b19fc61..f25f810f9387 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -174,6 +174,8 @@ bool g_bSteamIsActiveWindow = false; - bool g_bForceInternal = false; - bool b_bForceFrameLimit = false; - bool g_bRefreshHalveEnable = false; -+bool g_bDPMS = false; -+bool g_bDPMS_set = false; - - namespace gamescope - { -@@ -2421,7 +2423,7 @@ gamescope::ConVar cv_paint_cursor_plane{ "paint_cursor_plane", true }; - gamescope::ConVar cv_paint_mura_plane{ "paint_mura_plane", true }; - - static void --paint_all( global_focus_t *pFocus, bool async ) -+paint_all(global_focus_t *pFocus, bool async, bool dpms) - { - if ( !pFocus ) - return; -@@ -2479,6 +2481,7 @@ paint_all( global_focus_t *pFocus, bool async ) - frameInfo.outputEncodingEOTF = g_ColorMgmt.pending.outputEncodingEOTF; - frameInfo.allowVRR = cv_adaptive_sync; - frameInfo.bFadingOut = fadingOut; -+ frameInfo.dpms = dpms; - - // If the window we'd paint as the base layer is the streaming client, - // find the video underlay and put it up first in the scenegraph -@@ -6234,6 +6237,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - { - g_bRefreshHalveEnable = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeFrameHalveAtom, 0 ); - } -+ if (ev->atom == ctx->atoms.gamescopeDPMS) -+ { -+ g_bDPMS = !!get_prop(ctx, ctx->root, ctx->atoms.gamescopeDPMS, 0); -+ } - } - - static int -@@ -7470,6 +7477,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ - ctx->atoms.targets = XInternAtom(ctx->dpy, "TARGETS", false); - - ctx->atoms.gamescopeFrameHalveAtom = XInternAtom( ctx->dpy, "GAMESCOPE_STEAMUI_HALFHZ", false );; -+ ctx->atoms.gamescopeDPMS = XInternAtom(ctx->dpy, "GAMESCOPE_DPMS", false); - - ctx->root_width = DisplayWidth(ctx->dpy, ctx->scr); - ctx->root_height = DisplayHeight(ctx->dpy, ctx->scr); -@@ -8611,10 +8619,14 @@ steamcompmgr_main(int argc, char **argv) - bShouldPaint = false; - } - -+ if ( g_bDPMS != g_bDPMS_set && vblank ) -+ bShouldPaint = true; -+ - if ( bShouldPaint ) - { -- paint_all( pPaintFocus, eFlipType == FlipType::Async ); -- -+ paint_all( pPaintFocus, eFlipType == FlipType::Async, g_bDPMS ); -+ -+ g_bDPMS_set = g_bDPMS; - bPainted = true; - } - } -diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp -index e4eec9fa0c48..2347cbb3340c 100644 ---- a/src/xwayland_ctx.hpp -+++ b/src/xwayland_ctx.hpp -@@ -248,6 +248,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable - Atom targets; - - Atom gamescopeFrameHalveAtom; -+ Atom gamescopeDPMS; - } atoms; - - bool HasQueuedEvents(); --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Sun, 29 Jun 2025 13:16:59 +0200 -Subject: update misyltoad urls - ---- - .gitmodules | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/.gitmodules b/.gitmodules -index ec7d4e430ee8..17ba783f809b 100644 ---- a/.gitmodules -+++ b/.gitmodules -@@ -1,12 +1,12 @@ - [submodule "subprojects/wlroots"] - path = subprojects/wlroots -- url = https://github.com/Joshua-Ashton/wlroots.git -+ url = https://github.com/misyltoad/wlroots.git - [submodule "subprojects/libliftoff"] - path = subprojects/libliftoff - url = https://gitlab.freedesktop.org/emersion/libliftoff.git - [submodule "subprojects/vkroots"] - path = subprojects/vkroots -- url = https://github.com/Joshua-Ashton/vkroots -+ url = https://github.com/misyltoad/vkroots - [submodule "subprojects/libdisplay-info"] - path = subprojects/libdisplay-info - url = https://gitlab.freedesktop.org/emersion/libdisplay-info -@@ -15,7 +15,7 @@ - url = https://github.com/ValveSoftware/openvr.git - [submodule "src/reshade"] - path = src/reshade -- url = https://github.com/Joshua-Ashton/reshade -+ url = https://github.com/misyltoad/reshade - [submodule "thirdparty/SPIRV-Headers"] - path = thirdparty/SPIRV-Headers - url = https://github.com/KhronosGroup/SPIRV-Headers/ --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 29 Aug 2025 15:31:34 +0200 -Subject: fix: drain timer fds to avoid epoll_wait returning constantly - -Currently, if the VBlank or VRR timers expire without being rescheduled, -their FDs remain readable, causing epoll_wait to return instantly.|Drain -the FDs in the OnPollIn handlers to prevent this. ---- - src/waitable.h | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/src/waitable.h b/src/waitable.h -index 30edf8f52deb..36ac61ee7233 100644 ---- a/src/waitable.h -+++ b/src/waitable.h -@@ -182,6 +182,11 @@ namespace gamescope - ArmTimer( 0ul, false ); - } - -+ void OnPollIn() -+ { -+ IWaitable::Drain(m_nFD); -+ } -+ - int GetFD() - { - return m_nFD; -@@ -200,6 +205,7 @@ namespace gamescope - - void OnPollIn() final - { -+ ITimerWaitable::OnPollIn(); - m_fnPollFunc(); - } - private: --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Sat, 30 Aug 2025 15:12:39 +0200 -Subject: fix(intel): allow night mode and color adjustment via compositing - ---- - src/Backends/DRMBackend.cpp | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 2861f30aaf66..3c4e5907b2a9 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -3481,6 +3481,17 @@ namespace gamescope - bNeedsFullComposite |= pFrameInfo->bFadingOut; - bNeedsFullComposite |= !g_reshade_effect.empty(); - -+ if ( !SupportsColorManagement() ) { -+ // Fuzzy match default values to see if we need to composite -+ bNeedsFullComposite |= g_ColorMgmt.pending.nightmode.amount != 0.0f; -+ bNeedsFullComposite |= g_ColorMgmt.pending.outputVirtualWhite.x > 0 && -+ abs(g_ColorMgmt.pending.outputVirtualWhite.x - 0.3127f) > 0.001f; -+ bNeedsFullComposite |= g_ColorMgmt.pending.outputVirtualWhite.y > 0 && -+ abs(g_ColorMgmt.pending.outputVirtualWhite.y - 0.3290f) > 0.001f; -+ bNeedsFullComposite |= g_ColorMgmt.pending.sdrGamutWideness >= 0 && -+ abs(g_ColorMgmt.pending.sdrGamutWideness - 0.5f) > 0.02f; -+ } -+ - if ( g_bOutputHDREnabled ) - { - bNeedsFullComposite |= g_bHDRItmEnable; --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Sat, 30 Aug 2025 15:32:00 +0200 -Subject: fix(hdr): disable PQ on handheld internal displays - -For some reason, the PQ transfer function does not work on current -handhelds. So use gamma 22 instead. This allows us to skip creating -configs and read the HDR metadata from the displays. ---- - src/Backends/DRMBackend.cpp | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 3c4e5907b2a9..83da1bfe231b 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -2465,7 +2465,13 @@ namespace gamescope - pHDRStaticMetadata && pHDRStaticMetadata->eotfs && pHDRStaticMetadata->eotfs->pq ) - { - m_Mutable.HDR.bExposeHDRSupport = true; -- m_Mutable.HDR.eOutputEncodingEOTF = EOTF_PQ; -+ if (GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL) -+ // Current handheld internal displays have issues -+ // with PQ, e.g., Ayaneo 3, Steam Deck etc. -+ // Use Gamma 2.2 as the safest option for now. -+ m_Mutable.HDR.eOutputEncodingEOTF = EOTF_Gamma22; -+ else -+ m_Mutable.HDR.eOutputEncodingEOTF = EOTF_PQ; - m_Mutable.HDR.uMaxContentLightLevel = - pHDRStaticMetadata->desired_content_max_luminance - ? nits_to_u16( pHDRStaticMetadata->desired_content_max_luminance ) --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 29 Aug 2025 17:17:06 +0200 -Subject: chore: use system glm, stb - ---- - meson.build | 6 ++---- - 1 file changed, 2 insertions(+), 4 deletions(-) - -diff --git a/meson.build b/meson.build -index 5e5bd4cdc7c4..802e4a052bcd 100644 ---- a/meson.build -+++ b/meson.build -@@ -50,10 +50,8 @@ dep_x11 = dependency('x11') - dep_wayland = dependency('wayland-client') - vulkan_dep = dependency('vulkan') - --glm_proj = subproject('glm') --glm_dep = glm_proj.get_variable('glm_dep') --stb_proj = subproject('stb') --stb_dep = stb_proj.get_variable('stb_dep') -+glm_dep = dependency('glm') -+stb_dep = dependency('stb') - - if get_option('enable_openvr_support') - openvr_dep = dependency('openvr', version: '>= 2.7', required : false) --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 29 Aug 2025 19:04:17 +0200 -Subject: Revert "mangoapp: plumb engineName" - -This reverts commit b9f20436d1bdf7bd8212541817b254e1b4c8eb1e. ---- - layer/VkLayer_FROG_gamescope_wsi.cpp | 9 +-------- - protocol/gamescope-swapchain.xml | 1 - - src/WaylandServer/WaylandServerLegacy.h | 1 - - src/mangoapp.cpp | 6 ------ - src/steamcompmgr.cpp | 6 ------ - src/steamcompmgr.hpp | 1 - - src/steamcompmgr_shared.hpp | 2 -- - src/wlserver.cpp | 4 +--- - 8 files changed, 2 insertions(+), 28 deletions(-) - -diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp -index 263cbc37bd88..d1835a4c7487 100644 ---- a/layer/VkLayer_FROG_gamescope_wsi.cpp -+++ b/layer/VkLayer_FROG_gamescope_wsi.cpp -@@ -404,7 +404,6 @@ namespace GamescopeWSILayer { - struct GamescopeInstanceData { - wl_display* display; - uint32_t appId = 0; -- std::string engineName; - GamescopeLayerClient::Flags flags = 0; - }; - VKROOTS_DEFINE_SYNCHRONIZED_MAP_TYPE(GamescopeInstance, VkInstance); -@@ -631,14 +630,9 @@ namespace GamescopeWSILayer { - { - uint32_t appId = clientAppId(); - -- std::string engineName; -- if (pCreateInfo->pApplicationInfo && pCreateInfo->pApplicationInfo->pEngineName) -- engineName = pCreateInfo->pApplicationInfo->pEngineName; -- - auto state = GamescopeInstance::create(*pInstance, GamescopeInstanceData { - .display = display, - .appId = appId, -- .engineName = engineName, - .flags = defaultLayerClientFlags(pCreateInfo->pApplicationInfo, appId), - }); - -@@ -1275,8 +1269,7 @@ namespace GamescopeWSILayer { - uint32_t(pCreateInfo->imageColorSpace), - uint32_t(pCreateInfo->compositeAlpha), - uint32_t(pCreateInfo->preTransform), -- uint32_t(pCreateInfo->clipped), -- gamescopeInstance->engineName.c_str()); -+ uint32_t(pCreateInfo->clipped)); - - return VK_SUCCESS; - } -diff --git a/protocol/gamescope-swapchain.xml b/protocol/gamescope-swapchain.xml -index 58ac8463b752..91be3fc02d67 100644 ---- a/protocol/gamescope-swapchain.xml -+++ b/protocol/gamescope-swapchain.xml -@@ -89,7 +89,6 @@ - - - -- - - - -diff --git a/src/WaylandServer/WaylandServerLegacy.h b/src/WaylandServer/WaylandServerLegacy.h -index 63ee2ca17e8c..0facb7dc8b1e 100644 ---- a/src/WaylandServer/WaylandServerLegacy.h -+++ b/src/WaylandServer/WaylandServerLegacy.h -@@ -29,7 +29,6 @@ struct wlserver_vk_swapchain_feedback - VkCompositeAlphaFlagBitsKHR vk_composite_alpha; - VkSurfaceTransformFlagBitsKHR vk_pre_transform; - VkBool32 vk_clipped; -- std::shared_ptr vk_engine_name; - - std::shared_ptr hdr_metadata_blob; - }; -diff --git a/src/mangoapp.cpp b/src/mangoapp.cpp -index d8e1ce7edafe..91e01bc275c6 100644 ---- a/src/mangoapp.cpp -+++ b/src/mangoapp.cpp -@@ -31,7 +31,6 @@ struct mangoapp_msg_v1 { - uint16_t displayRefresh; - bool bAppWantsHDR : 1; - bool bSteamFocused : 1; -- char engineName[40]; - - // WARNING: Always ADD fields, never remove or repurpose fields - } __attribute__((packed)) mangoapp_msg_v1; -@@ -61,11 +60,6 @@ void mangoapp_update( uint64_t visible_frametime, uint64_t app_frametime_ns, uin - mangoapp_msg_v1.displayRefresh = (uint16_t) gamescope::ConvertmHzToHz( g_nOutputRefresh ); - mangoapp_msg_v1.bAppWantsHDR = g_bAppWantsHDRCached; - mangoapp_msg_v1.bSteamFocused = g_focusedBaseAppId == 769; -- memset(mangoapp_msg_v1.engineName, 0, sizeof(mangoapp_msg_v1.engineName)); -- if (focusWindow_engine) -- focusWindow_engine->copy(mangoapp_msg_v1.engineName, sizeof(mangoapp_msg_v1.engineName) / sizeof(char)); -- else -- std::string("gamescope").copy(mangoapp_msg_v1.engineName, sizeof(mangoapp_msg_v1.engineName) / sizeof(char)); - msgsnd(msgid, &mangoapp_msg_v1, sizeof(mangoapp_msg_v1) - sizeof(mangoapp_msg_v1.hdr.msg_type), IPC_NOWAIT); - } - -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index f25f810f9387..d5a6a4af51df 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -1026,7 +1026,6 @@ int g_BlurRadius = 5; - unsigned int g_BlurFadeStartTime = 0; - - pid_t focusWindow_pid; --std::shared_ptr focusWindow_engine = nullptr; - - focus_t g_steamcompmgr_xdg_focus; - std::vector> g_steamcompmgr_xdg_wins; -@@ -6396,9 +6395,6 @@ bool handle_done_commit( steamcompmgr_win_t *w, xwayland_ctx_t *ctx, uint64_t co - uint32_t j; - for ( j = 0; j < w->commit_queue.size(); j++ ) - { -- if (w->commit_queue[ j ]->feedback.has_value()) -- w->engineName = w->commit_queue[ j ]->feedback->vk_engine_name; -- - if ( w->commit_queue[ j ]->commitID == commitID ) - { - gpuvis_trace_printf( "commit %lu done", w->commit_queue[ j ]->commitID ); -@@ -6443,8 +6439,6 @@ bool handle_done_commit( steamcompmgr_win_t *w, xwayland_ctx_t *ctx, uint64_t co - if ( !cv_paint_debug_pause_base_plane ) - g_HeldCommits[ HELD_COMMIT_BASE ] = w->commit_queue[ j ]; - hasRepaint = true; -- -- focusWindow_engine = w->engineName; - } - - if ( w == pFocus->overrideWindow ) -diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp -index 98e927296483..2f489a26a0aa 100644 ---- a/src/steamcompmgr.hpp -+++ b/src/steamcompmgr.hpp -@@ -144,7 +144,6 @@ struct wlserver_x11_surface_info *lookup_x11_surface_info_from_xid( gamescope_xw - - extern gamescope::VBlankTime g_SteamCompMgrVBlankTime; - extern pid_t focusWindow_pid; --extern std::shared_ptr focusWindow_engine; - - void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_server); - void gamescope_set_selection(std::string contents, GamescopeSelection eSelection); -diff --git a/src/steamcompmgr_shared.hpp b/src/steamcompmgr_shared.hpp -index 5a2198d97bed..4027013148b2 100644 ---- a/src/steamcompmgr_shared.hpp -+++ b/src/steamcompmgr_shared.hpp -@@ -149,8 +149,6 @@ struct steamcompmgr_win_t { - bool unlockedForFrameCallback = false; - bool receivedDoneCommit = false; - -- std::shared_ptr engineName; -- - std::vector< gamescope::Rc > commit_queue; - std::shared_ptr> icon; - -diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index a694b5245a97..42c6bc0c2430 100644 ---- a/src/wlserver.cpp -+++ b/src/wlserver.cpp -@@ -862,8 +862,7 @@ static void gamescope_swapchain_swapchain_feedback( struct wl_client *client, st - uint32_t vk_colorspace, - uint32_t vk_composite_alpha, - uint32_t vk_pre_transform, -- uint32_t vk_clipped, -- const char *vk_engine_name) -+ uint32_t vk_clipped) - { - wlserver_wl_surface_info *wl_info = (wlserver_wl_surface_info *)wl_resource_get_user_data( resource ); - if ( wl_info ) -@@ -875,7 +874,6 @@ static void gamescope_swapchain_swapchain_feedback( struct wl_client *client, st - .vk_composite_alpha = VkCompositeAlphaFlagBitsKHR(vk_composite_alpha), - .vk_pre_transform = VkSurfaceTransformFlagBitsKHR(vk_pre_transform), - .vk_clipped = VkBool32(vk_clipped), -- .vk_engine_name = std::make_shared(vk_engine_name), - .hdr_metadata_blob = nullptr, - }); - } --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Sun, 31 Aug 2025 20:55:02 +0200 -Subject: fix: separate blend tf to its own check - -Currently, blend tf and other color mgmt checks are combined into one -check. However, new hardware does not support the blend tf for a plane, -causing loss of all color mgmt features. Separate the checks so that -color mgmt can still be used on such hardware. - -Also, add the other function checks to drm_supports_color_mgmt so that -there are no edge cases where only subproperties are supported. ---- - src/Backends/DRMBackend.cpp | 40 +++++++++++++++++++++++++++++-------- - 1 file changed, 32 insertions(+), 8 deletions(-) - -diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 83da1bfe231b..c1a714569bf2 100644 ---- a/src/Backends/DRMBackend.cpp -+++ b/src/Backends/DRMBackend.cpp -@@ -559,6 +559,7 @@ extern std::string g_reshade_effect; - - bool drm_update_color_mgmt(struct drm_t *drm); - bool drm_supports_color_mgmt(struct drm_t *drm); -+bool drm_supports_srgb_to_pq(struct drm_t *drm); - bool drm_set_connector( struct drm_t *drm, gamescope::CDRMConnector *conn ); - - struct drm_color_ctm2 { -@@ -2691,13 +2692,15 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo - } - } - -- if ( drm_supports_color_mgmt( drm ) ) -+ if ( drm_supports_srgb_to_pq( drm ) ) - { - if (!cv_drm_debug_disable_blend_tf && !bSinglePlane) - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_BLEND_TF", drm->pending.output_tf ); - else -- liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_BLEND_TF", AMDGPU_TRANSFER_FUNCTION_DEFAULT ); -- -+ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_BLEND_TF", AMDGPU_TRANSFER_FUNCTION_DEFAULT ); -+ } -+ if ( drm_supports_color_mgmt( drm ) ) -+ { - if (!cv_drm_debug_disable_ctm && frameInfo->layers[i].ctm != nullptr) - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_CTM", frameInfo->layers[i].ctm->GetBlobValue() ); - else -@@ -2712,13 +2715,16 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo - liftoff_layer_unset_property( drm->lo_layers[ i ], "COLOR_ENCODING" ); - liftoff_layer_unset_property( drm->lo_layers[ i ], "COLOR_RANGE" ); - -+ if ( drm_supports_srgb_to_pq( drm ) ) -+ { -+ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_BLEND_TF", AMDGPU_TRANSFER_FUNCTION_DEFAULT ); -+ } - if ( drm_supports_color_mgmt( drm ) ) - { - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_DEGAMMA_TF", AMDGPU_TRANSFER_FUNCTION_DEFAULT ); - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_SHAPER_LUT", 0 ); - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_SHAPER_TF", 0 ); - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_LUT3D", 0 ); -- liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_BLEND_TF", AMDGPU_TRANSFER_FUNCTION_DEFAULT ); - liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_CTM", 0 ); - } - } -@@ -2870,7 +2876,7 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI - - bool bSinglePlane = frameInfo->layerCount < 2 && cv_drm_single_plane_optimizations; - -- if ( drm_supports_color_mgmt( &g_DRM ) && frameInfo->applyOutputColorMgmt ) -+ if ( drm_supports_srgb_to_pq( &g_DRM ) && frameInfo->applyOutputColorMgmt ) - { - if ( !cv_drm_debug_disable_output_tf && !bSinglePlane ) - { -@@ -3371,7 +3377,20 @@ bool drm_supports_color_mgmt(struct drm_t *drm) - if ( !drm->pPrimaryPlane ) - return false; - -- return drm->pPrimaryPlane->GetProperties().AMD_PLANE_CTM.has_value() && drm->pPrimaryPlane->GetProperties().AMD_PLANE_BLEND_TF.has_value(); -+ return drm->pPrimaryPlane->GetProperties().AMD_PLANE_CTM.has_value() && // dm->dc->caps.color.mpc.gamut_remap -+ drm->pPrimaryPlane->GetProperties().AMD_PLANE_SHAPER_LUT.has_value() && // dpp_color_caps.hw_3d_lut -+ drm->pPrimaryPlane->GetProperties().AMD_PLANE_DEGAMMA_TF.has_value(); // dpp_color_caps.dgam_ram || dpp_color_caps.gamma_corr -+} -+ -+bool drm_supports_srgb_to_pq(struct drm_t *drm) -+{ -+ if ( g_bForceDisableColorMgmt ) -+ return false; -+ -+ if ( !drm->pPrimaryPlane ) -+ return false; -+ -+ return drm->pPrimaryPlane->GetProperties().AMD_PLANE_BLEND_TF.has_value(); // dpp_color_caps.ogam_ram - } - - std::span drm_get_valid_refresh_rates( struct drm_t *drm ) -@@ -3501,12 +3520,12 @@ namespace gamescope - if ( g_bOutputHDREnabled ) - { - bNeedsFullComposite |= g_bHDRItmEnable; -- if ( !SupportsColorManagement() ) -+ if ( !SupportsSRGBtoPQ() ) - bNeedsFullComposite |= ( pFrameInfo->layerCount > 1 || pFrameInfo->layers[0].colorspace != GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ ); - } - else - { -- if ( !SupportsColorManagement() ) -+ if ( !SupportsSRGBtoPQ() ) - bNeedsFullComposite |= ColorspaceIsHDR( pFrameInfo->layers[0].colorspace ); - } - -@@ -3915,6 +3934,11 @@ namespace gamescope - return drm_supports_color_mgmt( &g_DRM ); - } - -+ bool SupportsSRGBtoPQ() const -+ { -+ return drm_supports_srgb_to_pq( &g_DRM ); -+ } -+ - int Commit( const FrameInfo_t *pFrameInfo ) - { - drm_t *drm = &g_DRM; --- -2.51.0 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Colin Kinloch -Date: Fri, 1 Aug 2025 16:06:23 +0100 -Subject: WaylandBackend: Check features before using color management - -This stops compositors lacking required features, transfer functions or -primaries from triggering protocol errors on start. ---- - src/Backends/WaylandBackend.cpp | 32 ++++++++++++++++++-------------- - 1 file changed, 18 insertions(+), 14 deletions(-) - -diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp -index 664ed0eac070..1171980ba61d 100644 ---- a/src/Backends/WaylandBackend.cpp -+++ b/src/Backends/WaylandBackend.cpp -@@ -1990,13 +1990,14 @@ namespace gamescope - return false; - if ( !Algorithm::Contains( m_WPColorManagerFeatures.eFeatures, WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES ) ) - return false; -+ if ( !Algorithm::Contains( m_WPColorManagerFeatures.eFeatures, WP_COLOR_MANAGER_V1_FEATURE_WINDOWS_SCRGB ) ) -+ return false; - - // Transfer Functions - if ( !Algorithm::Contains( m_WPColorManagerFeatures.eTransferFunctions, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB ) ) - return false; - if ( !Algorithm::Contains( m_WPColorManagerFeatures.eTransferFunctions, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ ) ) - return false; -- // TODO: Need scRGB - - // Primaries - if ( !Algorithm::Contains( m_WPColorManagerFeatures.ePrimaries, WP_COLOR_MANAGER_V1_PRIMARIES_SRGB ) ) -@@ -2006,6 +2007,22 @@ namespace gamescope - - return true; - }(); -+ -+ if ( m_WPColorManagerFeatures.bSupportsGamescopeColorManagement ) -+ { -+ // HDR10. -+ { -+ wp_image_description_creator_params_v1 *pParams = wp_color_manager_v1_create_parametric_creator( m_pWPColorManager ); -+ wp_image_description_creator_params_v1_set_primaries_named( pParams, WP_COLOR_MANAGER_V1_PRIMARIES_BT2020 ); -+ wp_image_description_creator_params_v1_set_tf_named( pParams, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ ); -+ m_pWPImageDescriptions[ GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ ] = wp_image_description_creator_params_v1_create( pParams ); -+ } -+ -+ // scRGB -+ { -+ m_pWPImageDescriptions[ GAMESCOPE_APP_TEXTURE_COLORSPACE_SCRGB ] = wp_color_manager_v1_create_windows_scrgb( m_pWPColorManager ); -+ } -+ } - } - - m_pLibDecor = libdecor_new( m_pDisplay, &s_LibDecorInterface ); -@@ -2476,19 +2493,6 @@ namespace gamescope - { - m_pWPColorManager = (wp_color_manager_v1 *)wl_registry_bind( pRegistry, uName, &wp_color_manager_v1_interface, 1u ); - wp_color_manager_v1_add_listener( m_pWPColorManager, &s_WPColorManagerListener, this ); -- -- // HDR10. -- { -- wp_image_description_creator_params_v1 *pParams = wp_color_manager_v1_create_parametric_creator( m_pWPColorManager ); -- wp_image_description_creator_params_v1_set_primaries_named( pParams, WP_COLOR_MANAGER_V1_PRIMARIES_BT2020 ); -- wp_image_description_creator_params_v1_set_tf_named( pParams, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ ); -- m_pWPImageDescriptions[ GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ ] = wp_image_description_creator_params_v1_create( pParams ); -- } -- -- // scRGB -- { -- m_pWPImageDescriptions[ GAMESCOPE_APP_TEXTURE_COLORSPACE_SCRGB ] = wp_color_manager_v1_create_windows_scrgb( m_pWPColorManager ); -- } - } - else if ( !strcmp( pInterface, zwp_pointer_constraints_v1_interface.name ) ) - { --- -2.51.0 diff --git a/anda/games/terra-gamescope/terra-gamescope.spec b/anda/games/terra-gamescope/terra-gamescope.spec index 3f1e43d863..cd793a43bb 100755 --- a/anda/games/terra-gamescope/terra-gamescope.spec +++ b/anda/games/terra-gamescope/terra-gamescope.spec @@ -2,18 +2,17 @@ %global _default_patch_fuzz 2 %global build_timestamp %(date +"%Y%m%d") -#global gamescope_tag 3.15.11 -%global gamescope_commit 2f30679c80791844c29402d232462874fe23dd46 +%global gamescope_commit 0fd7f48010fd0cf9cb577d7e282facb8e611a288 %define short_commit %(echo %{gamescope_commit} | cut -c1-8) Name: terra-gamescope #Version: 100.%{gamescope_tag} -Version: 134.%{short_commit} +Version: 135.%{short_commit} Release: 1%?dist Summary: Micro-compositor for video games on Wayland License: BSD -URL: https://github.com/ValveSoftware/gamescope +URL: https://github.com/OpenGamingCollective/gamescope Provides: gamescope = %{version}-%{release} Conflicts: gamescope @@ -21,68 +20,65 @@ Conflicts: gamescope # Create stb.pc to satisfy dependency('stb') Source0: stb.pc -Patch0: 0001-cstdint.patch +Patch0: Use-system-stb-glm.patch -# https://hhd.dev/ -# https://github.com/ChimeraOS/gamescope -Patch1: handheld.patch +Patch1: 0001-cstdint.patch -#Patch2: https://github.com/ValveSoftware/gamescope/pull/1867.patch +# Fix build with libinput >= 1.27 / GCC 16 (-Werror=switch) +Patch2: 0002-wlroots-libinput-switch-keypad-slide.patch -BuildRequires: meson >= 0.54.0 -BuildRequires: ninja-build BuildRequires: cmake BuildRequires: gcc BuildRequires: gcc-c++ +BuildRequires: git-core BuildRequires: glm-devel BuildRequires: google-benchmark-devel -BuildRequires: libXmu-devel BuildRequires: libXcursor-devel -BuildRequires: libeis-devel -BuildRequires: pixman-devel +BuildRequires: libXmu-devel +BuildRequires: meson >= 0.54.0 +BuildRequires: ninja-build +BuildRequires: pkgconfig(hwdata) +BuildRequires: pkgconfig(libavif) +BuildRequires: pkgconfig(libcap) +BuildRequires: pkgconfig(libdecor-0) BuildRequires: pkgconfig(libdisplay-info) -BuildRequires: pkgconfig(pixman-1) +BuildRequires: pkgconfig(libdrm) +BuildRequires: pkgconfig(libeis-1.0) +BuildRequires: (pkgconfig(libliftoff) >= %{libliftoff_minver} with pkgconfig(libliftoff) < 0.6) +BuildRequires: pkgconfig(libpipewire-0.3) +BuildRequires: pkgconfig(libudev) +BuildRequires: pkgconfig(luajit) +#BuildRequires: pkgconfig(openvr) >= 2.7 +BuildRequires: pkgconfig(sdl2) +BuildRequires: pkgconfig(vulkan) +BuildRequires: pkgconfig(wayland-protocols) >= 1.17 +BuildRequires: pkgconfig(wayland-scanner) +BuildRequires: pkgconfig(wayland-server) +BuildRequires: pkgconfig(wlroots-0.18) BuildRequires: pkgconfig(x11) -BuildRequires: pkgconfig(xdamage) BuildRequires: pkgconfig(xcomposite) -BuildRequires: pkgconfig(xrender) +BuildRequires: pkgconfig(xdamage) BuildRequires: pkgconfig(xext) BuildRequires: pkgconfig(xfixes) -BuildRequires: pkgconfig(xxf86vm) -BuildRequires: pkgconfig(xtst) -BuildRequires: pkgconfig(xres) -BuildRequires: pkgconfig(libdrm) -BuildRequires: pkgconfig(vulkan) -BuildRequires: pkgconfig(wayland-scanner) -BuildRequires: pkgconfig(wayland-server) >= 1.23.0 -BuildRequires: pkgconfig(wayland-protocols) >= 1.17 BuildRequires: pkgconfig(xkbcommon) -BuildRequires: pkgconfig(sdl2) -BuildRequires: pkgconfig(libpipewire-0.3) -BuildRequires: pkgconfig(libavif) -BuildRequires: pkgconfig(wlroots) -BuildRequires: pkgconfig(libliftoff) -BuildRequires: pkgconfig(libcap) -BuildRequires: pkgconfig(hwdata) -BuildRequires: pkgconfig(lcms2) -BuildRequires: pkgconfig(luajit) +BuildRequires: pkgconfig(xrender) +BuildRequires: pkgconfig(xres) +BuildRequires: pkgconfig(xtst) +BuildRequires: pkgconfig(xxf86vm) BuildRequires: spirv-headers-devel # Enforce the the minimum EVR to contain fixes for all of: # CVE-2021-28021 CVE-2021-42715 CVE-2021-42716 CVE-2022-28041 CVE-2023-43898 # CVE-2023-45661 CVE-2023-45662 CVE-2023-45663 CVE-2023-45664 CVE-2023-45666 -# CVE-2023-45667 -BuildRequires: stb_image-devel >= 2.28^20231011gitbeebb24-12 +# CVE-2023-45667, upstream issues #1860, #1861 +BuildRequires: stb_image-devel >= 2.30^20251025gitf1c79c0-2 # Header-only library: -static is for tracking per guidelines BuildRequires: stb_image-static BuildRequires: stb_image_resize-devel BuildRequires: stb_image_resize-static BuildRequires: stb_image_write-devel BuildRequires: stb_image_write-static +#BuildRequires: vkroots-devel BuildRequires: /usr/bin/glslangValidator -BuildRequires: libdecor-devel -BuildRequires: libXdamage-devel -BuildRequires: xorg-x11-server-Xwayland-devel -BuildRequires: git # libliftoff hasn't bumped soname, but API/ABI has changed for 0.2.0 release Requires: libliftoff%{?_isa} >= %{libliftoff_minver} @@ -94,6 +90,17 @@ Requires: terra-gamescope-libs(x86-32) = %{version}-%{release} Recommends: mesa-dri-drivers Recommends: mesa-vulkan-drivers +# submodule deps +BuildRequires: pkgconfig(lcms2) +BuildRequires: pkgconfig(libinput) >= 1.21.0 +BuildRequires: pkgconfig(libseat) +BuildRequires: pkgconfig(x11-xcb) +BuildRequires: pkgconfig(xcb) +BuildRequires: pkgconfig(xcb-errors) +BuildRequires: pkgconfig(xcb-icccm) +BuildRequires: pkgconfig(xcb-renderutil) +BuildRequires: pkgconfig(xwayland) + %description %{name} is the micro-compositor optimized for running video games on Wayland. @@ -140,5 +147,8 @@ export PKG_CONFIG_PATH=pkgconfig %{_datadir}/vulkan/implicit_layer.d/VkLayer_FROG_gamescope_wsi.*.json %changelog +* Fri Mar 13 2026 Kyle Gospodnetich +- Switch to OGC sources + * Thu Jan 2 2025 Owen-sz - Package gamescope, port from Bazzite