Commit 7dafe3eb by Shahbaz Youssefi Committed by Commit Bot

Vulkan: optimize image memory barriers

Each image was tracking its current layout, but not the pipeline stage it was used. Additionally, the barrier access masks were inferred from the layout. This incurred two inefficiencies: - The src pipeline stage mask often included all stages, causing unnecessarily heavy barriers. - The access masks included all possible accesses by a layout, which in some cases was overkill, like VK_ACCESS_MEMORY_WRITE_BIT for VK_IMAGE_LAYOUT_GENERAL (which will eventually used for compute shader output). This change instead creates an enum where each element represents the layout, the stage and access masks when transitioning into the layout and the stage and access masks when transitioning out of that layout. The image will instead track a value of this enum (instead of VkImageLayout), which allows it to create the layout transition barriers as tight as possible, since it includes all the necessary information. Bug: angleproject:2999 Change-Id: I91535ce06d10530a6fc217ad3b94b7e288521e25 Reviewed-on: https://chromium-review.googlesource.com/c/1440074 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent f3e823db
...@@ -427,7 +427,7 @@ angle::Result FramebufferVk::blitWithCopy(ContextVk *contextVk, ...@@ -427,7 +427,7 @@ angle::Result FramebufferVk::blitWithCopy(ContextVk *contextVk,
ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
vk::ImageHelper *readImage = readRenderTarget->getImageForRead( vk::ImageHelper *readImage = readRenderTarget->getImageForRead(
&mFramebuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer); &mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer);
VkImageAspectFlags aspectMask = VkImageAspectFlags aspectMask =
vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer); vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer);
...@@ -505,9 +505,8 @@ angle::Result FramebufferVk::blitWithReadback(ContextVk *contextVk, ...@@ -505,9 +505,8 @@ angle::Result FramebufferVk::blitWithReadback(ContextVk *contextVk,
// destination target. // destination target.
vk::ImageHelper *imageForWrite = drawRenderTarget->getImageForWrite(&mFramebuffer); vk::ImageHelper *imageForWrite = drawRenderTarget->getImageForWrite(&mFramebuffer);
imageForWrite->changeLayoutWithStages( imageForWrite->changeLayout(imageForWrite->getAspectFlags(), vk::ImageLayout::TransferDst,
imageForWrite->getAspectFlags(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
commandBuffer->copyBufferToImage(destBufferHandle, imageForWrite->getImage(), commandBuffer->copyBufferToImage(destBufferHandle, imageForWrite->getImage(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion); VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
...@@ -667,7 +666,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, ...@@ -667,7 +666,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
colorBlit ? VK_IMAGE_ASPECT_COLOR_BIT colorBlit ? VK_IMAGE_ASPECT_COLOR_BIT
: vk::GetDepthStencilAspectFlags(readImageFormat.textureFormat()); : vk::GetDepthStencilAspectFlags(readImageFormat.textureFormat());
vk::ImageHelper *srcImage = readRenderTarget->getImageForRead( vk::ImageHelper *srcImage = readRenderTarget->getImageForRead(
&mFramebuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer); &mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer);
const gl::Extents sourceFrameBufferExtents = readRenderTarget->getImageExtents(); const gl::Extents sourceFrameBufferExtents = readRenderTarget->getImageExtents();
gl::Rectangle readRect = readRectIn; gl::Rectangle readRect = readRectIn;
...@@ -702,9 +701,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk, ...@@ -702,9 +701,7 @@ angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
// Requirement of the copyImageToBuffer, the dst image must be in // Requirement of the copyImageToBuffer, the dst image must be in
// VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout. // VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL layout.
dstImage->changeLayoutWithStages(aspectMask, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, dstImage->changeLayout(aspectMask, vk::ImageLayout::TransferDst, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
commandBuffer->blitImage(srcImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer->blitImage(srcImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, dstImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
...@@ -1108,8 +1105,8 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk, ...@@ -1108,8 +1105,8 @@ angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
// Note that although we're reading from the image, we need to update the layout below. // Note that although we're reading from the image, we need to update the layout below.
vk::ImageHelper *srcImage = renderTarget->getImageForRead( vk::ImageHelper *srcImage =
&mFramebuffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, commandBuffer); renderTarget->getImageForRead(&mFramebuffer, vk::ImageLayout::TransferSrc, commandBuffer);
const angle::Format *readFormat = &srcImage->getFormat().textureFormat(); const angle::Format *readFormat = &srcImage->getFormat().textureFormat();
......
...@@ -860,15 +860,13 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk, ...@@ -860,15 +860,13 @@ angle::Result ProgramVk::updateTexturesDescriptorSet(ContextVk *contextVk,
vk::ImageHelper &image = textureVk->getImage(); vk::ImageHelper &image = textureVk->getImage();
// Ensure the image is in read-only layout // Ensure the image is in read-only layout
if (image.getCurrentLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) if (image.isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly))
{ {
vk::CommandBuffer *srcLayoutChange; vk::CommandBuffer *srcLayoutChange;
ANGLE_TRY(image.recordCommands(contextVk, &srcLayoutChange)); ANGLE_TRY(image.recordCommands(contextVk, &srcLayoutChange));
image.changeLayoutWithStages( image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, vk::ImageLayout::FragmentShaderReadOnly, srcLayoutChange);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
srcLayoutChange);
} }
image.addReadDependency(framebuffer); image.addReadDependency(framebuffer);
......
...@@ -59,10 +59,8 @@ void RenderTargetVk::onColorDraw(vk::FramebufferHelper *framebufferVk, ...@@ -59,10 +59,8 @@ void RenderTargetVk::onColorDraw(vk::FramebufferHelper *framebufferVk,
renderPassDesc->packAttachment(mImage->getFormat()); renderPassDesc->packAttachment(mImage->getFormat());
// TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361 // TODO(jmadill): Use automatic layout transition. http://anglebug.com/2361
mImage->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, commandBuffer);
// Set up dependencies between the RT resource and the Framebuffer. // Set up dependencies between the RT resource and the Framebuffer.
mImage->addWriteDependency(framebufferVk); mImage->addWriteDependency(framebufferVk);
...@@ -82,9 +80,7 @@ void RenderTargetVk::onDepthStencilDraw(vk::FramebufferHelper *framebufferVk, ...@@ -82,9 +80,7 @@ void RenderTargetVk::onDepthStencilDraw(vk::FramebufferHelper *framebufferVk,
const angle::Format &format = mImage->getFormat().textureFormat(); const angle::Format &format = mImage->getFormat().textureFormat();
VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format); VkImageAspectFlags aspectFlags = vk::GetDepthStencilAspectFlags(format);
mImage->changeLayoutWithStages(aspectFlags, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, mImage->changeLayout(aspectFlags, vk::ImageLayout::DepthStencilAttachment, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, commandBuffer);
// Set up dependencies between the RT resource and the Framebuffer. // Set up dependencies between the RT resource and the Framebuffer.
mImage->addWriteDependency(framebufferVk); mImage->addWriteDependency(framebufferVk);
...@@ -134,7 +130,7 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image, vk::ImageView ...@@ -134,7 +130,7 @@ void RenderTargetVk::updateSwapchainImage(vk::ImageHelper *image, vk::ImageView
} }
vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readingResource, vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readingResource,
VkImageLayout layout, vk::ImageLayout layout,
vk::CommandBuffer *commandBuffer) vk::CommandBuffer *commandBuffer)
{ {
ASSERT(mImage && mImage->valid()); ASSERT(mImage && mImage->valid());
...@@ -142,9 +138,7 @@ vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readi ...@@ -142,9 +138,7 @@ vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readi
// TODO(jmadill): Better simultaneous resource access. http://anglebug.com/2679 // TODO(jmadill): Better simultaneous resource access. http://anglebug.com/2679
mImage->addWriteDependency(readingResource); mImage->addWriteDependency(readingResource);
mImage->changeLayoutWithStages(mImage->getAspectFlags(), layout, mImage->changeLayout(mImage->getAspectFlags(), layout, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
return mImage; return mImage;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "libANGLE/FramebufferAttachment.h" #include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/renderer/renderer_utils.h" #include "libANGLE/renderer/renderer_utils.h"
#include "libANGLE/renderer/vulkan/vk_helpers.h"
namespace rx namespace rx
{ {
...@@ -62,7 +63,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget ...@@ -62,7 +63,7 @@ class RenderTargetVk final : public FramebufferAttachmentRenderTarget
// getImageForRead will also transition the resource to the given layout. // getImageForRead will also transition the resource to the given layout.
vk::ImageHelper *getImageForRead(vk::CommandGraphResource *readingResource, vk::ImageHelper *getImageForRead(vk::CommandGraphResource *readingResource,
VkImageLayout layout, vk::ImageLayout layout,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
vk::ImageHelper *getImageForWrite(vk::CommandGraphResource *writingResource) const; vk::ImageHelper *getImageForWrite(vk::CommandGraphResource *writingResource) const;
......
...@@ -572,15 +572,12 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL ...@@ -572,15 +572,12 @@ angle::Result WindowSurfaceVk::swapImpl(DisplayVk *displayVk, EGLint *rects, EGL
ANGLE_TRY(renderer->finishToSerial(displayVk, mSwapSerials[mCurrentSwapSerialIndex])); ANGLE_TRY(renderer->finishToSerial(displayVk, mSwapSerials[mCurrentSwapSerialIndex]));
} }
vk::CommandBuffer *swapCommands = nullptr;
ANGLE_TRY(mSwapchainImages[mCurrentSwapchainImageIndex].image.recordCommands(displayVk,
&swapCommands));
SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex]; SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
image.image.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, vk::CommandBuffer *swapCommands = nullptr;
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, ANGLE_TRY(image.image.recordCommands(displayVk, &swapCommands));
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, swapCommands);
image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, swapCommands);
ANGLE_TRY(renderer->flush(displayVk)); ANGLE_TRY(renderer->flush(displayVk));
......
...@@ -628,9 +628,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk, ...@@ -628,9 +628,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
// Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout. // Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout.
mImage->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
// Allocate enough memory to copy the sourceArea region of the source texture into its pixel // Allocate enough memory to copy the sourceArea region of the source texture into its pixel
// buffer. // buffer.
......
...@@ -733,24 +733,20 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk, ...@@ -733,24 +733,20 @@ angle::Result UtilsVk::copyImage(ContextVk *contextVk,
pipelineDesc.setScissor(scissor); pipelineDesc.setScissor(scissor);
// Change source layout outside render pass // Change source layout outside render pass
if (src->getCurrentLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) if (src->isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly))
{ {
vk::CommandBuffer *srcLayoutChange; vk::CommandBuffer *srcLayoutChange;
ANGLE_TRY(src->recordCommands(contextVk, &srcLayoutChange)); ANGLE_TRY(src->recordCommands(contextVk, &srcLayoutChange));
src->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, src->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::FragmentShaderReadOnly,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, srcLayoutChange);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, srcLayoutChange);
} }
// Change destination layout outside render pass as well // Change destination layout outside render pass as well
vk::CommandBuffer *destLayoutChange; vk::CommandBuffer *destLayoutChange;
ANGLE_TRY(dest->recordCommands(contextVk, &destLayoutChange)); ANGLE_TRY(dest->recordCommands(contextVk, &destLayoutChange));
dest->changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, dest->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, destLayoutChange);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, destLayoutChange);
vk::CommandBuffer *commandBuffer; vk::CommandBuffer *commandBuffer;
ANGLE_TRY( ANGLE_TRY(
......
...@@ -30,74 +30,166 @@ constexpr int kLineLoopDynamicBufferMinSize = 1024 * 1024; ...@@ -30,74 +30,166 @@ constexpr int kLineLoopDynamicBufferMinSize = 1024 * 1024;
// This is an arbitrary max. We can change this later if necessary. // This is an arbitrary max. We can change this later if necessary.
constexpr uint32_t kDefaultDescriptorPoolMaxSets = 2048; constexpr uint32_t kDefaultDescriptorPoolMaxSets = 2048;
// Gets access flags based on layout. struct ImageMemoryBarrierData
VkAccessFlags GetSrcLayoutAccessFlags(VkImageLayout layout) {
{ // The Vk layout corresponding to the ImageLayout key.
switch (layout) VkImageLayout layout;
{ // The stage in which the image is used (or Bottom/Top if not using any specific stage). Unless
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: // Bottom/Top (Bottom used for transition to and Top used for transition from), the two values
return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; // should match.
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: VkPipelineStageFlags dstStageMask;
return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; VkPipelineStageFlags srcStageMask;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: // Access mask when transitioning into this layout.
return VK_ACCESS_TRANSFER_WRITE_BIT; VkAccessFlags dstAccessMask;
case VK_IMAGE_LAYOUT_PREINITIALIZED: // Access mask when transitioning out from this layout. Note that source access mask never
return VK_ACCESS_HOST_WRITE_BIT; // needs a READ bit, as WAR hazards don't need memory barriers (just execution barriers).
case VK_IMAGE_LAYOUT_GENERAL: VkAccessFlags srcAccessMask;
return VK_ACCESS_MEMORY_WRITE_BIT;
case VK_IMAGE_LAYOUT_UNDEFINED: // If access is read-only, the execution barrier can be skipped altogether if retransitioning to
// Note: source access mask never needs a READ bit, as WAR hazards // the same layout. This is because read-after-read does not need an execution or memory
// don't need memory barriers (just execution barriers). // barrier.
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: bool isReadOnlyAccess;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: };
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
return 0; // clang-format off
default: constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
// TODO(jmadill): Investigate other flags. {
UNREACHABLE(); ImageLayout::Undefined,
return 0; {
} VK_IMAGE_LAYOUT_UNDEFINED,
} VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VkAccessFlags GetDstLayoutAccessFlags(VkImageLayout layout) // Transition to: we don't expect to transition into Undefined.
{ 0,
switch (layout) // Transition from: there's no data in the image to care about.
0,
true,
},
},
{
ImageLayout::PreInitialized,
{
VK_IMAGE_LAYOUT_PREINITIALIZED,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
// Transition to: we don't expect to transition into PreInitialized.
0,
// Transition from: all writes must finish before barrier.
VK_ACCESS_HOST_WRITE_BIT,
false,
},
},
{
ImageLayout::TransferSrc,
{
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
// Transition to: all reads must happen after barrier.
VK_ACCESS_TRANSFER_READ_BIT,
// Transition from: RAR and WAR don't need memory barrier.
0,
true,
},
},
{
ImageLayout::TransferDst,
{
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
// Transition to: all writes must happen after barrier.
VK_ACCESS_TRANSFER_WRITE_BIT,
// Transition from: all writes must finish before barrier.
VK_ACCESS_TRANSFER_WRITE_BIT,
false,
},
},
{
ImageLayout::ComputeShaderReadOnly,
{
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
// Transition to: all reads must happen after barrier.
VK_ACCESS_SHADER_READ_BIT,
// Transition from: RAR and WAR don't need memory barrier.
0,
true,
},
},
{
ImageLayout::ComputeShaderWrite,
{
VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
// Transition to: all reads and writes must happen after barrier.
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
// Transition from: all writes must finish before barrier.
VK_ACCESS_SHADER_WRITE_BIT,
false,
},
},
{
ImageLayout::FragmentShaderReadOnly,
{
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
// Transition to: all reads must happen after barrier.
VK_ACCESS_SHADER_READ_BIT,
// Transition from: RAR and WAR don't need memory barrier.
0,
true,
},
},
{
ImageLayout::ColorAttachment,
{
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// Transition to: all reads and writes must happen after barrier.
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
// Transition from: all writes must finish before barrier.
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
false,
},
},
{
ImageLayout::DepthStencilAttachment,
{
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
// Transition to: all reads and writes must happen after barrier.
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
// Transition from: all writes must finish before barrier.
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
false,
},
},
{ {
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: ImageLayout::Present,
return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; {
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: // transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
return VK_ACCESS_TRANSFER_READ_BIT;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
return VK_ACCESS_TRANSFER_WRITE_BIT;
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
// vkQueuePresentKHR automatically performs the appropriate memory barriers:
// //
// > Any writes to memory backing the images referenced by the pImageIndices and // > Any writes to memory backing the images referenced by the pImageIndices and
// > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
// > is executed, are automatically made visible to the read access performed by the // > is executed, are automatically made visible to the read access performed by the
// > presentation engine. // > presentation engine.
return 0; 0,
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: // Transition from: RAR and WAR don't need memory barrier.
return VK_ACCESS_SHADER_READ_BIT; 0,
case VK_IMAGE_LAYOUT_GENERAL: true,
// NOTE(syoussefi): compute writes to images require them to be in GENERAL layout, },
// and in those cases VK_ACCESS_SHADER_READ/WRITE_BIT are sufficient. However, the },
// GENERAL layout covers so many cases that we can't narrow the access flags here. };
// The possible solutions are either adding VK_IMAGE_LAYOUT_SHADER_WRITE_OPTIMAL to // clang-format on
// Vulkan, or tracking the necessary access mask alongside the old layout.
return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
case VK_IMAGE_LAYOUT_PREINITIALIZED:
case VK_IMAGE_LAYOUT_UNDEFINED:
return 0;
default:
// TODO(jmadill): Investigate other flags.
UNREACHABLE();
return 0;
}
}
VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType) VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
{ {
...@@ -1124,7 +1216,7 @@ ImageHelper::ImageHelper() ...@@ -1124,7 +1216,7 @@ ImageHelper::ImageHelper()
: CommandGraphResource(CommandGraphResourceType::Image), : CommandGraphResource(CommandGraphResourceType::Image),
mFormat(nullptr), mFormat(nullptr),
mSamples(0), mSamples(0),
mCurrentLayout(VK_IMAGE_LAYOUT_UNDEFINED), mCurrentLayout(ImageLayout::Undefined),
mLayerCount(0), mLayerCount(0),
mLevelCount(0), mLevelCount(0),
mStagingBuffer(kStagingBufferFlags, kStagingBufferSize, true) mStagingBuffer(kStagingBufferFlags, kStagingBufferSize, true)
...@@ -1143,7 +1235,7 @@ ImageHelper::ImageHelper(ImageHelper &&other) ...@@ -1143,7 +1235,7 @@ ImageHelper::ImageHelper(ImageHelper &&other)
mStagingBuffer(std::move(other.mStagingBuffer)), mStagingBuffer(std::move(other.mStagingBuffer)),
mSubresourceUpdates(std::move(other.mSubresourceUpdates)) mSubresourceUpdates(std::move(other.mSubresourceUpdates))
{ {
other.mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; other.mCurrentLayout = ImageLayout::Undefined;
other.mLayerCount = 0; other.mLayerCount = 0;
other.mLevelCount = 0; other.mLevelCount = 0;
} }
...@@ -1201,7 +1293,7 @@ angle::Result ImageHelper::init(Context *context, ...@@ -1201,7 +1293,7 @@ angle::Result ImageHelper::init(Context *context,
imageInfo.pQueueFamilyIndices = nullptr; imageInfo.pQueueFamilyIndices = nullptr;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; mCurrentLayout = ImageLayout::Undefined;
ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo)); ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
...@@ -1294,7 +1386,7 @@ void ImageHelper::destroy(VkDevice device) ...@@ -1294,7 +1386,7 @@ void ImageHelper::destroy(VkDevice device)
{ {
mImage.destroy(device); mImage.destroy(device);
mDeviceMemory.destroy(device); mDeviceMemory.destroy(device);
mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; mCurrentLayout = ImageLayout::Undefined;
mLayerCount = 0; mLayerCount = 0;
mLevelCount = 0; mLevelCount = 0;
} }
...@@ -1330,7 +1422,7 @@ angle::Result ImageHelper::init2DStaging(Context *context, ...@@ -1330,7 +1422,7 @@ angle::Result ImageHelper::init2DStaging(Context *context,
mLayerCount = layerCount; mLayerCount = layerCount;
mLevelCount = 1; mLevelCount = 1;
mCurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED; mCurrentLayout = ImageLayout::Undefined;
VkImageCreateInfo imageInfo = {}; VkImageCreateInfo imageInfo = {};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
...@@ -1348,7 +1440,7 @@ angle::Result ImageHelper::init2DStaging(Context *context, ...@@ -1348,7 +1440,7 @@ angle::Result ImageHelper::init2DStaging(Context *context,
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.queueFamilyIndexCount = 0; imageInfo.queueFamilyIndexCount = 0;
imageInfo.pQueueFamilyIndices = nullptr; imageInfo.pQueueFamilyIndices = nullptr;
imageInfo.initialLayout = mCurrentLayout; imageInfo.initialLayout = getCurrentLayout();
ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo)); ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
...@@ -1395,18 +1487,39 @@ GLint ImageHelper::getSamples() const ...@@ -1395,18 +1487,39 @@ GLint ImageHelper::getSamples() const
return mSamples; return mSamples;
} }
void ImageHelper::changeLayoutWithStages(VkImageAspectFlags aspectMask, VkImageLayout ImageHelper::getCurrentLayout() const
VkImageLayout newLayout, {
VkPipelineStageFlags srcStageMask, return kImageMemoryBarrierData[mCurrentLayout].layout;
VkPipelineStageFlags dstStageMask, }
CommandBuffer *commandBuffer)
bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout)
{
const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
// If transitioning to the same read-only layout (RAR), don't generate a barrier.
bool sameLayoutReadAfterRead = mCurrentLayout == newLayout && layoutData.isReadOnlyAccess;
return !sameLayoutReadAfterRead;
}
void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
CommandBuffer *commandBuffer)
{ {
if (!isLayoutChangeNecessary(newLayout))
{
return;
}
const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
const ImageMemoryBarrierData &transitionTo = kImageMemoryBarrierData[newLayout];
VkImageMemoryBarrier imageMemoryBarrier = {}; VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.srcAccessMask = 0; imageMemoryBarrier.srcAccessMask = transitionFrom.srcAccessMask;
imageMemoryBarrier.dstAccessMask = 0; imageMemoryBarrier.dstAccessMask = transitionTo.dstAccessMask;
imageMemoryBarrier.oldLayout = mCurrentLayout; imageMemoryBarrier.oldLayout = transitionFrom.layout;
imageMemoryBarrier.newLayout = newLayout; imageMemoryBarrier.newLayout = transitionTo.layout;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.image = mImage.getHandle(); imageMemoryBarrier.image = mImage.getHandle();
...@@ -1418,13 +1531,8 @@ void ImageHelper::changeLayoutWithStages(VkImageAspectFlags aspectMask, ...@@ -1418,13 +1531,8 @@ void ImageHelper::changeLayoutWithStages(VkImageAspectFlags aspectMask,
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0; imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = mLayerCount; imageMemoryBarrier.subresourceRange.layerCount = mLayerCount;
// TODO(jmadill): Test all the permutations of the access flags. commandBuffer->pipelineBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask, 0, 0,
imageMemoryBarrier.srcAccessMask = GetSrcLayoutAccessFlags(mCurrentLayout); nullptr, 0, nullptr, 1, &imageMemoryBarrier);
imageMemoryBarrier.dstAccessMask = GetDstLayoutAccessFlags(newLayout);
commandBuffer->pipelineBarrier(srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
&imageMemoryBarrier);
mCurrentLayout = newLayout; mCurrentLayout = newLayout;
} }
...@@ -1447,9 +1555,7 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color, ...@@ -1447,9 +1555,7 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color,
{ {
ASSERT(valid()); ASSERT(valid());
changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
commandBuffer);
VkImageSubresourceRange range = {}; VkImageSubresourceRange range = {};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
...@@ -1458,7 +1564,7 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color, ...@@ -1458,7 +1564,7 @@ void ImageHelper::clearColorLayer(const VkClearColorValue &color,
range.baseArrayLayer = baseArrayLayer; range.baseArrayLayer = baseArrayLayer;
range.layerCount = layerCount; range.layerCount = layerCount;
commandBuffer->clearColorImage(mImage, mCurrentLayout, color, 1, &range); commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
} }
void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
...@@ -1468,9 +1574,7 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, ...@@ -1468,9 +1574,7 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
{ {
ASSERT(valid()); ASSERT(valid());
changeLayoutWithStages(imageAspectFlags, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, changeLayout(imageAspectFlags, ImageLayout::TransferDst, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
commandBuffer);
VkImageSubresourceRange clearRange = { VkImageSubresourceRange clearRange = {
/*aspectMask*/ clearAspectFlags, /*aspectMask*/ clearAspectFlags,
...@@ -1480,7 +1584,7 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags, ...@@ -1480,7 +1584,7 @@ void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
/*layerCount*/ 1, /*layerCount*/ 1,
}; };
commandBuffer->clearDepthStencilImage(mImage, mCurrentLayout, depthStencil, 1, &clearRange); commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange);
} }
gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
...@@ -1504,21 +1608,8 @@ void ImageHelper::Copy(ImageHelper *srcImage, ...@@ -1504,21 +1608,8 @@ void ImageHelper::Copy(ImageHelper *srcImage,
{ {
ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid()); ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
if (srcImage->getCurrentLayout() != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && srcImage->changeLayout(srcImage->getAspectFlags(), ImageLayout::TransferSrc, commandBuffer);
srcImage->getCurrentLayout() != VK_IMAGE_LAYOUT_GENERAL) dstImage->changeLayout(dstImage->getAspectFlags(), ImageLayout::TransferDst, commandBuffer);
{
srcImage->changeLayoutWithStages(
srcImage->getAspectFlags(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer);
}
if (dstImage->getCurrentLayout() != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
dstImage->getCurrentLayout() != VK_IMAGE_LAYOUT_GENERAL)
{
dstImage->changeLayoutWithStages(
dstImage->getAspectFlags(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, commandBuffer);
}
VkImageCopy region = {}; VkImageCopy region = {};
region.srcSubresource.aspectMask = aspectMask; region.srcSubresource.aspectMask = aspectMask;
...@@ -1548,9 +1639,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -1548,9 +1639,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(recordCommands(contextVk, &commandBuffer)); ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
commandBuffer);
// We are able to use blitImage since the image format we are using supports it. This // We are able to use blitImage since the image format we are using supports it. This
// is a faster way we can generate the mips. // is a faster way we can generate the mips.
...@@ -1575,7 +1664,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -1575,7 +1664,7 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1); int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
barrier.subresourceRange.baseMipLevel = mipLevel - 1; barrier.subresourceRange.baseMipLevel = mipLevel - 1;
barrier.oldLayout = mCurrentLayout; barrier.oldLayout = getCurrentLayout();
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
...@@ -1617,8 +1706,8 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint ...@@ -1617,8 +1706,8 @@ angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint
0, 0, nullptr, 0, nullptr, 1, &barrier); 0, 0, nullptr, 0, nullptr, 1, &barrier);
// This is just changing the internal state of the image helper so that the next call // This is just changing the internal state of the image helper so that the next call
// to changeLayoutWithStages will use this layout as the "oldLayout" argument. // to changeLayout will use this layout as the "oldLayout" argument.
mCurrentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; mCurrentLayout = ImageLayout::TransferSrc;
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -1903,9 +1992,7 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, ...@@ -1903,9 +1992,7 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
// Do not move this above the for loop, otherwise multiple updates can have race conditions // Do not move this above the for loop, otherwise multiple updates can have race conditions
// and not be applied correctly as seen in: // and not be applied correctly as seen in:
// dEQP-gles2.functional_texture_specification_texsubimage2d_align_2d* tests on Windows AMD // dEQP-gles2.functional_texture_specification_texsubimage2d_align_2d* tests on Windows AMD
changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, commandBuffer);
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
commandBuffer);
if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer) if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer)
{ {
...@@ -1917,10 +2004,8 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk, ...@@ -1917,10 +2004,8 @@ angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
// Note: currently, the staging images are only made through color attachment writes. If // Note: currently, the staging images are only made through color attachment writes. If
// they were written to otherwise in the future, the src stage of this transition should // they were written to otherwise in the future, the src stage of this transition should
// be adjusted appropriately. // be adjusted appropriately.
update.image.image->changeLayoutWithStages( update.image.image->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, vk::ImageLayout::TransferSrc, commandBuffer);
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
commandBuffer);
update.image.image->addReadDependency(this); update.image.image->addReadDependency(this);
......
...@@ -471,6 +471,53 @@ class BufferHelper final : public CommandGraphResource ...@@ -471,6 +471,53 @@ class BufferHelper final : public CommandGraphResource
VkFlags mCurrentReadAccess; VkFlags mCurrentReadAccess;
}; };
// Imagine an image going through a few layout transitions:
//
// srcStage 1 dstStage 2 srcStage 2 dstStage 3
// Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3
// srcAccess 1 dstAccess 2 srcAccess 2 dstAccess 3
// \_________________ ___________________/
// \/
// A transition
//
// Every transition requires 6 pieces of information: from/to layouts, src/dst stage masks and
// src/dst access masks. At the moment we decide to transition the image to Layout 2 (i.e.
// Transition 1), we need to have Layout 1, srcStage 1 and srcAccess 1 stored as history of the
// image. To perform the transition, we need to know Layout 2, dstStage 2 and dstAccess 2.
// Additionally, we need to know srcStage 2 and srcAccess 2 to retain them for the next transition.
//
// That is, with the history kept, on every new transition we need 5 pieces of new information:
// layout/dstStage/dstAccess to transition into the layout, and srcStage/srcAccess for the future
// transition out from it. Given the small number of possible combinations of these values, an
// enum is used were each value encapsulates these 5 pieces of information:
//
// +--------------------------------+
// srcStage 1 | dstStage 2 srcStage 2 | dstStage 3
// Layout 1 ------Transition 1-----> Layout 2 ------Transition 2------> Layout 3
// srcAccess 1 |dstAccess 2 srcAccess 2| dstAccess 3
// +--------------- ---------------+
// \/
// One enum value
//
// Note that, while generally dstStage for the to-transition and srcStage for the from-transition
// are the same, they may occasionally be BOTTOM_OF_PIPE and TOP_OF_PIPE respectively.
enum class ImageLayout
{
Undefined = 0,
PreInitialized = 1,
TransferSrc = 2,
TransferDst = 3,
ComputeShaderReadOnly = 4,
ComputeShaderWrite = 5,
FragmentShaderReadOnly = 6,
ColorAttachment = 7,
DepthStencilAttachment = 8,
Present = 9,
InvalidEnum = 10,
EnumCount = 10,
};
class ImageHelper final : public CommandGraphResource class ImageHelper final : public CommandGraphResource
{ {
public: public:
...@@ -541,13 +588,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -541,13 +588,7 @@ class ImageHelper final : public CommandGraphResource
const Format &getFormat() const; const Format &getFormat() const;
GLint getSamples() const; GLint getSamples() const;
VkImageLayout getCurrentLayout() const { return mCurrentLayout; } VkImageLayout getCurrentLayout() const;
void changeLayoutWithStages(VkImageAspectFlags aspectMask,
VkImageLayout newLayout,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
CommandBuffer *commandBuffer);
void clearColor(const VkClearColorValue &color, void clearColor(const VkClearColorValue &color,
uint32_t baseMipLevel, uint32_t baseMipLevel,
...@@ -624,6 +665,15 @@ class ImageHelper final : public CommandGraphResource ...@@ -624,6 +665,15 @@ class ImageHelper final : public CommandGraphResource
bool hasStagedUpdates() const; bool hasStagedUpdates() const;
// changeLayout automatically skips the layout change if it's unnecessary. This function can be
// used to prevent creating a command graph node and subsequently a command buffer for the sole
// purpose of performing a transition (which may then not be issued).
bool isLayoutChangeNecessary(ImageLayout newLayout);
void changeLayout(VkImageAspectFlags aspectMask,
ImageLayout newLayout,
CommandBuffer *commandBuffer);
private: private:
struct SubresourceUpdate struct SubresourceUpdate
{ {
...@@ -675,7 +725,7 @@ class ImageHelper final : public CommandGraphResource ...@@ -675,7 +725,7 @@ class ImageHelper final : public CommandGraphResource
GLint mSamples; GLint mSamples;
// Current state. // Current state.
VkImageLayout mCurrentLayout; ImageLayout mCurrentLayout;
// Cached properties. // Cached properties.
uint32_t mLayerCount; uint32_t mLayerCount;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment