Commit 594e0e14 by Jamie Madill Committed by Commit Bot

Vulkan: Add DS ReadOnly mode to Framebuffer/RP caches.

Allows ANGLE to create Framebuffers and RenderPasses with a read- only depth/stencil layout. Also allows us to transition our Images to this new DepthStencilReadOnly layout. Internal code redesign. No functional change to our command stream. Bug: angleproject:4959 Change-Id: I9b80063bdaec8f5d6c89037e0618c85e1c11b78d Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2354280Reviewed-by: 's avatarCharlie Lao <cclao@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent a13f1061
......@@ -1695,7 +1695,8 @@ void FramebufferVk::updateRenderPassDesc()
if (depthStencilRenderTarget)
{
mRenderPassDesc.packDepthStencilAttachment(
depthStencilRenderTarget->getImageForRenderPass().getFormat().intendedFormatID);
depthStencilRenderTarget->getImageForRenderPass().getFormat().intendedFormatID,
vk::ResourceAccess::Write);
}
}
......
......@@ -291,6 +291,7 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
// Pack depth/stencil attachment, if any
if (desc.hasDepthStencilAttachment())
{
ResourceAccess dsAccess = desc.getDepthStencilAccess();
uint32_t depthStencilIndex = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
uint32_t depthStencilIndexVk = colorAttachmentCount;
......@@ -299,7 +300,18 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
const vk::Format &format = context->getRenderer()->getFormat(formatID);
depthStencilAttachmentRef.attachment = depthStencilIndexVk;
switch (dsAccess)
{
case ResourceAccess::ReadOnly:
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
break;
case ResourceAccess::Write:
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
break;
default:
UNREACHABLE();
}
UnpackAttachmentDesc(&attachmentDescs[depthStencilIndexVk], format, desc.samples(),
ops[depthStencilIndexVk]);
......@@ -466,13 +478,44 @@ void RenderPassDesc::setSamples(GLint samples)
SetBitField(mLogSamples, PackSampleCount(samples));
}
// We can use a bit packing trick to combine two states into a smaller number of bits. The first
// state is the "depth stencil access" mode which can be Unused/ReadOnly/Write. Naively the DS
// access would take 2 bits. The color attachment count state can have 9 values: no attachments +
// 1-8 attachments. Naively this would take 4 bits. So our total bit count naively would be 6. We
// can pack into 5 bits simply by treating the combination of the 9*3 values as an enum with 27
// values. 5 bits gives us 32 possible values. Mod and divide allow us to access the two different
// state components of the enum.
enum PackedAttachmentCount : uint8_t
{
NoColor = 0,
ColorMax = NoColor + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
NoColorDepthStencilRead = ColorMax + 1,
ColorMaxDepthStencilRead = NoColorDepthStencilRead + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
NoColorDepthStencilWrite = ColorMaxDepthStencilRead + 1,
ColorMaxDepthStencilWrite = NoColorDepthStencilWrite + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS,
EnumCount,
};
static_assert(PackedAttachmentCount::EnumCount < angle::Bit<uint8_t>(5), "Bit overflow");
size_t RenderPassDesc::colorAttachmentRange() const
{
return mPackedColorAttachmentRangeAndDSAccess % (PackedAttachmentCount::ColorMax + 1);
}
ResourceAccess RenderPassDesc::getDepthStencilAccess() const
{
return static_cast<ResourceAccess>(mPackedColorAttachmentRangeAndDSAccess /
(PackedAttachmentCount::ColorMax + 1));
}
void RenderPassDesc::packColorAttachment(size_t colorIndexGL, angle::FormatID formatID)
{
ASSERT(colorIndexGL < mAttachmentFormats.size());
static_assert(angle::kNumANGLEFormats < std::numeric_limits<uint8_t>::max(),
"Too many ANGLE formats to fit in uint8_t");
// Force the user to pack the depth/stencil attachment last.
ASSERT(mHasDepthStencilAttachment == false);
ASSERT(!hasDepthStencilAttachment());
// This function should only be called for enabled GL color attachments.
ASSERT(formatID != angle::FormatID::NONE);
......@@ -481,7 +524,8 @@ void RenderPassDesc::packColorAttachment(size_t colorIndexGL, angle::FormatID fo
// Set color attachment range such that it covers the range from index 0 through last
// active index. This is the reason why we need depth/stencil to be packed last.
SetBitField(mColorAttachmentRange, std::max<size_t>(mColorAttachmentRange, colorIndexGL + 1));
SetBitField(mPackedColorAttachmentRangeAndDSAccess,
std::max<size_t>(mPackedColorAttachmentRangeAndDSAccess, colorIndexGL + 1));
}
void RenderPassDesc::packColorAttachmentGap(size_t colorIndexGL)
......@@ -490,17 +534,17 @@ void RenderPassDesc::packColorAttachmentGap(size_t colorIndexGL)
static_assert(angle::kNumANGLEFormats < std::numeric_limits<uint8_t>::max(),
"Too many ANGLE formats to fit in uint8_t");
// Force the user to pack the depth/stencil attachment last.
ASSERT(mHasDepthStencilAttachment == false);
ASSERT(!hasDepthStencilAttachment());
// Use NONE as a flag for gaps in GL color attachments.
uint8_t &packedFormat = mAttachmentFormats[colorIndexGL];
SetBitField(packedFormat, angle::FormatID::NONE);
}
void RenderPassDesc::packDepthStencilAttachment(angle::FormatID formatID)
void RenderPassDesc::packDepthStencilAttachment(angle::FormatID formatID, ResourceAccess access)
{
// Though written as Count, there is only ever a single depth/stencil attachment.
ASSERT(mHasDepthStencilAttachment == false);
ASSERT(access != ResourceAccess::Unused);
ASSERT(!hasDepthStencilAttachment());
size_t index = depthStencilAttachmentIndex();
ASSERT(index < mAttachmentFormats.size());
......@@ -508,7 +552,10 @@ void RenderPassDesc::packDepthStencilAttachment(angle::FormatID formatID)
uint8_t &packedFormat = mAttachmentFormats[index];
SetBitField(packedFormat, formatID);
mHasDepthStencilAttachment = true;
size_t colorRange = colorAttachmentRange();
size_t offset =
access == ResourceAccess::ReadOnly ? NoColorDepthStencilRead : NoColorDepthStencilWrite;
SetBitField(mPackedColorAttachmentRangeAndDSAccess, colorRange + offset);
}
void RenderPassDesc::packColorResolveAttachment(size_t colorIndexGL)
......@@ -538,14 +585,16 @@ bool RenderPassDesc::isColorAttachmentEnabled(size_t colorIndexGL) const
size_t RenderPassDesc::attachmentCount() const
{
size_t colorAttachmentCount = 0;
for (size_t i = 0; i < mColorAttachmentRange; ++i)
size_t colorRange = colorAttachmentRange();
for (size_t i = 0; i < colorRange; ++i)
{
colorAttachmentCount += isColorAttachmentEnabled(i);
}
// Note that there are no gaps in depth/stencil attachments. In fact there is a maximum of 1 of
// it.
return colorAttachmentCount + mColorResolveAttachmentMask.count() + mHasDepthStencilAttachment;
size_t depthStencilCount = hasDepthStencilAttachment() ? 1 : 0;
return colorAttachmentCount + mColorResolveAttachmentMask.count() + depthStencilCount;
}
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
......@@ -1812,7 +1861,7 @@ void FramebufferDesc::update(uint32_t index, ImageViewSubresourceSerial serial)
mSerials[index] = serial;
if (serial.imageViewSerial.valid())
{
mMaxIndex = std::max(mMaxIndex, index + 1);
mMaxIndex = std::max(mMaxIndex, static_cast<uint16_t>(index + 1));
}
}
......@@ -1831,6 +1880,11 @@ void FramebufferDesc::updateDepthStencil(ImageViewSubresourceSerial serial)
update(kFramebufferDescDepthStencilIndex, serial);
}
void FramebufferDesc::updateReadOnlyDepth(bool readOnlyDepth)
{
mReadOnlyDepth = readOnlyDepth;
}
size_t FramebufferDesc::hash() const
{
return angle::ComputeGenericHash(&mSerials, sizeof(mSerials[0]) * (mMaxIndex + 1));
......@@ -1839,6 +1893,7 @@ size_t FramebufferDesc::hash() const
void FramebufferDesc::reset()
{
mMaxIndex = 0;
mReadOnlyDepth = false;
memset(&mSerials, 0, sizeof(mSerials));
}
......@@ -1849,6 +1904,11 @@ bool FramebufferDesc::operator==(const FramebufferDesc &other) const
return false;
}
if (mReadOnlyDepth != other.mReadOnlyDepth)
{
return false;
}
size_t validRegionSize = sizeof(mSerials[0]) * mMaxIndex;
return memcmp(&mSerials, &other.mSerials, validRegionSize) == 0;
}
......@@ -2090,9 +2150,20 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk,
if (desc.hasDepthStencilAttachment())
{
vk::ResourceAccess dsAccess = desc.getDepthStencilAccess();
vk::ImageLayout imageLayout;
if (dsAccess == vk::ResourceAccess::ReadOnly)
{
imageLayout = vk::ImageLayout::DepthStencilReadOnly;
}
else
{
ASSERT(dsAccess == vk::ResourceAccess::Write);
imageLayout = vk::ImageLayout::DepthStencilAttachment;
}
uint32_t depthStencilIndexVk = colorAttachmentCount;
ops.initWithLoadStore(depthStencilIndexVk, vk::ImageLayout::DepthStencilAttachment,
vk::ImageLayout::DepthStencilAttachment);
ops.initWithLoadStore(depthStencilIndexVk, imageLayout, imageLayout);
}
return getRenderPassWithOps(contextVk, serial, desc, ops, renderPassOut);
......
......@@ -59,6 +59,13 @@ using RefCountedSamplerYcbcrConversion = RefCounted<SamplerYcbcrConversion>;
// Enable struct padding warnings for the code below since it is used in caches.
ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
enum ResourceAccess
{
Unused,
ReadOnly,
Write,
};
class alignas(4) RenderPassDesc final
{
public:
......@@ -73,18 +80,22 @@ class alignas(4) RenderPassDesc final
void packColorAttachmentGap(size_t colorIndexGL);
// The caller must pack the depth/stencil attachment last, which is packed right after the color
// attachments (including gaps), i.e. with an index starting from |colorAttachmentRange()|.
void packDepthStencilAttachment(angle::FormatID angleFormatID);
void packDepthStencilAttachment(angle::FormatID angleFormatID, ResourceAccess access);
// Indicate that a color attachment should have a corresponding resolve attachment.
void packColorResolveAttachment(size_t colorIndexGL);
size_t hash() const;
// Color attachments are in [0, colorAttachmentRange()), with possible gaps.
size_t colorAttachmentRange() const { return mColorAttachmentRange; }
size_t colorAttachmentRange() const;
size_t depthStencilAttachmentIndex() const { return colorAttachmentRange(); }
bool isColorAttachmentEnabled(size_t colorIndexGL) const;
bool hasDepthStencilAttachment() const { return mHasDepthStencilAttachment; }
bool hasDepthStencilAttachment() const
{
return getDepthStencilAccess() != ResourceAccess::Unused;
}
ResourceAccess getDepthStencilAccess() const;
bool hasColorResolveAttachment(size_t colorIndexGL) const
{
return mColorResolveAttachmentMask.test(colorIndexGL);
......@@ -107,8 +118,12 @@ class alignas(4) RenderPassDesc final
private:
// Store log(samples), to be able to store it in 3 bits.
uint8_t mLogSamples : 3;
uint8_t mColorAttachmentRange : 4;
uint8_t mHasDepthStencilAttachment : 1;
// Color attachment count has 9 values: from 0-8 valid attachments. The depths/stencil
// attachment can have 3 values: no depth stencil, read only, and writable depth/stencil.
// We can pack these 9*3 = 27 possible values in 5 bits.
uint8_t mPackedColorAttachmentRangeAndDSAccess : 5;
// Whether each color attachment has a corresponding resolve attachment. Color resolve
// attachments can be used to optimize resolve through glBlitFramebuffer() as well as support
// GL_EXT_multisampled_render_to_texture and GL_EXT_multisampled_render_to_texture2.
......@@ -900,6 +915,7 @@ class FramebufferDesc
void updateColor(uint32_t index, ImageViewSubresourceSerial serial);
void updateColorResolve(uint32_t index, ImageViewSubresourceSerial serial);
void updateDepthStencil(ImageViewSubresourceSerial serial);
void updateReadOnlyDepth(bool readOnlyDepth);
size_t hash() const;
void reset();
......@@ -911,7 +927,8 @@ class FramebufferDesc
void update(uint32_t index, ImageViewSubresourceSerial serial);
// Note: this is an exclusive index. If there is one index it will be "1".
uint32_t mMaxIndex;
uint16_t mMaxIndex;
uint16_t mReadOnlyDepth;
FramebufferAttachmentArray<ImageViewSubresourceSerial> mSerials;
};
......
......@@ -344,6 +344,20 @@ constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemory
},
},
{
ImageLayout::DepthStencilReadOnly,
{
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
kAllShadersPipelineStageFlags | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
kAllShadersPipelineStageFlags | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
// Transition to: all reads and writes must happen after barrier.
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
// Transition from: all writes must finish before barrier.
0,
BarrierType::ReadOnly,
PipelineStage::EarlyFragmentTest,
},
},
{
ImageLayout::DepthStencilAttachment,
{
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
......@@ -902,7 +916,7 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
if (mIsRenderPassCommandBuffer)
{
size_t attachmentCount = mRenderPassDesc.attachmentCount();
size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment();
size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
size_t colorAttachmentCount = attachmentCount - depthStencilAttachmentCount;
std::string loadOps, storeOps;
......
......@@ -1074,6 +1074,7 @@ enum class ImageLayout
AllGraphicsShadersReadOnly,
AllGraphicsShadersWrite,
ColorAttachment,
DepthStencilReadOnly,
DepthStencilAttachment,
Present,
......
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