diff --git a/spec_files/gamescope/add_720p_var.patch b/spec_files/gamescope/39/add_720p_var.patch similarity index 100% rename from spec_files/gamescope/add_720p_var.patch rename to spec_files/gamescope/39/add_720p_var.patch diff --git a/spec_files/gamescope/chimeraos.patch b/spec_files/gamescope/39/chimeraos.patch similarity index 100% rename from spec_files/gamescope/chimeraos.patch rename to spec_files/gamescope/39/chimeraos.patch diff --git a/spec_files/gamescope/crashfix.patch b/spec_files/gamescope/39/crashfix.patch similarity index 100% rename from spec_files/gamescope/crashfix.patch rename to spec_files/gamescope/39/crashfix.patch diff --git a/spec_files/gamescope/gamescope.spec b/spec_files/gamescope/39/gamescope.spec similarity index 100% rename from spec_files/gamescope/gamescope.spec rename to spec_files/gamescope/39/gamescope.spec diff --git a/spec_files/gamescope/legion_go.patch b/spec_files/gamescope/39/legion_go.patch similarity index 100% rename from spec_files/gamescope/legion_go.patch rename to spec_files/gamescope/39/legion_go.patch diff --git a/spec_files/gamescope/stb.pc b/spec_files/gamescope/39/stb.pc similarity index 100% rename from spec_files/gamescope/stb.pc rename to spec_files/gamescope/39/stb.pc diff --git a/spec_files/gamescope/touch_gestures_env.patch b/spec_files/gamescope/39/touch_gestures_env.patch similarity index 100% rename from spec_files/gamescope/touch_gestures_env.patch rename to spec_files/gamescope/39/touch_gestures_env.patch diff --git a/spec_files/gamescope/40/1149.patch b/spec_files/gamescope/40/1149.patch new file mode 100644 index 00000000..1fc9f060 --- /dev/null +++ b/spec_files/gamescope/40/1149.patch @@ -0,0 +1,544 @@ +From 85432af61b779a02b636fdc29d98aba5e89fcff7 Mon Sep 17 00:00:00 2001 +From: Andrew O'Neil +Date: Sat, 24 Feb 2024 11:40:08 +1100 +Subject: [PATCH] Update AMD color management for Linux 6.8 + +--- + src/drm.cpp | 258 ++++++++++++++++++++++++++-------------------- + src/drm_include.h | 76 +++++++------- + 2 files changed, 188 insertions(+), 146 deletions(-) + +diff --git a/src/drm.cpp b/src/drm.cpp +index 9420ccbe4..29b8d06f5 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -148,15 +148,15 @@ namespace gamescope + std::optional rotation; + std::optional COLOR_ENCODING; + std::optional COLOR_RANGE; +- std::optional VALVE1_PLANE_DEGAMMA_TF; +- std::optional VALVE1_PLANE_DEGAMMA_LUT; +- std::optional VALVE1_PLANE_CTM; +- std::optional VALVE1_PLANE_HDR_MULT; +- std::optional VALVE1_PLANE_SHAPER_LUT; +- std::optional VALVE1_PLANE_SHAPER_TF; +- std::optional VALVE1_PLANE_LUT3D; +- std::optional VALVE1_PLANE_BLEND_TF; +- std::optional VALVE1_PLANE_BLEND_LUT; ++ std::optional AMD_PLANE_DEGAMMA_TF; ++ std::optional AMD_PLANE_DEGAMMA_LUT; ++ std::optional AMD_PLANE_CTM; ++ std::optional AMD_PLANE_HDR_MULT; ++ std::optional AMD_PLANE_SHAPER_LUT; ++ std::optional AMD_PLANE_SHAPER_TF; ++ std::optional AMD_PLANE_LUT3D; ++ std::optional AMD_PLANE_BLEND_TF; ++ std::optional AMD_PLANE_BLEND_LUT; + std::optional DUMMY_END; + }; + PlaneProperties &GetProperties() { return m_Props; } +@@ -187,7 +187,7 @@ namespace gamescope + std::optional CTM; + std::optional VRR_ENABLED; + std::optional OUT_FENCE_PTR; +- std::optional VALVE1_CRTC_REGAMMA_TF; ++ std::optional AMD_CRTC_REGAMMA_TF; + std::optional DUMMY_END; + }; + CRTCProperties &GetProperties() { return m_Props; } +@@ -401,7 +401,7 @@ struct drm_t { + uint32_t color_mgmt_serial; + std::shared_ptr lut3d_id[ EOTF_Count ]; + std::shared_ptr shaperlut_id[ EOTF_Count ]; +- drm_valve1_transfer_function output_tf = DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT; ++ amdgpu_transfer_function output_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + } current, pending; + + /* FBs in the atomic request, but not yet submitted to KMS */ +@@ -1287,8 +1287,8 @@ void finish_drm(struct drm_t *drm) + if ( pCRTC->GetProperties().OUT_FENCE_PTR ) + pCRTC->GetProperties().OUT_FENCE_PTR->SetPendingValue( req, 0, true ); + +- if ( pCRTC->GetProperties().VALVE1_CRTC_REGAMMA_TF ) +- pCRTC->GetProperties().VALVE1_CRTC_REGAMMA_TF->SetPendingValue( req, 0, true ); ++ if ( pCRTC->GetProperties().AMD_CRTC_REGAMMA_TF ) ++ pCRTC->GetProperties().AMD_CRTC_REGAMMA_TF->SetPendingValue( req, 0, true ); + } + + for ( std::unique_ptr< gamescope::CDRMPlane > &pPlane : drm->planes ) +@@ -1313,32 +1313,32 @@ void finish_drm(struct drm_t *drm) + //if ( pPlane->GetProperties().zpos ) + // pPlane->GetProperties().zpos->SetPendingValue( req, , true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_DEGAMMA_TF ) +- pPlane->GetProperties().VALVE1_PLANE_DEGAMMA_TF->SetPendingValue( req, DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_DEGAMMA_TF ) ++ pPlane->GetProperties().AMD_PLANE_DEGAMMA_TF->SetPendingValue( req, AMDGPU_TRANSFER_FUNCTION_DEFAULT, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_DEGAMMA_LUT ) +- pPlane->GetProperties().VALVE1_PLANE_DEGAMMA_LUT->SetPendingValue( req, 0, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_DEGAMMA_LUT ) ++ pPlane->GetProperties().AMD_PLANE_DEGAMMA_LUT->SetPendingValue( req, 0, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_CTM ) +- pPlane->GetProperties().VALVE1_PLANE_CTM->SetPendingValue( req, 0, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_CTM ) ++ pPlane->GetProperties().AMD_PLANE_CTM->SetPendingValue( req, 0, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_HDR_MULT ) +- pPlane->GetProperties().VALVE1_PLANE_HDR_MULT->SetPendingValue( req, 0x100000000ULL, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_HDR_MULT ) ++ pPlane->GetProperties().AMD_PLANE_HDR_MULT->SetPendingValue( req, 0x100000000ULL, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_SHAPER_TF ) +- pPlane->GetProperties().VALVE1_PLANE_SHAPER_TF->SetPendingValue( req, DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_SHAPER_TF ) ++ pPlane->GetProperties().AMD_PLANE_SHAPER_TF->SetPendingValue( req, AMDGPU_TRANSFER_FUNCTION_DEFAULT, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_SHAPER_LUT ) +- pPlane->GetProperties().VALVE1_PLANE_SHAPER_LUT->SetPendingValue( req, 0, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_SHAPER_LUT ) ++ pPlane->GetProperties().AMD_PLANE_SHAPER_LUT->SetPendingValue( req, 0, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_LUT3D ) +- pPlane->GetProperties().VALVE1_PLANE_LUT3D->SetPendingValue( req, 0, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_LUT3D ) ++ pPlane->GetProperties().AMD_PLANE_LUT3D->SetPendingValue( req, 0, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_BLEND_TF ) +- pPlane->GetProperties().VALVE1_PLANE_BLEND_TF->SetPendingValue( req, DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_BLEND_TF ) ++ pPlane->GetProperties().AMD_PLANE_BLEND_TF->SetPendingValue( req, AMDGPU_TRANSFER_FUNCTION_DEFAULT, true ); + +- if ( pPlane->GetProperties().VALVE1_PLANE_BLEND_LUT ) +- pPlane->GetProperties().VALVE1_PLANE_BLEND_LUT->SetPendingValue( req, 0, true ); ++ if ( pPlane->GetProperties().AMD_PLANE_BLEND_LUT ) ++ pPlane->GetProperties().AMD_PLANE_BLEND_LUT->SetPendingValue( req, 0, true ); + } + + // We can't do a non-blocking commit here or else risk EBUSY in case the +@@ -1637,37 +1637,73 @@ struct LiftoffStateCacheEntryKasher + + std::unordered_set g_LiftoffStateCache; + +-static inline drm_valve1_transfer_function colorspace_to_plane_degamma_tf(GamescopeAppTextureColorspace colorspace) ++static inline amdgpu_transfer_function colorspace_to_plane_degamma_tf(GamescopeAppTextureColorspace colorspace) + { + switch ( colorspace ) + { + default: // Linear in this sense is SRGB. Linear = sRGB image view doing automatic sRGB -> Linear which doesn't happen on DRM side. + case GAMESCOPE_APP_TEXTURE_COLORSPACE_SRGB: +- return DRM_VALVE1_TRANSFER_FUNCTION_SRGB; ++ return AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF; + case GAMESCOPE_APP_TEXTURE_COLORSPACE_PASSTHRU: + case GAMESCOPE_APP_TEXTURE_COLORSPACE_SCRGB: + // Use LINEAR TF for scRGB float format as 80 nit = 1.0 in scRGB, which matches + // what PQ TF decodes to/encodes from. + // AMD internal format is FP16, and generally expected for 1.0 -> 80 nit. + // which just so happens to match scRGB. +- return DRM_VALVE1_TRANSFER_FUNCTION_LINEAR; ++ return AMDGPU_TRANSFER_FUNCTION_IDENTITY; + case GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ: +- return DRM_VALVE1_TRANSFER_FUNCTION_PQ; ++ return AMDGPU_TRANSFER_FUNCTION_PQ_EOTF; + } + } + +-static inline drm_valve1_transfer_function colorspace_to_plane_shaper_tf(GamescopeAppTextureColorspace colorspace) ++static inline amdgpu_transfer_function colorspace_to_plane_shaper_tf(GamescopeAppTextureColorspace colorspace) + { + switch ( colorspace ) + { + default: + case GAMESCOPE_APP_TEXTURE_COLORSPACE_SRGB: +- return DRM_VALVE1_TRANSFER_FUNCTION_SRGB; ++ return AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF; + case GAMESCOPE_APP_TEXTURE_COLORSPACE_SCRGB: // scRGB Linear -> PQ for shaper + 3D LUT + case GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ: +- return DRM_VALVE1_TRANSFER_FUNCTION_PQ; ++ return AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF; + case GAMESCOPE_APP_TEXTURE_COLORSPACE_PASSTHRU: +- return DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT; ++ return AMDGPU_TRANSFER_FUNCTION_DEFAULT; ++ } ++} ++ ++static inline amdgpu_transfer_function inverse_tf(amdgpu_transfer_function tf) ++{ ++ switch ( tf ) ++ { ++ default: ++ case AMDGPU_TRANSFER_FUNCTION_DEFAULT: ++ return AMDGPU_TRANSFER_FUNCTION_DEFAULT; ++ case AMDGPU_TRANSFER_FUNCTION_IDENTITY: ++ return AMDGPU_TRANSFER_FUNCTION_IDENTITY; ++ case AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_BT709_OETF: ++ return AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF; ++ case AMDGPU_TRANSFER_FUNCTION_PQ_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF: ++ return AMDGPU_TRANSFER_FUNCTION_BT709_OETF; ++ case AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_PQ_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF; ++ case AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF: ++ return AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF; + } + } + +@@ -1862,33 +1898,33 @@ namespace gamescope + auto rawProperties = GetRawProperties(); + if ( rawProperties ) + { +- m_Props.type = CDRMAtomicProperty::Instantiate( "type", this, *rawProperties ); +- m_Props.IN_FORMATS = CDRMAtomicProperty::Instantiate( "IN_FORMATS", this, *rawProperties ); +- +- m_Props.FB_ID = CDRMAtomicProperty::Instantiate( "FB_ID", this, *rawProperties ); +- m_Props.CRTC_ID = CDRMAtomicProperty::Instantiate( "CRTC_ID", this, *rawProperties ); +- m_Props.SRC_X = CDRMAtomicProperty::Instantiate( "SRC_X", this, *rawProperties ); +- m_Props.SRC_Y = CDRMAtomicProperty::Instantiate( "SRC_Y", this, *rawProperties ); +- m_Props.SRC_W = CDRMAtomicProperty::Instantiate( "SRC_W", this, *rawProperties ); +- m_Props.SRC_H = CDRMAtomicProperty::Instantiate( "SRC_H", this, *rawProperties ); +- m_Props.CRTC_X = CDRMAtomicProperty::Instantiate( "CRTC_X", this, *rawProperties ); +- m_Props.CRTC_Y = CDRMAtomicProperty::Instantiate( "CRTC_Y", this, *rawProperties ); +- m_Props.CRTC_W = CDRMAtomicProperty::Instantiate( "CRTC_W", this, *rawProperties ); +- m_Props.CRTC_H = CDRMAtomicProperty::Instantiate( "CRTC_H", this, *rawProperties ); +- m_Props.zpos = CDRMAtomicProperty::Instantiate( "zpos", this, *rawProperties ); +- m_Props.alpha = CDRMAtomicProperty::Instantiate( "alpha", this, *rawProperties ); +- m_Props.rotation = CDRMAtomicProperty::Instantiate( "rotation", this, *rawProperties ); +- m_Props.COLOR_ENCODING = CDRMAtomicProperty::Instantiate( "COLOR_ENCODING", this, *rawProperties ); +- m_Props.COLOR_RANGE = CDRMAtomicProperty::Instantiate( "COLOR_RANGE", this, *rawProperties ); +- m_Props.VALVE1_PLANE_DEGAMMA_TF = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_DEGAMMA_TF", this, *rawProperties ); +- m_Props.VALVE1_PLANE_DEGAMMA_LUT = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_DEGAMMA_LUT", this, *rawProperties ); +- m_Props.VALVE1_PLANE_CTM = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_CTM", this, *rawProperties ); +- m_Props.VALVE1_PLANE_HDR_MULT = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_HDR_MULT", this, *rawProperties ); +- m_Props.VALVE1_PLANE_SHAPER_LUT = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_SHAPER_LUT", this, *rawProperties ); +- m_Props.VALVE1_PLANE_SHAPER_TF = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_SHAPER_TF", this, *rawProperties ); +- m_Props.VALVE1_PLANE_LUT3D = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_LUT3D", this, *rawProperties ); +- m_Props.VALVE1_PLANE_BLEND_TF = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_BLEND_TF", this, *rawProperties ); +- m_Props.VALVE1_PLANE_BLEND_LUT = CDRMAtomicProperty::Instantiate( "VALVE1_PLANE_BLEND_LUT", this, *rawProperties ); ++ m_Props.type = CDRMAtomicProperty::Instantiate( "type", this, *rawProperties ); ++ m_Props.IN_FORMATS = CDRMAtomicProperty::Instantiate( "IN_FORMATS", this, *rawProperties ); ++ ++ m_Props.FB_ID = CDRMAtomicProperty::Instantiate( "FB_ID", this, *rawProperties ); ++ m_Props.CRTC_ID = CDRMAtomicProperty::Instantiate( "CRTC_ID", this, *rawProperties ); ++ m_Props.SRC_X = CDRMAtomicProperty::Instantiate( "SRC_X", this, *rawProperties ); ++ m_Props.SRC_Y = CDRMAtomicProperty::Instantiate( "SRC_Y", this, *rawProperties ); ++ m_Props.SRC_W = CDRMAtomicProperty::Instantiate( "SRC_W", this, *rawProperties ); ++ m_Props.SRC_H = CDRMAtomicProperty::Instantiate( "SRC_H", this, *rawProperties ); ++ m_Props.CRTC_X = CDRMAtomicProperty::Instantiate( "CRTC_X", this, *rawProperties ); ++ m_Props.CRTC_Y = CDRMAtomicProperty::Instantiate( "CRTC_Y", this, *rawProperties ); ++ m_Props.CRTC_W = CDRMAtomicProperty::Instantiate( "CRTC_W", this, *rawProperties ); ++ m_Props.CRTC_H = CDRMAtomicProperty::Instantiate( "CRTC_H", this, *rawProperties ); ++ m_Props.zpos = CDRMAtomicProperty::Instantiate( "zpos", this, *rawProperties ); ++ m_Props.alpha = CDRMAtomicProperty::Instantiate( "alpha", this, *rawProperties ); ++ m_Props.rotation = CDRMAtomicProperty::Instantiate( "rotation", this, *rawProperties ); ++ m_Props.COLOR_ENCODING = CDRMAtomicProperty::Instantiate( "COLOR_ENCODING", this, *rawProperties ); ++ m_Props.COLOR_RANGE = CDRMAtomicProperty::Instantiate( "COLOR_RANGE", this, *rawProperties ); ++ m_Props.AMD_PLANE_DEGAMMA_TF = CDRMAtomicProperty::Instantiate( "AMD_PLANE_DEGAMMA_TF", this, *rawProperties ); ++ m_Props.AMD_PLANE_DEGAMMA_LUT = CDRMAtomicProperty::Instantiate( "AMD_PLANE_DEGAMMA_LUT", this, *rawProperties ); ++ m_Props.AMD_PLANE_CTM = CDRMAtomicProperty::Instantiate( "AMD_PLANE_CTM", this, *rawProperties ); ++ m_Props.AMD_PLANE_HDR_MULT = CDRMAtomicProperty::Instantiate( "AMD_PLANE_HDR_MULT", this, *rawProperties ); ++ m_Props.AMD_PLANE_SHAPER_LUT = CDRMAtomicProperty::Instantiate( "AMD_PLANE_SHAPER_LUT", this, *rawProperties ); ++ m_Props.AMD_PLANE_SHAPER_TF = CDRMAtomicProperty::Instantiate( "AMD_PLANE_SHAPER_TF", this, *rawProperties ); ++ m_Props.AMD_PLANE_LUT3D = CDRMAtomicProperty::Instantiate( "AMD_PLANE_LUT3D", this, *rawProperties ); ++ m_Props.AMD_PLANE_BLEND_TF = CDRMAtomicProperty::Instantiate( "AMD_PLANE_BLEND_TF", this, *rawProperties ); ++ m_Props.AMD_PLANE_BLEND_LUT = CDRMAtomicProperty::Instantiate( "AMD_PLANE_BLEND_LUT", this, *rawProperties ); + } + } + +@@ -1908,14 +1944,14 @@ namespace gamescope + auto rawProperties = GetRawProperties(); + if ( rawProperties ) + { +- m_Props.ACTIVE = CDRMAtomicProperty::Instantiate( "ACTIVE", this, *rawProperties ); +- m_Props.MODE_ID = CDRMAtomicProperty::Instantiate( "MODE_ID", this, *rawProperties ); +- m_Props.GAMMA_LUT = CDRMAtomicProperty::Instantiate( "GAMMA_LUT", this, *rawProperties ); +- m_Props.DEGAMMA_LUT = CDRMAtomicProperty::Instantiate( "DEGAMMA_LUT", this, *rawProperties ); +- m_Props.CTM = CDRMAtomicProperty::Instantiate( "CTM", this, *rawProperties ); +- m_Props.VRR_ENABLED = CDRMAtomicProperty::Instantiate( "VRR_ENABLED", this, *rawProperties ); +- m_Props.OUT_FENCE_PTR = CDRMAtomicProperty::Instantiate( "OUT_FENCE_PTR", this, *rawProperties ); +- m_Props.VALVE1_CRTC_REGAMMA_TF = CDRMAtomicProperty::Instantiate( "VALVE1_CRTC_REGAMMA_TF", this, *rawProperties ); ++ m_Props.ACTIVE = CDRMAtomicProperty::Instantiate( "ACTIVE", this, *rawProperties ); ++ m_Props.MODE_ID = CDRMAtomicProperty::Instantiate( "MODE_ID", this, *rawProperties ); ++ m_Props.GAMMA_LUT = CDRMAtomicProperty::Instantiate( "GAMMA_LUT", this, *rawProperties ); ++ m_Props.DEGAMMA_LUT = CDRMAtomicProperty::Instantiate( "DEGAMMA_LUT", this, *rawProperties ); ++ m_Props.CTM = CDRMAtomicProperty::Instantiate( "CTM", this, *rawProperties ); ++ m_Props.VRR_ENABLED = CDRMAtomicProperty::Instantiate( "VRR_ENABLED", this, *rawProperties ); ++ m_Props.OUT_FENCE_PTR = CDRMAtomicProperty::Instantiate( "OUT_FENCE_PTR", this, *rawProperties ); ++ m_Props.AMD_CRTC_REGAMMA_TF = CDRMAtomicProperty::Instantiate( "AMD_CRTC_REGAMMA_TF", this, *rawProperties ); + } + } + +@@ -2376,8 +2412,8 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo + + if ( drm_supports_color_mgmt( drm ) ) + { +- drm_valve1_transfer_function degamma_tf = colorspace_to_plane_degamma_tf( entry.layerState[i].colorspace ); +- drm_valve1_transfer_function shaper_tf = colorspace_to_plane_shaper_tf( entry.layerState[i].colorspace ); ++ amdgpu_transfer_function degamma_tf = colorspace_to_plane_degamma_tf( entry.layerState[i].colorspace ); ++ amdgpu_transfer_function shaper_tf = colorspace_to_plane_shaper_tf( entry.layerState[i].colorspace ); + + if ( entry.layerState[i].ycbcr ) + { +@@ -2389,27 +2425,27 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo + // + // Doing LINEAR/DEFAULT here introduces banding so... this is the best way. + // (sRGB DEGAMMA does NOT work on YUV planes!) +- degamma_tf = DRM_VALVE1_TRANSFER_FUNCTION_BT709; +- shaper_tf = DRM_VALVE1_TRANSFER_FUNCTION_BT709; ++ degamma_tf = AMDGPU_TRANSFER_FUNCTION_BT709_OETF; ++ shaper_tf = AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF; + } + + if (!g_bDisableDegamma) +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", degamma_tf ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_DEGAMMA_TF", degamma_tf ); + else +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", 0 ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_DEGAMMA_TF", 0 ); + + if ( !g_bDisableShaperAnd3DLUT ) + { +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", drm->pending.shaperlut_id[ ColorSpaceToEOTFIndex( entry.layerState[i].colorspace ) ]->GetBlobValue() ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", shaper_tf ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", drm->pending.lut3d_id[ ColorSpaceToEOTFIndex( entry.layerState[i].colorspace ) ]->GetBlobValue() ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_SHAPER_LUT", drm->pending.shaperlut_id[ ColorSpaceToEOTFIndex( entry.layerState[i].colorspace ) ]->GetBlobValue() ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_SHAPER_TF", shaper_tf ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_LUT3D", drm->pending.lut3d_id[ ColorSpaceToEOTFIndex( entry.layerState[i].colorspace ) ]->GetBlobValue() ); + // Josh: See shaders/colorimetry.h colorspace_blend_tf if you have questions as to why we start doing sRGB for BLEND_TF despite potentially working in Gamma 2.2 space prior. + } + else + { +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 ); ++ 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 ); + } + } + } +@@ -2417,25 +2453,25 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo + { + if ( drm_supports_color_mgmt( drm ) ) + { +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_CTM", 0 ); ++ 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_CTM", 0 ); + } + } + + if ( drm_supports_color_mgmt( drm ) ) + { + if (!g_bDisableBlendTF && !bSinglePlane) +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", drm->pending.output_tf ); ++ 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 ], "VALVE1_PLANE_BLEND_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_BLEND_TF", AMDGPU_TRANSFER_FUNCTION_DEFAULT ); + + if (frameInfo->layers[i].ctm != nullptr) +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_CTM", frameInfo->layers[i].ctm->GetBlobValue() ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_CTM", frameInfo->layers[i].ctm->GetBlobValue() ); + else +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_CTM", 0 ); ++ liftoff_layer_set_property( drm->lo_layers[ i ], "AMD_PLANE_CTM", 0 ); + } + } + else +@@ -2447,12 +2483,12 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo + + if ( drm_supports_color_mgmt( drm ) ) + { +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_DEGAMMA_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT ); +- liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_CTM", 0 ); ++ 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 ); + } + } + } +@@ -2533,7 +2569,7 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI + drm->needs_modeset = true; + } + +- uint32_t uColorimetry = DRM_MODE_COLORIMETRY_DEFAULT; ++ drm_colorspace uColorimetry = DRM_MODE_COLORIMETRY_DEFAULT; + + const bool bWantsHDR10 = g_bOutputHDREnabled && frameInfo->outputEncodingEOTF == EOTF_PQ; + gamescope::BackendBlob *pHDRMetadata = nullptr; +@@ -2571,17 +2607,17 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI + if ( !g_bDisableRegamma && !bSinglePlane ) + { + drm->pending.output_tf = g_bOutputHDREnabled +- ? DRM_VALVE1_TRANSFER_FUNCTION_PQ +- : DRM_VALVE1_TRANSFER_FUNCTION_SRGB; ++ ? AMDGPU_TRANSFER_FUNCTION_PQ_EOTF ++ : AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF; + } + else + { +- drm->pending.output_tf = DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT; ++ drm->pending.output_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + } + } + else + { +- drm->pending.output_tf = DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT; ++ drm->pending.output_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; + } + + uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK; +@@ -2644,8 +2680,8 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI + if ( pCRTC->GetProperties().OUT_FENCE_PTR ) + pCRTC->GetProperties().OUT_FENCE_PTR->SetPendingValue( drm->req, 0, bForceInRequest ); + +- if ( pCRTC->GetProperties().VALVE1_CRTC_REGAMMA_TF ) +- pCRTC->GetProperties().VALVE1_CRTC_REGAMMA_TF->SetPendingValue( drm->req, 0, bForceInRequest ); ++ if ( pCRTC->GetProperties().AMD_CRTC_REGAMMA_TF ) ++ pCRTC->GetProperties().AMD_CRTC_REGAMMA_TF->SetPendingValue( drm->req, 0, bForceInRequest ); + } + + if ( drm->pConnector ) +@@ -2679,8 +2715,8 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI + + if ( drm->pCRTC ) + { +- if ( drm->pCRTC->GetProperties().VALVE1_CRTC_REGAMMA_TF ) +- drm->pCRTC->GetProperties().VALVE1_CRTC_REGAMMA_TF->SetPendingValue( drm->req, drm->pending.output_tf, bForceInRequest ); ++ if ( drm->pCRTC->GetProperties().AMD_CRTC_REGAMMA_TF ) ++ drm->pCRTC->GetProperties().AMD_CRTC_REGAMMA_TF->SetPendingValue( drm->req, inverse_tf(drm->pending.output_tf), bForceInRequest ); + } + + drm->flags = flags; +@@ -2995,7 +3031,7 @@ bool drm_supports_color_mgmt(struct drm_t *drm) + if ( !drm->pPrimaryPlane ) + return false; + +- return drm->pPrimaryPlane->GetProperties().VALVE1_PLANE_CTM.has_value(); ++ return drm->pPrimaryPlane->GetProperties().AMD_PLANE_CTM.has_value(); + } + + std::span drm_get_valid_refresh_rates( struct drm_t *drm ) +diff --git a/src/drm_include.h b/src/drm_include.h +index 500c3040a..d0ed3ce9e 100644 +--- a/src/drm_include.h ++++ b/src/drm_include.h +@@ -28,19 +28,22 @@ enum drm_color_range { + DRM_COLOR_RANGE_MAX, + }; + +-enum drm_valve1_transfer_function { +- DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT, +- +- DRM_VALVE1_TRANSFER_FUNCTION_SRGB, +- DRM_VALVE1_TRANSFER_FUNCTION_BT709, +- DRM_VALVE1_TRANSFER_FUNCTION_PQ, +- DRM_VALVE1_TRANSFER_FUNCTION_LINEAR, +- DRM_VALVE1_TRANSFER_FUNCTION_UNITY, +- DRM_VALVE1_TRANSFER_FUNCTION_HLG, +- DRM_VALVE1_TRANSFER_FUNCTION_GAMMA22, +- DRM_VALVE1_TRANSFER_FUNCTION_GAMMA24, +- DRM_VALVE1_TRANSFER_FUNCTION_GAMMA26, +- DRM_VALVE1_TRANSFER_FUNCTION_MAX, ++enum amdgpu_transfer_function { ++ AMDGPU_TRANSFER_FUNCTION_DEFAULT, ++ AMDGPU_TRANSFER_FUNCTION_SRGB_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_BT709_INV_OETF, ++ AMDGPU_TRANSFER_FUNCTION_PQ_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_IDENTITY, ++ AMDGPU_TRANSFER_FUNCTION_GAMMA22_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_GAMMA24_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_GAMMA26_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_SRGB_INV_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_BT709_OETF, ++ AMDGPU_TRANSFER_FUNCTION_PQ_INV_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_GAMMA22_INV_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_GAMMA24_INV_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_GAMMA26_INV_EOTF, ++ AMDGPU_TRANSFER_FUNCTION_COUNT + }; + + enum drm_panel_orientation { +@@ -51,28 +54,31 @@ enum drm_panel_orientation { + DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, + }; + +-/* For Default case, driver will set the colorspace */ +-#define DRM_MODE_COLORIMETRY_DEFAULT 0 +-/* CEA 861 Normal Colorimetry options */ +-#define DRM_MODE_COLORIMETRY_NO_DATA 0 +-#define DRM_MODE_COLORIMETRY_SMPTE_170M_YCC 1 +-#define DRM_MODE_COLORIMETRY_BT709_YCC 2 +-/* CEA 861 Extended Colorimetry Options */ +-#define DRM_MODE_COLORIMETRY_XVYCC_601 3 +-#define DRM_MODE_COLORIMETRY_XVYCC_709 4 +-#define DRM_MODE_COLORIMETRY_SYCC_601 5 +-#define DRM_MODE_COLORIMETRY_OPYCC_601 6 +-#define DRM_MODE_COLORIMETRY_OPRGB 7 +-#define DRM_MODE_COLORIMETRY_BT2020_CYCC 8 +-#define DRM_MODE_COLORIMETRY_BT2020_RGB 9 +-#define DRM_MODE_COLORIMETRY_BT2020_YCC 10 +-/* Additional Colorimetry extension added as part of CTA 861.G */ +-#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 11 +-#define DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER 12 +-/* Additional Colorimetry Options added for DP 1.4a VSC Colorimetry Format */ +-#define DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED 13 +-#define DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT 14 +-#define DRM_MODE_COLORIMETRY_BT601_YCC 15 ++enum drm_colorspace { ++ /* For Default case, driver will set the colorspace */ ++ DRM_MODE_COLORIMETRY_DEFAULT = 0, ++ /* CEA 861 Normal Colorimetry options */ ++ DRM_MODE_COLORIMETRY_NO_DATA = 0, ++ DRM_MODE_COLORIMETRY_SMPTE_170M_YCC = 1, ++ DRM_MODE_COLORIMETRY_BT709_YCC = 2, ++ /* CEA 861 Extended Colorimetry Options */ ++ DRM_MODE_COLORIMETRY_XVYCC_601 = 3, ++ DRM_MODE_COLORIMETRY_XVYCC_709 = 4, ++ DRM_MODE_COLORIMETRY_SYCC_601 = 5, ++ DRM_MODE_COLORIMETRY_OPYCC_601 = 6, ++ DRM_MODE_COLORIMETRY_OPRGB = 7, ++ DRM_MODE_COLORIMETRY_BT2020_CYCC = 8, ++ DRM_MODE_COLORIMETRY_BT2020_RGB = 9, ++ DRM_MODE_COLORIMETRY_BT2020_YCC = 10, ++ /* Additional Colorimetry extension added as part of CTA 861.G */ ++ DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65 = 11, ++ DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER = 12, ++ /* Additional Colorimetry Options added for DP 1.4a VSC Colorimetry Format */ ++ DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED = 13, ++ DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT = 14, ++ DRM_MODE_COLORIMETRY_BT601_YCC = 15, ++ DRM_MODE_COLORIMETRY_COUNT ++}; + + /* Content type options */ + #define DRM_MODE_CONTENT_TYPE_NO_DATA 0 diff --git a/spec_files/gamescope/40/add_720p_var.patch b/spec_files/gamescope/40/add_720p_var.patch new file mode 100644 index 00000000..05ff1c72 --- /dev/null +++ b/spec_files/gamescope/40/add_720p_var.patch @@ -0,0 +1,35 @@ +From 19c6635d5e20dd429cb23b4a7c728afa306fae0a Mon Sep 17 00:00:00 2001 +From: Sterophonick +Date: Sat, 10 Feb 2024 22:00:36 -0700 +Subject: [PATCH] steamcompmgr: add env var to enable/disable 720p restriction + +--- + src/steamcompmgr.cpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 00c00e9..795898c 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -137,6 +137,9 @@ extern float g_flInternalDisplayBrightnessNits; + extern float g_flHDRItmSdrNits; + extern float g_flHDRItmTargetNits; + ++// define env_to_bool to point to the function in drm: remove in later patches pl0x ++extern bool env_to_bool(const char *env); ++ + uint64_t g_lastWinSeq = 0; + + static std::shared_ptr s_scRGB709To2020Matrix; +@@ -5657,7 +5660,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + int width = xwayland_mode_ctl[ 1 ]; + int height = xwayland_mode_ctl[ 2 ]; + +- if ( g_nOutputWidth != 1280 && width == 1280 ) ++ if ( g_nOutputWidth != 1280 && width == 1280 && !env_to_bool(getenv("GAMESCOPE_ENABLE_720P_RESTRICT")) ) + { + width = g_nOutputWidth; + height = g_nOutputHeight; +-- +2.43.0 + diff --git a/spec_files/gamescope/40/chimeraos.patch b/spec_files/gamescope/40/chimeraos.patch new file mode 100644 index 00000000..a2018692 --- /dev/null +++ b/spec_files/gamescope/40/chimeraos.patch @@ -0,0 +1,974 @@ +From 4cafbd696c342c1f45eea6242dcaadd26e8e4a3d Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Fri, 6 Oct 2023 17:22:41 -0500 +Subject: [PATCH 1/9] Add initial rotation atom controls + +--- + src/drm.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ + src/drm.hpp | 11 +++++++++++ + src/steamcompmgr.cpp | 32 ++++++++++++++++++++++++++++++++ + src/xwayland_ctx.hpp | 1 + + 4 files changed, 86 insertions(+) + +diff --git a/src/drm.cpp b/src/drm.cpp +index c2694f0..de5e3ca 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -45,6 +45,7 @@ struct drm_t g_DRM = {}; + uint32_t g_nDRMFormat = DRM_FORMAT_INVALID; + uint32_t g_nDRMFormatOverlay = DRM_FORMAT_INVALID; // for partial composition, we may have more limited formats than base planes + alpha. + bool g_bRotated = false; ++bool g_rotate_ctl_enable = false; + bool g_bUseLayers = true; + bool g_bDebugLayers = false; + const char *g_sOutputName = nullptr; +@@ -65,6 +66,7 @@ bool g_bSupportsAsyncFlips = false; + + enum drm_mode_generation g_drmModeGeneration = DRM_MODE_GENERATE_CVT; + enum g_panel_orientation g_drmModeOrientation = PANEL_ORIENTATION_AUTO; ++enum g_rotate_ctl g_drmRotateCTL; + std::atomic g_drmEffectiveOrientation[DRM_SCREEN_TYPE_COUNT]{ {DRM_MODE_ROTATE_0}, {DRM_MODE_ROTATE_0} }; + + bool g_bForceDisableColorMgmt = false; +@@ -2010,6 +2012,27 @@ static void update_drm_effective_orientation(struct drm_t *drm, struct connector + static void update_drm_effective_orientations(struct drm_t *drm, struct connector *conn, const drmModeModeInfo *mode) + { + drm_screen_type screenType = drm_get_connector_type(conn->connector); ++ ++ if (g_rotate_ctl_enable) ++ { ++ switch (g_drmRotateCTL) ++ { ++ default: ++ case NORMAL: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_0; ++ break; ++ case LEFT_UP: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_90; ++ break; ++ case UPSIDEDOWN: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_180; ++ break; ++ case RIGHT_UP: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_270; ++ break; ++ } ++ return; ++ } + if (screenType == DRM_SCREEN_TYPE_INTERNAL) + { + update_drm_effective_orientation(drm, conn, mode); +@@ -3083,6 +3106,25 @@ bool drm_set_refresh( struct drm_t *drm, int refresh ) + return drm_set_mode(drm, &mode); + } + ++void drm_set_orientation( struct drm_t *drm, bool isRotated) ++{ ++ int width = g_nOutputWidth; ++ int height = g_nOutputHeight; ++ g_bRotated = isRotated; ++ if ( g_bRotated ) { ++ int tmp = width; ++ width = height; ++ height = tmp; ++ } ++ ++ if (!drm->connector || !drm->connector->connector) ++ return; ++ ++ drmModeConnector *connector = drm->connector->connector; ++ const drmModeModeInfo *mode = find_mode(connector, width, height, 0); ++ update_drm_effective_orientations(drm, drm->connector, mode); ++} ++ + bool drm_set_resolution( struct drm_t *drm, int width, int height ) + { + if (!drm->connector || !drm->connector->connector) +diff --git a/src/drm.hpp b/src/drm.hpp +index 6810797..b2ab49f 100644 +--- a/src/drm.hpp ++++ b/src/drm.hpp +@@ -325,13 +325,24 @@ enum g_panel_orientation { + PANEL_ORIENTATION_AUTO, + }; + ++enum g_rotate_ctl{ ++ NORMAL, ++ LEFT_UP, ++ UPSIDEDOWN, ++ RIGHT_UP, ++}; ++ + extern enum drm_mode_generation g_drmModeGeneration; + extern enum g_panel_orientation g_drmModeOrientation; ++extern enum g_rotate_ctl g_drmRotateCTL; ++extern bool g_rotate_ctl_enable; + + extern std::atomic g_drmEffectiveOrientation[DRM_SCREEN_TYPE_COUNT]; // DRM_MODE_ROTATE_* + + extern bool g_bForceDisableColorMgmt; + ++void drm_set_orientation( struct drm_t *drm, bool isRotated ); ++ + bool init_drm(struct drm_t *drm, int width, int height, int refresh, bool wants_adaptive_sync); + void finish_drm(struct drm_t *drm); + int drm_commit(struct drm_t *drm, const struct FrameInfo_t *frameInfo ); +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index b02fa33..277a54c 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -5644,6 +5644,37 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + if ( g_upscaleFilter == GamescopeUpscaleFilter::FSR || g_upscaleFilter == GamescopeUpscaleFilter::NIS ) + hasRepaint = true; + } ++ if ( ev->atom == ctx->atoms.gamescopeRotateControl ) ++ { ++ std::vector< uint32_t > drm_rot_ctl; ++ bool rotate = get_prop( ctx, ctx->root, ctx->atoms.gamescopeRotateControl, drm_rot_ctl ); ++ bool rotated = false; ++ if ( rotate && drm_rot_ctl.size() == 1 ) ++ { ++ xwm_log.debugf("drm_rot_ctl %d", drm_rot_ctl[0]); ++ g_rotate_ctl_enable = true; ++ switch ( drm_rot_ctl[0] ) ++ { ++ case 0: ++ g_drmRotateCTL = NORMAL; ++ rotated = false; ++ break; ++ case 1: ++ g_drmRotateCTL = LEFT_UP; ++ rotated = true; ++ break; ++ case 2: ++ g_drmRotateCTL = UPSIDEDOWN; ++ rotated = false; ++ break; ++ case 3: ++ g_drmRotateCTL = RIGHT_UP; ++ rotated = true; ++ break; ++ } ++ drm_set_orientation(&g_DRM, rotated); ++ } ++ } + if ( ev->atom == ctx->atoms.gamescopeXWaylandModeControl ) + { + std::vector< uint32_t > xwayland_mode_ctl; +@@ -7248,6 +7279,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ + ctx->atoms.gamescopeFSRSharpness = XInternAtom( ctx->dpy, "GAMESCOPE_FSR_SHARPNESS", false ); + ctx->atoms.gamescopeSharpness = XInternAtom( ctx->dpy, "GAMESCOPE_SHARPNESS", false ); + ++ ctx->atoms.gamescopeRotateControl = XInternAtom( ctx->dpy, "GAMESCOPE_ROTATE_CONTROL", false ); + ctx->atoms.gamescopeXWaylandModeControl = XInternAtom( ctx->dpy, "GAMESCOPE_XWAYLAND_MODE_CONTROL", false ); + ctx->atoms.gamescopeFPSLimit = XInternAtom( ctx->dpy, "GAMESCOPE_FPS_LIMIT", false ); + ctx->atoms.gamescopeDynamicRefresh[DRM_SCREEN_TYPE_INTERNAL] = XInternAtom( ctx->dpy, "GAMESCOPE_DYNAMIC_REFRESH", false ); +diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp +index 5764c4b..6231007 100644 +--- a/src/xwayland_ctx.hpp ++++ b/src/xwayland_ctx.hpp +@@ -146,6 +146,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable + Atom gamescopeFSRSharpness; + Atom gamescopeSharpness; + ++ Atom gamescopeRotateControl; + Atom gamescopeXWaylandModeControl; + + Atom gamescopeFPSLimit; +-- +2.42.0 + + +From 4d8f1c32f1be873bf009b3d14b1ff3756495da63 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Sat, 7 Oct 2023 10:38:09 -0500 +Subject: [PATCH 2/9] Flag drm_out_of_date to ensure rotation logic gets reset + +--- + src/steamcompmgr.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 277a54c..236bba4 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -5673,6 +5673,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + break; + } + drm_set_orientation(&g_DRM, rotated); ++ g_DRM.out_of_date = 2; + } + } + if ( ev->atom == ctx->atoms.gamescopeXWaylandModeControl ) +-- +2.42.0 + + +From b145e5cde74d026ffceddee7f4096a23e60e6112 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Tue, 25 Apr 2023 06:45:01 -0500 +Subject: [PATCH 3/9] Add --force-panel-type and --force-external-orientation + arguments (#2) + +* Add --force-panel-type and --force-external-orientation arguments. + +* Rotate only the internal display when faked as "external" + +* Try to prevent the external display from being rotated when --force-panel-type external is used. + +* Fixed docking issue when --force-panel-type external is used and you dock/undock the handheld. +--- + src/drm.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++------- + src/drm.hpp | 15 +++++++++++++++ + src/main.cpp | 36 +++++++++++++++++++++++++++++++++++ + 3 files changed, 98 insertions(+), 7 deletions(-) + +diff --git a/src/drm.cpp b/src/drm.cpp +index de5e3ca..f4fe8fd 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -46,6 +46,7 @@ uint32_t g_nDRMFormat = DRM_FORMAT_INVALID; + uint32_t g_nDRMFormatOverlay = DRM_FORMAT_INVALID; // for partial composition, we may have more limited formats than base planes + alpha. + bool g_bRotated = false; + bool g_rotate_ctl_enable = false; ++bool g_bDisplayTypeInternal = false; + bool g_bUseLayers = true; + bool g_bDebugLayers = false; + const char *g_sOutputName = nullptr; +@@ -68,6 +69,8 @@ enum drm_mode_generation g_drmModeGeneration = DRM_MODE_GENERATE_CVT; + enum g_panel_orientation g_drmModeOrientation = PANEL_ORIENTATION_AUTO; + enum g_rotate_ctl g_drmRotateCTL; + std::atomic g_drmEffectiveOrientation[DRM_SCREEN_TYPE_COUNT]{ {DRM_MODE_ROTATE_0}, {DRM_MODE_ROTATE_0} }; ++enum g_panel_external_orientation g_drmModeExternalOrientation = PANEL_EXTERNAL_ORIENTATION_AUTO; ++enum g_panel_type g_drmPanelType = PANEL_TYPE_AUTO; + + bool g_bForceDisableColorMgmt = false; + +@@ -1981,8 +1984,29 @@ static uint64_t determine_drm_orientation(struct drm_t *drm, struct connector *c + static void update_drm_effective_orientation(struct drm_t *drm, struct connector *conn, const drmModeModeInfo *mode) + { + drm_screen_type screenType = drm_get_connector_type(conn->connector); +- +- if (screenType == DRM_SCREEN_TYPE_INTERNAL) ++ if ( screenType == DRM_SCREEN_TYPE_EXTERNAL && g_bDisplayTypeInternal == true ) ++ { ++ switch ( g_drmModeExternalOrientation ) ++ { ++ case PANEL_EXTERNAL_ORIENTATION_0: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_0; ++ break; ++ case PANEL_EXTERNAL_ORIENTATION_90: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_90; ++ break; ++ case PANEL_EXTERNAL_ORIENTATION_180: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_180; ++ break; ++ case PANEL_EXTERNAL_ORIENTATION_270: ++ g_drmEffectiveOrientation[screenType] = DRM_MODE_ROTATE_270; ++ break; ++ case PANEL_EXTERNAL_ORIENTATION_AUTO: ++ g_drmEffectiveOrientation[screenType] = determine_drm_orientation(drm, conn, mode); ++ break; ++ } ++ return; ++ } ++ else if ( screenType == DRM_SCREEN_TYPE_INTERNAL ) + { + switch ( g_drmModeOrientation ) + { +@@ -2933,11 +2957,27 @@ bool drm_get_vrr_in_use(struct drm_t *drm) + + drm_screen_type drm_get_connector_type(drmModeConnector *connector) + { +- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || +- connector->connector_type == DRM_MODE_CONNECTOR_LVDS || +- connector->connector_type == DRM_MODE_CONNECTOR_DSI) +- return DRM_SCREEN_TYPE_INTERNAL; +- ++ // Set to the default state of false to make sure the external display isn't rotated when a system is docked ++ g_bDisplayTypeInternal = false; ++ switch ( g_drmPanelType ) ++ { ++ case PANEL_TYPE_INTERNAL: ++ return DRM_SCREEN_TYPE_INTERNAL; ++ break; ++ case PANEL_TYPE_EXTERNAL: ++ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || ++ connector->connector_type == DRM_MODE_CONNECTOR_LVDS || ++ connector->connector_type == DRM_MODE_CONNECTOR_DSI) ++ g_bDisplayTypeInternal = true; ++ return DRM_SCREEN_TYPE_EXTERNAL; ++ break; ++ case PANEL_TYPE_AUTO: ++ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP || ++ connector->connector_type == DRM_MODE_CONNECTOR_LVDS || ++ connector->connector_type == DRM_MODE_CONNECTOR_DSI) ++ return DRM_SCREEN_TYPE_INTERNAL; ++ break; ++ } + return DRM_SCREEN_TYPE_EXTERNAL; + } + +diff --git a/src/drm.hpp b/src/drm.hpp +index b2ab49f..53fc540 100644 +--- a/src/drm.hpp ++++ b/src/drm.hpp +@@ -331,11 +331,26 @@ enum g_rotate_ctl{ + UPSIDEDOWN, + RIGHT_UP, + }; ++enum g_panel_external_orientation { ++ PANEL_EXTERNAL_ORIENTATION_0, /* NORMAL */ ++ PANEL_EXTERNAL_ORIENTATION_270, /* RIGHT */ ++ PANEL_EXTERNAL_ORIENTATION_90, /* LEFT */ ++ PANEL_EXTERNAL_ORIENTATION_180, /* UPSIDE DOWN */ ++ PANEL_EXTERNAL_ORIENTATION_AUTO, ++}; ++ ++enum g_panel_type { ++ PANEL_TYPE_INTERNAL, ++ PANEL_TYPE_EXTERNAL, ++ PANEL_TYPE_AUTO, ++}; + + extern enum drm_mode_generation g_drmModeGeneration; + extern enum g_panel_orientation g_drmModeOrientation; + extern enum g_rotate_ctl g_drmRotateCTL; + extern bool g_rotate_ctl_enable; ++extern enum g_panel_external_orientation g_drmModeExternalOrientation; ++extern enum g_panel_type g_drmPanelType; + + extern std::atomic g_drmEffectiveOrientation[DRM_SCREEN_TYPE_COUNT]; // DRM_MODE_ROTATE_* + +diff --git a/src/main.cpp b/src/main.cpp +index 76721d6..f6ba34f 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -118,6 +118,8 @@ const struct option *gamescope_options = (struct option[]){ + { "disable-xres", no_argument, nullptr, 'x' }, + { "fade-out-duration", required_argument, nullptr, 0 }, + { "force-orientation", required_argument, nullptr, 0 }, ++ { "force-external-orientation", required_argument, nullptr, 0 }, ++ { "force-panel-type", required_argument, nullptr, 0 }, + { "force-windows-fullscreen", no_argument, nullptr, 0 }, + + { "disable-color-management", no_argument, nullptr, 0 }, +@@ -167,6 +169,8 @@ const char usage[] = + " --xwayland-count create N xwayland servers\n" + " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" + " --force-orientation rotate the internal display (left, right, normal, upsidedown)\n" ++ " --force-external-orientation rotate the external display (left, right, normal, upsidedown)\n" ++ " --force-panel-type force gamescope to treat the display as either internal or external\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" + " --hdr-enabled enable HDR output (needs Gamescope WSI layer enabled for support from clients)\n" +@@ -353,6 +357,18 @@ static enum drm_mode_generation parse_drm_mode_generation(const char *str) + } + } + ++static enum g_panel_type force_panel_type(const char *str) ++{ ++ if (strcmp(str, "internal") == 0) { ++ return PANEL_TYPE_INTERNAL; ++ } else if (strcmp(str, "external") == 0) { ++ return PANEL_TYPE_EXTERNAL; ++ } else { ++ fprintf( stderr, "gamescope: invalid value for --force-panel-type\n" ); ++ exit(1); ++ } ++} ++ + static enum g_panel_orientation force_orientation(const char *str) + { + if (strcmp(str, "normal") == 0) { +@@ -408,6 +424,22 @@ static enum GamescopeUpscaleFilter parse_upscaler_filter(const char *str) + struct sigaction handle_signal_action = {}; + extern pid_t child_pid; + ++static enum g_panel_external_orientation force_external_orientation(const char *str) ++{ ++ if (strcmp(str, "normal") == 0) { ++ return PANEL_EXTERNAL_ORIENTATION_0; ++ } else if (strcmp(str, "right") == 0) { ++ return PANEL_EXTERNAL_ORIENTATION_270; ++ } else if (strcmp(str, "left") == 0) { ++ return PANEL_EXTERNAL_ORIENTATION_90; ++ } else if (strcmp(str, "upsidedown") == 0) { ++ return PANEL_EXTERNAL_ORIENTATION_180; ++ } else { ++ fprintf( stderr, "gamescope: invalid value for --force-external-orientation\n" ); ++ exit(1); ++ } ++} ++ + static void handle_signal( int sig ) + { + switch ( sig ) { +@@ -614,6 +646,10 @@ int main(int argc, char **argv) + g_drmModeGeneration = parse_drm_mode_generation( optarg ); + } else if (strcmp(opt_name, "force-orientation") == 0) { + g_drmModeOrientation = force_orientation( optarg ); ++ } else if (strcmp(opt_name, "force-external-orientation") == 0) { ++ g_drmModeExternalOrientation = force_external_orientation( optarg ); ++ } else if (strcmp(opt_name, "force-panel-type") == 0) { ++ g_drmPanelType = force_panel_type( optarg ); + } else if (strcmp(opt_name, "sharpness") == 0 || + strcmp(opt_name, "fsr-sharpness") == 0) { + g_upscaleFilterSharpness = atoi( optarg ); +-- +2.42.0 + + +From 4d1f8e34b70fee42e4e30feac16eda7aa2aa63e7 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Tue, 25 Jul 2023 18:05:05 -0500 +Subject: [PATCH 4/9] Set default to native resolution of display if Steam + tries to force 720p/800p + +You can select 720p/800p still in game or via Steam's resolution setting +Steam > Settings > Display > Resolution + +This effectively reverts the changes Valve made a year ago forcing us to +720p. +--- + src/steamcompmgr.cpp | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 236bba4..60f9828 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -5685,6 +5685,13 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + size_t server_idx = size_t{ xwayland_mode_ctl[ 0 ] }; + int width = xwayland_mode_ctl[ 1 ]; + int height = xwayland_mode_ctl[ 2 ]; ++ ++ if ( g_nOutputWidth != 1280 && width == 1280 ) ++ { ++ width = g_nOutputWidth; ++ height = g_nOutputHeight; ++ } ++ + bool allowSuperRes = !!xwayland_mode_ctl[ 3 ]; + + if ( !allowSuperRes ) +-- +2.42.0 + + +From 8959ef22543eb94d329ef9c117ec662061a3db6c Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Wed, 26 Jul 2023 20:46:29 -0500 +Subject: [PATCH 5/9] Fix internal display touchscreen orientation when it's + forced + +--- + src/main.cpp | 6 ++++++ + src/main.hpp | 2 ++ + src/wlserver.cpp | 25 +++++++++++++++++++++++++ + 3 files changed, 33 insertions(+) + +diff --git a/src/main.cpp b/src/main.cpp +index f6ba34f..17409b5 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -269,6 +269,8 @@ bool g_bHeadless = false; + + bool g_bGrabbed = false; + ++bool g_bExternalForced = false; ++ + GamescopeUpscaleFilter g_upscaleFilter = GamescopeUpscaleFilter::LINEAR; + GamescopeUpscaleScaler g_upscaleScaler = GamescopeUpscaleScaler::AUTO; + +@@ -427,12 +429,16 @@ extern pid_t child_pid; + static enum g_panel_external_orientation force_external_orientation(const char *str) + { + if (strcmp(str, "normal") == 0) { ++ g_bExternalForced = true; + return PANEL_EXTERNAL_ORIENTATION_0; + } else if (strcmp(str, "right") == 0) { ++ g_bExternalForced = true; + return PANEL_EXTERNAL_ORIENTATION_270; + } else if (strcmp(str, "left") == 0) { ++ g_bExternalForced = true; + return PANEL_EXTERNAL_ORIENTATION_90; + } else if (strcmp(str, "upsidedown") == 0) { ++ g_bExternalForced = true; + return PANEL_EXTERNAL_ORIENTATION_180; + } else { + fprintf( stderr, "gamescope: invalid value for --force-external-orientation\n" ); +diff --git a/src/main.hpp b/src/main.hpp +index 7d8e9f1..97ec0a8 100644 +--- a/src/main.hpp ++++ b/src/main.hpp +@@ -23,6 +23,8 @@ extern bool g_bFullscreen; + + extern bool g_bGrabbed; + ++extern bool g_bExternalForced; ++ + enum class GamescopeUpscaleFilter : uint32_t + { + LINEAR = 0, +diff --git a/src/wlserver.cpp b/src/wlserver.cpp +index 3fbc4ff..dc37f97 100644 +--- a/src/wlserver.cpp ++++ b/src/wlserver.cpp +@@ -1976,6 +1976,31 @@ static void apply_touchscreen_orientation(double *x, double *y ) + ty = 1.0 - *x; + break; + } ++ // Rotate screen if it's forced with --force-external-orientation ++ ++ if ( g_bExternalForced == true) ++ { ++ switch ( g_drmEffectiveOrientation[DRM_SCREEN_TYPE_EXTERNAL] ) ++ { ++ default: ++ case DRM_MODE_ROTATE_0: ++ tx = *x; ++ ty = *y; ++ break; ++ case DRM_MODE_ROTATE_90: ++ tx = 1.0 - *y; ++ ty = *x; ++ break; ++ case DRM_MODE_ROTATE_180: ++ tx = 1.0 - *x; ++ ty = 1.0 - *y; ++ break; ++ case DRM_MODE_ROTATE_270: ++ tx = *y; ++ ty = 1.0 - *x; ++ break; ++ } ++ } + + *x = tx; + *y = ty; +-- +2.42.0 + + +From 17a8118d9ede790f27fa085a1d287f31e81abb64 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Fri, 6 Oct 2023 23:58:17 -0500 +Subject: [PATCH 6/9] Add initial display selection atom + +--- + src/drm.cpp | 20 +++++++++++++ + src/drm.hpp | 1 + + src/steamcompmgr.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++ + src/xwayland_ctx.hpp | 1 + + 4 files changed, 91 insertions(+) + +diff --git a/src/drm.cpp b/src/drm.cpp +index f4fe8fd..d2f7677 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -50,6 +50,7 @@ bool g_bDisplayTypeInternal = false; + bool g_bUseLayers = true; + bool g_bDebugLayers = false; + const char *g_sOutputName = nullptr; ++char* targetConnector = (char*)"eDP-1"; + + #ifndef DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP + #define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 +@@ -1245,6 +1246,19 @@ static bool setup_best_connector(struct drm_t *drm, bool force, bool initial) + } + } + ++ for (auto &kv : drm->connectors) { ++ struct connector *conn = &kv.second; ++ drm_log.debugf("force set adapter"); ++ drm_log.debugf("conn->name: %s", conn->name); ++ drm_log.debugf("targetConnector: %s", targetConnector); ++ if (strcmp(conn->name, targetConnector) == 0) ++ { ++ drm_log.debugf("target was found!!!"); ++ drm_log.infof(" %s (%s)", conn->name, targetConnector); ++ best = conn; ++ } ++ } ++ + if (!force) { + if ((!best && drm->connector) || (best && best == drm->connector)) { + // Let's keep our current connector +@@ -2907,6 +2921,12 @@ static bool drm_set_crtc( struct drm_t *drm, struct crtc *crtc ) + return true; + } + ++void drm_set_prefered_connector( struct drm_t *drm, char* name ) ++{ ++ drm_log.infof("selecting prefered connector %s", name); ++ targetConnector = name; ++} ++ + bool drm_set_connector( struct drm_t *drm, struct connector *conn ) + { + drm_log.infof("selecting connector %s", conn->name); +diff --git a/src/drm.hpp b/src/drm.hpp +index 53fc540..739f51b 100644 +--- a/src/drm.hpp ++++ b/src/drm.hpp +@@ -368,6 +368,7 @@ uint32_t drm_fbid_from_dmabuf( struct drm_t *drm, struct wlr_buffer *buf, struct + void drm_lock_fbid( struct drm_t *drm, uint32_t fbid ); + void drm_unlock_fbid( struct drm_t *drm, uint32_t fbid ); + void drm_drop_fbid( struct drm_t *drm, uint32_t fbid ); ++void drm_set_prefered_connector( struct drm_t *drm, char* name ); + bool drm_set_connector( struct drm_t *drm, struct connector *conn ); + bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ); + bool drm_set_refresh( struct drm_t *drm, int refresh ); +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 60f9828..aeef706 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -5719,6 +5719,74 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + } + } + } ++ if ( ev->atom == ctx->atoms.gamescopeConnectorControl ) ++ { ++ std::vector< uint32_t > connector_ctl; ++ bool hasConnectorCtrl = get_prop( ctx, ctx->root, ctx->atoms.gamescopeConnectorControl, connector_ctl ); ++ char* adapter_type; ++ if ( hasConnectorCtrl && connector_ctl.size() == 1 ) ++ { ++ switch (connector_ctl[0]) ++ { ++ case 0: ++ adapter_type = (char*)"eDP-1"; ++ break; ++ case 1: ++ adapter_type = (char*)"eDP-2"; ++ break; ++ case 2: ++ adapter_type = (char*)"eDP-3"; ++ break; ++ case 3: ++ adapter_type = (char*)"DP-1"; ++ break; ++ case 4: ++ adapter_type = (char*)"DP-2"; ++ break; ++ case 5: ++ adapter_type = (char*)"DP-3"; ++ break; ++ case 6: ++ adapter_type = (char*)"HDMI-A-1"; ++ break; ++ case 7: ++ adapter_type = (char*)"HDMI-A-2"; ++ break; ++ case 8: ++ adapter_type = (char*)"HDMI-A-3"; ++ break; ++ case 9: ++ adapter_type = (char*)"HDMI-B-1"; ++ break; ++ case 10: ++ adapter_type = (char*)"HDMI-B-2"; ++ break; ++ case 11: ++ adapter_type = (char*)"HDMI-B-3"; ++ break; ++ case 12: ++ adapter_type = (char*)"HDMI-C-1"; ++ break; ++ case 13: ++ adapter_type = (char*)"HDMI-C-2"; ++ break; ++ case 14: ++ adapter_type = (char*)"HDMI-C-3"; ++ break; ++ case 15: ++ adapter_type = (char*)"DSI-1"; ++ break; ++ case 16: ++ adapter_type = (char*)"DSI-2"; ++ break; ++ case 17: ++ adapter_type = (char*)"DSI-3"; ++ break; ++ } ++ g_DRM.out_of_date = 2; ++ drm_set_prefered_connector(&g_DRM, adapter_type); ++ } ++ } + if ( ev->atom == ctx->atoms.gamescopeFPSLimit ) + { + g_nSteamCompMgrTargetFPS = get_prop( ctx, ctx->root, ctx->atoms.gamescopeFPSLimit, 0 ); +@@ -7289,6 +7357,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ + + ctx->atoms.gamescopeRotateControl = XInternAtom( ctx->dpy, "GAMESCOPE_ROTATE_CONTROL", false ); + ctx->atoms.gamescopeXWaylandModeControl = XInternAtom( ctx->dpy, "GAMESCOPE_XWAYLAND_MODE_CONTROL", false ); ++ ctx->atoms.gamescopeConnectorControl = XInternAtom(ctx->dpy, "GAMESCOPE_CONNECTOR_CONTROL", false ); + ctx->atoms.gamescopeFPSLimit = XInternAtom( ctx->dpy, "GAMESCOPE_FPS_LIMIT", false ); + ctx->atoms.gamescopeDynamicRefresh[DRM_SCREEN_TYPE_INTERNAL] = XInternAtom( ctx->dpy, "GAMESCOPE_DYNAMIC_REFRESH", false ); + ctx->atoms.gamescopeDynamicRefresh[DRM_SCREEN_TYPE_EXTERNAL] = XInternAtom( ctx->dpy, "GAMESCOPE_DYNAMIC_REFRESH_EXTERNAL", false ); +diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp +index 6231007..9dbc544 100644 +--- a/src/xwayland_ctx.hpp ++++ b/src/xwayland_ctx.hpp +@@ -149,6 +149,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable + Atom gamescopeRotateControl; + Atom gamescopeXWaylandModeControl; + ++ Atom gamescopeConnectorControl; + Atom gamescopeFPSLimit; + Atom gamescopeDynamicRefresh[DRM_SCREEN_TYPE_COUNT]; + Atom gamescopeLowLatency; +-- +2.42.0 + + +From 8b94b4297324bddf48f3578592cdb6f9fe20e5a4 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Mon, 9 Oct 2023 11:21:11 -0500 +Subject: [PATCH 7/9] Use sysfs connector_ids for target device selection. + +--- + src/drm.cpp | 14 +++-------- + src/drm.hpp | 2 +- + src/steamcompmgr.cpp | 60 +------------------------------------------- + 3 files changed, 6 insertions(+), 70 deletions(-) + +diff --git a/src/drm.cpp b/src/drm.cpp +index d2f7677..59516c7 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -50,7 +50,7 @@ bool g_bDisplayTypeInternal = false; + bool g_bUseLayers = true; + bool g_bDebugLayers = false; + const char *g_sOutputName = nullptr; +-char* targetConnector = (char*)"eDP-1"; ++uint32_t targetConnector; + + #ifndef DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP + #define DRM_CAP_ATOMIC_ASYNC_PAGE_FLIP 0x15 +@@ -1248,13 +1248,8 @@ static bool setup_best_connector(struct drm_t *drm, bool force, bool initial) + + for (auto &kv : drm->connectors) { + struct connector *conn = &kv.second; +- drm_log.debugf("force set adapter"); +- drm_log.debugf("conn->name: %s", conn->name); +- drm_log.debugf("targetConnector: %s", targetConnector); +- if (strcmp(conn->name, targetConnector) == 0) ++ if ( conn->id == targetConnector) + { +- drm_log.debugf("target was found!!!"); +- drm_log.infof(" %s (%s)", conn->name, targetConnector); + best = conn; + } + } +@@ -2921,10 +2916,9 @@ static bool drm_set_crtc( struct drm_t *drm, struct crtc *crtc ) + return true; + } + +-void drm_set_prefered_connector( struct drm_t *drm, char* name ) ++void drm_set_prefered_connector( struct drm_t *drm, uint32_t connector_type_id ) + { +- drm_log.infof("selecting prefered connector %s", name); +- targetConnector = name; ++ targetConnector = connector_type_id; + } + + bool drm_set_connector( struct drm_t *drm, struct connector *conn ) +diff --git a/src/drm.hpp b/src/drm.hpp +index 739f51b..6320bf7 100644 +--- a/src/drm.hpp ++++ b/src/drm.hpp +@@ -368,7 +368,7 @@ uint32_t drm_fbid_from_dmabuf( struct drm_t *drm, struct wlr_buffer *buf, struct + void drm_lock_fbid( struct drm_t *drm, uint32_t fbid ); + void drm_unlock_fbid( struct drm_t *drm, uint32_t fbid ); + void drm_drop_fbid( struct drm_t *drm, uint32_t fbid ); +-void drm_set_prefered_connector( struct drm_t *drm, char* name ); ++void drm_set_prefered_connector( struct drm_t *drm, uint32_t connector_type_id ); + bool drm_set_connector( struct drm_t *drm, struct connector *conn ); + bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ); + bool drm_set_refresh( struct drm_t *drm, int refresh ); +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index aeef706..9a3f495 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -5723,68 +5723,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + { + std::vector< uint32_t > connector_ctl; + bool hasConnectorCtrl = get_prop( ctx, ctx->root, ctx->atoms.gamescopeConnectorControl, connector_ctl ); +- char* adapter_type; + if ( hasConnectorCtrl && connector_ctl.size() == 1 ) + { +- switch (connector_ctl[0]) +- { +- case 0: +- adapter_type = (char*)"eDP-1"; +- break; +- case 1: +- adapter_type = (char*)"eDP-2"; +- break; +- case 2: +- adapter_type = (char*)"eDP-3"; +- break; +- case 3: +- adapter_type = (char*)"DP-1"; +- break; +- case 4: +- adapter_type = (char*)"DP-2"; +- break; +- case 5: +- adapter_type = (char*)"DP-3"; +- break; +- case 6: +- adapter_type = (char*)"HDMI-A-1"; +- break; +- case 7: +- adapter_type = (char*)"HDMI-A-2"; +- break; +- case 8: +- adapter_type = (char*)"HDMI-A-3"; +- break; +- case 9: +- adapter_type = (char*)"HDMI-B-1"; +- break; +- case 10: +- adapter_type = (char*)"HDMI-B-2"; +- break; +- case 11: +- adapter_type = (char*)"HDMI-B-3"; +- break; +- case 12: +- adapter_type = (char*)"HDMI-C-1"; +- break; +- case 13: +- adapter_type = (char*)"HDMI-C-2"; +- break; +- case 14: +- adapter_type = (char*)"HDMI-C-3"; +- break; +- case 15: +- adapter_type = (char*)"DSI-1"; +- break; +- case 16: +- adapter_type = (char*)"DSI-2"; +- break; +- case 17: +- adapter_type = (char*)"DSI-3"; +- break; +- } + g_DRM.out_of_date = 2; +- drm_set_prefered_connector(&g_DRM, adapter_type); ++ drm_set_prefered_connector(&g_DRM, connector_ctl[0]); + } + } + if ( ev->atom == ctx->atoms.gamescopeFPSLimit ) +-- +2.42.0 + + +From 40cb952642118fb983ec4e3deedd7410dbf69a07 Mon Sep 17 00:00:00 2001 +From: Matthew Anderson +Date: Tue, 16 Jan 2024 13:57:50 -0600 +Subject: [PATCH 8/9] Add edge gesture support to open Home and QAM + +--- + src/wlserver.cpp | 28 +++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/src/wlserver.cpp b/src/wlserver.cpp +index dc37f97..e7fb7c9 100644 +--- a/src/wlserver.cpp ++++ b/src/wlserver.cpp +@@ -2048,8 +2048,34 @@ void wlserver_touchmotion( double x, double y, int touch_id, uint32_t time ) + + if ( get_effective_touch_mode() == WLSERVER_TOUCH_CLICK_PASSTHROUGH ) + { ++ bool start_gesture = false; + wlr_seat_touch_notify_motion( wlserver.wlr.seat, time, touch_id, wlserver.mouse_surface_cursorx, wlserver.mouse_surface_cursory ); +- } ++ ++ // Round the x-coordinate to the nearest whole number ++ uint32_t roundedCursorX = static_cast(std::round(wlserver.mouse_surface_cursorx)); ++ // Grab 2% of the display to be used for the edge range ++ double edge_range = g_nOutputWidth * 0.02; ++ ++ // if the touch cursor x position is less or equal to the range then start the gesture for left to right ++ if (roundedCursorX <= edge_range) { ++ start_gesture = true; ++ } ++ // if the touch cursor x position is the output width minus the edge range value then we are doing right to left ++ if (roundedCursorX >= g_nOutputWidth - edge_range) { ++ start_gesture = true; ++ } ++ // when the gesture is started and we are moving to the end of the edge range open home ++ if (start_gesture && roundedCursorX >= 1 && roundedCursorX <= edge_range) { ++ wl_log.infof("Detected Home gesture"); ++ wlserver_open_steam_menu(0); ++ start_gesture = false; ++ } ++ // when the gesture is started and we are moving from the output width minus the edge range to the output width open QAM ++ if (start_gesture && roundedCursorX >= g_nOutputWidth - edge_range && roundedCursorX <= g_nOutputWidth ) { ++ wl_log.infof("Detected QAM gesture"); ++ wlserver_open_steam_menu(1); ++ start_gesture = false; ++ } } + else if ( get_effective_touch_mode() == WLSERVER_TOUCH_CLICK_DISABLED ) + { + return; +-- +2.42.0 + + +From f975e7a804100bb031fab0526d6714530381ec45 Mon Sep 17 00:00:00 2001 +From: Bouke Sybren Haarsma +Date: Wed, 3 Jan 2024 17:03:04 +0100 +Subject: [PATCH 9/9] remove hacky texture + +This will use more hardware planes, causing some devices to composite yeilding lower framerates +--- + src/steamcompmgr.cpp | 29 ----------------------------- + 1 file changed, 29 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 9a3f495..9e7eee5 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -2540,35 +2540,6 @@ paint_all(bool async) + if ( overlay == global_focus.inputFocusWindow ) + update_touch_scaling( &frameInfo ); + } +- else +- { +- auto tex = vulkan_get_hacky_blank_texture(); +- if ( !BIsNested() && tex != nullptr ) +- { +- // HACK! HACK HACK HACK +- // To avoid stutter when toggling the overlay on +- int curLayer = frameInfo.layerCount++; +- +- FrameInfo_t::Layer_t *layer = &frameInfo.layers[ curLayer ]; +- +- +- layer->scale.x = g_nOutputWidth == tex->width() ? 1.0f : tex->width() / (float)g_nOutputWidth; +- layer->scale.y = g_nOutputHeight == tex->height() ? 1.0f : tex->height() / (float)g_nOutputHeight; +- layer->offset.x = 0.0f; +- layer->offset.y = 0.0f; +- layer->opacity = 1.0f; // BLAH +- layer->zpos = g_zposOverlay; +- layer->applyColorMgmt = g_ColorMgmt.pending.enabled; +- +- layer->colorspace = GAMESCOPE_APP_TEXTURE_COLORSPACE_LINEAR; +- layer->ctm = nullptr; +- layer->tex = tex; +- layer->fbid = tex->fbid(); +- +- layer->filter = GamescopeUpscaleFilter::NEAREST; +- layer->blackBorder = true; +- } +- } + + if (notification) + { +-- +2.42.0 + diff --git a/spec_files/gamescope/40/crashfix.patch b/spec_files/gamescope/40/crashfix.patch new file mode 100644 index 00000000..f50180e0 --- /dev/null +++ b/spec_files/gamescope/40/crashfix.patch @@ -0,0 +1,57 @@ +From adaa5e064a6149e1f8122cc55589f60b6f58f7ea Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20Gu=C3=A9rin?= +Date: Tue, 19 Dec 2023 16:34:17 -0800 +Subject: [PATCH 1/2] drm: fix NPE while in headless mode + +caused by e810317 +--- + src/drm.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/drm.cpp b/src/drm.cpp +index 59516c7..8759321 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -3337,6 +3337,7 @@ void drm_get_native_colorimetry( struct drm_t *drm, + *displayEOTF = EOTF_Gamma22; + *outputEncodingColorimetry = displaycolorimetry_709; + *outputEncodingEOTF = EOTF_Gamma22; ++ return; + } + + *displayColorimetry = drm->connector->metadata.colorimetry; +-- +2.42.0 + + +From 08c56c656539c88b23d243869b00cf3dd33bcb1d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20Gu=C3=A9rin?= +Date: Wed, 20 Dec 2023 17:18:32 -0800 +Subject: [PATCH 2/2] drm: fix other headless NPE + +fixes a980d912 +--- + src/drm.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/drm.cpp b/src/drm.cpp +index 8759321..d632128 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -2584,10 +2584,10 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI + assert( drm->req == nullptr ); + drm->req = drmModeAtomicAlloc(); + +- bool bConnectorSupportsHDR = drm->connector->metadata.supportsST2084; +- bool bConnectorHDR = g_bOutputHDREnabled && bConnectorSupportsHDR; +- + if (drm->connector != nullptr) { ++ bool bConnectorSupportsHDR = drm->connector->metadata.supportsST2084; ++ bool bConnectorHDR = g_bOutputHDREnabled && bConnectorSupportsHDR; ++ + if (drm->connector->has_colorspace) { + drm->connector->pending.colorspace = ( bConnectorHDR ) ? DRM_MODE_COLORIMETRY_BT2020_RGB : DRM_MODE_COLORIMETRY_DEFAULT; + } +-- +2.42.0 + diff --git a/spec_files/gamescope/40/gamescope.spec b/spec_files/gamescope/40/gamescope.spec new file mode 100644 index 00000000..96a52a71 --- /dev/null +++ b/spec_files/gamescope/40/gamescope.spec @@ -0,0 +1,112 @@ +%global libliftoff_minver 0.4.1 + +Name: gamescope +Version: 3.13.19 +Release: 1%{?dist}.bazzite.{{{ git_dir_version }}} +Summary: Micro-compositor for video games on Wayland + +License: BSD +URL: https://github.com/ValveSoftware/gamescope + +# Create stb.pc to satisfy dependency('stb') +Source1: stb.pc + +# https://github.com/ChimeraOS/gamescope +Source2: chimeraos.patch +Source3: crashfix.patch +Source4: add_720p_var.patch +Source5: touch_gestures_env.patch +Source6: legion_go.patch + +# https://github.com/ValveSoftware/gamescope/pull/1149 +Source7: 1149.patch + +BuildRequires: meson >= 0.54.0 +BuildRequires: ninja-build +BuildRequires: cmake +BuildRequires: gcc +BuildRequires: gcc-c++ +BuildRequires: glm-devel +BuildRequires: google-benchmark-devel +BuildRequires: libXmu-devel +BuildRequires: pkgconfig(libdisplay-info) +BuildRequires: pkgconfig(x11) +BuildRequires: pkgconfig(xdamage) +BuildRequires: pkgconfig(xcomposite) +BuildRequires: pkgconfig(xrender) +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) +BuildRequires: pkgconfig(wayland-protocols) >= 1.17 +BuildRequires: pkgconfig(xkbcommon) +BuildRequires: pkgconfig(sdl2) +BuildRequires: pkgconfig(libpipewire-0.3) +BuildRequires: (pkgconfig(wlroots) >= 0.17.0 with pkgconfig(wlroots) < 0.18.0) +BuildRequires: (pkgconfig(libliftoff) >= 0.4.1 with pkgconfig(libliftoff) < 0.5) +BuildRequires: pkgconfig(libcap) +BuildRequires: pkgconfig(hwdata) +BuildRequires: pkgconfig(xwayland) +BuildRequires: pkgconfig(xcursor) +BuildRequires: vkroots-devel +BuildRequires: /usr/bin/glslangValidator +BuildRequires: git +BuildRequires: stb_image-devel +BuildRequires: stb_image_write-devel +BuildRequires: stb_image_resize-devel + +# libliftoff hasn't bumped soname, but API/ABI has changed for 0.2.0 release +Requires: libliftoff%{?_isa} >= %{libliftoff_minver} +Requires: xorg-x11-server-Xwayland +Requires: google-benchmark +Requires: gamescope-libs = %{version}-%{release} +Recommends: mesa-dri-drivers +Recommends: mesa-vulkan-drivers + +%description +%{name} is the micro-compositor optimized for running video games on Wayland. + +%package libs +Summary: libs for %{name} +%description libs +%summary + +%prep +git clone --single-branch --branch %{version} https://github.com/ValveSoftware/gamescope.git +cd gamescope +git submodule update --init --recursive +mkdir -p pkgconfig +cp %{SOURCE1} pkgconfig/stb.pc +patch -Np1 < %{SOURCE2} +patch -Np1 < %{SOURCE3} +patch -Np1 < %{SOURCE4} +patch -Np1 < %{SOURCE5} +patch -Np1 < %{SOURCE6} +patch -Np1 < %{SOURCE7} + +%build +cd gamescope +export PKG_CONFIG_PATH=pkgconfig +%meson -Dpipewire=enabled -Denable_gamescope=true -Denable_gamescope_wsi_layer=true -Denable_openvr_support=true -Dforce_fallback_for=[] +%meson_build + +%install +cd gamescope +%meson_install --skip-subprojects + +%files +%license gamescope/LICENSE +%doc gamescope/README.md +%attr(0755, root, root) %caps(cap_sys_nice=eip) %{_bindir}/gamescope + +%files libs +%{_libdir}/*.so +%{_datadir}/vulkan/implicit_layer.d/ + +%changelog +{{{ git_dir_changelog }}} diff --git a/spec_files/gamescope/40/legion_go.patch b/spec_files/gamescope/40/legion_go.patch new file mode 100644 index 00000000..e2a3ac8d --- /dev/null +++ b/spec_files/gamescope/40/legion_go.patch @@ -0,0 +1,30 @@ +diff --git a/src/drm.cpp b/src/drm.cpp +index acff5e5..fdf58ee 100644 +--- a/src/drm.cpp ++++ b/src/drm.cpp +@@ -101,6 +101,12 @@ static uint32_t galileo_display_rates[] = + 90, + }; + ++static uint32_t legion_go_display_rates[] = ++{ ++ 60, ++ 144, ++}; ++ + static uint32_t get_conn_display_info_flags(struct drm_t *drm, struct connector *connector) + { + if (!connector) +@@ -911,8 +917,11 @@ static void parse_edid( drm_t *drm, struct connector *conn) + conn->valid_display_rates = std::span(galileo_display_rates); + } else { + conn->is_galileo_display = 0; +- if ( conn->is_steam_deck_display ) ++ if ( conn->is_steam_deck_display ) { + conn->valid_display_rates = std::span(steam_deck_display_rates); ++ } else if ( strcmp(conn->make_pnp, "LEN") == 0 && strcmp(conn->model, "Go Display") == 0 ) { ++ conn->valid_display_rates = std::span(legion_go_display_rates); ++ } + } + + drm_hdr_parse_edid(drm, conn, edid); diff --git a/spec_files/gamescope/40/stb.pc b/spec_files/gamescope/40/stb.pc new file mode 100644 index 00000000..02c304a9 --- /dev/null +++ b/spec_files/gamescope/40/stb.pc @@ -0,0 +1,7 @@ +prefix=/usr +includedir=${prefix}/include/stb + +Name: stb +Description: Single-file public domain libraries for C/C++ +Version: 0.1.0 +Cflags: -I${includedir} diff --git a/spec_files/gamescope/40/touch_gestures_env.patch b/spec_files/gamescope/40/touch_gestures_env.patch new file mode 100644 index 00000000..45befc22 --- /dev/null +++ b/spec_files/gamescope/40/touch_gestures_env.patch @@ -0,0 +1,77 @@ +diff --git a/src/wlserver.cpp b/src/wlserver.cpp +index d569ee5..0512ab0 100644 +--- a/src/wlserver.cpp ++++ b/src/wlserver.cpp +@@ -66,6 +66,8 @@ extern "C" { + + static LogScope wl_log("wlserver"); + ++extern bool env_to_bool(const char *env); ++ + struct wlserver_t wlserver = { + .touch_down_ids = {} + }; +@@ -2043,34 +2045,38 @@ void wlserver_touchmotion( double x, double y, int touch_id, uint32_t time ) + + if ( get_effective_touch_mode() == WLSERVER_TOUCH_CLICK_PASSTHROUGH ) + { +- bool start_gesture = false; + wlr_seat_touch_notify_motion( wlserver.wlr.seat, time, touch_id, wlserver.mouse_surface_cursorx, wlserver.mouse_surface_cursory ); + +- // Round the x-coordinate to the nearest whole number +- uint32_t roundedCursorX = static_cast(std::round(wlserver.mouse_surface_cursorx)); +- // Grab 2% of the display to be used for the edge range +- double edge_range = g_nOutputWidth * 0.02; +- +- // if the touch cursor x position is less or equal to the range then start the gesture for left to right +- if (roundedCursorX <= edge_range) { +- start_gesture = true; +- } +- // if the touch cursor x position is the output width minus the edge range value then we are doing right to left +- if (roundedCursorX >= g_nOutputWidth - edge_range) { +- start_gesture = true; +- } +- // when the gesture is started and we are moving to the end of the edge range open home +- if (start_gesture && roundedCursorX >= 1 && roundedCursorX <= edge_range) { +- wl_log.infof("Detected Home gesture"); +- wlserver_open_steam_menu(0); +- start_gesture = false; ++ if (!env_to_bool(getenv("GAMESCOPE_DISABLE_TOUCH_GESTURES"))) { ++ bool start_gesture = false; ++ ++ // Round the x-coordinate to the nearest whole number ++ uint32_t roundedCursorX = static_cast(std::round(wlserver.mouse_surface_cursorx)); ++ // Grab 2% of the display to be used for the edge range ++ double edge_range = g_nOutputWidth * 0.02; ++ ++ // if the touch cursor x position is less or equal to the range then start the gesture for left to right ++ if (roundedCursorX <= edge_range) { ++ start_gesture = true; ++ } ++ // if the touch cursor x position is the output width minus the edge range value then we are doing right to left ++ if (roundedCursorX >= g_nOutputWidth - edge_range) { ++ start_gesture = true; ++ } ++ // when the gesture is started and we are moving to the end of the edge range open home ++ if (start_gesture && roundedCursorX >= 1 && roundedCursorX <= edge_range) { ++ wl_log.infof("Detected Home gesture"); ++ wlserver_open_steam_menu(0); ++ start_gesture = false; ++ } ++ // when the gesture is started and we are moving from the output width minus the edge range to the output width open QAM ++ if (start_gesture && roundedCursorX >= g_nOutputWidth - edge_range && roundedCursorX <= g_nOutputWidth ) { ++ wl_log.infof("Detected QAM gesture"); ++ wlserver_open_steam_menu(1); ++ start_gesture = false; ++ } + } +- // when the gesture is started and we are moving from the output width minus the edge range to the output width open QAM +- if (start_gesture && roundedCursorX >= g_nOutputWidth - edge_range && roundedCursorX <= g_nOutputWidth ) { +- wl_log.infof("Detected QAM gesture"); +- wlserver_open_steam_menu(1); +- start_gesture = false; +- } } ++ } + else if ( get_effective_touch_mode() == WLSERVER_TOUCH_CLICK_DISABLED ) + { + return;