@@ -421,6 +421,7 @@ bool PlVkRenderer::isExtensionSupportedByPhysicalDevice(VkPhysicalDevice device,
421421bool PlVkRenderer::initialize (PDECODER_PARAMETERS params)
422422{
423423 m_Window = params->window ;
424+ m_MaxVideoFps = params->frameRate ;
424425
425426 unsigned int instanceExtensionCount = 0 ;
426427 if (!SDL_Vulkan_GetInstanceExtensions (params->window , &instanceExtensionCount, nullptr )) {
@@ -488,18 +489,17 @@ bool PlVkRenderer::initialize(PDECODER_PARAMETERS params)
488489 return false ;
489490 }
490491
491- VkPresentModeKHR presentMode;
492492 if (params->enableVsync ) {
493493 // FIFO mode improves frame pacing compared with Mailbox, especially for
494494 // platforms like X11 that lack a VSyncSource implementation for Pacer.
495- presentMode = VK_PRESENT_MODE_FIFO_KHR ;
495+ m_VkPresentMode = VK_PRESENT_MODE_FIFO_KHR ;
496496 }
497497 else {
498498 // We want immediate mode for V-Sync disabled if possible
499499 if (isPresentModeSupportedByPhysicalDevice (m_Vulkan->phys_device , VK_PRESENT_MODE_IMMEDIATE_KHR )) {
500500 SDL_LogInfo (SDL_LOG_CATEGORY_APPLICATION ,
501501 " Using Immediate present mode with V-Sync disabled" );
502- presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR ;
502+ m_VkPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR ;
503503 }
504504 else {
505505 SDL_LogWarn (SDL_LOG_CATEGORY_APPLICATION ,
@@ -509,41 +509,26 @@ bool PlVkRenderer::initialize(PDECODER_PARAMETERS params)
509509 if (isPresentModeSupportedByPhysicalDevice (m_Vulkan->phys_device , VK_PRESENT_MODE_FIFO_RELAXED_KHR )) {
510510 SDL_LogInfo (SDL_LOG_CATEGORY_APPLICATION ,
511511 " Using FIFO Relaxed present mode with V-Sync disabled" );
512- presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR ;
512+ m_VkPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR ;
513513 }
514514 // Mailbox at least provides non-blocking behavior
515515 else if (isPresentModeSupportedByPhysicalDevice (m_Vulkan->phys_device , VK_PRESENT_MODE_MAILBOX_KHR )) {
516516 SDL_LogInfo (SDL_LOG_CATEGORY_APPLICATION ,
517517 " Using Mailbox present mode with V-Sync disabled" );
518- presentMode = VK_PRESENT_MODE_MAILBOX_KHR ;
518+ m_VkPresentMode = VK_PRESENT_MODE_MAILBOX_KHR ;
519519 }
520520 // FIFO is always supported
521521 else {
522522 SDL_LogInfo (SDL_LOG_CATEGORY_APPLICATION ,
523523 " Using FIFO present mode with V-Sync disabled" );
524- presentMode = VK_PRESENT_MODE_FIFO_KHR ;
524+ m_VkPresentMode = VK_PRESENT_MODE_FIFO_KHR ;
525525 }
526526 }
527527 }
528528
529- pl_vulkan_swapchain_params vkSwapchainParams = {};
530- vkSwapchainParams.surface = m_VkSurface;
531- vkSwapchainParams.present_mode = presentMode;
532- vkSwapchainParams.swapchain_depth = 1 ; // No queued frames
533- #if PL_API_VER >= 338
534- vkSwapchainParams.disable_10bit_sdr = true ; // Some drivers don't dither 10-bit SDR output correctly
535- #endif
536-
537- {
538- // Don't let Qt take DRM master from us during pl_vulkan_create_swapchain()
539- DrmMasterLocker locker;
540-
541- m_Swapchain = pl_vulkan_create_swapchain (m_Vulkan, &vkSwapchainParams);
542- if (m_Swapchain == nullptr ) {
543- SDL_LogError (SDL_LOG_CATEGORY_APPLICATION ,
544- " pl_vulkan_create_swapchain() failed" );
545- return false ;
546- }
529+ // Start with a swapchain that is double-buffered for lowest display latency
530+ if (!createSwapchain (1 )) {
531+ return false ;
547532 }
548533
549534 m_Renderer = pl_renderer_create (m_Log, m_Vulkan->gpu );
@@ -622,6 +607,35 @@ bool PlVkRenderer::initialize(PDECODER_PARAMETERS params)
622607 return true ;
623608}
624609
610+
611+ bool PlVkRenderer::createSwapchain (int depth)
612+ {
613+ pl_swapchain_destroy (&m_Swapchain);
614+
615+ pl_vulkan_swapchain_params vkSwapchainParams = {};
616+ vkSwapchainParams.surface = m_VkSurface;
617+ vkSwapchainParams.present_mode = m_VkPresentMode;
618+ vkSwapchainParams.swapchain_depth = depth;
619+ #if PL_API_VER >= 338
620+ vkSwapchainParams.disable_10bit_sdr = true ; // Some drivers don't dither 10-bit SDR output correctly
621+ #endif
622+
623+ {
624+ // Don't let Qt take DRM master from us during pl_vulkan_create_swapchain()
625+ DrmMasterLocker locker;
626+
627+ m_Swapchain = pl_vulkan_create_swapchain (m_Vulkan, &vkSwapchainParams);
628+ if (m_Swapchain == nullptr ) {
629+ SDL_LogError (SDL_LOG_CATEGORY_APPLICATION ,
630+ " pl_vulkan_create_swapchain() failed" );
631+ return false ;
632+ }
633+ }
634+
635+ m_SwapchainDepth = depth;
636+ return true ;
637+ }
638+
625639bool PlVkRenderer::prepareDecoderContext (AVCodecContext *context, AVDictionary **)
626640{
627641 if (m_HwDeviceCtx) {
@@ -991,6 +1005,10 @@ void PlVkRenderer::renderFrame(AVFrame *frame)
9911005 targetFrame.crop .x1 = dst.x + dst.w ;
9921006 targetFrame.crop .y1 = dst.y + dst.h ;
9931007
1008+ #ifdef PLVK_USE_DYNAMIC_SWAPCHAIN_DEPTH
1009+ Uint32 renderStartTime = SDL_GetTicks ();
1010+ #endif
1011+
9941012 // Render the video image and overlays into the swapchain buffer
9951013 targetFrame.num_overlays = (int )overlays.size ();
9961014 targetFrame.overlays = overlays.data ();
@@ -1013,6 +1031,32 @@ void PlVkRenderer::renderFrame(AVFrame *frame)
10131031 goto UnmapExit;
10141032 }
10151033
1034+ #ifdef PLVK_USE_DYNAMIC_SWAPCHAIN_DEPTH
1035+ // Trigger a switch to triple-buffered mode if our frame presentation time
1036+ // exceeds 110% of the frame interval for half a second of frames.
1037+ if (SDL_GetTicks () - renderStartTime > (1100U / m_MaxVideoFps)) {
1038+ m_DelayedPresents++;
1039+ }
1040+ else if (m_DelayedPresents > 0 ) {
1041+ m_DelayedPresents--;
1042+ }
1043+
1044+ if (m_DelayedPresents == m_MaxVideoFps / 2 && m_SwapchainDepth < 2 ) {
1045+ SDL_LogWarn (SDL_LOG_CATEGORY_APPLICATION ,
1046+ " Switching to triple-buffered swapchain after delayed presentations" );
1047+ if (!createSwapchain (2 )) {
1048+ // Recreate the renderer
1049+ SDL_Event event;
1050+ event.type = SDL_RENDER_DEVICE_RESET ;
1051+ SDL_PushEvent (&event);
1052+ goto UnmapExit;
1053+ }
1054+
1055+ // Restore the swapchain's colorspace from the previous swapchain frame
1056+ pl_swapchain_colorspace_hint (m_Swapchain, &targetFrame.color );
1057+ }
1058+ #endif
1059+
10161060#ifdef Q_OS_WIN32
10171061 // On Windows, we swap buffers here instead of waitToRender()
10181062 // to avoid some performance problems on Nvidia GPUs.
0 commit comments