From e4a2b5b3a6e486b3c26206b376f14789c98ed029 Mon Sep 17 00:00:00 2001 From: swinston Date: Sat, 5 Jul 2025 15:08:03 -0700 Subject: [PATCH 1/2] Enable multisampling and improve depth handling in rendering pipeline - Set up MSAA sample count using `getMaxUsableSampleCount()` and integrate it throughout the pipeline. - Add support for depth attachment in the pipeline with appropriate format detection. - Refactor image layout transitions to handle color, depth, and multisampled images. - Introduce `transition_image_layout_custom()` for flexible image layout transitions. - Update rendering pass to include multisampled color and depth attachments with clear values. --- attachments/30_multisampling.cpp | 98 ++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 450406aa..54c7515a 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -181,6 +181,7 @@ class HelloTriangleApplication { setupDebugMessenger(); createSurface(); pickPhysicalDevice(); + msaaSamples = getMaxUsableSampleCount(); createLogicalDevice(); createSwapChain(); createImageViews(); @@ -528,7 +529,12 @@ class HelloTriangleApplication { pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo); - vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ .colorAttachmentCount = 1, .pColorAttachmentFormats = &swapChainImageFormat }; + vk::Format depthFormat = findDepthFormat(); + vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapChainImageFormat, + .depthAttachmentFormat = depthFormat + }; vk::GraphicsPipelineCreateInfo pipelineInfo{ .pNext = &pipelineRenderingCreateInfo, .stageCount = 2, .pStages = shaderStages, @@ -1019,7 +1025,8 @@ class HelloTriangleApplication { void recordCommandBuffer(uint32_t imageIndex) { commandBuffers[currentFrame].begin({}); - // Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL + // Before starting rendering, transition the images to the appropriate layouts + // Transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL transition_image_layout( imageIndex, vk::ImageLayout::eUndefined, @@ -1029,19 +1036,60 @@ class HelloTriangleApplication { vk::PipelineStageFlagBits2::eTopOfPipe, // srcStage vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage ); + + // Transition the multisampled color image to COLOR_ATTACHMENT_OPTIMAL + transition_image_layout_custom( + colorImage, + vk::ImageLayout::eUndefined, + vk::ImageLayout::eColorAttachmentOptimal, + {}, + vk::AccessFlagBits2::eColorAttachmentWrite, + vk::PipelineStageFlagBits2::eTopOfPipe, + vk::PipelineStageFlagBits2::eColorAttachmentOutput, + vk::ImageAspectFlagBits::eColor + ); + + // Transition the depth image to DEPTH_ATTACHMENT_OPTIMAL + transition_image_layout_custom( + depthImage, + vk::ImageLayout::eUndefined, + vk::ImageLayout::eDepthAttachmentOptimal, + {}, + vk::AccessFlagBits2::eDepthStencilAttachmentWrite, + vk::PipelineStageFlagBits2::eTopOfPipe, + vk::PipelineStageFlagBits2::eEarlyFragmentTests, + vk::ImageAspectFlagBits::eDepth + ); vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f); - vk::RenderingAttachmentInfo attachmentInfo = { - .imageView = swapChainImageViews[imageIndex], + vk::ClearValue clearDepth = vk::ClearDepthStencilValue(1.0f, 0); + + // Color attachment (multisampled) with resolve attachment + vk::RenderingAttachmentInfo colorAttachment = { + .imageView = colorImageView, .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, + .resolveMode = vk::ResolveModeFlagBits::eAverage, + .resolveImageView = swapChainImageViews[imageIndex], + .resolveImageLayout = vk::ImageLayout::eColorAttachmentOptimal, .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, .clearValue = clearColor }; + + // Depth attachment + vk::RenderingAttachmentInfo depthAttachment = { + .imageView = depthImageView, + .imageLayout = vk::ImageLayout::eDepthAttachmentOptimal, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .clearValue = clearDepth + }; + vk::RenderingInfo renderingInfo = { .renderArea = { .offset = { 0, 0 }, .extent = swapChainExtent }, .layerCount = 1, .colorAttachmentCount = 1, - .pColorAttachments = &attachmentInfo + .pColorAttachments = &colorAttachment, + .pDepthAttachment = &depthAttachment }; commandBuffers[currentFrame].beginRendering(renderingInfo); commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); @@ -1052,7 +1100,9 @@ class HelloTriangleApplication { commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr); commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0); commandBuffers[currentFrame].endRendering(); - // After rendering, transition the swapchain image to PRESENT_SRC + // After rendering, transition the images to appropriate layouts + + // Transition the swapchain image to PRESENT_SRC transition_image_layout( imageIndex, vk::ImageLayout::eColorAttachmentOptimal, @@ -1100,6 +1150,42 @@ class HelloTriangleApplication { commandBuffers[currentFrame].pipelineBarrier2(dependency_info); } + void transition_image_layout_custom( + vk::raii::Image& image, + vk::ImageLayout old_layout, + vk::ImageLayout new_layout, + vk::AccessFlags2 src_access_mask, + vk::AccessFlags2 dst_access_mask, + vk::PipelineStageFlags2 src_stage_mask, + vk::PipelineStageFlags2 dst_stage_mask, + vk::ImageAspectFlags aspect_mask + ) { + vk::ImageMemoryBarrier2 barrier = { + .srcStageMask = src_stage_mask, + .srcAccessMask = src_access_mask, + .dstStageMask = dst_stage_mask, + .dstAccessMask = dst_access_mask, + .oldLayout = old_layout, + .newLayout = new_layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = image, + .subresourceRange = { + .aspectMask = aspect_mask, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + vk::DependencyInfo dependency_info = { + .dependencyFlags = {}, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &barrier + }; + commandBuffers[currentFrame].pipelineBarrier2(dependency_info); + } + void createSyncObjects() { presentCompleteSemaphore.clear(); renderFinishedSemaphore.clear(); From 798d43f5b3d2e7c58a54e47595fdca644bcd04ae Mon Sep 17 00:00:00 2001 From: swinston Date: Sat, 5 Jul 2025 15:19:19 -0700 Subject: [PATCH 2/2] Add depth attachment support to rendering pipeline - Integrate depth attachment format detection into pipeline setup. - Transition depth images to optimal layouts for depth/stencil usage. - Include depth attachment in rendering configuration with appropriate clear values. --- attachments/27_depth_buffering.cpp | 49 ++++++++++++++++++++++++++++-- attachments/28_model_loading.cpp | 49 ++++++++++++++++++++++++++++-- attachments/29_mipmapping.cpp | 49 ++++++++++++++++++++++++++++-- 3 files changed, 138 insertions(+), 9 deletions(-) diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index 8c0a9e14..aad4fe41 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -516,7 +516,12 @@ class HelloTriangleApplication { pipelineLayout = vk::raii::PipelineLayout( device, pipelineLayoutInfo ); - vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ .colorAttachmentCount = 1, .pColorAttachmentFormats = &swapChainImageFormat }; + vk::Format depthFormat = findDepthFormat(); + vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapChainImageFormat, + .depthAttachmentFormat = depthFormat + }; vk::GraphicsPipelineCreateInfo pipelineInfo{ .pNext = &pipelineRenderingCreateInfo, .stageCount = 2, .pStages = shaderStages, @@ -889,19 +894,57 @@ class HelloTriangleApplication { vk::PipelineStageFlagBits2::eTopOfPipe, // srcStage vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage ); + // Transition depth image to depth attachment optimal layout + vk::ImageMemoryBarrier2 depthBarrier = { + .srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe, + .srcAccessMask = {}, + .dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests | vk::PipelineStageFlagBits2::eLateFragmentTests, + .dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = depthImage, + .subresourceRange = { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + vk::DependencyInfo depthDependencyInfo = { + .dependencyFlags = {}, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &depthBarrier + }; + commandBuffers[currentFrame].pipelineBarrier2(depthDependencyInfo); + vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f); - vk::RenderingAttachmentInfo attachmentInfo = { + vk::ClearValue clearDepth = vk::ClearDepthStencilValue(1.0f, 0); + + vk::RenderingAttachmentInfo colorAttachmentInfo = { .imageView = swapChainImageViews[imageIndex], .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, .clearValue = clearColor }; + + vk::RenderingAttachmentInfo depthAttachmentInfo = { + .imageView = depthImageView, + .imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .clearValue = clearDepth + }; + vk::RenderingInfo renderingInfo = { .renderArea = { .offset = { 0, 0 }, .extent = swapChainExtent }, .layerCount = 1, .colorAttachmentCount = 1, - .pColorAttachments = &attachmentInfo + .pColorAttachments = &colorAttachmentInfo, + .pDepthAttachment = &depthAttachmentInfo }; commandBuffers[currentFrame].beginRendering(renderingInfo); commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index 509430f7..faaf20cb 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -520,7 +520,12 @@ class HelloTriangleApplication { pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo); - vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ .colorAttachmentCount = 1, .pColorAttachmentFormats = &swapChainImageFormat }; + vk::Format depthFormat = findDepthFormat(); + vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapChainImageFormat, + .depthAttachmentFormat = depthFormat + }; vk::GraphicsPipelineCreateInfo pipelineInfo{ .pNext = &pipelineRenderingCreateInfo, .stageCount = 2, .pStages = shaderStages, @@ -934,19 +939,57 @@ class HelloTriangleApplication { vk::PipelineStageFlagBits2::eTopOfPipe, // srcStage vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage ); + // Transition depth image to depth attachment optimal layout + vk::ImageMemoryBarrier2 depthBarrier = { + .srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe, + .srcAccessMask = {}, + .dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests | vk::PipelineStageFlagBits2::eLateFragmentTests, + .dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = depthImage, + .subresourceRange = { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + vk::DependencyInfo depthDependencyInfo = { + .dependencyFlags = {}, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &depthBarrier + }; + commandBuffers[currentFrame].pipelineBarrier2(depthDependencyInfo); + vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f); - vk::RenderingAttachmentInfo attachmentInfo = { + vk::ClearValue clearDepth = vk::ClearDepthStencilValue(1.0f, 0); + + vk::RenderingAttachmentInfo colorAttachmentInfo = { .imageView = swapChainImageViews[imageIndex], .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, .clearValue = clearColor }; + + vk::RenderingAttachmentInfo depthAttachmentInfo = { + .imageView = depthImageView, + .imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .clearValue = clearDepth + }; + vk::RenderingInfo renderingInfo = { .renderArea = { .offset = { 0, 0 }, .extent = swapChainExtent }, .layerCount = 1, .colorAttachmentCount = 1, - .pColorAttachments = &attachmentInfo + .pColorAttachments = &colorAttachmentInfo, + .pDepthAttachment = &depthAttachmentInfo }; commandBuffers[currentFrame].beginRendering(renderingInfo); commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline); diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index 1c487b8b..c44cacc3 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -520,7 +520,12 @@ class HelloTriangleApplication { pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo); - vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ .colorAttachmentCount = 1, .pColorAttachmentFormats = &swapChainImageFormat }; + vk::Format depthFormat = findDepthFormat(); + vk::PipelineRenderingCreateInfo pipelineRenderingCreateInfo{ + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapChainImageFormat, + .depthAttachmentFormat = depthFormat + }; vk::GraphicsPipelineCreateInfo pipelineInfo{ .pNext = &pipelineRenderingCreateInfo, .stageCount = 2, .pStages = shaderStages, @@ -1000,19 +1005,57 @@ class HelloTriangleApplication { vk::PipelineStageFlagBits2::eTopOfPipe, // srcStage vk::PipelineStageFlagBits2::eColorAttachmentOutput // dstStage ); + // Transition depth image to depth attachment optimal layout + vk::ImageMemoryBarrier2 depthBarrier = { + .srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe, + .srcAccessMask = {}, + .dstStageMask = vk::PipelineStageFlagBits2::eEarlyFragmentTests | vk::PipelineStageFlagBits2::eLateFragmentTests, + .dstAccessMask = vk::AccessFlagBits2::eDepthStencilAttachmentRead | vk::AccessFlagBits2::eDepthStencilAttachmentWrite, + .oldLayout = vk::ImageLayout::eUndefined, + .newLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = depthImage, + .subresourceRange = { + .aspectMask = vk::ImageAspectFlagBits::eDepth, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 + } + }; + vk::DependencyInfo depthDependencyInfo = { + .dependencyFlags = {}, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &depthBarrier + }; + commandBuffers[currentFrame].pipelineBarrier2(depthDependencyInfo); + vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f); - vk::RenderingAttachmentInfo attachmentInfo = { + vk::ClearValue clearDepth = vk::ClearDepthStencilValue(1.0f, 0); + + vk::RenderingAttachmentInfo colorAttachmentInfo = { .imageView = swapChainImageViews[imageIndex], .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, .clearValue = clearColor }; + + vk::RenderingAttachmentInfo depthAttachmentInfo = { + .imageView = depthImageView, + .imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eDontCare, + .clearValue = clearDepth + }; + vk::RenderingInfo renderingInfo = { .renderArea = { .offset = { 0, 0 }, .extent = swapChainExtent }, .layerCount = 1, .colorAttachmentCount = 1, - .pColorAttachments = &attachmentInfo + .pColorAttachments = &colorAttachmentInfo, + .pDepthAttachment = &depthAttachmentInfo }; commandBuffers[currentFrame].beginRendering(renderingInfo); commandBuffers[currentFrame].bindPipeline(vk::PipelineBindPoint::eGraphics, *graphicsPipeline);