steamcompmgr: Implement fades

This commit is contained in:
Joshua Ashton 2021-12-11 02:19:21 +00:00 committed by Pierre-Loup A. Griffais
parent 8a84b4d7e6
commit 95baa301c7

View file

@ -174,6 +174,7 @@ static Window currentKeyboardFocusWindow;
static Window currentOverlayWindow; static Window currentOverlayWindow;
static Window currentNotificationWindow; static Window currentNotificationWindow;
static Window currentOverrideWindow; static Window currentOverrideWindow;
static Window currentFadeWindow;
bool hasFocusWindow; bool hasFocusWindow;
@ -207,9 +208,7 @@ unsigned int cursorHideTime = 10'000;
bool gotXError = false; bool gotXError = false;
win fadeOutWindow; unsigned int fadeOutStartTime = 0;
bool fadeOutWindowGone;
unsigned int fadeOutStartTime;
extern float g_flMaxWindowScale; extern float g_flMaxWindowScale;
extern bool g_bIntegerScale; extern bool g_bIntegerScale;
@ -263,11 +262,13 @@ static Atom gamescopeInputCounterAtom;
enum HeldCommitTypes_t enum HeldCommitTypes_t
{ {
HELD_COMMIT_BASE, HELD_COMMIT_BASE,
HELD_COMMIT_FADE,
HELD_COMMIT_COUNT, HELD_COMMIT_COUNT,
}; };
std::array<commit_t, HELD_COMMIT_COUNT> g_HeldCommits; std::array<commit_t, HELD_COMMIT_COUNT> g_HeldCommits;
bool g_bPendingFade = false;
/* opacity property name; sometime soon I'll write up an EWMH spec for it */ /* opacity property name; sometime soon I'll write up an EWMH spec for it */
#define OPACITY_PROP "_NET_WM_WINDOW_OPACITY" #define OPACITY_PROP "_NET_WM_WINDOW_OPACITY"
@ -1159,7 +1160,7 @@ struct BaseLayerInfo_t
std::array< BaseLayerInfo_t, HELD_COMMIT_COUNT > g_CachedPlanes = {}; std::array< BaseLayerInfo_t, HELD_COMMIT_COUNT > g_CachedPlanes = {};
static bool static bool
paint_cached_base_layer(const commit_t& commit, const BaseLayerInfo_t& base, struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline) paint_cached_base_layer(const commit_t& commit, const BaseLayerInfo_t& base, struct Composite_t *pComposite, struct VulkanPipeline_t *pPipeline, float flOpacityScale)
{ {
if (!commit.done) if (!commit.done)
return false; return false;
@ -1169,7 +1170,7 @@ paint_cached_base_layer(const commit_t& commit, const BaseLayerInfo_t& base, str
pComposite->data.vScale[ curLayer ].y = base.scale[1]; pComposite->data.vScale[ curLayer ].y = base.scale[1];
pComposite->data.vOffset[ curLayer ].x = base.offset[0]; pComposite->data.vOffset[ curLayer ].x = base.offset[0];
pComposite->data.vOffset[ curLayer ].y = base.offset[1]; pComposite->data.vOffset[ curLayer ].y = base.offset[1];
pComposite->data.flOpacity[ curLayer ] = base.opacity; pComposite->data.flOpacity[ curLayer ] = base.opacity * flOpacityScale;
pPipeline->layerBindings[ curLayer ].tex = commit.vulkanTex; pPipeline->layerBindings[ curLayer ].tex = commit.vulkanTex;
pPipeline->layerBindings[ curLayer ].fbid = commit.fb_id; pPipeline->layerBindings[ curLayer ].fbid = commit.fb_id;
@ -1182,7 +1183,7 @@ paint_cached_base_layer(const commit_t& commit, const BaseLayerInfo_t& base, str
static bool static bool
paint_window(Display *dpy, win *w, win *scaleW, struct Composite_t *pComposite, paint_window(Display *dpy, win *w, win *scaleW, struct Composite_t *pComposite,
struct VulkanPipeline_t *pPipeline, bool notificationMode, MouseCursor *cursor, bool bBasePlane = false) struct VulkanPipeline_t *pPipeline, bool notificationMode, MouseCursor *cursor, bool bBasePlane = false, float flOpacityScale = 1.0f, bool bFadeTarget = false)
{ {
uint32_t sourceWidth, sourceHeight; uint32_t sourceWidth, sourceHeight;
int drawXOffset = 0, drawYOffset = 0; int drawXOffset = 0, drawYOffset = 0;
@ -1197,7 +1198,15 @@ paint_window(Display *dpy, win *w, win *scaleW, struct Composite_t *pComposite,
// If we're the base plane and have no valid contents // If we're the base plane and have no valid contents
// pick up that buffer we've been holding onto if we have one. // pick up that buffer we've been holding onto if we have one.
if ( g_HeldCommits[ HELD_COMMIT_BASE ].done ) if ( g_HeldCommits[ HELD_COMMIT_BASE ].done )
return paint_cached_base_layer( g_HeldCommits[ HELD_COMMIT_BASE ], g_CachedPlanes[ HELD_COMMIT_BASE ], pComposite, pPipeline ); return paint_cached_base_layer( g_HeldCommits[ HELD_COMMIT_BASE ], g_CachedPlanes[ HELD_COMMIT_BASE ], pComposite, pPipeline, flOpacityScale );
}
else
{
if ( g_bPendingFade )
{
fadeOutStartTime = get_time_in_milliseconds();
g_bPendingFade = false;
}
} }
} }
@ -1256,7 +1265,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; pComposite->data.flOpacity[ curLayer ] = ( w->isOverlay ? 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;
@ -1324,6 +1333,8 @@ paint_window(Display *dpy, win *w, win *scaleW, struct Composite_t *pComposite,
basePlane.opacity = pComposite->data.flOpacity[ curLayer ]; basePlane.opacity = pComposite->data.flOpacity[ curLayer ];
g_CachedPlanes[ HELD_COMMIT_BASE ] = basePlane; g_CachedPlanes[ HELD_COMMIT_BASE ] = basePlane;
if ( !bFadeTarget )
g_CachedPlanes[ HELD_COMMIT_FADE ] = basePlane;
} }
pComposite->nLayerCount += 1; pComposite->nLayerCount += 1;
@ -1387,6 +1398,11 @@ paint_debug_info(Display *dpy)
static bool g_bFirstFrame = true; static bool g_bFirstFrame = true;
static bool is_fading_out()
{
return fadeOutStartTime || g_bPendingFade;
}
static void static void
paint_all(Display *dpy, MouseCursor *cursor) paint_all(Display *dpy, MouseCursor *cursor)
{ {
@ -1401,7 +1417,7 @@ paint_all(Display *dpy, MouseCursor *cursor)
win *input; win *input;
unsigned int currentTime = get_time_in_milliseconds(); unsigned int currentTime = get_time_in_milliseconds();
bool fadingOut = ((currentTime - fadeOutStartTime) < FADE_OUT_DURATION && fadeOutWindow.id != None); bool fadingOut = ( currentTime - fadeOutStartTime < FADE_OUT_DURATION || g_bPendingFade ) && g_HeldCommits[HELD_COMMIT_FADE].done;
w = find_win(dpy, currentFocusWindow); w = find_win(dpy, currentFocusWindow);
overlay = find_win(dpy, currentOverlayWindow); overlay = find_win(dpy, currentOverlayWindow);
@ -1445,22 +1461,6 @@ paint_all(Display *dpy, MouseCursor *cursor)
struct VulkanPipeline_t pipeline = {}; struct VulkanPipeline_t pipeline = {};
bool bValidContents = false; bool bValidContents = false;
// Fading out from previous window?
if (fadingOut)
{
double newOpacity = ((currentTime - fadeOutStartTime) / (double)FADE_OUT_DURATION);
// Draw it in the background
fadeOutWindow.opacity = (1.0 - newOpacity) * OPAQUE;
bValidContents |= paint_window(dpy, &fadeOutWindow, &fadeOutWindow, &composite, &pipeline, false, cursor);
// Blend new window on top with linear crossfade
w->opacity = newOpacity * OPAQUE;
bValidContents |= paint_window(dpy, w, w, &composite, &pipeline, false, cursor);
}
else
{
// If the window we'd paint as the base layer is the streaming client, // If the window we'd paint as the base layer is the streaming client,
// find the video underlay and put it up first in the scenegraph // find the video underlay and put it up first in the scenegraph
if ( w->isSteamStreamingClient == true ) if ( w->isSteamStreamingClient == true )
@ -1485,21 +1485,31 @@ paint_all(Display *dpy, MouseCursor *cursor)
} }
else else
{ {
// Just draw focused window as normal, be it Steam or the game if ( fadingOut )
bValidContents |= paint_window(dpy, w, w, &composite, &pipeline, false, cursor);
}
if (fadeOutWindow.id) {
if (fadeOutWindowGone)
{ {
// This is the only reference to these resources now. float opacityScale = g_bPendingFade
fadeOutWindowGone = false; ? 0.0f
} : ((currentTime - fadeOutStartTime) / (float)FADE_OUT_DURATION);
fadeOutWindow.id = None;
}
}
bValidContents |= paint_cached_base_layer(g_HeldCommits[HELD_COMMIT_FADE], g_CachedPlanes[HELD_COMMIT_FADE], &composite, &pipeline, 1.0f - opacityScale);
bValidContents |= paint_window(dpy, w, w, &composite, &pipeline, false, cursor, true, opacityScale, true);
}
else
{
{
if ( g_HeldCommits[HELD_COMMIT_FADE].done )
{
release_commit(g_HeldCommits[HELD_COMMIT_FADE]);
g_HeldCommits[HELD_COMMIT_FADE] = commit_t{};
g_bPendingFade = false;
fadeOutStartTime = 0;
currentFadeWindow = None;
}
}
// Just draw focused window as normal, be it Steam or the game
bValidContents |= paint_window(dpy, w, w, &composite, &pipeline, false, cursor, true);
}
}
// TODO: We want to paint this at the same scale as the normal window and probably // TODO: We want to paint this at the same scale as the normal window and probably
// with an offset. // with an offset.
@ -2062,22 +2072,31 @@ found:
return; return;
} }
// if (fadeOutWindow.id == None && currentFocusWindow != focus->id)
// {
// // Initiate fade out if switching focus
// w = find_win(dpy, currentFocusWindow);
//
// if (w)
// {
// ensure_win_resources(dpy, w);
// fadeOutWindow = *w;
// fadeOutStartTime = get_time_in_milliseconds();
// }
// }
// if (fadeOutWindow.id && currentFocusWindow != focus->id)
if ( prevFocusWindow != focus->id ) if ( prevFocusWindow != focus->id )
{ {
if ( FADE_OUT_DURATION != 0 && !g_bFirstFrame )
{
if ( !g_HeldCommits[ HELD_COMMIT_FADE ].done )
{
currentFadeWindow = prevFocusWindow;
ref_commit( g_HeldCommits[ HELD_COMMIT_BASE ] );
g_HeldCommits[ HELD_COMMIT_FADE ] = g_HeldCommits[ HELD_COMMIT_BASE ];
g_bPendingFade = true;
}
else
{
// If we end up fading back to what we were going to fade to, cancel the fade.
if ( currentFadeWindow != None && focus->id == currentFadeWindow )
{
release_commit( g_HeldCommits[ HELD_COMMIT_FADE ] );
g_HeldCommits[ HELD_COMMIT_FADE ] = commit_t{};
g_bPendingFade = false;
fadeOutStartTime = 0;
currentFadeWindow = None;
}
}
}
hasRepaint = true; hasRepaint = true;
/* Some games (e.g. DOOM Eternal) don't react well to being put back as /* Some games (e.g. DOOM Eternal) don't react well to being put back as
@ -2396,15 +2415,6 @@ static void
finish_unmap_win(Display *dpy, win *w) finish_unmap_win(Display *dpy, win *w)
{ {
// TODO clear done commits here? // TODO clear done commits here?
// if (fadeOutWindow.id != w->id)
// {
// teardown_win_resources( w );
// }
if (fadeOutWindow.id == w->id)
{
fadeOutWindowGone = true;
}
/* don't care about properties anymore */ /* don't care about properties anymore */
set_ignore(dpy, NextRequest(dpy)); set_ignore(dpy, NextRequest(dpy));
@ -2773,6 +2783,8 @@ destroy_win(Display *dpy, Window id, bool gone, bool fade)
currentFocusWindow = None; currentFocusWindow = None;
currentFocusWin = nullptr; currentFocusWin = nullptr;
} }
if (currentFadeWindow == id && gone)
currentFadeWindow = None;
if (currentInputFocusWindow == id && gone) if (currentInputFocusWindow == id && gone)
currentInputFocusWindow = None; currentInputFocusWindow = None;
if (currentOverlayWindow == id && gone) if (currentOverlayWindow == id && gone)
@ -4182,12 +4194,19 @@ steamcompmgr_main(int argc, char **argv)
check_new_wayland_res(); check_new_wayland_res();
if ( ( g_bTakeScreenshot == true || hasRepaint == true ) && vblank == true ) if ( ( g_bTakeScreenshot == true || hasRepaint == true || is_fading_out() ) && vblank == true )
{ {
paint_all(dpy, cursor.get()); paint_all(dpy, cursor.get());
// Consumed the need to repaint here // Consumed the need to repaint here
hasRepaint = false; hasRepaint = false;
// If we're in the middle of a fade, pump an event into the loop to
// make sure we keep pushing frames even if the app isn't updating.
if ( is_fading_out() )
{
nudge_steamcompmgr();
}
} }
// TODO: Look into making this _RAW // TODO: Look into making this _RAW
@ -4196,13 +4215,6 @@ steamcompmgr_main(int argc, char **argv)
struct timespec now; struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
// If we're in the middle of a fade, pump an event into the loop to
// make sure we keep pushing frames even if the app isn't updating.
if (fadeOutWindow.id)
{
nudge_steamcompmgr();
}
cursor->updatePosition(); cursor->updatePosition();
// Ask for a new surface every vblank // Ask for a new surface every vblank