steamcompmgr: Implement external overlay support

This commit is contained in:
Trigg 2022-01-04 06:24:59 +00:00 committed by Joshie
parent 9a26fa583a
commit 610483bd23

View file

@ -146,6 +146,7 @@ struct win {
uint32_t inputFocusMode; uint32_t inputFocusMode;
uint32_t appID; uint32_t appID;
bool isOverlay; bool isOverlay;
bool isExternalOverlay;
bool isFullscreen; bool isFullscreen;
bool isSysTrayIcon; bool isSysTrayIcon;
bool sizeHintsSpecified; bool sizeHintsSpecified;
@ -189,6 +190,7 @@ static Window currentInputFocusWindow;
uint32_t currentInputFocusMode; uint32_t currentInputFocusMode;
static Window currentKeyboardFocusWindow; static Window currentKeyboardFocusWindow;
static Window currentOverlayWindow; static Window currentOverlayWindow;
static Window currentExternalOverlayWindow;
static Window currentNotificationWindow; static Window currentNotificationWindow;
static Window currentOverrideWindow; static Window currentOverrideWindow;
static Window currentFadeWindow; static Window currentFadeWindow;
@ -236,6 +238,7 @@ extern bool g_bIntegerScale;
static Atom steamAtom; static Atom steamAtom;
static Atom gameAtom; static Atom gameAtom;
static Atom overlayAtom; static Atom overlayAtom;
static Atom externalOverlayAtom;
static Atom gamesRunningAtom; static Atom gamesRunningAtom;
static Atom screenZoomAtom; static Atom screenZoomAtom;
static Atom screenScaleAtom; static Atom screenScaleAtom;
@ -293,6 +296,7 @@ bool g_bPendingFade = false;
#define GAME_PROP "STEAM_GAME" #define GAME_PROP "STEAM_GAME"
#define STEAM_PROP "STEAM_BIGPICTURE" #define STEAM_PROP "STEAM_BIGPICTURE"
#define OVERLAY_PROP "STEAM_OVERLAY" #define OVERLAY_PROP "STEAM_OVERLAY"
#define EXTERNAL_OVERLAY_PROP "GAMESCOPE_EXTERNAL_OVERLAY"
#define GAMES_RUNNING_PROP "STEAM_GAMES_RUNNING" #define GAMES_RUNNING_PROP "STEAM_GAMES_RUNNING"
#define SCREEN_SCALE_PROP "STEAM_SCREEN_SCALE" #define SCREEN_SCALE_PROP "STEAM_SCREEN_SCALE"
#define SCREEN_MAGNIFICATION_PROP "STEAM_SCREEN_MAGNIFICATION" #define SCREEN_MAGNIFICATION_PROP "STEAM_SCREEN_MAGNIFICATION"
@ -355,13 +359,15 @@ static LogScope xwm_log("xwm");
#ifdef WORKAROUND_ZPOS_BUG #ifdef WORKAROUND_ZPOS_BUG
static const uint32_t g_zposBase = 0; static const uint32_t g_zposBase = 0;
static const uint32_t g_zposOverride = 0; static const uint32_t g_zposOverride = 0;
static const uint32_t g_zposOverlay = 1; static const uint32_t g_zposExternalOverlay = 1;
static const uint32_t g_zposCursor = 2; static const uint32_t g_zposOverlay = 2;
static const uint32_t g_zposCursor = 3;
#else #else
static const uint32_t g_zposBase = 0; static const uint32_t g_zposBase = 0;
static const uint32_t g_zposOverride = 1; static const uint32_t g_zposOverride = 1;
static const uint32_t g_zposOverlay = 2; static const uint32_t g_zposExternalOverlay = 2;
static const uint32_t g_zposCursor = 3; static const uint32_t g_zposOverlay = 3;
static const uint32_t g_zposCursor = 4;
#endif #endif
// poor man's semaphore // poor man's semaphore
@ -1270,7 +1276,7 @@ paint_window(Display *dpy, win *w, win *scaleW, struct Composite_t *pComposite,
int curLayer = pComposite->nLayerCount; int curLayer = pComposite->nLayerCount;
pComposite->data.flOpacity[ curLayer ] = ( w->isOverlay ? w->opacity / (float)OPAQUE : 1.0f ) * flOpacityScale; pComposite->data.flOpacity[ curLayer ] = ( (w->isOverlay || w->isExternalOverlay) ? w->opacity / (float)OPAQUE : 1.0f ) * flOpacityScale;
pComposite->data.vScale[ curLayer ].x = 1.0 / currentScaleRatio; pComposite->data.vScale[ curLayer ].x = 1.0 / currentScaleRatio;
pComposite->data.vScale[ curLayer ].y = 1.0 / currentScaleRatio; pComposite->data.vScale[ curLayer ].y = 1.0 / currentScaleRatio;
@ -1318,11 +1324,15 @@ paint_window(Display *dpy, win *w, win *scaleW, struct Composite_t *pComposite,
{ {
pPipeline->layerBindings[ curLayer ].zpos = g_zposOverlay; pPipeline->layerBindings[ curLayer ].zpos = g_zposOverlay;
} }
if ( w->isExternalOverlay )
{
pPipeline->layerBindings[ curLayer ].zpos = g_zposExternalOverlay;
}
pPipeline->layerBindings[ curLayer ].tex = lastCommit->vulkanTex; pPipeline->layerBindings[ curLayer ].tex = lastCommit->vulkanTex;
pPipeline->layerBindings[ curLayer ].fbid = lastCommit->fb_id; pPipeline->layerBindings[ curLayer ].fbid = lastCommit->fb_id;
pPipeline->layerBindings[ curLayer ].bFilter = w->isOverlay ? true : g_bFilterGameWindow; pPipeline->layerBindings[ curLayer ].bFilter = (w->isOverlay || w->isExternalOverlay) ? true : g_bFilterGameWindow;
if ( bBasePlane ) if ( bBasePlane )
{ {
@ -1376,6 +1386,7 @@ paint_debug_info(Display *dpy)
} }
win *overlay = find_win(dpy, currentOverlayWindow); win *overlay = find_win(dpy, currentOverlayWindow);
win *externalOverlay = find_win(dpy, currentExternalOverlayWindow);
win *notification = find_win(dpy, currentNotificationWindow); win *notification = find_win(dpy, currentNotificationWindow);
if (overlay && gamesRunningCount && overlay->opacity) if (overlay && gamesRunningCount && overlay->opacity)
@ -1384,6 +1395,12 @@ paint_debug_info(Display *dpy)
paint_message(messageBuffer, Y, 1.0f, 0.0f, 1.0f); Y += textYMax; paint_message(messageBuffer, Y, 1.0f, 0.0f, 1.0f); Y += textYMax;
} }
if (externalOverlay && externalOverlay->opacity)
{
sprintf(messageBuffer, "Compositing external overlay at opacity %f", externalOverlay->opacity / (float)OPAQUE);
paint_message(messageBuffer, Y, 1.0f, 0.0f, 1.0f); Y += textYMax;
}
if (notification && gamesRunningCount && notification->opacity) if (notification && gamesRunningCount && notification->opacity)
{ {
sprintf(messageBuffer, "Compositing notification at opacity %f", notification->opacity / (float)OPAQUE); sprintf(messageBuffer, "Compositing notification at opacity %f", notification->opacity / (float)OPAQUE);
@ -1422,6 +1439,7 @@ paint_all(Display *dpy, MouseCursor *cursor)
gpuvis_trace_begin_ctx_printf( paintID, "paint_all" ); gpuvis_trace_begin_ctx_printf( paintID, "paint_all" );
win *w; win *w;
win *overlay; win *overlay;
win *externalOverlay;
win *notification; win *notification;
win *override; win *override;
win *input; win *input;
@ -1431,6 +1449,7 @@ paint_all(Display *dpy, MouseCursor *cursor)
w = find_win(dpy, currentFocusWindow); w = find_win(dpy, currentFocusWindow);
overlay = find_win(dpy, currentOverlayWindow); overlay = find_win(dpy, currentOverlayWindow);
externalOverlay = find_win(dpy, currentExternalOverlayWindow);
notification = find_win(dpy, currentNotificationWindow); notification = find_win(dpy, currentNotificationWindow);
override = find_win(dpy, currentOverrideWindow); override = find_win(dpy, currentOverrideWindow);
input = find_win(dpy, currentInputFocusWindow); input = find_win(dpy, currentInputFocusWindow);
@ -1533,7 +1552,18 @@ paint_all(Display *dpy, MouseCursor *cursor)
if ( override && !w->isSteamStreamingClient ) if ( override && !w->isSteamStreamingClient )
{ {
paint_window(dpy, override, w, &composite, &pipeline, false, cursor); paint_window(dpy, override, w, &composite, &pipeline, false, cursor);
update_touch_scaling( &composite ); update_touch_scaling( &composite );
}
if (externalOverlay)
{
if (externalOverlay->opacity)
{
paint_window(dpy, externalOverlay, externalOverlay, &composite, &pipeline, false, cursor);
if ( externalOverlay->id == currentInputFocusWindow )
update_touch_scaling( &composite );
}
} }
if (inGame && overlay) if (inGame && overlay)
@ -1895,7 +1925,7 @@ determine_and_apply_focus(Display *dpy, MouseCursor *cursor)
} }
if ( w->a.map_state == IsViewable && w->a.c_class == InputOutput && w->isOverlay == false && if ( w->a.map_state == IsViewable && w->a.c_class == InputOutput && w->isOverlay == false &&
( win_has_game_id( w ) || w->isSteam || w->isSteamStreamingClient ) && w->isExternalOverlay == false && ( win_has_game_id( w ) || w->isSteam || w->isSteamStreamingClient ) &&
(w->opacity > TRANSLUCENT || w->isSteamStreamingClient == true ) ) (w->opacity > TRANSLUCENT || w->isSteamStreamingClient == true ) )
{ {
vecPossibleFocusWindows.push_back( w ); vecPossibleFocusWindows.push_back( w );
@ -1914,6 +1944,14 @@ determine_and_apply_focus(Display *dpy, MouseCursor *cursor)
} }
} }
if (w->isExternalOverlay)
{
if(w->opacity >= maxOpacity)
{
currentExternalOverlayWindow = w->id;
}
}
if ( w->isOverlay && w->inputFocusMode ) if ( w->isOverlay && w->inputFocusMode )
{ {
inputFocus = w; inputFocus = w;
@ -2412,6 +2450,7 @@ map_win(Display *dpy, Window id, unsigned long sequence)
w->appID = w->id; w->appID = w->id;
} }
w->isOverlay = get_prop(dpy, w->id, overlayAtom, 0); w->isOverlay = get_prop(dpy, w->id, overlayAtom, 0);
w->isExternalOverlay = get_prop(dpy, w->id, externalOverlayAtom, 0);
get_size_hints(dpy, w); get_size_hints(dpy, w);
@ -2623,6 +2662,7 @@ add_win(Display *dpy, Window id, Window prev, unsigned long sequence)
} }
new_win->isOverlay = false; new_win->isOverlay = false;
new_win->isExternalOverlay = false;
new_win->isSteam = false; new_win->isSteam = false;
new_win->isSteamStreamingClient = false; new_win->isSteamStreamingClient = false;
new_win->isSteamStreamingClientVideo = false; new_win->isSteamStreamingClientVideo = false;
@ -2830,6 +2870,8 @@ destroy_win(Display *dpy, Window id, bool gone, bool fade)
currentInputFocusWindow = None; currentInputFocusWindow = None;
if (currentOverlayWindow == id && gone) if (currentOverlayWindow == id && gone)
currentOverlayWindow = None; currentOverlayWindow = None;
if (currentExternalOverlayWindow == id && gone)
currentExternalOverlayWindow = None;
if (currentNotificationWindow == id && gone) if (currentNotificationWindow == id && gone)
currentNotificationWindow = None; currentNotificationWindow = None;
if (currentOverrideWindow == id && gone) if (currentOverrideWindow == id && gone)
@ -2850,7 +2892,7 @@ damage_win(Display *dpy, XDamageNotifyEvent *de)
if (!w) if (!w)
return; return;
if (w->isOverlay && !w->opacity) if ((w->isOverlay || w->isExternalOverlay) && !w->opacity)
return; return;
// First damage event we get, compute focus; we only want to focus damaged // First damage event we get, compute focus; we only want to focus damaged
@ -3052,6 +3094,10 @@ handle_property_notify(Display *dpy, XPropertyEvent *ev)
{ {
hasRepaint = true; hasRepaint = true;
} }
if ( w->id == currentExternalOverlayWindow )
{
hasRepaint = true;
}
} }
unsigned int maxOpacity = 0; unsigned int maxOpacity = 0;
@ -3066,6 +3112,10 @@ handle_property_notify(Display *dpy, XPropertyEvent *ev)
maxOpacity = w->opacity; maxOpacity = w->opacity;
} }
} }
if (w->isExternalOverlay)
{
currentExternalOverlayWindow = w->id;
}
} }
} }
} }
@ -3411,7 +3461,11 @@ void handle_done_commits( void )
hasRepaint = true; hasRepaint = true;
} }
} }
// If this is an external overlay, repaint
if ( w->id == currentExternalOverlayWindow && w->opacity != TRANSLUCENT )
{
hasRepaint = true;
}
// If this is the main plane, repaint // If this is the main plane, repaint
if ( w->id == currentFocusWindow && !w->isSteamStreamingClient ) if ( w->id == currentFocusWindow && !w->isSteamStreamingClient )
{ {
@ -4050,6 +4104,7 @@ steamcompmgr_main(int argc, char **argv)
steamTouchClickModeAtom = XInternAtom(dpy, "STEAM_TOUCH_CLICK_MODE", false); steamTouchClickModeAtom = XInternAtom(dpy, "STEAM_TOUCH_CLICK_MODE", false);
gameAtom = XInternAtom(dpy, GAME_PROP, false); gameAtom = XInternAtom(dpy, GAME_PROP, false);
overlayAtom = XInternAtom(dpy, OVERLAY_PROP, false); overlayAtom = XInternAtom(dpy, OVERLAY_PROP, false);
externalOverlayAtom = XInternAtom(dpy, EXTERNAL_OVERLAY_PROP, false);
opacityAtom = XInternAtom(dpy, OPACITY_PROP, false); opacityAtom = XInternAtom(dpy, OPACITY_PROP, false);
gamesRunningAtom = XInternAtom(dpy, GAMES_RUNNING_PROP, false); gamesRunningAtom = XInternAtom(dpy, GAMES_RUNNING_PROP, false);
screenScaleAtom = XInternAtom(dpy, SCREEN_SCALE_PROP, false); screenScaleAtom = XInternAtom(dpy, SCREEN_SCALE_PROP, false);