Move vkAcquireNextImageKHR() into waitToRender() so it can overlap with new frame arrival

This commit is contained in:
Cameron Gutman 2023-12-17 16:47:38 -06:00
parent 708bec2937
commit 058739321c
2 changed files with 52 additions and 13 deletions

View file

@ -107,6 +107,9 @@ PlVkRenderer::PlVkRenderer(IFFmpegRenderer* backendRenderer) :
PlVkRenderer::~PlVkRenderer() PlVkRenderer::~PlVkRenderer()
{ {
// The render context must have been cleaned up by now
SDL_assert(!m_HasPendingSwapchainFrame);
if (m_Vulkan != nullptr) { if (m_Vulkan != nullptr) {
for (int i = 0; i < (int)SDL_arraysize(m_Overlays); i++) { for (int i = 0; i < (int)SDL_arraysize(m_Overlays); i++) {
pl_tex_destroy(m_Vulkan->gpu, &m_Overlays[i].overlay.tex); pl_tex_destroy(m_Vulkan->gpu, &m_Overlays[i].overlay.tex);
@ -594,10 +597,32 @@ bool PlVkRenderer::isSurfacePresentationSupportedByPhysicalDevice(VkPhysicalDevi
return false; return false;
} }
void PlVkRenderer::waitToRender()
{
// Get the next swapchain buffer for rendering. If this fails, renderFrame()
// will try again.
//
// NB: After calling this successfully, we *MUST* call pl_swapchain_submit_frame(),
// hence the implementation of cleanupRenderContext() which does just this in case
// renderFrame() wasn't called after waitToRender().
if (pl_swapchain_start_frame(m_Swapchain, &m_SwapchainFrame)) {
m_HasPendingSwapchainFrame = true;
}
}
void PlVkRenderer::cleanupRenderContext()
{
// We have to submit a pending swapchain frame before shutting down
// in order to release a mutex that pl_swapchain_start_frame() acquires.
if (m_HasPendingSwapchainFrame) {
pl_swapchain_submit_frame(m_Swapchain);
m_HasPendingSwapchainFrame = false;
}
}
void PlVkRenderer::renderFrame(AVFrame *frame) void PlVkRenderer::renderFrame(AVFrame *frame)
{ {
pl_frame mappedFrame, targetFrame; pl_frame mappedFrame, targetFrame;
pl_swapchain_frame swapchainFrame;
if (!mapAvFrameToPlacebo(frame, &mappedFrame)) { if (!mapAvFrameToPlacebo(frame, &mappedFrame)) {
// This function logs internally // This function logs internally
@ -618,10 +643,13 @@ void PlVkRenderer::renderFrame(AVFrame *frame)
texturesToDestroy.reserve(Overlay::OverlayMax); texturesToDestroy.reserve(Overlay::OverlayMax);
overlays.reserve(Overlay::OverlayMax); overlays.reserve(Overlay::OverlayMax);
// Get the next swapchain buffer for rendering // Normally waitToRender() would already have this populated for us, but in case
// // it failed, we will try again here before resetting the renderer.
// NB: After calling this successfully, we *MUST* call pl_swapchain_submit_frame()! if (!m_HasPendingSwapchainFrame) {
if (!pl_swapchain_start_frame(m_Swapchain, &swapchainFrame)) { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Retrying after pl_swapchain_start_frame() failed in waitToRender()");
if (!pl_swapchain_start_frame(m_Swapchain, &m_SwapchainFrame)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"pl_swapchain_start_frame() failed"); "pl_swapchain_start_frame() failed");
@ -632,7 +660,11 @@ void PlVkRenderer::renderFrame(AVFrame *frame)
goto UnmapExit; goto UnmapExit;
} }
pl_frame_from_swapchain(&targetFrame, &swapchainFrame); // After calling this successfully, we *MUST* call pl_swapchain_submit_frame()!
m_HasPendingSwapchainFrame = true;
}
pl_frame_from_swapchain(&targetFrame, &m_SwapchainFrame);
// We perform minimal processing under the overlay lock to avoid blocking threads updating the overlay // We perform minimal processing under the overlay lock to avoid blocking threads updating the overlay
SDL_AtomicLock(&m_OverlayLock); SDL_AtomicLock(&m_OverlayLock);
@ -713,6 +745,7 @@ void PlVkRenderer::renderFrame(AVFrame *frame)
} }
// Submit the frame for display and swap buffers // Submit the frame for display and swap buffers
m_HasPendingSwapchainFrame = false;
if (!pl_swapchain_submit_frame(m_Swapchain)) { if (!pl_swapchain_submit_frame(m_Swapchain)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"pl_swapchain_submit_frame() failed"); "pl_swapchain_submit_frame() failed");

View file

@ -14,6 +14,8 @@ public:
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override; virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override;
virtual void renderFrame(AVFrame* frame) override; virtual void renderFrame(AVFrame* frame) override;
virtual bool testRenderFrame(AVFrame* frame) override; virtual bool testRenderFrame(AVFrame* frame) override;
virtual void waitToRender() override;
virtual void cleanupRenderContext() override;
virtual void notifyOverlayUpdated(Overlay::OverlayType) override; virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
virtual int getRendererAttributes() override; virtual int getRendererAttributes() override;
virtual int getDecoderCapabilities() override; virtual int getDecoderCapabilities() override;
@ -49,6 +51,10 @@ private:
pl_tex m_Textures[PL_MAX_PLANES] = {}; pl_tex m_Textures[PL_MAX_PLANES] = {};
pl_color_space m_LastColorspace = {}; pl_color_space m_LastColorspace = {};
// Pending swapchain state shared between waitToRender(), renderFrame(), and cleanupRenderContext()
pl_swapchain_frame m_SwapchainFrame = {};
bool m_HasPendingSwapchainFrame = false;
// Overlay state // Overlay state
SDL_SpinLock m_OverlayLock = 0; SDL_SpinLock m_OverlayLock = 0;
struct { struct {