我正在努力将 ImGui 安装到我的项目中。因此,我为主渲染和 UI(ImGui) 渲染创建了两个渲染通道。另外,正如 ImGui 的建议一样,我制作了不同的命令缓冲区和帧缓冲区。 当重新创建时,将重新创建主命令缓冲区、帧缓冲区、图像、imageView,并相应地重新创建 UI 的命令缓冲区和帧缓冲区。 UI 重新创建发生在主重新创建之后。之后会出现错误有时:
VulkanCore: [VULKAN ERROR]: Validation Error: [ UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout ] Object 0: handle = 0x2aab4061990, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x4dae5635 | vkQueueSubmit(): pSubmits[0].pCommandBuffers[1] command buffer VkCommandBuffer 0x2aab4061990[] expects VkImage 0xd0e29300000000aa[] (subresource: aspectMask 0x1 array layer 0, mip level 0) to be in layout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL--instead, current layout is VK_IMAGE_LAYOUT_UNDEFINED.
VulkanCore: [VULKAN ERROR]: Validation Error: [ VUID-VkPresentInfoKHR-pImageIndices-01296 ] Object 0: handle = 0x2aab3d21540, type = VK_OBJECT_TYPE_QUEUE; | MessageID = 0xc7aabc16 | vkQueuePresentKHR(): pSwapchains[0] images passed to present must be in layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL. The Vulkan spec states: Each element of pImageIndices must be the index of a presentable image acquired from the swapchain specified by the corresponding element of the pSwapchains array, and the presented image subresource must be in the VK_IMAGE_LAYOUT_PRESENT_SRC_KHR layout at the time the operation is executed on a VkDevice (https://github.com/KhronosGroup/Vulkan-Docs/search?q=)VUID-VkPresentInfoKHR-pImageIndices-01296)
我听说过图像内存障碍,但我不理解如何实现它们,并且我认为可以避免它们。我不明白如何首先将图像转换为最佳颜色然后再呈现。 所以有创建两个渲染通道的代码:
//the main one
// Color attachment setup
const vk::AttachmentDescription colorAttachment(
vk::AttachmentDescriptionFlags(), // Flags (default)
swapchainImageFormat, // Format of the swapchain images
vk::SampleCountFlagBits::e1, // Sample count (1 sample per pixel)
vk::AttachmentLoadOp::eClear, // Clear attachment at the start of the render pass
vk::AttachmentStoreOp::eStore, // Store the attachment after the render pass finishes
vk::AttachmentLoadOp::eDontCare, // Stencil load operation (not used here)
vk::AttachmentStoreOp::eDontCare, // Stencil store operation (not used here)
vk::ImageLayout::eUndefined, // Initial layout before rendering
vk::ImageLayout::eColorAttachmentOptimal // Final layout for color attachment after rendering
);
// Depth attachment setup
const vk::AttachmentDescription depthAttachment(
vk::AttachmentDescriptionFlags(), // Flags (default)
DeviceManager::FindSupportedFormat(physicalDevice, // Find a suitable depth format
{vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint},
vk::ImageTiling::eOptimal, vk::FormatFeatureFlagBits::eDepthStencilAttachment),
vk::SampleCountFlagBits::e1, // 1 sample per pixel
vk::AttachmentLoadOp::eClear, // Clear depth attachment at the start
vk::AttachmentStoreOp::eDontCare, // Don't store depth data after rendering
vk::AttachmentLoadOp::eDontCare, // No stencil load operation
vk::AttachmentStoreOp::eDontCare, // No stencil store operation
vk::ImageLayout::eUndefined, // Initial layout (undefined)
vk::ImageLayout::eDepthStencilAttachmentOptimal // Optimal layout for depth/stencil attachment
);
// Attachment references for the subpass
const vk::AttachmentReference colorAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal); // Refers to the color attachment
const vk::AttachmentReference depthAttachmentRef(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); // Refers to the depth attachment
// Subpass description
const vk::SubpassDescription subpassDescription(
vk::SubpassDescriptionFlags(), // Flags (none)
vk::PipelineBindPoint::eGraphics, // Subpass used in graphics pipeline
0, // Input attachments (none)
nullptr, // Pointer to input attachments (none)
1, // Color attachment count
&colorAttachmentRef, // Reference to color attachment
nullptr, // Resolve attachments (none)
&depthAttachmentRef // Reference to depth attachment
);
// Subpass dependency (for handling pipeline transitions)
const vk::SubpassDependency subpassDependency(
VK_SUBPASS_EXTERNAL, // Source subpass (external dependency)
0, // Destination subpass
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, // Source stage (before rendering)
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests, // Destination stage (during rendering)
vk::AccessFlagBits::eNone, // Source access mask (no read/write operations before rendering)
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite // Destination access mask (write operations for color and depth)
);
// Array of attachments (color + depth)
std::array<vk::AttachmentDescription, 2> attachments{ colorAttachment, depthAttachment };
// Render pass creation info
const vk::RenderPassCreateInfo renderPassInfo(
vk::RenderPassCreateFlagBits(), // Flags (default)
attachments.size(), // Number of attachments
attachments.data(), // Pointer to the attachments
1, // Number of subpasses
&subpassDescription, // Subpass description
1, // Number of dependencies
&subpassDependency // Subpass dependency description
);
// Create the render pass and return it
return device.createRenderPass(renderPassInfo);
//the UI’s
// Define the color attachment description
const vk::AttachmentDescription colorAttachment(
vk::AttachmentDescriptionFlags(), // Flags
swapchainImageFormat, // Format of the swapchain image
vk::SampleCountFlagBits::e1, // Sample count (no multisampling)
vk::AttachmentLoadOp::eLoad, // Load operation (load existing data)
vk::AttachmentStoreOp::eStore, // Store operation (store after rendering)
vk::AttachmentLoadOp::eDontCare, // Stencil load operation (don't care)
vk::AttachmentStoreOp::eDontCare, // Stencil store operation (don't care)
vk::ImageLayout::eColorAttachmentOptimal, // Initial layout (optimal for color attachments)
vk::ImageLayout::ePresentSrcKHR // Final layout (ready for presentation)
);
// Reference to the color attachment
const vk::AttachmentReference colorAttachmentRef(
0, // Attachment index in the render pass
vk::ImageLayout::eColorAttachmentOptimal // Layout used in the subpass
);
// Describe the subpass
const vk::SubpassDescription subpassDescription(
vk::SubpassDescriptionFlags(), // Subpass flags
vk::PipelineBindPoint::eGraphics, // Pipeline bind point (graphics)
0, // No input attachments
nullptr, // No input attachments array
1, // One color attachment
&colorAttachmentRef, // Reference to the color attachment
nullptr, // No resolve attachments
nullptr // No depth/stencil attachment
);
// Define subpass dependency (synchronization)
const vk::SubpassDependency subpassDependency{
VK_SUBPASS_EXTERNAL, // Source subpass (external)
0, // Destination subpass (subpass 0)
vk::PipelineStageFlagBits::eColorAttachmentOutput, // Wait at color attachment output
vk::PipelineStageFlagBits::eColorAttachmentOutput, // Signal at color attachment output
vk::AccessFlagBits::eColorAttachmentWrite, // Wait for color attachment write access
vk::AccessFlagBits::eColorAttachmentWrite // Ensure color attachment write access
};
// Define array of attachments
std::array attachments{ colorAttachment };
// Create render pass creation info
const vk::RenderPassCreateInfo renderPassInfo{
vk::RenderPassCreateFlags(), // Flags for render pass creation
attachments.size(), // Number of attachments
attachments.data(), // Pointer to attachment descriptions
1, // One subpass
&subpassDescription, // Pointer to subpass description
1, // One subpass dependency
&subpassDependency // Pointer to subpass dependency
};
// Create and return the render pass
return device.createRenderPass(renderPassInfo);
重新创建后,我应该如何处理这两个渲染通道之间的图像布局转换? 任何建议或指示将不胜感激!
要处理 Vulkan 中的主渲染通道和 ImGui 渲染通道之间的图像布局转换,您需要使用图像内存屏障。在每次渲染过程之前,记录一个障碍,将图像从当前布局(例如,
VK_IMAGE_LAYOUT_UNDEFINED
或 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
)过渡到所需的布局(例如,VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
用于渲染,VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
用于演示)。
在渲染通道命令之前添加此障碍:
vk::ImageMemoryBarrier barrier{};
barrier.image = swapchainImage;
barrier.oldLayout = vk::ImageLayout::eUndefined; // Adjust as needed
barrier.newLayout = vk::ImageLayout::eColorAttachmentOptimal; // Adjust as needed
barrier.srcAccessMask = vk::AccessFlagBits::eNone;
barrier.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput, {}, barrier.srcAccessMask, barrier.dstAccessMask, nullptr, 0, nullptr, 1, &barrier);