Skip to content

Commit 9e4db9f

Browse files
committed
GPU Vulkan Display: Improve present mode selection
1 parent a3f4839 commit 9e4db9f

2 files changed

Lines changed: 40 additions & 14 deletions

File tree

‎GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.cxx‎

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

114117
vk::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);

‎GPU/GPUTracking/display/backend/GPUDisplayBackendVulkan.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend
9090
using FeatureChain = vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan11Features, vk::PhysicalDeviceVulkan12Features, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceVulkan14Features, vk::PhysicalDeviceSwapchainMaintenance1FeaturesKHR, vk::PhysicalDevicePresentIdFeaturesKHR, vk::PhysicalDevicePresentWaitFeaturesKHR>;
9191
double checkDevice(vk::PhysicalDevice device, const std::vector<const char*>& reqDeviceExtensions, const FeatureChain& reqDeviceFeatures, bool silent = false);
9292
vk::Extent2D chooseSwapExtent(const vk::SurfaceCapabilitiesKHR& capabilities);
93+
vk::PresentModeKHR chooseSwapPresentMode();
9394
void transitionImageLayout(vk::CommandBuffer commandBuffer, vk::Image image, vk::Format format, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
9495
VulkanBuffer createBuffer(size_t size, const void* srcData = nullptr, vk::BufferUsageFlags type = vk::BufferUsageFlagBits::eVertexBuffer, int32_t deviceMemory = 1);
9596
void writeToBuffer(VulkanBuffer& buffer, size_t size, const void* srcData);
@@ -212,6 +213,8 @@ class GPUDisplayBackendVulkan : public GPUDisplayBackend
212213
bool mZActive = false;
213214
bool mSmoothLinesSupported = false; // Optional Vulkan 1.4 feature smoothLines, enabled if available
214215
bool mSmoothLines = false;
216+
bool mPresentModeErrorShown = false;
217+
bool mFifoLatestReadySupported = false; // Optional present mode FIFO_LATEST_READY (VK_KHR / VK_EXT_present_mode_fifo_latest_ready), enabled if available
215218
bool mStrictLines = false;
216219
bool mZSupported = false;
217220
bool mStencilSupported = false;

0 commit comments

Comments
 (0)