@@ -96,19 +96,22 @@ static vk::SurfaceFormatKHR chooseSwapSurfaceFormat(const std::vector<vk::Surfac
9696 return availableFormats[0 ];
9797}
9898
99- static vk::PresentModeKHR chooseSwapPresentMode ( const std::vector<vk::PresentModeKHR>& availablePresentModes, vk::PresentModeKHR desiredMode = vk::PresentModeKHR::eMailbox )
99+ vk::PresentModeKHR GPUDisplayBackendVulkan::chooseSwapPresentMode ( )
100100{
101- for (const auto & availablePresentMode : availablePresentModes) {
102- if (availablePresentMode == desiredMode) {
103- return availablePresentMode;
101+ // Lowest latency first. VSync: no tearing, MAILBOX, then FIFO_LATEST_READY (shows the newest ready image at each vblank). No VSync: IMMEDIATE, else the same (often no IMMEDIATE on Wayland). FIFO is always supported.
102+ const bool vsync = mDisplay ->cfgR ().drawQualityVSync ;
103+ const auto & available = mSwapChainDetails .presentModes ;
104+ for (vk::PresentModeKHR mode : {vk::PresentModeKHR::eImmediate, vk::PresentModeKHR::eMailbox, vk::PresentModeKHR::eFifoLatestReady, vk::PresentModeKHR::eFifo}) {
105+ if ((mode == vk::PresentModeKHR::eImmediate && vsync) || (mode == vk::PresentModeKHR::eFifoLatestReady && !mFifoLatestReadySupported ) || std::find (available.begin (), available.end (), mode) == available.end ()) {
106+ continue ;
104107 }
108+ if (mode != (vsync ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eImmediate) && !mPresentModeErrorShown ) {
109+ mPresentModeErrorShown = true ;
110+ GPUError (" VULKAN ERROR: Desired present mode %s not available, using %s" , vsync ? " MAILBOX" : " IMMEDIATE" , vk::to_string (mode).c_str ());
111+ }
112+ return mode;
105113 }
106- static bool errorShown = false ;
107- if (!errorShown) {
108- errorShown = true ;
109- GPUError (" VULKAN ERROR: Desired present mode not available, using FIFO mode" );
110- }
111- return vk::PresentModeKHR::eFifo;
114+ return vk::PresentModeKHR::eFifo; // Unreachable, FIFO is always supported
112115}
113116
114117vk::Extent2D GPUDisplayBackendVulkan::chooseSwapExtent (const vk::SurfaceCapabilitiesKHR& capabilities)
@@ -532,6 +535,19 @@ void GPUDisplayBackendVulkan::createDevice()
532535 }
533536 mSmoothLinesSupported = getFeatures (mPhysicalDevice , reqDeviceFeatures).get <vk::PhysicalDeviceVulkan14Features>().smoothLines ;
534537 reqDeviceFeatures.get <vk::PhysicalDeviceVulkan14Features>().smoothLines = mSmoothLinesSupported ;
538+ std::vector<const char *> deviceExtensions = reqDeviceExtensions;
539+ vk::PhysicalDevicePresentModeFifoLatestReadyFeaturesKHR fifoLatestReadyFeatures{};
540+ const std::vector<vk::ExtensionProperties> availableDeviceExtensions = mPhysicalDevice .enumerateDeviceExtensionProperties (nullptr );
541+ for (const char * ext : {VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME , VK_EXT_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME }) { // Optional, same feature struct for both
542+ if (std::any_of (availableDeviceExtensions.begin (), availableDeviceExtensions.end (), [ext](const auto & e) { return strcmp (ext, e.extensionName ) == 0 ; })) {
543+ mFifoLatestReadySupported = mPhysicalDevice .getFeatures2 <vk::PhysicalDeviceFeatures2, vk::PhysicalDevicePresentModeFifoLatestReadyFeaturesKHR>().get <vk::PhysicalDevicePresentModeFifoLatestReadyFeaturesKHR>().presentModeFifoLatestReady ;
544+ if (mFifoLatestReadySupported ) {
545+ deviceExtensions.emplace_back (ext);
546+ fifoLatestReadyFeatures.presentModeFifoLatestReady = VK_TRUE ;
547+ }
548+ break ;
549+ }
550+ }
535551
536552 updateSwapChainDetails (mPhysicalDevice );
537553 vk::PhysicalDeviceProperties deviceProperties = mPhysicalDevice .getProperties ();
@@ -545,7 +561,7 @@ void GPUDisplayBackendVulkan::createDevice()
545561 mStencilSupported = (bool )(depth64FormatProperties.optimalTilingFeatures & vk::FormatFeatureFlagBits::eDepthStencilAttachment);
546562 bool mailboxSupported = std::find (mSwapChainDetails .presentModes .begin (), mSwapChainDetails .presentModes .end (), vk::PresentModeKHR::eMailbox) != mSwapChainDetails .presentModes .end ();
547563 if (mDisplay ->GetProcessingSettings ().debugLevel >= 2 ) {
548- GPUInfo (" Max MSAA: %d, 32 bit Z buffer %d, 32 bit Z buffer + stencil buffer %d, Mailbox present mode %d, smooth lines %d\n " , (int32_t )mMaxMSAAsupported , (int32_t )mZSupported , (int32_t )mStencilSupported , (int32_t )mailboxSupported, (int32_t )mSmoothLinesSupported );
564+ GPUInfo (" Max MSAA: %d, 32 bit Z buffer %d, 32 bit Z buffer + stencil buffer %d, Mailbox present mode %d, FIFO latest ready present mode %d, smooth lines %d\n " , (int32_t )mMaxMSAAsupported , (int32_t )mZSupported , (int32_t )mStencilSupported , (int32_t )mailboxSupported, ( int32_t ) mFifoLatestReadySupported , (int32_t )mSmoothLinesSupported );
549565 }
550566
551567 vk::DeviceQueueCreateInfo queueCreateInfo{};
@@ -557,9 +573,13 @@ void GPUDisplayBackendVulkan::createDevice()
557573 deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo;
558574 deviceCreateInfo.queueCreateInfoCount = 1 ;
559575 deviceCreateInfo.pNext = &reqDeviceFeatures.get <vk::PhysicalDeviceFeatures2>();
576+ if (mFifoLatestReadySupported ) {
577+ fifoLatestReadyFeatures.pNext = &reqDeviceFeatures.get <vk::PhysicalDeviceFeatures2>();
578+ deviceCreateInfo.pNext = &fifoLatestReadyFeatures;
579+ }
560580 deviceCreateInfo.pEnabledFeatures = nullptr ;
561- deviceCreateInfo.enabledExtensionCount = static_cast <uint32_t >(reqDeviceExtensions .size ());
562- deviceCreateInfo.ppEnabledExtensionNames = reqDeviceExtensions .data ();
581+ deviceCreateInfo.enabledExtensionCount = static_cast <uint32_t >(deviceExtensions .size ());
582+ deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions .data ();
563583 mDevice = mPhysicalDevice .createDevice (deviceCreateInfo, nullptr );
564584 VULKAN_HPP_DEFAULT_DISPATCHER .init (mDevice );
565585 mGraphicsQueue = mDevice .getQueue (mGraphicsFamily , 0 );
@@ -720,7 +740,10 @@ void GPUDisplayBackendVulkan::createSwapChain(vk::SwapchainKHR oldSwapChain)
720740{
721741 updateSwapChainDetails (mPhysicalDevice );
722742 mSurfaceFormat = chooseSwapSurfaceFormat (mSwapChainDetails .formats );
723- mPresentMode = chooseSwapPresentMode (mSwapChainDetails .presentModes , mDisplay ->cfgR ().drawQualityVSync ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eImmediate);
743+ mPresentMode = chooseSwapPresentMode ();
744+ if (mDisplay ->GetProcessingSettings ().debugLevel >= 2 ) {
745+ GPUInfo (" Vulkan present mode %s (VSync %d)" , vk::to_string (mPresentMode ).c_str (), (int32_t )mDisplay ->cfgR ().drawQualityVSync );
746+ }
724747 vk::Extent2D extent = chooseSwapExtent (mSwapChainDetails .capabilities );
725748
726749 uint32_t imageCount = std::max<uint32_t >(mSwapChainDetails .capabilities .minImageCount + 1 , mDisplay ->cfg ().vulkan .nFramesInFlight + 1 );
0 commit comments