From 058739321c8251ffcc4fc2b37ff673db79828c37 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 17 Dec 2023 16:47:38 -0600 Subject: [PATCH] Move vkAcquireNextImageKHR() into waitToRender() so it can overlap with new frame arrival --- app/streaming/video/ffmpeg-renderers/plvk.cpp | 59 +++++++++++++++---- app/streaming/video/ffmpeg-renderers/plvk.h | 6 ++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/app/streaming/video/ffmpeg-renderers/plvk.cpp b/app/streaming/video/ffmpeg-renderers/plvk.cpp index 1bd7c700..29eeadfa 100644 --- a/app/streaming/video/ffmpeg-renderers/plvk.cpp +++ b/app/streaming/video/ffmpeg-renderers/plvk.cpp @@ -107,6 +107,9 @@ PlVkRenderer::PlVkRenderer(IFFmpegRenderer* backendRenderer) : PlVkRenderer::~PlVkRenderer() { + // The render context must have been cleaned up by now + SDL_assert(!m_HasPendingSwapchainFrame); + if (m_Vulkan != nullptr) { for (int i = 0; i < (int)SDL_arraysize(m_Overlays); i++) { pl_tex_destroy(m_Vulkan->gpu, &m_Overlays[i].overlay.tex); @@ -594,10 +597,32 @@ bool PlVkRenderer::isSurfacePresentationSupportedByPhysicalDevice(VkPhysicalDevi 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) { pl_frame mappedFrame, targetFrame; - pl_swapchain_frame swapchainFrame; if (!mapAvFrameToPlacebo(frame, &mappedFrame)) { // This function logs internally @@ -618,21 +643,28 @@ void PlVkRenderer::renderFrame(AVFrame *frame) texturesToDestroy.reserve(Overlay::OverlayMax); overlays.reserve(Overlay::OverlayMax); - // Get the next swapchain buffer for rendering - // - // NB: After calling this successfully, we *MUST* call pl_swapchain_submit_frame()! - if (!pl_swapchain_start_frame(m_Swapchain, &swapchainFrame)) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "pl_swapchain_start_frame() failed"); + // Normally waitToRender() would already have this populated for us, but in case + // it failed, we will try again here before resetting the renderer. + if (!m_HasPendingSwapchainFrame) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "Retrying after pl_swapchain_start_frame() failed in waitToRender()"); - // Recreate the renderer - SDL_Event event; - event.type = SDL_RENDER_TARGETS_RESET; - SDL_PushEvent(&event); - goto UnmapExit; + if (!pl_swapchain_start_frame(m_Swapchain, &m_SwapchainFrame)) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "pl_swapchain_start_frame() failed"); + + // Recreate the renderer + SDL_Event event; + event.type = SDL_RENDER_TARGETS_RESET; + SDL_PushEvent(&event); + goto UnmapExit; + } + + // After calling this successfully, we *MUST* call pl_swapchain_submit_frame()! + m_HasPendingSwapchainFrame = true; } - pl_frame_from_swapchain(&targetFrame, &swapchainFrame); + pl_frame_from_swapchain(&targetFrame, &m_SwapchainFrame); // We perform minimal processing under the overlay lock to avoid blocking threads updating the overlay SDL_AtomicLock(&m_OverlayLock); @@ -713,6 +745,7 @@ void PlVkRenderer::renderFrame(AVFrame *frame) } // Submit the frame for display and swap buffers + m_HasPendingSwapchainFrame = false; if (!pl_swapchain_submit_frame(m_Swapchain)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "pl_swapchain_submit_frame() failed"); diff --git a/app/streaming/video/ffmpeg-renderers/plvk.h b/app/streaming/video/ffmpeg-renderers/plvk.h index 588fcb4d..51ae0db5 100644 --- a/app/streaming/video/ffmpeg-renderers/plvk.h +++ b/app/streaming/video/ffmpeg-renderers/plvk.h @@ -14,6 +14,8 @@ public: virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override; virtual void renderFrame(AVFrame* frame) override; virtual bool testRenderFrame(AVFrame* frame) override; + virtual void waitToRender() override; + virtual void cleanupRenderContext() override; virtual void notifyOverlayUpdated(Overlay::OverlayType) override; virtual int getRendererAttributes() override; virtual int getDecoderCapabilities() override; @@ -49,6 +51,10 @@ private: pl_tex m_Textures[PL_MAX_PLANES] = {}; 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 SDL_SpinLock m_OverlayLock = 0; struct {