mirror of
https://github.com/terrapkg/packages.git
synced 2026-06-05 11:22:19 +00:00
23852fb5d9
(cherry picked from commit d5350cea38)
Co-authored-by: Pornpipat Popum <cappy@cappuchino.xyz>
2051 lines
80 KiB
Diff
Executable File
2051 lines
80 KiB
Diff
Executable File
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Antheas Kapenekakis <git@antheas.dev>
|
|
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 <host>"
|
|
+ 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 <ruinairas1992@gmail.com>
|
|
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 <me@kylegospodneti.ch>
|
|
Co-authored-by: Antheas Kapenekakis <git@antheas.dev>
|
|
---
|
|
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<uint32_t> g_customRefreshRates;
|
|
+// eg: 60,60,90,110-120
|
|
+static std::vector<uint32_t> parse_custom_refresh_rates( const char *str )
|
|
+{
|
|
+ std::vector<uint32_t> 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 <getopt.h>
|
|
|
|
#include <atomic>
|
|
+#include <vector>
|
|
|
|
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<uint32_t> 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 <git@antheas.dev>
|
|
---
|
|
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 <honjow311@gmail.com>
|
|
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 <git@antheas.dev>
|
|
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<sol::table> otDynamicRefreshRates = tTable["dynamic_refresh_rates"];
|
|
sol::optional<sol::function> ofnDynamicModegen = tTable["dynamic_modegen"];
|
|
|
|
- if ( otDynamicRefreshRates && ofnDynamicModegen )
|
|
+ if ( otDynamicRefreshRates && !ofnDynamicModegen )
|
|
+ m_Mutable.ValidDynamicRefreshRates = TableToVector<uint32_t>( *otDynamicRefreshRates );
|
|
+ else if ( otDynamicRefreshRates && ofnDynamicModegen )
|
|
{
|
|
m_Mutable.ValidDynamicRefreshRates = TableToVector<uint32_t>( *otDynamicRefreshRates );
|
|
|
|
--
|
|
2.51.0
|
|
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Antheas Kapenekakis <git@antheas.dev>
|
|
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<uint64_t> vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc<CVulkanTexture> pPipewireTexture, bool partial, gamescope::Rc<CVulkanTexture> pOutputOverride, bool increment, std::unique_ptr<CVulkanCmdBuffer> pInCommandBuffer )
|
|
+std::optional<uint64_t> vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc<CVulkanTexture> pPipewireTexture, bool partial, gamescope::Rc<CVulkanTexture> pOutputOverride, bool increment, std::unique_ptr<CVulkanCmdBuffer> pInCommandBuffer, bool applyRotation )
|
|
{
|
|
EOTF outputTF = frameInfo->outputEncodingEOTF;
|
|
if (!frameInfo->applyOutputColorMgmt)
|
|
@@ -3978,7 +4011,15 @@ std::optional<uint64_t> 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<RcasPushData_t>(frameInfo, g_upscaleFilterSharpness / 10.0f);
|
|
|
|
cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup));
|
|
@@ -4021,7 +4062,15 @@ std::optional<uint64_t> 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<BlitPushData_t>(&nisFrameInfo);
|
|
|
|
int pixelsPerGroup = 8;
|
|
@@ -4059,7 +4108,15 @@ std::optional<uint64_t> 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<uint64_t> 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<BlitPushData_t>(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<BlitPushData_t>(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<BlitPushData_t>(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<BlitPushData_t>(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<CVulkanTexture> vulkan_create_texture_from_dmabuf( struct wl
|
|
gamescope::OwningRc<CVulkanTexture> 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<CVulkanTexture> vulkan_create_texture_from_wlr_buffer( struct wlr_buffer *buf, gamescope::OwningRc<gamescope::IBackendFb> pBackendFb );
|
|
|
|
-std::optional<uint64_t> vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc<CVulkanTexture> pScreenshotTexture, bool partial, gamescope::Rc<CVulkanTexture> pOutputOverride = nullptr, bool increment = true, std::unique_ptr<CVulkanCmdBuffer> pInCommandBuffer = nullptr );
|
|
+std::optional<uint64_t> vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc<CVulkanTexture> pScreenshotTexture, bool partial, gamescope::Rc<CVulkanTexture> pOutputOverride = nullptr, bool increment = true, std::unique_ptr<CVulkanCmdBuffer> pInCommandBuffer = nullptr, bool applyRotation = false );
|
|
void vulkan_wait( uint64_t ulSeqNo, bool bReset );
|
|
gamescope::Rc<CVulkanTexture> vulkan_get_last_output_image( bool partial, bool defer );
|
|
gamescope::Rc<CVulkanTexture> 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<CVulkanTexture> nisScalerImage;
|
|
gamescope::OwningRc<CVulkanTexture> nisUsmImage;
|
|
+
|
|
+ // Rotated
|
|
+ gamescope::OwningRc<CVulkanTexture> 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 <you@example.com>
|
|
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<bool>("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<VkPhysicalDevicePresentWaitFeaturesKHR>(pFeatures);
|
|
+ }
|
|
pDispatch->GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
|
|
}
|
|
|
|
--
|
|
2.51.0
|
|
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Antheas Kapenekakis <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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 <typename T>
|
|
using CAutoDeletePtr = std::unique_ptr<T, void(*)(T*)>;
|
|
|
|
@@ -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<uint64_t>( 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 <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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<bool> cv_paint_cursor_plane{ "paint_cursor_plane", true };
|
|
gamescope::ConVar<bool> 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 <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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 <git@antheas.dev>
|
|
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 @@
|
|
<arg name="vk_composite_alpha" type="uint" summary="VkCompositeAlphaFlagBitsKHR of swapchain"/>
|
|
<arg name="vk_pre_transform" type="uint" summary="VkSurfaceTransformFlagBitsKHR of swapchain"/>
|
|
<arg name="vk_clipped" type="uint" summary="clipped (VkBool32) of swapchain"/>
|
|
- <arg name="vk_engine_name" type="string" summary="Engine name"/>
|
|
</request>
|
|
|
|
<request name="set_present_mode">
|
|
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<std::string> vk_engine_name;
|
|
|
|
std::shared_ptr<gamescope::BackendBlob> 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<std::string> focusWindow_engine = nullptr;
|
|
|
|
focus_t g_steamcompmgr_xdg_focus;
|
|
std::vector<std::shared_ptr<steamcompmgr_win_t>> 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<std::string> 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<std::string> engineName;
|
|
-
|
|
std::vector< gamescope::Rc<commit_t> > commit_queue;
|
|
std::shared_ptr<std::vector< uint32_t >> 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<std::string>(vk_engine_name),
|
|
.hdr_metadata_blob = nullptr,
|
|
});
|
|
}
|
|
--
|
|
2.51.0
|
|
|
|
|
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Antheas Kapenekakis <git@antheas.dev>
|
|
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<const uint32_t> 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 <colin.kinloch@collabora.com>
|
|
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
|