I recently started learning Vulkan, and have been using this (vulkan-tutorial[.]com) tutorial to start. I’ve gone all the way through the Vertex Buffer section, and have the validation layers active. I have some flickering issues, and I’ve started troubleshooting which has lead to the question alluded to in the title.
Question:
Why doesn’t vkGetPhysicalDeviceSurfacePresentModesKHR()
detect all supported presentation modes as defined by VkPresentModeKHR
?
Explanation:
My investigation lead to evaluating what VkPresentModeKHR
was being chosen. The code that chooses the present mode is as follows:
VkPresentModeKHR GraphicsManager::chooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes) {
//Check for availability of triple buffer
for (const auto& availablePresentMode : availablePresentModes) {
if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
return availablePresentMode;
}
}
//Fallback mode with guaranteed support
return VK_PRESENT_MODE_FIFO_KHR;
}
To my surprise, I discovered that the fallback VK_PRESENT_MODE_FIFO_KHR
was being chosen. Out of curiosity, I inserted return VK_PRESENT_MODE_MAILBOX_KHR;
as the first line of the function, to force the VK_PRESENT_MODE_MAILBOX_KHR
present mode, and the flickering stopped. I then investigated how availablePresentModes
was determined.
My class has the struct:
//Swap chain support details
struct SwapChainSupportDetails {
VkSurfaceCapabilitiesKHR capabilities;
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> presentModes;
};
I get the SwapChainSupportDetails
with a function call:
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
GraphicsManager::SwapChainSupportDetails GraphicsManager::querySwapChainSupport(VkPhysicalDevice device) {
SwapChainSupportDetails details;
//Basic surface capabilities
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.capabilities);
//Surface formats
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr);
if (formatCount != 0) {
details.formats.resize(formatCount);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.formats.data());
}
//Presentation modes
//!Does not return all compatible present modes
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr);
if (presentModeCount != 0) {
details.presentModes.resize(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.presentModes.data());
}
return details;
}
The function call vkGetPhysicalDeviceSurfacePresentModesKHR()
fills in details.presentModes
with VK_PRESENT_MODE_IMMEDIATE_KHR
and VK_PRESENT_MODE_FIFO_KHR
.
This explains why my call to chooseSwapPresentMode()
chooses the fallback.
VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
As I stated at the beginning, I can force VK_PRESENT_MODE_MAILBOX_KHR
, and I don’t get any errors from the validation layers, the program doesn’t crash, and the flickering stops. Clearly this means that VK_PRESENT_MODE_MAILBOX_KHR
is compatible, but Vulkan doesn’t return it as a compatible mode in the function call vkGetPhysicalDeviceSurfacePresentModesKHR()
, why?
Specs:
OS: Arch Linux
GPU: NVIDIA GTX 1660 Ti Mobile
Driver: nvidia 535.98-2
Language: C++
My CPU has integrated graphics, but my program only sees the 1660 as compatible, and I have verified that my program is running on the 1660 with the command prime-smi
as well as verifying the vendor code of the gpu in my program matches NVIDIA.