rendervulkan: Seamless full -> deferred composition switch

This commit is contained in:
Joshua Ashton 2023-06-27 11:19:25 +01:00 committed by Joshie
parent 31eefd41a0
commit 5e99ecb46b
3 changed files with 58 additions and 56 deletions

View file

@ -105,8 +105,6 @@ struct VulkanOutput_t
VkFence acquireFence;
uint32_t nOutImage; // swapchain index in nested mode, or ping/pong between two RTs
uint32_t nOutImagePartial;
uint32_t nOutPresentImagePartial;
std::vector<std::shared_ptr<CVulkanTexture>> outputImages;
std::vector<std::shared_ptr<CVulkanTexture>> outputImagesPartialOverlay;
@ -2891,7 +2889,7 @@ std::shared_ptr<CVulkanTexture> vulkan_create_debug_white_texture()
void vulkan_present_to_openvr( void )
{
//static auto texture = vulkan_create_debug_white_texture();
auto texture = vulkan_get_last_output_image( false );
auto texture = vulkan_get_last_output_image( false, false );
vr::VRVulkanTextureData_t data =
{
@ -3088,8 +3086,6 @@ bool vulkan_remake_output_images()
g_device.waitIdle();
pOutput->nOutImage = 0;
pOutput->nOutImagePartial = 0;
pOutput->nOutPresentImagePartial = 2;
// Delete screenshot image to be remade if needed
for (auto& pScreenshotImage : pOutput->pScreenshotImages)
@ -3578,42 +3574,21 @@ bool vulkan_screenshot( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVu
return true;
}
std::unique_ptr<std::thread> partial_wait_thread;
uint64_t partial_sequence = 0;
std::unique_ptr<std::thread> defer_wait_thread;
uint64_t defer_sequence = 0;
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pPipewireTexture, bool partial )
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pPipewireTexture, bool partial, bool defer )
{
if ( partial_wait_thread )
if ( defer_wait_thread )
{
partial_wait_thread->join();
partial_wait_thread = nullptr;
defer_wait_thread->join();
defer_wait_thread = nullptr;
g_device.resetCmdBuffers(partial_sequence);
partial_sequence = 0;
g_device.resetCmdBuffers(defer_sequence);
defer_sequence = 0;
}
if ( partial )
{
if ( !g_bWasPartialComposite )
{
g_output.nOutPresentImagePartial = g_output.nOutImage;
g_output.nOutImagePartial = g_output.nOutImage;
}
else
{
g_output.nOutPresentImagePartial = g_output.nOutImagePartial;
}
g_output.nOutImagePartial = ( g_output.nOutImagePartial + 1 ) % 3;
}
else
{
if (g_bWasPartialComposite)
{
g_output.nOutImage = ( g_output.nOutImagePartial + 1 ) % 3;
}
}
auto compositeImage = partial ? g_output.outputImagesPartialOverlay[ g_output.nOutImagePartial ] : g_output.outputImages[ g_output.nOutImage ];
auto compositeImage = partial ? g_output.outputImagesPartialOverlay[ g_output.nOutImage ] : g_output.outputImages[ g_output.nOutImage ];
auto cmdBuffer = g_device.commandBuffer();
@ -3797,36 +3772,52 @@ bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVul
uint64_t sequence = g_device.submit(std::move(cmdBuffer));
if ( partial )
if ( defer )
{
partial_wait_thread = std::make_unique<std::thread>([sequence]
defer_wait_thread = std::make_unique<std::thread>([sequence]
{
g_device.wait(sequence, false);
});
defer_sequence = sequence;
}
else
{
g_device.wait(sequence);
}
if ( !BIsSDLSession() )
{
g_output.nOutImage = !g_output.nOutImage;
}
if ( !BIsSDLSession() )
{
g_output.nOutImage = ( g_output.nOutImage + 1 ) % 3;
}
return true;
}
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( bool partial )
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( bool partial, bool defer )
{
// Get previous image ( +2 )
// 1 2 3
// |
// |
uint32_t nRegularImage = ( g_output.nOutImage + 2 ) % 3;
// Get previous previous image ( +1 )
// 1 2 3
// |
// |
uint32_t nDeferredImage = ( g_output.nOutImage + 1 ) % 3;
uint32_t nOutImage = defer ? nDeferredImage : nRegularImage;
if ( partial )
{
uint32_t nOutImage = g_output.nOutPresentImagePartial;
//vk_log.infof( "Partial overlay frame: %d", nOutImage );
//vk_log.infof( "Partial overlay frame: %d", nDeferredImage );
return g_output.outputImagesPartialOverlay[ nOutImage ];
}
return g_output.outputImages[ !g_output.nOutImage ];
return g_output.outputImages[ nOutImage ];
}
bool vulkan_primary_dev_id(dev_t *id)

View file

@ -329,8 +329,8 @@ 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( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture, bool partial );
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( bool partial );
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture, bool partial, bool deferred );
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);
void vulkan_present_to_window( void );

View file

@ -2435,6 +2435,7 @@ paint_all(bool async)
bNeedsFullComposite |= !!(g_uCompositeDebug & CompositeDebugFlag::Heatmap);
static int g_nLastSingleOverlayZPos = 0;
static bool g_bWasCompositing = false;
if ( !bNeedsFullComposite && !bWantsPartialComposite )
{
@ -2443,6 +2444,7 @@ paint_all(bool async)
{
bDoComposite = false;
g_bWasPartialComposite = false;
g_bWasCompositing = false;
if ( frameInfo.layerCount == 2 )
g_nLastSingleOverlayZPos = frameInfo.layers[1].zpos;
}
@ -2497,6 +2499,13 @@ paint_all(bool async)
}
}
// If we ever promoted from partial -> full, for the first frame
// do NOT defer this partial composition.
// We were already stalling for the full composition before, so it's not an issue
// for latency, we just need to make sure we get 1 partial frame that isn't deferred
// in time so we don't lose layers.
bool bDefer = !bNeedsFullComposite && ( !g_bWasCompositing || g_bWasPartialComposite );
// If doing a partial composition then remove the baseplane
// from our frameinfo to composite.
if ( !bNeedsFullComposite )
@ -2511,14 +2520,16 @@ paint_all(bool async)
compositeFrameInfo.shaperLut[ nEOTF ] = nullptr;
compositeFrameInfo.lut3D[ nEOTF ] = nullptr;
}
// If using composite debug markers, make sure we mark them as partial
// so we know!
if ( g_uCompositeDebug & CompositeDebugFlag::Markers )
g_uCompositeDebug |= CompositeDebugFlag::Markers_Partial;
}
bool bResult = vulkan_composite( &compositeFrameInfo, pPipewireTexture, !bNeedsFullComposite );
// If using composite debug markers, make sure we mark them as partial
// so we know!
if ( bDefer && !!( g_uCompositeDebug & CompositeDebugFlag::Markers ) )
g_uCompositeDebug |= CompositeDebugFlag::Markers_Partial;
bool bResult = vulkan_composite( &compositeFrameInfo, pPipewireTexture, !bNeedsFullComposite, bDefer );
g_bWasCompositing = true;
g_uCompositeDebug &= ~CompositeDebugFlag::Markers_Partial;
@ -2559,7 +2570,7 @@ paint_all(bool async)
baseLayer->opacity = 1.0;
baseLayer->zpos = g_zposBase;
baseLayer->tex = vulkan_get_last_output_image( false );
baseLayer->tex = vulkan_get_last_output_image( false, false );
baseLayer->fbid = baseLayer->tex->fbid();
baseLayer->applyColorMgmt = false;
baseLayer->allowBlending = false;
@ -2571,7 +2582,7 @@ paint_all(bool async)
}
else
{
if ( g_bWasPartialComposite )
if ( g_bWasPartialComposite || !bDefer )
{
presentCompFrameInfo.applyOutputColorMgmt = true;
presentCompFrameInfo.layerCount = 2;
@ -2585,7 +2596,7 @@ paint_all(bool async)
overlayLayer->opacity = 1.0;
overlayLayer->zpos = g_zposOverlay;
overlayLayer->tex = vulkan_get_last_output_image( true );
overlayLayer->tex = vulkan_get_last_output_image( true, bDefer );
overlayLayer->fbid = overlayLayer->tex->fbid();
overlayLayer->applyColorMgmt = true;
overlayLayer->allowBlending = true;