From 26c56e1cf244b9295a25de1023f6767052482343 Mon Sep 17 00:00:00 2001 From: swinston Date: Thu, 29 Oct 2026 11:08:43 -0700 Subject: [PATCH] Convert the texture mapping and mipmap barriers to synchronization2 (ImageMemoryBarrier2/pipelineBarrier2) in the chapters and attachments. Fixes #508. --- attachments/24_texture_image.cpp | 32 ++++++------ attachments/25_sampler.cpp | 32 ++++++------ attachments/26_texture_mapping.cpp | 32 ++++++------ attachments/27_depth_buffering.cpp | 32 ++++++------ attachments/28_model_loading.cpp | 32 ++++++------ attachments/29_mipmapping.cpp | 75 +++++++++++++++------------- attachments/30_multisampling.cpp | 75 +++++++++++++++------------- attachments/34_android.cpp | 32 ++++++------ attachments/35_gltf_ktx.cpp | 22 ++++---- attachments/36_multiple_objects.cpp | 22 ++++---- attachments/38_ray_tracing.cpp | 22 ++++---- en/06_Texture_mapping/00_Images.adoc | 56 ++++++++++----------- en/09_Generating_Mipmaps.adoc | 59 ++++++++++++---------- 13 files changed, 263 insertions(+), 260 deletions(-) diff --git a/attachments/24_texture_image.cpp b/attachments/24_texture_image.cpp index b8d61315..23c4e5f8 100644 --- a/attachments/24_texture_image.cpp +++ b/attachments/24_texture_image.cpp @@ -552,37 +552,35 @@ class HelloTriangleApplication void transitionImageLayout(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Image &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/25_sampler.cpp b/attachments/25_sampler.cpp index 0608f172..dedd303e 100644 --- a/attachments/25_sampler.cpp +++ b/attachments/25_sampler.cpp @@ -578,37 +578,35 @@ class HelloTriangleApplication void transitionImageLayout(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Image &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/26_texture_mapping.cpp b/attachments/26_texture_mapping.cpp index 26811191..6021ab57 100644 --- a/attachments/26_texture_mapping.cpp +++ b/attachments/26_texture_mapping.cpp @@ -580,37 +580,35 @@ class HelloTriangleApplication void transitionImageLayout(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Image &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/27_depth_buffering.cpp b/attachments/27_depth_buffering.cpp index dfb24250..1e51dcf0 100644 --- a/attachments/27_depth_buffering.cpp +++ b/attachments/27_depth_buffering.cpp @@ -634,37 +634,35 @@ class HelloTriangleApplication void transitionImageLayout(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Image &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/28_model_loading.cpp b/attachments/28_model_loading.cpp index fe4ada52..c4b43d99 100644 --- a/attachments/28_model_loading.cpp +++ b/attachments/28_model_loading.cpp @@ -641,37 +641,35 @@ class HelloTriangleApplication void transitionImageLayout(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Image &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/29_mipmapping.cpp b/attachments/29_mipmapping.cpp index d80a73cb..4cd1078d 100644 --- a/attachments/29_mipmapping.cpp +++ b/attachments/29_mipmapping.cpp @@ -608,14 +608,17 @@ class HelloTriangleApplication throw std::runtime_error("texture image format does not support linear blitting!"); } - vk::ImageMemoryBarrier barrier = {.srcAccessMask = vk::AccessFlagBits::eTransferWrite, - .dstAccessMask = vk::AccessFlagBits::eTransferRead, - .oldLayout = vk::ImageLayout::eTransferDstOptimal, - .newLayout = vk::ImageLayout::eTransferSrcOptimal, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; + vk::ImageMemoryBarrier2 barrier = {.srcStageMask = vk::PipelineStageFlagBits2::eTransfer, + .srcAccessMask = vk::AccessFlagBits2::eTransferWrite, + .dstStageMask = vk::PipelineStageFlagBits2::eTransfer, + .dstAccessMask = vk::AccessFlagBits2::eTransferRead, + .oldLayout = vk::ImageLayout::eTransferDstOptimal, + .newLayout = vk::ImageLayout::eTransferSrcOptimal, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; int32_t mipWidth = texWidth; int32_t mipHeight = texHeight; @@ -625,10 +628,12 @@ class HelloTriangleApplication barrier.subresourceRange.baseMipLevel = i - 1; barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); vk::ImageBlit blit = {.srcSubresource = {.aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = i - 1, .layerCount = 1}, .srcOffsets = std::array({{}, {mipWidth, mipHeight, 1}}), @@ -639,10 +644,12 @@ class HelloTriangleApplication barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferRead; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); if (1 < mipWidth) { @@ -657,10 +664,12 @@ class HelloTriangleApplication barrier.subresourceRange.baseMipLevel = mipLevels - 1; barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); } void createTextureImageView() @@ -732,37 +741,35 @@ class HelloTriangleApplication void transitionImageLayout( vk::raii::CommandBuffer &commandBuffer, vk::raii::Image const &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, uint32_t mipLevels) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = mipLevels, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = mipLevels, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/30_multisampling.cpp b/attachments/30_multisampling.cpp index 9a312fa2..13195094 100644 --- a/attachments/30_multisampling.cpp +++ b/attachments/30_multisampling.cpp @@ -637,14 +637,17 @@ class HelloTriangleApplication throw std::runtime_error("texture image format does not support linear blitting!"); } - vk::ImageMemoryBarrier barrier = {.srcAccessMask = vk::AccessFlagBits::eTransferWrite, - .dstAccessMask = vk::AccessFlagBits::eTransferRead, - .oldLayout = vk::ImageLayout::eTransferDstOptimal, - .newLayout = vk::ImageLayout::eTransferSrcOptimal, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; + vk::ImageMemoryBarrier2 barrier = {.srcStageMask = vk::PipelineStageFlagBits2::eTransfer, + .srcAccessMask = vk::AccessFlagBits2::eTransferWrite, + .dstStageMask = vk::PipelineStageFlagBits2::eTransfer, + .dstAccessMask = vk::AccessFlagBits2::eTransferRead, + .oldLayout = vk::ImageLayout::eTransferDstOptimal, + .newLayout = vk::ImageLayout::eTransferSrcOptimal, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; int32_t mipWidth = texWidth; int32_t mipHeight = texHeight; @@ -654,10 +657,12 @@ class HelloTriangleApplication barrier.subresourceRange.baseMipLevel = i - 1; barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); vk::ImageBlit blit = {.srcSubresource = {.aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = i - 1, .layerCount = 1}, .srcOffsets = std::array({{}, {mipWidth, mipHeight, 1}}), @@ -668,10 +673,12 @@ class HelloTriangleApplication barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferRead; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); if (1 < mipWidth) { @@ -686,10 +693,12 @@ class HelloTriangleApplication barrier.subresourceRange.baseMipLevel = mipLevels - 1; barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); } vk::SampleCountFlagBits getMaxUsableSampleCount() @@ -793,37 +802,35 @@ class HelloTriangleApplication void transitionImageLayout( vk::raii::CommandBuffer &commandBuffer, vk::raii::Image const &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, uint32_t mipLevels) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = mipLevels, .layerCount = 1}}; - - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = mipLevels, .layerCount = 1}}; if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); } void copyBufferToImage(vk::raii::CommandBuffer &commandBuffer, const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height) diff --git a/attachments/34_android.cpp b/attachments/34_android.cpp index c32c6361..2c920b5c 100644 --- a/attachments/34_android.cpp +++ b/attachments/34_android.cpp @@ -1642,7 +1642,7 @@ class HelloTriangleApplication .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; commandBuffer.begin(beginInfo); - vk::ImageMemoryBarrier barrier{ + vk::ImageMemoryBarrier2 barrier{ .oldLayout = oldLayout, .newLayout = newLayout, .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, @@ -1655,36 +1655,32 @@ class HelloTriangleApplication .baseArrayLayer = 0, .layerCount = 1}}; - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; - if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eNone; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.srcAccessMask = vk::AccessFlagBits2::eNone; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("Unsupported layout transition"); } - commandBuffer.pipelineBarrier( - sourceStage, destinationStage, - vk::DependencyFlagBits::eByRegion, - nullptr, - nullptr, - barrier); + vk::DependencyInfo dependencyInfo{ + .dependencyFlags = vk::DependencyFlagBits::eByRegion, + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &barrier}; + commandBuffer.pipelineBarrier2(dependencyInfo); commandBuffer.end(); diff --git a/attachments/35_gltf_ktx.cpp b/attachments/35_gltf_ktx.cpp index 777010f4..33fc523e 100644 --- a/attachments/35_gltf_ktx.cpp +++ b/attachments/35_gltf_ktx.cpp @@ -900,36 +900,34 @@ class VulkanApplication { auto commandBuffer = beginSingleTimeCommands(); - vk::ImageMemoryBarrier barrier{ + vk::ImageMemoryBarrier2 barrier{ .oldLayout = oldLayout, .newLayout = newLayout, .image = *image, .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}}; - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; - if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer->pipelineBarrier(sourceStage, destinationStage, {}, {}, nullptr, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer->pipelineBarrier2(dependencyInfo); endSingleTimeCommands(*commandBuffer); } diff --git a/attachments/36_multiple_objects.cpp b/attachments/36_multiple_objects.cpp index 9afc9003..ced8f1cb 100644 --- a/attachments/36_multiple_objects.cpp +++ b/attachments/36_multiple_objects.cpp @@ -971,36 +971,34 @@ class VulkanApplication { auto commandBuffer = beginSingleTimeCommands(); - vk::ImageMemoryBarrier barrier{ + vk::ImageMemoryBarrier2 barrier{ .oldLayout = oldLayout, .newLayout = newLayout, .image = *image, .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}}; - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; - if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer->pipelineBarrier(sourceStage, destinationStage, {}, {}, nullptr, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer->pipelineBarrier2(dependencyInfo); endSingleTimeCommands(*commandBuffer); } diff --git a/attachments/38_ray_tracing.cpp b/attachments/38_ray_tracing.cpp index e0843931..744802f5 100644 --- a/attachments/38_ray_tracing.cpp +++ b/attachments/38_ray_tracing.cpp @@ -834,36 +834,34 @@ class VulkanRaytracingApplication { auto commandBuffer = beginSingleTimeCommands(); - vk::ImageMemoryBarrier barrier{ + vk::ImageMemoryBarrier2 barrier{ .oldLayout = oldLayout, .newLayout = newLayout, .image = image, .subresourceRange = {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}}; - vk::PipelineStageFlags sourceStage; - vk::PipelineStageFlags destinationStage; - if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } - commandBuffer->pipelineBarrier(sourceStage, destinationStage, {}, {}, nullptr, barrier); + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; + commandBuffer->pipelineBarrier2(dependencyInfo); endSingleTimeCommands(*commandBuffer); } diff --git a/en/06_Texture_mapping/00_Images.adoc b/en/06_Texture_mapping/00_Images.adoc index 8a535ada..68cbbf61 100644 --- a/en/06_Texture_mapping/00_Images.adoc +++ b/en/06_Texture_mapping/00_Images.adoc @@ -352,17 +352,18 @@ void transitionImageLayout(vk::raii::CommandBuffer &commandBuffer, const vk::rai ---- One of the most common ways to perform layout transitions is using an _image memory barrier_. +Just like when we transitioned the swapchain image while recording the command buffer, we use the synchronization2 versions of these structures, `vk::ImageMemoryBarrier2` and `vk::DependencyInfo`. A pipeline barrier like that is generally used to synchronize access to resources, like ensuring that a write to a buffer completes before reading from it, but it can also be used to transition image layouts and transfer queue family ownership when `vk::SharingMode::eExclusive` is used. There is an equivalent _buffer memory barrier_ to do this for buffers. [,c++] ---- -vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; +vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; ---- `oldLayout` and `newLayout` specify the the layout transition. @@ -375,26 +376,27 @@ The `image` and `subresourceRange` specify the image that is affected and the sp Our image is not an array and does not have mipmapping levels, so only one level and layer are specified. Barriers are primarily used for synchronization purposes, so you must specify which types of operations that involve the resource must happen before the barrier, and which operations that involve the resource must wait on the barrier. +With synchronization2, each barrier carries its own `srcStageMask`, `srcAccessMask`, `dstStageMask` and `dstAccessMask`. The right values depend on the old and new layout, so we'll get back to this once we've figured out which transitions we're going to use. [,c++] ---- -commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, {}, barrier); +vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; +commandBuffer.pipelineBarrier2(dependencyInfo); ---- -All types of pipeline barriers are submitted using the same function. -The first parameter specifies in which pipeline stage the operations occur that should happen before the barrier. -The second parameter specifies the pipeline stage in which operations will wait on the barrier. +All types of pipeline barriers are submitted using the same function, with the barriers of each kind gathered into a `vk::DependencyInfo`. +The stage masks inside the barrier specify in which pipeline stage the operations occur that should happen before the barrier, and in which pipeline stage operations will wait on the barrier. The pipeline stages that you are allowed to specify before and after the barrier depend on how you use the resource before and after the barrier. The allowed values are listed in https://docs.vulkan.org/spec/latest/chapters/synchronization.html#synchronization-access-types-supported[this table] of the specification. -For example, if you're going to read from a uniform after the barrier, you would specify a usage of `vk::AccessFlagBits::eUniformRead` and the earliest shader that will read from the uniform as pipeline stage, for example `vk::PipelineStageFlagBits::eFragmentShader`. +For example, if you're going to read from a uniform after the barrier, you would specify a usage of `vk::AccessFlagBits2::eUniformRead` and the earliest shader that will read from the uniform as pipeline stage, for example `vk::PipelineStageFlagBits2::eFragmentShader`. It would not make sense to specify a non-shader pipeline stage for this type of usage and the validation layers will warn you when you specify a pipeline stage that does not match the type of usage. -The third parameter is either `{}` or `vk::DependencyFlagBits::eByRegion`. +The `dependencyFlags` member of `vk::DependencyInfo` can be left empty or set to `vk::DependencyFlagBits::eByRegion`. The latter turns the barrier into a per-region condition. That means that the implementation is allowed to already begin reading from the parts of a resource that were written so far, for example. -The last three parameters reference arrays of pipeline barriers of the three available types: memory barriers, buffer memory barriers, and image memory barriers like the one we're using here. +The remaining members of `vk::DependencyInfo` reference arrays of barriers of the three available types: memory barriers, buffer memory barriers, and image memory barriers like the one we're using here. == Copying buffer to image @@ -483,35 +485,33 @@ These rules are specified using the following access masks and pipeline stages: [,c++] ---- -vk::PipelineStageFlags sourceStage; -vk::PipelineStageFlags destinationStage; - if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal) { barrier.srcAccessMask = {}; - barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eTransferWrite; - sourceStage = vk::PipelineStageFlagBits::eTopOfPipe; - destinationStage = vk::PipelineStageFlagBits::eTransfer; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eNone; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; } else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal) { - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; - sourceStage = vk::PipelineStageFlagBits::eTransfer; - destinationStage = vk::PipelineStageFlagBits::eFragmentShader; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; } else { throw std::invalid_argument("unsupported layout transition!"); } -commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, nullptr, barrier); +vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; +commandBuffer.pipelineBarrier2(dependencyInfo); ---- As you can see in the aforementioned table, transfer writes must occur in the pipeline transfer stage. -Since the writings don't have to wait on anything, you may specify an empty access mask and the earliest possible pipeline stage `vk::PipelineStageFlagBits::eTopOfPipe` for the pre-barrier operations. -It should be noted that `vk::PipelineStageFlagBits::eTransfer` is not a _real_ stage within the graphics and compute pipelines. +Since the writings don't have to wait on anything, you may specify an empty access mask and `vk::PipelineStageFlagBits2::eNone` for the pre-barrier operations. +It should be noted that `vk::PipelineStageFlagBits2::eTransfer` is not a _real_ stage within the graphics and compute pipelines. It is more of a pseudo-stage where transfers happen. See https://docs.vulkan.org/spec/latest/chapters/synchronization.html#VkPipelineStageFlagBits[the documentation] for more information and other examples of pseudo-stages. @@ -520,8 +520,8 @@ The image will be written in the same pipeline stage and subsequently read by th If we need to do more transitions in the future, then we'll extend the function. The application should now run successfully, although there are of course no visual changes yet. -One thing to note is that command buffer submission results in implicit `vk::AccessFlagBits::eHostWrite` synchronization at the beginning. -Since the `transitionImageLayout` function executes a command buffer with only a single command, you could use this implicit synchronization and set `srcAccessMask` to `0` if you ever needed a `vk::AccessFlagBits::eHostWrite` dependency in a layout transition. +One thing to note is that command buffer submission results in implicit `vk::AccessFlagBits2::eHostWrite` synchronization at the beginning. +Since the `transitionImageLayout` function executes a command buffer with only a single command, you could use this implicit synchronization and set `srcAccessMask` to `0` if you ever needed a `vk::AccessFlagBits2::eHostWrite` dependency in a layout transition. It's up to you if you want to be explicit about it or not, but I'm personally not a fan of relying on these OpenGL-like "hidden" operations. There is actually a special type of image layout that supports all operations, `vk::ImageLayout::eGeneral`. diff --git a/en/09_Generating_Mipmaps.adoc b/en/09_Generating_Mipmaps.adoc index 60ef0a68..971c4d6d 100644 --- a/en/09_Generating_Mipmaps.adoc +++ b/en/09_Generating_Mipmaps.adoc @@ -90,12 +90,12 @@ vk::raii::ImageView createImageView(vk::Image const &image, vk::Format format, v void transitionImageLayout( vk::raii::CommandBuffer &commandBuffer, vk::raii::Image const &image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout, uint32_t mipLevels) { - vk::ImageMemoryBarrier barrier{.oldLayout = oldLayout, - .newLayout = newLayout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = mipLevels, .layerCount = 1}}; + vk::ImageMemoryBarrier2 barrier{.oldLayout = oldLayout, + .newLayout = newLayout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = mipLevels, .layerCount = 1}}; ... ---- @@ -192,20 +192,23 @@ void generateMipmaps(vk::raii::CommandBuffer &commandBuffer, int32_t texHeight, uint32_t mipLevels) { - vk::ImageMemoryBarrier barrier = {.srcAccessMask = vk::AccessFlagBits::eTransferWrite, - .dstAccessMask = vk::AccessFlagBits::eTransferRead, - .oldLayout = vk::ImageLayout::eTransferDstOptimal, - .newLayout = vk::ImageLayout::eTransferSrcOptimal, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = image, - .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; + vk::ImageMemoryBarrier2 barrier = {.srcStageMask = vk::PipelineStageFlagBits2::eTransfer, + .srcAccessMask = vk::AccessFlagBits2::eTransferWrite, + .dstStageMask = vk::PipelineStageFlagBits2::eTransfer, + .dstAccessMask = vk::AccessFlagBits2::eTransferRead, + .oldLayout = vk::ImageLayout::eTransferDstOptimal, + .newLayout = vk::ImageLayout::eTransferSrcOptimal, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = image, + .subresourceRange = {.aspectMask = vk::ImageAspectFlagBits::eColor, .levelCount = 1, .layerCount = 1}}; + vk::DependencyInfo dependencyInfo{.imageMemoryBarrierCount = 1, .pImageMemoryBarriers = &barrier}; } ---- -We're going to make several transitions, so we'll reuse this `vk::ImageMemoryBarrier`. +We're going to make several transitions, so we'll reuse this `vk::ImageMemoryBarrier2`, along with the `vk::DependencyInfo` that points at it. The fields set above will remain the same for all barriers. -`subresourceRange.miplevel`, `oldLayout`, `newLayout`, `srcAccessMask`, and `dstAccessMask` will be changed for each transition. +`subresourceRange.baseMipLevel`, `oldLayout`, `newLayout`, and the stage and access masks will be changed for each transition. [,c++] ---- @@ -225,10 +228,12 @@ Note that the loop variable starts at 1, not 0. barrier.subresourceRange.baseMipLevel = i - 1; barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; barrier.newLayout = vk::ImageLayout::eTransferSrcOptimal; -barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; -barrier.dstAccessMask = vk::AccessFlagBits::eTransferRead; +barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; +barrier.dstAccessMask = vk::AccessFlagBits2::eTransferRead; +barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; +barrier.dstStageMask = vk::PipelineStageFlagBits2::eTransfer; -commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, {}, {}, barrier); +commandBuffer.pipelineBarrier2(dependencyInfo); ---- First, we transition level `i - 1` to `vk::ImageLayout::eTransferSrcOptimal`. @@ -270,10 +275,12 @@ We use the `vk::Filter::eLinear` to enable interpolation. ---- barrier.oldLayout = vk::ImageLayout::eTransferSrcOptimal; barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; -barrier.srcAccessMask = vk::AccessFlagBits::eTransferRead; -barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; +barrier.srcAccessMask = vk::AccessFlagBits2::eTransferRead; +barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; +barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; +barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; -commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, barrier); +commandBuffer.pipelineBarrier2(dependencyInfo); ---- This barrier transitions mip level `i - 1` to `vk::ImageLayout::eShaderReadOnlyOptimal`. @@ -304,10 +311,12 @@ When this happens, that dimension should remain 1 for all remaining levels. barrier.subresourceRange.baseMipLevel = mipLevels - 1; barrier.oldLayout = vk::ImageLayout::eTransferDstOptimal; barrier.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite; - barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead; + barrier.srcAccessMask = vk::AccessFlagBits2::eTransferWrite; + barrier.dstAccessMask = vk::AccessFlagBits2::eShaderRead; + barrier.srcStageMask = vk::PipelineStageFlagBits2::eTransfer; + barrier.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader; - commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, {}, {}, barrier); + commandBuffer.pipelineBarrier2(dependencyInfo); } ----