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()
{
// 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");

View file

@ -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 {