steamcompmgr: Add the ability to take different types of screenshots

All layers, screen buffer, full composition, etc.
This commit is contained in:
Joshua Ashton 2023-10-26 22:50:32 +01:00
parent 59c1571e34
commit ce281a9291
5 changed files with 75 additions and 28 deletions

View file

@ -412,7 +412,7 @@ static void handle_signal( int sig )
{
switch ( sig ) {
case SIGUSR2:
take_screenshot();
take_screenshot( TAKE_SCREENSHOT_BASEPLANE_ONLY );
break;
case SIGHUP:
case SIGQUIT:

View file

@ -3543,7 +3543,7 @@ extern uint32_t g_reshade_technique_idx;
std::unique_ptr<std::thread> defer_wait_thread;
uint64_t defer_sequence = 0;
bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pPipewireTexture, bool partial, bool defer )
bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pPipewireTexture, bool partial, bool defer, std::shared_ptr<CVulkanTexture> pOutputOverride )
{
if ( defer_wait_thread )
{
@ -3585,7 +3585,11 @@ bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTex
g_reshadeManager.clear();
}
auto compositeImage = partial ? g_output.outputImagesPartialOverlay[ g_output.nOutImage ] : g_output.outputImages[ g_output.nOutImage ];
std::shared_ptr<CVulkanTexture> compositeImage;
if ( pOutputOverride )
compositeImage = pOutputOverride;
else
compositeImage = partial ? g_output.outputImagesPartialOverlay[ g_output.nOutImage ] : g_output.outputImages[ g_output.nOutImage ];
auto cmdBuffer = g_device.commandBuffer();
@ -3723,6 +3727,7 @@ bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTex
if ( pPipewireTexture != nullptr )
{
if (compositeImage->format() == pPipewireTexture->format() &&
compositeImage->width() == pPipewireTexture->width() &&
compositeImage->height() == pPipewireTexture->height()) {
@ -3782,7 +3787,7 @@ bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTex
g_device.wait(sequence);
}
if ( !BIsSDLSession() )
if ( !BIsSDLSession() && pOutputOverride == nullptr )
{
g_output.nOutImage = ( g_output.nOutImage + 1 ) % 3;
}

View file

@ -370,7 +370,7 @@ std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_dmabuf( struct wlr_dm
std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_bits( uint32_t width, uint32_t height, uint32_t contentWidth, uint32_t contentHeight, uint32_t drmFormat, CVulkanTexture::createFlags texCreateFlags, void *bits );
std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_wlr_buffer( struct wlr_buffer *buf );
bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture, bool partial, bool deferred );
bool vulkan_composite( struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture, bool partial, bool deferred, std::shared_ptr<CVulkanTexture> pOutputOverride = nullptr );
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( bool partial, bool defer );
std::shared_ptr<CVulkanTexture> vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, bool exportable, uint32_t drmFormat, EStreamColorspace colorspace = k_EStreamColorspace_Unknown);

View file

@ -1006,7 +1006,7 @@ struct wlr_buffer_map_entry {
static std::mutex wlr_buffer_map_lock;
static std::unordered_map<struct wlr_buffer*, wlr_buffer_map_entry> wlr_buffer_map;
static std::atomic< bool > g_bTakeScreenshot{false};
static std::atomic< int > g_nTakeScreenshot{ 0 };
static bool g_bPropertyRequestedScreenshot;
static std::atomic<bool> g_bForceRepaint{false};
@ -2584,7 +2584,7 @@ paint_all(bool async)
bool bDoComposite = true;
// Handoff from whatever thread to this one since we check ours twice
bool takeScreenshot = g_bTakeScreenshot.exchange(false);
int takeScreenshot = g_nTakeScreenshot.exchange( 0 );
bool propertyRequestedScreenshot = g_bPropertyRequestedScreenshot;
g_bPropertyRequestedScreenshot = false;
@ -2657,6 +2657,8 @@ paint_all(bool async)
bNeedsFullComposite |= fadingOut;
bNeedsFullComposite |= !g_reshade_effect.empty();
constexpr bool bHackForceNV12DumpScreenshot = false;
for (uint32_t i = 0; i < EOTF_Count; i++)
{
if (g_ColorMgmtLuts[i].HasLuts())
@ -2944,8 +2946,6 @@ paint_all(bool async)
if ( takeScreenshot )
{
constexpr bool bHackForceNV12DumpScreenshot = false;
uint32_t drmCaptureFormat = bHackForceNV12DumpScreenshot
? DRM_FORMAT_NV12
: DRM_FORMAT_XRGB8888;
@ -2954,25 +2954,58 @@ paint_all(bool async)
if ( pScreenshotTexture )
{
// Basically no color mgmt applied for screenshots. (aside from being able to handle HDR content with LUTs)
for ( uint32_t nInputEOTF = 0; nInputEOTF < EOTF_Count; nInputEOTF++ )
if ( takeScreenshot != TAKE_SCREENSHOT_SCREEN_BUFFER )
{
frameInfo.lut3D[nInputEOTF] = g_ScreenshotColorMgmtLuts[nInputEOTF].vk_lut3d;
frameInfo.shaperLut[nInputEOTF] = g_ScreenshotColorMgmtLuts[nInputEOTF].vk_lut1d;
}
// Remove everything but base planes from the screenshot.
for (int i = 0; i < frameInfo.layerCount; i++)
{
if (frameInfo.layers[i].zpos >= (int)g_zposExternalOverlay)
// Basically no color mgmt applied for screenshots. (aside from being able to handle HDR content with LUTs)
for ( uint32_t nInputEOTF = 0; nInputEOTF < EOTF_Count; nInputEOTF++ )
{
frameInfo.layerCount = i;
break;
frameInfo.lut3D[nInputEOTF] = g_ScreenshotColorMgmtLuts[nInputEOTF].vk_lut3d;
frameInfo.shaperLut[nInputEOTF] = g_ScreenshotColorMgmtLuts[nInputEOTF].vk_lut1d;
}
if ( takeScreenshot == TAKE_SCREENSHOT_BASEPLANE_ONLY )
{
// Remove everything but base planes from the screenshot.
for (int i = 0; i < frameInfo.layerCount; i++)
{
if (frameInfo.layers[i].zpos >= (int)g_zposExternalOverlay)
{
frameInfo.layerCount = i;
break;
}
}
// Re-enable output color management (blending) if it was disabled by mura.
frameInfo.applyOutputColorMgmt = true;
}
else
{
if ( is_mura_correction_enabled() )
{
// Remove the last layer which is for mura...
for (int i = 0; i < frameInfo.layerCount; i++)
{
if (frameInfo.layers[i].zpos >= (int)g_zposMuraCorrection)
{
frameInfo.layerCount = i;
break;
}
}
// Re-enable output color management (blending) if it was disabled by mura.
frameInfo.applyOutputColorMgmt = true;
}
}
}
frameInfo.applyOutputColorMgmt = true;
bool bResult = vulkan_screenshot( &frameInfo, pScreenshotTexture );
bool bResult;
if ( takeScreenshot == TAKE_SCREENSHOT_FULL_COMPOSITION || takeScreenshot == TAKE_SCREENSHOT_SCREEN_BUFFER )
bResult = vulkan_composite( &frameInfo, nullptr, false, false, pScreenshotTexture );
else
bResult = vulkan_screenshot( &frameInfo, pScreenshotTexture );
if ( bResult != true )
{
xwm_log.errorf("vulkan_screenshot failed");
@ -3061,16 +3094,17 @@ paint_all(bool async)
screenshotThread.detach();
takeScreenshot = false;
takeScreenshot = 0;
}
else
{
xwm_log.errorf( "Oh no, we ran out of screenshot images. Not actually writing a screenshot." );
XDeleteProperty( root_ctx->dpy, root_ctx->root, root_ctx->atoms.gamescopeScreenShotAtom );
takeScreenshot = false;
takeScreenshot = 0;
}
}
gpuvis_trace_end_ctx_printf( paintID, "paint_all" );
gpuvis_trace_printf( "paint_all %i layers, composite %i", (int)frameInfo.layerCount, bDoComposite );
}
@ -5326,7 +5360,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
{
if ( ev->state == PropertyNewValue )
{
g_bTakeScreenshot = true;
g_nTakeScreenshot = (int)get_prop( ctx, ctx->root, ctx->atoms.gamescopeScreenShotAtom, None );
g_bPropertyRequestedScreenshot = true;
}
}
@ -6430,9 +6464,9 @@ void nudge_steamcompmgr( void )
xwm_log.errorf_errno( "nudge_steamcompmgr: write failed" );
}
void take_screenshot( void )
void take_screenshot( int flags )
{
g_bTakeScreenshot = true;
g_nTakeScreenshot = flags;
nudge_steamcompmgr();
}
@ -7999,7 +8033,7 @@ steamcompmgr_main(int argc, char **argv)
const bool bSurfaceWantsAsync = (g_HeldCommits[HELD_COMMIT_BASE] && g_HeldCommits[HELD_COMMIT_BASE]->async);
const bool bForceRepaint = g_bForceRepaint.exchange(false);
const bool bForceSyncFlip = bForceRepaint || g_bTakeScreenshot || is_fading_out();
const bool bForceSyncFlip = bForceRepaint || is_fading_out();
// If we are compositing, always force sync flips because we currently wait
// for composition to finish before submitting.
// If we want to do async + composite, we should set up syncfile stuff and have DRM wait on it.

View file

@ -43,6 +43,14 @@ extern bool g_bForceHDRSupportDebug;
extern EStreamColorspace g_ForcedNV12ColorSpace;
enum TakeScreenshotMode_t
{
TAKE_SCREENSHOT_BASEPLANE_ONLY = 1, // Just the game/base plane
TAKE_SCREENSHOT_ALL_REAL_LAYERS = 2, // Just the game + steam overlay/perf overlays
TAKE_SCREENSHOT_FULL_COMPOSITION = 3, // Everything, but no display color management + no mura
TAKE_SCREENSHOT_SCREEN_BUFFER = 4, // Yes, mura comp, color management! Exactly what we put on the screen.
};
class MouseCursor
{
public:
@ -129,7 +137,7 @@ extern bool g_bFSRActive;
extern uint32_t inputCounter;
void nudge_steamcompmgr( void );
void take_screenshot( void );
void take_screenshot( int flags = TAKE_SCREENSHOT_BASEPLANE_ONLY );
void force_repaint( void );
extern void mangoapp_update( uint64_t visible_frametime, uint64_t app_frametime_ns, uint64_t latency_ns );