Merge pull request 'perf(window): hoist invariant per-frame Vulkan info structs to members' (#78) from claude/issue-43 into master
This commit is contained in:
commit
fa35d86021
2 changed files with 68 additions and 47 deletions
|
|
@ -430,6 +430,58 @@ Window::Window(std::uint32_t width, std::uint32_t height) : width(width), height
|
||||||
submitInfo.pSignalSemaphores = &semaphores.renderComplete;
|
submitInfo.pSignalSemaphores = &semaphores.renderComplete;
|
||||||
submitInfo.pNext = VK_NULL_HANDLE;
|
submitInfo.pNext = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
// Per-frame info structs: everything that never varies between frames is
|
||||||
|
// set here once. Render() only patches the barriers' image/oldLayout.
|
||||||
|
cmdBufInfo = {};
|
||||||
|
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
|
||||||
|
const VkImageSubresourceRange range {
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transition into VK_IMAGE_LAYOUT_GENERAL before recording passes. image
|
||||||
|
// and oldLayout are patched per frame (oldLayout depends on first use).
|
||||||
|
acquireBarrier = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.srcAccessMask = 0,
|
||||||
|
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = VK_NULL_HANDLE,
|
||||||
|
.subresourceRange = range,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Transition back to PRESENT_SRC_KHR after the passes. Only image varies.
|
||||||
|
presentBarrier = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
|
.dstAccessMask = 0,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
||||||
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
|
.image = VK_NULL_HANDLE,
|
||||||
|
.subresourceRange = range,
|
||||||
|
};
|
||||||
|
|
||||||
|
// pImageIndices/pSwapchains point at members, so they follow value changes
|
||||||
|
// (currentBuffer each frame, swapChain across recreation) on their own.
|
||||||
|
// The render-complete wait semaphore is fixed for the window's lifetime.
|
||||||
|
presentInfo = {};
|
||||||
|
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
|
presentInfo.pNext = NULL;
|
||||||
|
presentInfo.swapchainCount = 1;
|
||||||
|
presentInfo.pSwapchains = &swapChain;
|
||||||
|
presentInfo.pImageIndices = ¤tBuffer;
|
||||||
|
presentInfo.waitSemaphoreCount = 1;
|
||||||
|
presentInfo.pWaitSemaphores = &semaphores.renderComplete;
|
||||||
|
|
||||||
lastMousePos = {0,0};
|
lastMousePos = {0,0};
|
||||||
mouseDelta = {0,0};
|
mouseDelta = {0,0};
|
||||||
currentMousePos = {0,0};
|
currentMousePos = {0,0};
|
||||||
|
|
@ -689,18 +741,8 @@ void Window::Render() {
|
||||||
submitInfo.commandBufferCount = 1;
|
submitInfo.commandBufferCount = 1;
|
||||||
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||||
|
|
||||||
VkCommandBufferBeginInfo cmdBufInfo {};
|
|
||||||
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
|
|
||||||
Device::CheckVkResult(vkBeginCommandBuffer(drawCmdBuffers[currentBuffer], &cmdBufInfo));
|
Device::CheckVkResult(vkBeginCommandBuffer(drawCmdBuffers[currentBuffer], &cmdBufInfo));
|
||||||
|
|
||||||
VkImageSubresourceRange range{};
|
|
||||||
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
||||||
range.baseMipLevel = 0;
|
|
||||||
range.levelCount = VK_REMAINING_MIP_LEVELS;
|
|
||||||
range.baseArrayLayer = 0;
|
|
||||||
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
|
|
||||||
|
|
||||||
// On an image's first use after (re)creating the swapchain it is still in
|
// On an image's first use after (re)creating the swapchain it is still in
|
||||||
// VK_IMAGE_LAYOUT_UNDEFINED; every subsequent frame leaves it in
|
// VK_IMAGE_LAYOUT_UNDEFINED; every subsequent frame leaves it in
|
||||||
// PRESENT_SRC_KHR. Transitioning from the wrong oldLayout is a validation
|
// PRESENT_SRC_KHR. Transitioning from the wrong oldLayout is a validation
|
||||||
|
|
@ -709,20 +751,11 @@ void Window::Render() {
|
||||||
const bool firstUse = !imageInitialised[currentBuffer];
|
const bool firstUse = !imageInitialised[currentBuffer];
|
||||||
imageInitialised[currentBuffer] = true;
|
imageInitialised[currentBuffer] = true;
|
||||||
|
|
||||||
VkImageMemoryBarrier image_memory_barrier {
|
acquireBarrier.oldLayout = firstUse ? VK_IMAGE_LAYOUT_UNDEFINED
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||||
.srcAccessMask = 0,
|
acquireBarrier.image = images[currentBuffer];
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
||||||
.oldLayout = firstUse ? VK_IMAGE_LAYOUT_UNDEFINED
|
|
||||||
: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = images[currentBuffer],
|
|
||||||
.subresourceRange = range
|
|
||||||
};
|
|
||||||
|
|
||||||
vkCmdPipelineBarrier(drawCmdBuffers[currentBuffer], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
|
vkCmdPipelineBarrier(drawCmdBuffers[currentBuffer], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &acquireBarrier);
|
||||||
|
|
||||||
// Synthesise key-repeat events before listeners run, so the focused
|
// Synthesise key-repeat events before listeners run, so the focused
|
||||||
// widget's OnTextInput / OnKeyDown sees them in the same frame.
|
// widget's OnTextInput / OnKeyDown sees them in the same frame.
|
||||||
|
|
@ -787,35 +820,13 @@ void Window::Render() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VkImageMemoryBarrier image_memory_barrier2 {
|
presentBarrier.image = images[currentBuffer];
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
||||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
|
||||||
.dstAccessMask = 0,
|
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
|
||||||
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
|
||||||
.image = images[currentBuffer],
|
|
||||||
.subresourceRange = range
|
|
||||||
};
|
|
||||||
|
|
||||||
vkCmdPipelineBarrier(drawCmdBuffers[currentBuffer], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier2);
|
vkCmdPipelineBarrier(drawCmdBuffers[currentBuffer], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &presentBarrier);
|
||||||
|
|
||||||
Device::CheckVkResult(vkEndCommandBuffer(drawCmdBuffers[currentBuffer]));
|
Device::CheckVkResult(vkEndCommandBuffer(drawCmdBuffers[currentBuffer]));
|
||||||
|
|
||||||
Device::CheckVkResult(vkQueueSubmit(Device::queue, 1, &submitInfo, VK_NULL_HANDLE));
|
Device::CheckVkResult(vkQueueSubmit(Device::queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||||
VkPresentInfoKHR presentInfo = {};
|
|
||||||
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
||||||
presentInfo.pNext = NULL;
|
|
||||||
presentInfo.swapchainCount = 1;
|
|
||||||
presentInfo.pSwapchains = &swapChain;
|
|
||||||
presentInfo.pImageIndices = ¤tBuffer;
|
|
||||||
// Check if a wait semaphore has been specified to wait for before presenting the image
|
|
||||||
if (semaphores.renderComplete != VK_NULL_HANDLE)
|
|
||||||
{
|
|
||||||
presentInfo.pWaitSemaphores = &semaphores.renderComplete;
|
|
||||||
presentInfo.waitSemaphoreCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
VkResult result = vkQueuePresentKHR(Device::queue, &presentInfo);
|
VkResult result = vkQueuePresentKHR(Device::queue, &presentInfo);
|
||||||
if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR) {
|
if (result == VK_SUBOPTIMAL_KHR || result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,16 @@ export namespace Crafter {
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
VkCommandBuffer drawCmdBuffers[numFrames];
|
VkCommandBuffer drawCmdBuffers[numFrames];
|
||||||
VkSubmitInfo submitInfo;
|
VkSubmitInfo submitInfo;
|
||||||
|
// Per-frame Vulkan info structs whose contents are almost entirely
|
||||||
|
// invariant. Initialised once in the constructor; Render() patches only
|
||||||
|
// the few fields that change each frame (the two barriers' image and
|
||||||
|
// the acquire barrier's oldLayout). presentInfo.pImageIndices and
|
||||||
|
// pSwapchains point at the currentBuffer/swapChain members, so they
|
||||||
|
// track value changes (including swapchain recreation) automatically.
|
||||||
|
VkCommandBufferBeginInfo cmdBufInfo;
|
||||||
|
VkImageMemoryBarrier acquireBarrier;
|
||||||
|
VkImageMemoryBarrier presentBarrier;
|
||||||
|
VkPresentInfoKHR presentInfo;
|
||||||
Semaphores semaphores;
|
Semaphores semaphores;
|
||||||
std::uint32_t currentBuffer = 0;
|
std::uint32_t currentBuffer = 0;
|
||||||
VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
VkPipelineStageFlags submitPipelineStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue