perf(window): drop dead present-mode queries from swapchain recreate (#45)

CreateSwapchain unconditionally used VK_PRESENT_MODE_FIFO_KHR, but still
ran two vkGetPhysicalDeviceSurfacePresentModesKHR calls plus a heap-allocated
std::vector to enumerate present modes that were never consulted. Delete
them and assign the constant directly.

compositeAlpha is a surface property that does not change across swapchain
recreation, so select it once at construction instead of re-deriving it
(with another heap-allocated vector) on every resize configure. The
vkQueueWaitIdle before recreation is left intact as required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
catbot 2026-06-16 15:28:35 +00:00
commit 9ef554b97e
2 changed files with 28 additions and 29 deletions

View file

@ -405,6 +405,26 @@ Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height
colorFormat = selectedFormat.format; colorFormat = selectedFormat.format;
colorSpace = selectedFormat.colorSpace; colorSpace = selectedFormat.colorSpace;
// Select a supported composite alpha format (not all devices support alpha
// opaque). This is a surface property, so pick it once here rather than on
// every CreateSwapchain. Simply select the first available.
{
VkSurfaceCapabilitiesKHR surfCaps;
Device::CheckVkResult(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(Device::physDevice, vulkanSurface, &surfCaps));
const VkCompositeAlphaFlagBitsKHR compositeAlphaFlags[] = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
};
for (const VkCompositeAlphaFlagBitsKHR compositeAlphaFlag : compositeAlphaFlags) {
if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
compositeAlpha = compositeAlphaFlag;
break;
}
}
}
CreateSwapchain(); CreateSwapchain();
VkCommandBufferAllocateInfo cmdBufAllocateInfo {}; VkCommandBufferAllocateInfo cmdBufAllocateInfo {};
@ -896,18 +916,6 @@ void Window::CreateSwapchain()
} }
// Select a present mode for the swapchain
uint32_t presentModeCount;
Device::CheckVkResult(vkGetPhysicalDeviceSurfacePresentModesKHR(Device::physDevice, vulkanSurface, &presentModeCount, NULL));
assert(presentModeCount > 0);
std::vector<VkPresentModeKHR> presentModes(presentModeCount);
Device::CheckVkResult(vkGetPhysicalDeviceSurfacePresentModesKHR(Device::physDevice, vulkanSurface, &presentModeCount, presentModes.data()));
// The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
// This mode waits for the vertical blank ("v-sync")
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
// Find the transformation of the surface // Find the transformation of the surface
VkSurfaceTransformFlagsKHR preTransform; VkSurfaceTransformFlagsKHR preTransform;
if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
@ -920,22 +928,6 @@ void Window::CreateSwapchain()
preTransform = surfCaps.currentTransform; preTransform = surfCaps.currentTransform;
} }
// Find a supported composite alpha format (not all devices support alpha opaque)
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
// Simply select the first composite alpha format available
std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
};
for (auto& compositeAlphaFlag : compositeAlphaFlags) {
if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
compositeAlpha = compositeAlphaFlag;
break;
};
}
VkSwapchainCreateInfoKHR swapchainCI = {}; VkSwapchainCreateInfoKHR swapchainCI = {};
swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainCI.surface = vulkanSurface; swapchainCI.surface = vulkanSurface;
@ -948,7 +940,9 @@ void Window::CreateSwapchain()
swapchainCI.imageArrayLayers = 1; swapchainCI.imageArrayLayers = 1;
swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapchainCI.queueFamilyIndexCount = 0; swapchainCI.queueFamilyIndexCount = 0;
swapchainCI.presentMode = swapchainPresentMode; // VK_PRESENT_MODE_FIFO_KHR ("v-sync") is guaranteed available per spec, so
// it is used unconditionally — no present-mode enumeration is needed.
swapchainCI.presentMode = VK_PRESENT_MODE_FIFO_KHR;
// Setting oldSwapChain to the saved handle of the previous swapchain aids in resource reuse and makes sure that we can still present already acquired images // Setting oldSwapChain to the saved handle of the previous swapchain aids in resource reuse and makes sure that we can still present already acquired images
swapchainCI.oldSwapchain = oldSwapchain; swapchainCI.oldSwapchain = oldSwapchain;
// Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area

View file

@ -253,6 +253,11 @@ export namespace Crafter {
VkSwapchainKHR swapChain = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE;
VkFormat colorFormat; VkFormat colorFormat;
VkColorSpaceKHR colorSpace; VkColorSpaceKHR colorSpace;
// Supported composite-alpha mode for vulkanSurface. A surface property
// that does not change across swapchain recreation, so it is selected
// once at construction rather than re-derived on every CreateSwapchain
// (i.e. on every resize configure).
VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
VkImage images[numFrames]; VkImage images[numFrames];
VkImageViewCreateInfo imageViews[numFrames]; VkImageViewCreateInfo imageViews[numFrames];
// Tracks whether each swapchain image has been rendered (and thus // Tracks whether each swapchain image has been rendered (and thus