diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp index 134e19ac5f..716f9b48e1 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp @@ -267,6 +267,7 @@ namespace gamescope static std::optional Instantiate( const char *pszName, CDRMAtomicObject *pObject, const DRMObjectRawProperties& rawProperties ); + uint32_t GetPropertyId() const { return m_uPropertyId; } uint64_t GetPendingValue() const { return m_ulPendingValue; } uint64_t GetCurrentValue() const { return m_ulCurrentValue; } uint64_t GetInitialValue() const { return m_ulInitialValue; } @@ -1934,7 +1935,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_uOutputRotation == 0) { int64_t imageH = frameInfo->layers[ i ].tex->contentHeight() / frameInfo->layers[ i ].scale.y; @@ -2668,7 +2669,7 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo liftoff_layer_set_property( drm->lo_layers[ i ], "SRC_H", entry.layerState[i].srcH ); uint64_t ulOrientation = DRM_MODE_ROTATE_0; - switch ( drm->pConnector->GetCurrentOrientation() ) + switch ( g_uOutputRotation != 0 ? GAMESCOPE_PANEL_ORIENTATION_0 : drm->pConnector->GetCurrentOrientation() ) { default: case GAMESCOPE_PANEL_ORIENTATION_0: @@ -3278,6 +3279,29 @@ static void drm_unset_mode( struct drm_t *drm ) g_nDynamicRefreshHz = 0; g_bRotated = false; + g_uOutputRotation = 0; +} + +// Bitmask of DRM_MODE_ROTATE_* the plane can do at scanout (just ROTATE_0 if it can't rotate). +static uint64_t drm_plane_supported_rotations( struct drm_t *drm, gamescope::CDRMPlane *pPlane ) +{ + if ( !pPlane->GetProperties().rotation ) + return DRM_MODE_ROTATE_0; + + drmModePropertyRes *pProp = drmModeGetProperty( drm->fd, pPlane->GetProperties().rotation->GetPropertyId() ); + if ( !pProp ) + return DRM_MODE_ROTATE_0; + defer( drmModeFreeProperty( pProp ) ); + + if ( !( pProp->flags & DRM_MODE_PROP_BITMASK ) ) + return DRM_MODE_ROTATE_0; + + uint64_t ulSupported = 0; + for ( int i = 0; i < pProp->count_enums; i++ ) + if ( pProp->enums[i].value < 64 ) + ulSupported |= 1ull << pProp->enums[i].value; + + return ulSupported; } bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) @@ -3312,6 +3336,25 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) break; } + // Rotate in the compositor when the scanout plane can't do the panel's + // orientation. 90/270 transpose the output (g_bRotated); 180 flips in place. + g_uOutputRotation = 0; + uint32_t uStep = 0; + uint64_t uNeeded = 0; + switch ( drm->pConnector->GetCurrentOrientation() ) + { + case GAMESCOPE_PANEL_ORIENTATION_90: uStep = 1u; uNeeded = DRM_MODE_ROTATE_90; break; + case GAMESCOPE_PANEL_ORIENTATION_180: uStep = 2u; uNeeded = DRM_MODE_ROTATE_180; break; + case GAMESCOPE_PANEL_ORIENTATION_270: uStep = 3u; uNeeded = DRM_MODE_ROTATE_270; break; + default: break; + } + if ( uStep ) + { + const bool bScanoutCanRotate = drm->pPrimaryPlane && ( drm_plane_supported_rotations( drm, drm->pPrimaryPlane ) & uNeeded ); + if ( g_bForceCompositionRotation || !bScanoutCanRotate ) + g_uOutputRotation = uStep; + } + return true; } @@ -3566,6 +3609,7 @@ namespace gamescope } bNeedsFullComposite |= !!(g_uCompositeDebug & CompositeDebugFlag::Heatmap); + bNeedsFullComposite |= g_uOutputRotation != 0; // can't rotate planes at scanout bool bDoComposite = true; if ( !bNeedsFullComposite && !bWantsPartialComposite ) diff --git a/src/main.cpp b/src/main.cpp index 9fc54f0de3..968191b3d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -136,6 +136,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 }, + { "force-composition-rotation", no_argument, nullptr, 0 }, { "force-orientation", required_argument, nullptr, 0 }, { "force-windows-fullscreen", no_argument, nullptr, 0 }, @@ -201,6 +202,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" + " --force-composition-rotation always rotate the output in the compositor instead of at scanout (autodetected otherwise)\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" @@ -366,6 +368,9 @@ static gamescope::GamescopeModeGeneration parse_gamescope_mode_generation( const } } +bool g_bForceCompositionRotation = false; +uint32_t g_uOutputRotation = 0; + GamescopePanelOrientation g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_AUTO; static GamescopePanelOrientation force_orientation(const char *str) { @@ -798,6 +803,8 @@ int main(int argc, char **argv) gamescope::cv_touch_click_mode = (gamescope::TouchClickMode) parse_integer( optarg, opt_name ); } else if (strcmp(opt_name, "generate-drm-mode") == 0) { g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); + } else if (strcmp(opt_name, "force-composition-rotation") == 0) { + g_bForceCompositionRotation = true; } else if (strcmp(opt_name, "force-orientation") == 0) { g_DesiredInternalOrientation = force_orientation( optarg ); } else if (strcmp(opt_name, "sharpness") == 0 || diff --git a/src/main.hpp b/src/main.hpp index 45c5ec5a87..b4fc9027d7 100644 --- a/src/main.hpp +++ b/src/main.hpp @@ -22,6 +22,9 @@ extern int g_nOutputRefresh; // mHz extern bool g_bOutputHDREnabled; extern bool g_bForceInternal; +extern bool g_bForceCompositionRotation; +extern uint32_t g_uOutputRotation; + extern bool g_bFullscreen; extern bool g_bGrabbed; diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp index aefc6b21e9..83d1f12ee0 100644 --- a/src/rendervulkan.cpp +++ b/src/rendervulkan.cpp @@ -3300,8 +3300,14 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) uint32_t uDRMFormat = pOutput->uOutputFormat; + // Output images are physical-oriented; the panel scans out unrotated. + uint32_t uOutputWidth = g_nOutputWidth; + uint32_t uOutputHeight = g_nOutputHeight; + if ( g_uOutputRotation & 1u ) + std::swap( uOutputWidth, uOutputHeight ); + pOutput->outputImages[0] = new CVulkanTexture(); - bool bSuccess = pOutput->outputImages[0]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, uDRMFormat, outputImageflags ); + bool bSuccess = pOutput->outputImages[0]->BInit( uOutputWidth, uOutputHeight, 1u, uDRMFormat, outputImageflags ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -3309,7 +3315,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( uOutputWidth, uOutputHeight, 1u, uDRMFormat, outputImageflags ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -3317,7 +3323,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( uOutputWidth, uOutputHeight, 1u, uDRMFormat, outputImageflags ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -3332,7 +3338,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( uOutputWidth, uOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[0].get() ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -3340,7 +3346,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( uOutputWidth, uOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[1].get() ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -3348,7 +3354,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( uOutputWidth, uOutputHeight, 1u, uPartialDRMFormat, outputImageflags, nullptr, 0, 0, pOutput->outputImages[2].get() ); if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); @@ -3703,10 +3709,13 @@ struct BlitPushData_t float u_itmSdrNits; // unset float u_itmTargetNits; // unset - explicit BlitPushData_t(const struct FrameInfo_t *frameInfo) + uint32_t u_rotation; + + explicit BlitPushData_t(const struct FrameInfo_t *frameInfo, uint32_t rotation = 0) { u_shaderFilter = 0; u_alphaMode = 0; + u_rotation = rotation; for (int i = 0; i < frameInfo->layerCount; i++) { const FrameInfo_t::Layer_t *layer = &frameInfo->layers[i]; @@ -3751,6 +3760,7 @@ struct BlitPushData_t opacity[0] = 1.0f; u_shaderFilter = (uint32_t)GamescopeUpscaleFilter::LINEAR; u_alphaMode = 0; + u_rotation = 0; ctm[0] = glm::mat3x4 { 1, 0, 0, 0, @@ -3837,10 +3847,13 @@ struct RcasPushData_t float u_itmSdrNits; // unset float u_itmTargetNits; // unset - RcasPushData_t(const struct FrameInfo_t *frameInfo, float sharpness) + uint32_t u_rotation; + + RcasPushData_t(const struct FrameInfo_t *frameInfo, float sharpness, uint32_t rotation = 0) { uvec4_t tmp; FsrRcasCon(&tmp.x, sharpness); + u_rotation = rotation; u_layer0Offset.x = uint32_t(int32_t(frameInfo->layers[0].offset.x)); u_layer0Offset.y = uint32_t(int32_t(frameInfo->layers[0].offset.y)); u_borderMask = frameInfo->borderMask() >> 1u; @@ -4031,6 +4044,9 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco else compositeImage = partial ? g_output.outputImagesPartialOverlay[ g_output.nOutImage ] : g_output.outputImages[ g_output.nOutImage ]; + // Overrides (screenshots, upscale cache) are logical-sized, so never rotated. + const uint32_t uOutputRotation = pOutputOverride ? 0u : g_uOutputRotation; + auto cmdBuffer = pInCommandBuffer ? std::move( pInCommandBuffer ) : g_device.commandBuffer(); for (uint32_t i = 0; i < EOTF_Count; i++) @@ -4065,7 +4081,7 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco cmdBuffer->setSamplerUnnormalized(0, false); cmdBuffer->setSamplerNearest(0, false); cmdBuffer->bindTarget(compositeImage); - cmdBuffer->uploadConstants(frameInfo, g_upscaleFilterSharpness / 10.0f); + cmdBuffer->uploadConstants(frameInfo, g_upscaleFilterSharpness / 10.0f, uOutputRotation); cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); } @@ -4108,7 +4124,7 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, nisFrameInfo.layerCount, nisFrameInfo.ycbcrMask(), 0u, nisFrameInfo.colorspaceMask(), outputTF )); bind_all_layers(cmdBuffer.get(), &nisFrameInfo); cmdBuffer->bindTarget(compositeImage); - cmdBuffer->uploadConstants(&nisFrameInfo); + cmdBuffer->uploadConstants(&nisFrameInfo, uOutputRotation); int pixelsPerGroup = 8; @@ -4134,7 +4150,7 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco cmdBuffer->setSamplerUnnormalized(i, true); cmdBuffer->setSamplerNearest(i, false); } - cmdBuffer->uploadConstants(frameInfo); + cmdBuffer->uploadConstants(frameInfo, uOutputRotation); int pixelsPerGroup = 8; @@ -4158,7 +4174,7 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, frameInfo->layerCount, frameInfo->ycbcrMask(), 0u, frameInfo->colorspaceMask(), outputTF )); bind_all_layers(cmdBuffer.get(), frameInfo); cmdBuffer->bindTarget(compositeImage); - cmdBuffer->uploadConstants(frameInfo); + cmdBuffer->uploadConstants(frameInfo, uOutputRotation); const int pixelsPerGroup = 8; diff --git a/src/shaders/blit_push_data.h b/src/shaders/blit_push_data.h index caff0f3781..f81096b9cd 100644 --- a/src/shaders/blit_push_data.h +++ b/src/shaders/blit_push_data.h @@ -16,5 +16,7 @@ uniform layers_t { float u_nitsToLinear; // hdr -> sdr float u_itmSdrNits; float u_itmTargetNits; + + uint u_rotation; }; diff --git a/src/shaders/composite.h b/src/shaders/composite.h index 961379b0ab..229296e320 100644 --- a/src/shaders/composite.h +++ b/src/shaders/composite.h @@ -3,6 +3,23 @@ #include "shaderfilter.h" #include "alphamode.h" +// Rotate only the final store coordinate (CCW 90-degree steps: 1=90, 2=180, +// 3=270); the scene stays logical so sampling and blending are unchanged. +uvec2 outputLogicalSize(uint rotation) { + uvec2 size = imageSize(dst); + return (rotation & 1u) != 0u ? uvec2(size.y, size.x) : size; +} + +ivec2 rotateOutputCoord(uvec2 coord, uint rotation) { + uvec2 size = imageSize(dst); + switch (rotation) { + case 1u: return ivec2(coord.y, size.y - 1u - coord.x); + case 2u: return ivec2(size.x - 1u - coord.x, size.y - 1u - coord.y); + case 3u: return ivec2(size.x - 1u - coord.y, coord.x); + default: return ivec2(coord); + } +} + vec4 sampleRegular(sampler2D tex, vec2 coord, uint colorspace) { vec4 color = textureLod(tex, coord, 0); color.rgb = colorspace_plane_degamma_tf(color.rgb, colorspace); @@ -50,7 +67,7 @@ uint pseudo_random(uint seed) { return seed * 1664525u + 1013904223u; } -void compositing_debug(uvec2 coord) { +void compositing_debug(uvec2 coord, uint rotation) { uvec2 pos = coord; pos.x -= (u_frameId & 2) != 0 ? 128 : 0; pos.y -= (u_frameId & 1) != 0 ? 128 : 0; @@ -66,7 +83,7 @@ void compositing_debug(uvec2 coord) { if (time.x + time.y + time.z + time.w < 2.0f) value = vec4(0.0f, 0.0f, 0.0f, 1.0f); } - imageStore(dst, ivec2(coord), value); + imageStore(dst, rotateOutputCoord(coord, rotation), value); } } diff --git a/src/shaders/cs_composite_blit.comp b/src/shaders/cs_composite_blit.comp index b728d46c0e..4d974dcb15 100644 --- a/src/shaders/cs_composite_blit.comp +++ b/src/shaders/cs_composite_blit.comp @@ -21,7 +21,7 @@ vec4 sampleLayer(uint layerIdx, vec2 uv) { void main() { uvec2 coord = uvec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); - uvec2 outSize = imageSize(dst); + uvec2 outSize = outputLogicalSize(u_rotation); if (coord.x >= outSize.x || coord.y >= outSize.y) return; @@ -42,9 +42,9 @@ void main() { } outputValue.rgb = encodeOutputColor(outputValue.rgb); - imageStore(dst, ivec2(coord), outputValue); + imageStore(dst, rotateOutputCoord(coord, u_rotation), outputValue); // Indicator to quickly tell if we're in the compositing path or not. if (checkDebugFlag(compositedebug_Markers)) - compositing_debug(coord); + compositing_debug(coord, u_rotation); } diff --git a/src/shaders/cs_composite_blur.comp b/src/shaders/cs_composite_blur.comp index 2132b032c4..318b0e9f1e 100644 --- a/src/shaders/cs_composite_blur.comp +++ b/src/shaders/cs_composite_blur.comp @@ -24,7 +24,7 @@ vec4 sampleLayer(uint layerIdx, vec2 uv) { void main() { uvec2 coord = uvec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); - uvec2 outSize = imageSize(dst); + uvec2 outSize = outputLogicalSize(u_rotation); if (coord.x >= outSize.x || coord.y >= outSize.y) return; @@ -44,8 +44,8 @@ void main() { } outputValue = encodeOutputColor(outputValue); - imageStore(dst, ivec2(coord), vec4(outputValue, 0)); + imageStore(dst, rotateOutputCoord(coord, u_rotation), vec4(outputValue, 0)); if (checkDebugFlag(compositedebug_Markers)) - compositing_debug(coord); + compositing_debug(coord, u_rotation); } diff --git a/src/shaders/cs_composite_blur_cond.comp b/src/shaders/cs_composite_blur_cond.comp index 9a997bb33a..39b040554b 100644 --- a/src/shaders/cs_composite_blur_cond.comp +++ b/src/shaders/cs_composite_blur_cond.comp @@ -24,7 +24,7 @@ vec4 sampleLayer(uint layerIdx, vec2 uv) { void main() { uvec2 coord = uvec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y); - uvec2 outSize = imageSize(dst); + uvec2 outSize = outputLogicalSize(u_rotation); if (coord.x >= outSize.x || coord.y >= outSize.y) return; @@ -61,8 +61,8 @@ void main() { } outputValue = encodeOutputColor(outputValue); - imageStore(dst, ivec2(coord), vec4(outputValue, 0)); + imageStore(dst, rotateOutputCoord(coord, u_rotation), vec4(outputValue, 0)); if (checkDebugFlag(compositedebug_Markers)) - compositing_debug(coord); + compositing_debug(coord, u_rotation); } diff --git a/src/shaders/cs_composite_rcas.comp b/src/shaders/cs_composite_rcas.comp index 20cad55179..3caefb1487 100644 --- a/src/shaders/cs_composite_rcas.comp +++ b/src/shaders/cs_composite_rcas.comp @@ -29,6 +29,8 @@ uniform layers_t { float u_nitsToLinear; float u_itmSdrNits; float u_itmTargetNits; + + uint u_rotation; }; #include "composite.h" @@ -89,10 +91,10 @@ void rcasComposite(uvec2 pos) } outputValue = encodeOutputColor(outputValue); - imageStore(dst, ivec2(pos), vec4(outputValue, 0)); + imageStore(dst, rotateOutputCoord(pos, u_rotation), vec4(outputValue, 0)); if (checkDebugFlag(compositedebug_Markers)) - compositing_debug(pos); + compositing_debug(pos, u_rotation); } void main() diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp index cfdfc3bc74..6b31076917 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp @@ -892,6 +892,7 @@ global_focus_t *GetCurrentMouseFocus() uint32_t currentOutputWidth, currentOutputHeight; int currentOutputRefresh; +uint32_t currentOutputRotation = 0; bool currentHDROutput = false; bool currentHDRForce = false; @@ -2920,7 +2921,11 @@ paint_all( global_focus_t *pFocus, bool async ) std::optional oScreenshotSeq; if ( drmCaptureFormat == DRM_FORMAT_NV12 ) - oScreenshotSeq = vulkan_composite( &frameInfo, pScreenshotTexture, false, nullptr ); + { + // Logical-sized scratch keeps the capture unrotated and off the live output image. + gamescope::Rc pRGBTexture = vulkan_acquire_screenshot_texture( g_nOutputWidth, g_nOutputHeight, false, DRM_FORMAT_XRGB2101010 ); + oScreenshotSeq = vulkan_screenshot( &frameInfo, pRGBTexture, pScreenshotTexture ); + } else if ( oScreenshotInfo->eScreenshotType == GAMESCOPE_CONTROL_SCREENSHOT_TYPE_FULL_COMPOSITION || oScreenshotInfo->eScreenshotType == GAMESCOPE_CONTROL_SCREENSHOT_TYPE_SCREEN_BUFFER ) oScreenshotSeq = vulkan_composite( &frameInfo, nullptr, false, pScreenshotTexture ); @@ -3750,7 +3755,9 @@ void xwayland_ctx_t::DetermineAndApplyFocus( const std::vector< steamcompmgr_win { if (w->isOverlay) { - if (w->GetGeometry().nWidth > 1200 && w->opacity >= maxOpacity) + // The interactive overlay (Steam/QAM) spans the full output width or asks + // for input. Anything narrower is a notification. + if (( w->GetGeometry().nWidth >= ctx->root_width || w->inputFocusMode ) && w->opacity >= maxOpacity) { ctx->focus.overlayWindow = w; maxOpacity = w->opacity; @@ -5902,7 +5909,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) { if (w->isOverlay) { - if (w->GetGeometry().nWidth > 1200 && w->opacity >= maxOpacity) + if (( w->GetGeometry().nWidth >= ctx->root_width || w->inputFocusMode ) && w->opacity >= maxOpacity) { ctx->focus.overlayWindow = w; maxOpacity = w->opacity; @@ -8704,6 +8711,7 @@ steamcompmgr_main(int argc, char **argv) if ( currentOutputWidth != g_nOutputWidth || currentOutputHeight != g_nOutputHeight || currentOutputRefresh != g_nOutputRefresh || + currentOutputRotation != g_uOutputRotation || currentHDROutput != g_bOutputHDREnabled || currentHDRForce != g_bForceHDRSupportDebug ) { @@ -8754,6 +8762,7 @@ steamcompmgr_main(int argc, char **argv) currentOutputWidth = g_nOutputWidth; currentOutputHeight = g_nOutputHeight; currentOutputRefresh = g_nOutputRefresh; + currentOutputRotation = g_uOutputRotation; currentHDROutput = g_bOutputHDREnabled; currentHDRForce = g_bForceHDRSupportDebug;