Commit 06b4fb92 by Charlie Lao Committed by Commit Bot

Vulkan: Fool proof packed attachment index to vulkan and from OpenGL

ANGLE packs FBO attachments from OpenGL and uses packed attachments to create VkFramebuffer and renderpass. When we use attachment index into the attachment array, we must be very careful to use packed index for vulkan objects. It is easy to make mistakes here and introduce hard to debug bugs. This CL defines a PackedAttachmentIndex class that uses that to index into vulkan attachments and pass around APIs so that compiler would catch the error when wrong index is used. This also introduces PackedClearValuesArray that stores clear value in packed attachment index so that it is impossible to mix it with ClearValuesArray that stores clear value in GL attachment index. Bug: b/167301719 Change-Id: I68680522c60beeb5096e5211eaef89da28c7097e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2410366 Commit-Queue: Charlie Lao <cclao@google.com> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 39185acc
...@@ -2516,7 +2516,8 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle) ...@@ -2516,7 +2516,8 @@ void ContextVk::optimizeRenderPassForPresent(VkFramebuffer framebufferHandle)
// TODO(syoussefi): We currently don't store the layout of the resolve attachments, so once // TODO(syoussefi): We currently don't store the layout of the resolve attachments, so once
// multisampled backbuffers are optimized to use resolve attachments, this information needs to // multisampled backbuffers are optimized to use resolve attachments, this information needs to
// be stored somewhere. http://anglebug.com/4836 // be stored somewhere. http://anglebug.com/4836
mRenderPassCommands->updateRenderPassAttachmentFinalLayout(0, image.getCurrentImageLayout()); mRenderPassCommands->updateRenderPassAttachmentFinalLayout(vk::kAttachmentIndexZero,
image.getCurrentImageLayout());
} }
gl::GraphicsResetStatus ContextVk::getResetStatus() gl::GraphicsResetStatus ContextVk::getResetStatus()
...@@ -4532,13 +4533,14 @@ angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags, ...@@ -4532,13 +4533,14 @@ angle::Result ContextVk::onImageWrite(VkImageAspectFlags aspectFlags,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result ContextVk::beginNewRenderPass(const vk::Framebuffer &framebuffer, angle::Result ContextVk::beginNewRenderPass(
const gl::Rectangle &renderArea, const vk::Framebuffer &framebuffer,
const vk::RenderPassDesc &renderPassDesc, const gl::Rectangle &renderArea,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::RenderPassDesc &renderPassDesc,
const uint32_t depthStencilAttachmentIndex, const vk::AttachmentOpsArray &renderPassAttachmentOps,
const vk::ClearValuesArray &clearValues, const vk::PackedAttachmentIndex depthStencilAttachmentIndex,
vk::CommandBuffer **commandBufferOut) const vk::PackedClearValuesArray &clearValues,
vk::CommandBuffer **commandBufferOut)
{ {
// Next end any currently outstanding renderPass // Next end any currently outstanding renderPass
ANGLE_TRY(flushCommandsAndEndRenderPass()); ANGLE_TRY(flushCommandsAndEndRenderPass());
......
...@@ -547,8 +547,8 @@ class ContextVk : public ContextImpl, public vk::Context ...@@ -547,8 +547,8 @@ class ContextVk : public ContextImpl, public vk::Context
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const vk::RenderPassDesc &renderPassDesc, const vk::RenderPassDesc &renderPassDesc,
const vk::AttachmentOpsArray &renderPassAttachmentOps, const vk::AttachmentOpsArray &renderPassAttachmentOps,
const uint32_t depthStencilAttachmentIndex, const vk::PackedAttachmentIndex depthStencilAttachmentIndex,
const vk::ClearValuesArray &clearValues, const vk::PackedClearValuesArray &clearValues,
vk::CommandBuffer **commandBufferOut); vk::CommandBuffer **commandBufferOut);
// Only returns true if we have a started RP and we've run setupDraw. // Only returns true if we have a started RP and we've run setupDraw.
......
...@@ -1476,16 +1476,16 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk, ...@@ -1476,16 +1476,16 @@ angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
if (contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer)) if (contextVk->hasStartedRenderPassWithFramebuffer(currentFramebuffer))
{ {
// Set the appropriate storeOp for attachments. // Set the appropriate storeOp for attachments.
size_t attachmentIndexVk = 0; vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : mAttachedColorBufferMask) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
if (mState.getEnabledDrawBuffers()[colorIndexGL] && if (mState.getEnabledDrawBuffers()[colorIndexGL] &&
invalidateColorBuffers.test(colorIndexGL)) invalidateColorBuffers.test(colorIndexGL))
{ {
contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment( contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment(
attachmentIndexVk); colorIndexVk);
} }
++attachmentIndexVk; ++colorIndexVk;
} }
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
...@@ -2118,7 +2118,7 @@ void FramebufferVk::clearWithLoadOp(ContextVk *contextVk, ...@@ -2118,7 +2118,7 @@ void FramebufferVk::clearWithLoadOp(ContextVk *contextVk,
ASSERT(commands.getCommandBuffer().empty()); ASSERT(commands.getCommandBuffer().empty());
uint32_t colorIndexVk = 0; vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : mAttachedColorBufferMask) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
if (mState.getEnabledDrawBuffers()[colorIndexGL] && clearColorBuffers[colorIndexGL]) if (mState.getEnabledDrawBuffers()[colorIndexGL] && clearColorBuffers[colorIndexGL])
...@@ -2229,17 +2229,17 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2229,17 +2229,17 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// Initialize RenderPass info. // Initialize RenderPass info.
vk::AttachmentOpsArray renderPassAttachmentOps; vk::AttachmentOpsArray renderPassAttachmentOps;
vk::ClearValuesArray packedClearValues; vk::PackedClearValuesArray packedClearValues;
// Color attachments. // Color attachments.
const auto &colorRenderTargets = mRenderTargetCache.getColors(); const auto &colorRenderTargets = mRenderTargetCache.getColors();
uint32_t colorAttachmentCount = 0; vk::PackedAttachmentIndex colorIndexVk(0);
for (size_t colorIndexGL : mAttachedColorBufferMask) for (size_t colorIndexGL : mAttachedColorBufferMask)
{ {
RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL]; RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
ASSERT(colorRenderTarget); ASSERT(colorRenderTarget);
renderPassAttachmentOps.setLayouts(colorAttachmentCount, vk::ImageLayout::ColorAttachment, renderPassAttachmentOps.setLayouts(colorIndexVk, vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment); vk::ImageLayout::ColorAttachment);
const VkAttachmentStoreOp storeOp = colorRenderTarget->isImageTransient() const VkAttachmentStoreOp storeOp = colorRenderTarget->isImageTransient()
...@@ -2248,23 +2248,22 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2248,23 +2248,22 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
if (mDeferredClears.test(colorIndexGL)) if (mDeferredClears.test(colorIndexGL))
{ {
renderPassAttachmentOps.setOps(colorAttachmentCount, VK_ATTACHMENT_LOAD_OP_CLEAR, renderPassAttachmentOps.setOps(colorIndexVk, VK_ATTACHMENT_LOAD_OP_CLEAR, storeOp);
storeOp); packedClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT,
packedClearValues.store(colorAttachmentCount, VK_IMAGE_ASPECT_COLOR_BIT,
mDeferredClears[colorIndexGL]); mDeferredClears[colorIndexGL]);
mDeferredClears.reset(colorIndexGL); mDeferredClears.reset(colorIndexGL);
} }
else else
{ {
renderPassAttachmentOps.setOps(colorAttachmentCount, renderPassAttachmentOps.setOps(colorIndexVk,
colorRenderTarget->hasDefinedContent() colorRenderTarget->hasDefinedContent()
? VK_ATTACHMENT_LOAD_OP_LOAD ? VK_ATTACHMENT_LOAD_OP_LOAD
: VK_ATTACHMENT_LOAD_OP_DONT_CARE, : VK_ATTACHMENT_LOAD_OP_DONT_CARE,
storeOp); storeOp);
packedClearValues.store(colorAttachmentCount, VK_IMAGE_ASPECT_COLOR_BIT, packedClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT,
kUninitializedClearValue); kUninitializedClearValue);
} }
renderPassAttachmentOps.setStencilOps(colorAttachmentCount, VK_ATTACHMENT_LOAD_OP_DONT_CARE, renderPassAttachmentOps.setStencilOps(colorIndexVk, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE); VK_ATTACHMENT_STORE_OP_DONT_CARE);
// If there's a resolve attachment, and loadOp needs to be LOAD, the multisampled attachment // If there's a resolve attachment, and loadOp needs to be LOAD, the multisampled attachment
...@@ -2281,21 +2280,21 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk, ...@@ -2281,21 +2280,21 @@ angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
// always ever stays on a tiled renderer's tile and no memory backing is allocated for it. // always ever stays on a tiled renderer's tile and no memory backing is allocated for it.
// http://anglebug.com/4881 // http://anglebug.com/4881
if (colorRenderTarget->hasResolveAttachment() && colorRenderTarget->isImageTransient() && if (colorRenderTarget->hasResolveAttachment() && colorRenderTarget->isImageTransient() &&
renderPassAttachmentOps[colorAttachmentCount].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) renderPassAttachmentOps[colorIndexVk].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
{ {
ANGLE_TRY(copyResolveToMultisampedAttachment(contextVk, colorRenderTarget)); ANGLE_TRY(copyResolveToMultisampedAttachment(contextVk, colorRenderTarget));
} }
colorAttachmentCount++; ++colorIndexVk;
} }
// Depth/stencil attachment. // Depth/stencil attachment.
uint32_t depthStencilAttachmentIndex = vk::kInvalidAttachmentIndex; vk::PackedAttachmentIndex depthStencilAttachmentIndex = vk::kAttachmentIndexInvalid;
RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget(); RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
if (depthStencilRenderTarget) if (depthStencilRenderTarget)
{ {
// depth stencil attachment always immediately follow color attachment // depth stencil attachment always immediately follow color attachment
depthStencilAttachmentIndex = colorAttachmentCount; depthStencilAttachmentIndex = colorIndexVk;
VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; VkAttachmentLoadOp depthLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
......
...@@ -1120,14 +1120,15 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk, ...@@ -1120,14 +1120,15 @@ angle::Result UtilsVk::startRenderPass(ContextVk *contextVk,
ANGLE_VK_TRY(contextVk, framebuffer.init(contextVk->getDevice(), framebufferInfo)); ANGLE_VK_TRY(contextVk, framebuffer.init(contextVk->getDevice(), framebufferInfo));
vk::AttachmentOpsArray renderPassAttachmentOps; vk::AttachmentOpsArray renderPassAttachmentOps;
vk::ClearValuesArray clearValues; vk::PackedClearValuesArray clearValues;
clearValues.store(0, VK_IMAGE_ASPECT_COLOR_BIT, {}); clearValues.store(vk::kAttachmentIndexZero, VK_IMAGE_ASPECT_COLOR_BIT, {});
renderPassAttachmentOps.initWithLoadStore(0, vk::ImageLayout::ColorAttachment, renderPassAttachmentOps.initWithLoadStore(vk::kAttachmentIndexZero,
vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment); vk::ImageLayout::ColorAttachment);
ANGLE_TRY(contextVk->beginNewRenderPass(framebuffer, renderArea, renderPassDesc, ANGLE_TRY(contextVk->beginNewRenderPass(framebuffer, renderArea, renderPassDesc,
renderPassAttachmentOps, vk::kInvalidAttachmentIndex, renderPassAttachmentOps, vk::kAttachmentIndexInvalid,
clearValues, commandBufferOut)); clearValues, commandBufferOut));
contextVk->addGarbage(&framebuffer); contextVk->addGarbage(&framebuffer);
......
...@@ -243,8 +243,7 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -243,8 +243,7 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
FramebufferAttachmentArray<VkAttachmentDescription> attachmentDescs; FramebufferAttachmentArray<VkAttachmentDescription> attachmentDescs;
// Pack color attachments // Pack color attachments
uint32_t colorAttachmentCount = 0; PackedAttachmentIndex attachmentCount(0);
uint32_t attachmentCount = 0;
for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL) for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
{ {
// Vulkan says: // Vulkan says:
...@@ -262,19 +261,18 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -262,19 +261,18 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
continue; continue;
} }
uint32_t colorIndexVk = colorAttachmentCount++;
angle::FormatID formatID = desc[colorIndexGL]; angle::FormatID formatID = desc[colorIndexGL];
ASSERT(formatID != angle::FormatID::NONE); ASSERT(formatID != angle::FormatID::NONE);
const vk::Format &format = context->getRenderer()->getFormat(formatID); const vk::Format &format = context->getRenderer()->getFormat(formatID);
VkAttachmentReference colorRef; VkAttachmentReference colorRef;
colorRef.attachment = colorIndexVk; colorRef.attachment = attachmentCount.get();
colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachmentRefs.push_back(colorRef); colorAttachmentRefs.push_back(colorRef);
UnpackAttachmentDesc(&attachmentDescs[colorIndexVk], format, desc.samples(), UnpackAttachmentDesc(&attachmentDescs[attachmentCount.get()], format, desc.samples(),
ops[colorIndexVk]); ops[attachmentCount]);
++attachmentCount; ++attachmentCount;
} }
...@@ -283,14 +281,13 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -283,14 +281,13 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
if (desc.hasDepthStencilAttachment()) if (desc.hasDepthStencilAttachment())
{ {
ResourceAccess dsAccess = desc.getDepthStencilAccess(); ResourceAccess dsAccess = desc.getDepthStencilAccess();
uint32_t depthStencilIndex = static_cast<uint32_t>(desc.depthStencilAttachmentIndex()); uint32_t depthStencilIndexGL = static_cast<uint32_t>(desc.depthStencilAttachmentIndex());
uint32_t depthStencilIndexVk = colorAttachmentCount;
angle::FormatID formatID = desc[depthStencilIndex]; angle::FormatID formatID = desc[depthStencilIndexGL];
ASSERT(formatID != angle::FormatID::NONE); ASSERT(formatID != angle::FormatID::NONE);
const vk::Format &format = context->getRenderer()->getFormat(formatID); const vk::Format &format = context->getRenderer()->getFormat(formatID);
depthStencilAttachmentRef.attachment = depthStencilIndexVk; depthStencilAttachmentRef.attachment = attachmentCount.get();
switch (dsAccess) switch (dsAccess)
{ {
...@@ -304,14 +301,14 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -304,14 +301,14 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
UNREACHABLE(); UNREACHABLE();
} }
UnpackAttachmentDesc(&attachmentDescs[depthStencilIndexVk], format, desc.samples(), UnpackAttachmentDesc(&attachmentDescs[attachmentCount.get()], format, desc.samples(),
ops[depthStencilIndexVk]); ops[attachmentCount]);
++attachmentCount; ++attachmentCount;
} }
// Pack color resolve attachments // Pack color resolve attachments
const uint32_t nonResolveAttachmentCount = attachmentCount; const uint32_t nonResolveAttachmentCount = attachmentCount.get();
for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL) for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
{ {
if (!desc.hasColorResolveAttachment(colorIndexGL)) if (!desc.hasColorResolveAttachment(colorIndexGL))
...@@ -322,16 +319,15 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -322,16 +319,15 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
ASSERT(desc.isColorAttachmentEnabled(colorIndexGL)); ASSERT(desc.isColorAttachmentEnabled(colorIndexGL));
uint32_t colorResolveIndexVk = attachmentCount; const vk::Format &format = context->getRenderer()->getFormat(desc[colorIndexGL]);
const vk::Format &format = context->getRenderer()->getFormat(desc[colorIndexGL]);
VkAttachmentReference colorRef; VkAttachmentReference colorRef;
colorRef.attachment = colorResolveIndexVk; colorRef.attachment = attachmentCount.get();
colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorResolveAttachmentRefs.push_back(colorRef); colorResolveAttachmentRefs.push_back(colorRef);
UnpackResolveAttachmentDesc(&attachmentDescs[colorResolveIndexVk], format); UnpackResolveAttachmentDesc(&attachmentDescs[attachmentCount.get()], format);
++attachmentCount; ++attachmentCount;
} }
...@@ -344,8 +340,9 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -344,8 +340,9 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
subpassDesc.pInputAttachments = nullptr; subpassDesc.pInputAttachments = nullptr;
subpassDesc.colorAttachmentCount = static_cast<uint32_t>(colorAttachmentRefs.size()); subpassDesc.colorAttachmentCount = static_cast<uint32_t>(colorAttachmentRefs.size());
subpassDesc.pColorAttachments = colorAttachmentRefs.data(); subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = subpassDesc.pResolveAttachments = attachmentCount.get() > nonResolveAttachmentCount
attachmentCount > nonResolveAttachmentCount ? colorResolveAttachmentRefs.data() : nullptr; ? colorResolveAttachmentRefs.data()
: nullptr;
subpassDesc.pDepthStencilAttachment = subpassDesc.pDepthStencilAttachment =
(depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED ? &depthStencilAttachmentRef (depthStencilAttachmentRef.attachment != VK_ATTACHMENT_UNUSED ? &depthStencilAttachmentRef
: nullptr); : nullptr);
...@@ -355,7 +352,7 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context, ...@@ -355,7 +352,7 @@ angle::Result InitializeRenderPassFromDesc(vk::Context *context,
VkRenderPassCreateInfo createInfo = {}; VkRenderPassCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.flags = 0; createInfo.flags = 0;
createInfo.attachmentCount = attachmentCount; createInfo.attachmentCount = attachmentCount.get();
createInfo.pAttachments = attachmentDescs.data(); createInfo.pAttachments = attachmentDescs.data();
createInfo.subpassCount = 1; createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc; createInfo.pSubpasses = &subpassDesc;
...@@ -1555,17 +1552,17 @@ AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &othe ...@@ -1555,17 +1552,17 @@ AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &othe
return *this; return *this;
} }
const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index) const const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](PackedAttachmentIndex index) const
{ {
return mOps[index]; return mOps[index.get()];
} }
PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index) PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](PackedAttachmentIndex index)
{ {
return mOps[index]; return mOps[index.get()];
} }
void AttachmentOpsArray::initWithLoadStore(size_t index, void AttachmentOpsArray::initWithLoadStore(PackedAttachmentIndex index,
ImageLayout initialLayout, ImageLayout initialLayout,
ImageLayout finalLayout) ImageLayout finalLayout)
{ {
...@@ -1574,42 +1571,42 @@ void AttachmentOpsArray::initWithLoadStore(size_t index, ...@@ -1574,42 +1571,42 @@ void AttachmentOpsArray::initWithLoadStore(size_t index,
setStencilOps(index, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE); setStencilOps(index, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE);
} }
void AttachmentOpsArray::setLayouts(size_t index, void AttachmentOpsArray::setLayouts(PackedAttachmentIndex index,
ImageLayout initialLayout, ImageLayout initialLayout,
ImageLayout finalLayout) ImageLayout finalLayout)
{ {
PackedAttachmentOpsDesc &ops = mOps[index]; PackedAttachmentOpsDesc &ops = mOps[index.get()];
SetBitField(ops.initialLayout, initialLayout); SetBitField(ops.initialLayout, initialLayout);
SetBitField(ops.finalLayout, finalLayout); SetBitField(ops.finalLayout, finalLayout);
} }
void AttachmentOpsArray::setOps(size_t index, void AttachmentOpsArray::setOps(PackedAttachmentIndex index,
VkAttachmentLoadOp loadOp, VkAttachmentLoadOp loadOp,
VkAttachmentStoreOp storeOp) VkAttachmentStoreOp storeOp)
{ {
PackedAttachmentOpsDesc &ops = mOps[index]; PackedAttachmentOpsDesc &ops = mOps[index.get()];
SetBitField(ops.loadOp, loadOp); SetBitField(ops.loadOp, loadOp);
SetBitField(ops.storeOp, storeOp); SetBitField(ops.storeOp, storeOp);
} }
void AttachmentOpsArray::setStencilOps(size_t index, void AttachmentOpsArray::setStencilOps(PackedAttachmentIndex index,
VkAttachmentLoadOp loadOp, VkAttachmentLoadOp loadOp,
VkAttachmentStoreOp storeOp) VkAttachmentStoreOp storeOp)
{ {
PackedAttachmentOpsDesc &ops = mOps[index]; PackedAttachmentOpsDesc &ops = mOps[index.get()];
SetBitField(ops.stencilLoadOp, loadOp); SetBitField(ops.stencilLoadOp, loadOp);
SetBitField(ops.stencilStoreOp, storeOp); SetBitField(ops.stencilStoreOp, storeOp);
} }
void AttachmentOpsArray::setClearOp(size_t index) void AttachmentOpsArray::setClearOp(PackedAttachmentIndex index)
{ {
PackedAttachmentOpsDesc &ops = mOps[index]; PackedAttachmentOpsDesc &ops = mOps[index.get()];
SetBitField(ops.loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR); SetBitField(ops.loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
} }
void AttachmentOpsArray::setClearStencilOp(size_t index) void AttachmentOpsArray::setClearStencilOp(PackedAttachmentIndex index)
{ {
PackedAttachmentOpsDesc &ops = mOps[index]; PackedAttachmentOpsDesc &ops = mOps[index.get()];
SetBitField(ops.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR); SetBitField(ops.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
} }
...@@ -2138,7 +2135,7 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk, ...@@ -2138,7 +2135,7 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk,
// It would be nice to pre-populate the cache in the Renderer so we rarely miss here. // It would be nice to pre-populate the cache in the Renderer so we rarely miss here.
vk::AttachmentOpsArray ops; vk::AttachmentOpsArray ops;
uint32_t colorAttachmentCount = 0; vk::PackedAttachmentIndex colorIndexVk(0);
for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL) for (uint32_t colorIndexGL = 0; colorIndexGL < desc.colorAttachmentRange(); ++colorIndexGL)
{ {
if (!desc.isColorAttachmentEnabled(colorIndexGL)) if (!desc.isColorAttachmentEnabled(colorIndexGL))
...@@ -2146,9 +2143,9 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk, ...@@ -2146,9 +2143,9 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk,
continue; continue;
} }
uint32_t colorIndexVk = colorAttachmentCount++;
ops.initWithLoadStore(colorIndexVk, vk::ImageLayout::ColorAttachment, ops.initWithLoadStore(colorIndexVk, vk::ImageLayout::ColorAttachment,
vk::ImageLayout::ColorAttachment); vk::ImageLayout::ColorAttachment);
++colorIndexVk;
} }
if (desc.hasDepthStencilAttachment()) if (desc.hasDepthStencilAttachment())
...@@ -2165,8 +2162,7 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk, ...@@ -2165,8 +2162,7 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk,
imageLayout = vk::ImageLayout::DepthStencilAttachment; imageLayout = vk::ImageLayout::DepthStencilAttachment;
} }
uint32_t depthStencilIndexVk = colorAttachmentCount; ops.initWithLoadStore(colorIndexVk, imageLayout, imageLayout);
ops.initWithLoadStore(depthStencilIndexVk, imageLayout, imageLayout);
} }
return getRenderPassWithOps(contextVk, serial, desc, ops, renderPassOut); return getRenderPassWithOps(contextVk, serial, desc, ops, renderPassOut);
......
...@@ -237,6 +237,8 @@ struct PackedAttachmentOpsDesc final ...@@ -237,6 +237,8 @@ struct PackedAttachmentOpsDesc final
static_assert(sizeof(PackedAttachmentOpsDesc) == 2, "Size check failed"); static_assert(sizeof(PackedAttachmentOpsDesc) == 2, "Size check failed");
class PackedAttachmentIndex;
class AttachmentOpsArray final class AttachmentOpsArray final
{ {
public: public:
...@@ -245,18 +247,26 @@ class AttachmentOpsArray final ...@@ -245,18 +247,26 @@ class AttachmentOpsArray final
AttachmentOpsArray(const AttachmentOpsArray &other); AttachmentOpsArray(const AttachmentOpsArray &other);
AttachmentOpsArray &operator=(const AttachmentOpsArray &other); AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
const PackedAttachmentOpsDesc &operator[](size_t index) const; const PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index) const;
PackedAttachmentOpsDesc &operator[](size_t index); PackedAttachmentOpsDesc &operator[](PackedAttachmentIndex index);
// Initialize an attachment op with all load and store operations. // Initialize an attachment op with all load and store operations.
void initWithLoadStore(size_t index, ImageLayout initialLayout, ImageLayout finalLayout); void initWithLoadStore(PackedAttachmentIndex index,
ImageLayout initialLayout,
void setLayouts(size_t index, ImageLayout initialLayout, ImageLayout finalLayout); ImageLayout finalLayout);
void setOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp);
void setStencilOps(size_t index, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp); void setLayouts(PackedAttachmentIndex index,
ImageLayout initialLayout,
void setClearOp(size_t index); ImageLayout finalLayout);
void setClearStencilOp(size_t index); void setOps(PackedAttachmentIndex index,
VkAttachmentLoadOp loadOp,
VkAttachmentStoreOp storeOp);
void setStencilOps(PackedAttachmentIndex index,
VkAttachmentLoadOp loadOp,
VkAttachmentStoreOp storeOp);
void setClearOp(PackedAttachmentIndex index);
void setClearStencilOp(PackedAttachmentIndex index);
size_t hash() const; size_t hash() const;
......
...@@ -569,6 +569,31 @@ VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout) ...@@ -569,6 +569,31 @@ VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
return kImageMemoryBarrierData[imageLayout].layout; return kImageMemoryBarrierData[imageLayout].layout;
} }
// PackedClearValuesArray implementation
PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
PackedClearValuesArray::~PackedClearValuesArray() = default;
PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
default;
void PackedClearValuesArray::store(PackedAttachmentIndex index,
VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue)
{
ASSERT(aspectFlags != 0);
if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT)
{
storeNoDepthStencil(index, clearValue);
}
}
void PackedClearValuesArray::storeNoDepthStencil(PackedAttachmentIndex index,
const VkClearValue &clearValue)
{
mValues[index.get()] = clearValue;
}
// CommandBufferHelper implementation. // CommandBufferHelper implementation.
CommandBufferHelper::CommandBufferHelper() CommandBufferHelper::CommandBufferHelper()
: mPipelineBarriers(), : mPipelineBarriers(),
...@@ -587,7 +612,7 @@ CommandBufferHelper::CommandBufferHelper() ...@@ -587,7 +612,7 @@ CommandBufferHelper::CommandBufferHelper()
mDepthCmdSizeDisabled(kInfiniteCmdSize), mDepthCmdSizeDisabled(kInfiniteCmdSize),
mStencilCmdSizeInvalidated(kInfiniteCmdSize), mStencilCmdSizeInvalidated(kInfiniteCmdSize),
mStencilCmdSizeDisabled(kInfiniteCmdSize), mStencilCmdSizeDisabled(kInfiniteCmdSize),
mDepthStencilAttachmentIndex(kInvalidAttachmentIndex) mDepthStencilAttachmentIndex(kAttachmentIndexInvalid)
{} {}
CommandBufferHelper::~CommandBufferHelper() CommandBufferHelper::~CommandBufferHelper()
...@@ -836,8 +861,8 @@ void CommandBufferHelper::beginRenderPass(const Framebuffer &framebuffer, ...@@ -836,8 +861,8 @@ void CommandBufferHelper::beginRenderPass(const Framebuffer &framebuffer,
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const RenderPassDesc &renderPassDesc, const RenderPassDesc &renderPassDesc,
const AttachmentOpsArray &renderPassAttachmentOps, const AttachmentOpsArray &renderPassAttachmentOps,
const uint32_t depthStencilAttachmentIndex, const PackedAttachmentIndex depthStencilAttachmentIndex,
const ClearValuesArray &clearValues, const PackedClearValuesArray &clearValues,
CommandBuffer **commandBufferOut) CommandBuffer **commandBufferOut)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
...@@ -875,7 +900,7 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -875,7 +900,7 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
{ {
pauseTransformFeedbackIfStarted(); pauseTransformFeedbackIfStarted();
if (mDepthStencilAttachmentIndex == kInvalidAttachmentIndex) if (mDepthStencilAttachmentIndex == kAttachmentIndexInvalid)
{ {
return; return;
} }
...@@ -1066,6 +1091,7 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk) ...@@ -1066,6 +1091,7 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0; size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
size_t colorAttachmentCount = attachmentCount - depthStencilAttachmentCount; size_t colorAttachmentCount = attachmentCount - depthStencilAttachmentCount;
PackedAttachmentIndex attachmentIndexVk(0);
std::string loadOps, storeOps; std::string loadOps, storeOps;
if (colorAttachmentCount > 0) if (colorAttachmentCount > 0)
...@@ -1075,8 +1101,9 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk) ...@@ -1075,8 +1101,9 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
for (size_t i = 0; i < colorAttachmentCount; ++i) for (size_t i = 0; i < colorAttachmentCount; ++i)
{ {
loadOps += GetLoadOpShorthand(mAttachmentOps[i].loadOp); loadOps += GetLoadOpShorthand(mAttachmentOps[attachmentIndexVk].loadOp);
storeOps += GetStoreOpShorthand(mAttachmentOps[i].storeOp); storeOps += GetStoreOpShorthand(mAttachmentOps[attachmentIndexVk].storeOp);
++attachmentIndexVk;
} }
} }
...@@ -1086,13 +1113,12 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk) ...@@ -1086,13 +1113,12 @@ void CommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
loadOps += " Depth/Stencil: "; loadOps += " Depth/Stencil: ";
storeOps += " Depth/Stencil: "; storeOps += " Depth/Stencil: ";
size_t dsIndex = colorAttachmentCount;
loadOps += GetLoadOpShorthand(mAttachmentOps[dsIndex].loadOp); loadOps += GetLoadOpShorthand(mAttachmentOps[attachmentIndexVk].loadOp);
loadOps += GetLoadOpShorthand(mAttachmentOps[dsIndex].stencilLoadOp); loadOps += GetLoadOpShorthand(mAttachmentOps[attachmentIndexVk].stencilLoadOp);
storeOps += GetStoreOpShorthand(mAttachmentOps[dsIndex].storeOp); storeOps += GetStoreOpShorthand(mAttachmentOps[attachmentIndexVk].storeOp);
storeOps += GetStoreOpShorthand(mAttachmentOps[dsIndex].stencilStoreOp); storeOps += GetStoreOpShorthand(mAttachmentOps[attachmentIndexVk].stencilStoreOp);
} }
if (attachmentCount > 0) if (attachmentCount > 0)
...@@ -1123,7 +1149,7 @@ void CommandBufferHelper::reset() ...@@ -1123,7 +1149,7 @@ void CommandBufferHelper::reset()
mDepthCmdSizeDisabled = kInfiniteCmdSize; mDepthCmdSizeDisabled = kInfiniteCmdSize;
mStencilCmdSizeInvalidated = kInfiniteCmdSize; mStencilCmdSizeInvalidated = kInfiniteCmdSize;
mStencilCmdSizeDisabled = kInfiniteCmdSize; mStencilCmdSizeDisabled = kInfiniteCmdSize;
mDepthStencilAttachmentIndex = kInvalidAttachmentIndex; mDepthStencilAttachmentIndex = kAttachmentIndexInvalid;
mRenderPassUsedImages.clear(); mRenderPassUsedImages.clear();
} }
// This state should never change for non-renderPass command buffer // This state should never change for non-renderPass command buffer
...@@ -1167,11 +1193,11 @@ void CommandBufferHelper::pauseTransformFeedbackIfStarted() ...@@ -1167,11 +1193,11 @@ void CommandBufferHelper::pauseTransformFeedbackIfStarted()
mTransformFeedbackCounterBuffers.data()); mTransformFeedbackCounterBuffers.data());
} }
void CommandBufferHelper::updateRenderPassColorClear(size_t colorIndex, void CommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
const VkClearValue &clearValue) const VkClearValue &clearValue)
{ {
mAttachmentOps.setClearOp(colorIndex); mAttachmentOps.setClearOp(colorIndexVk);
mClearValues.store(static_cast<uint32_t>(colorIndex), VK_IMAGE_ASPECT_COLOR_BIT, clearValue); mClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT, clearValue);
} }
void CommandBufferHelper::updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags, void CommandBufferHelper::updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,
......
...@@ -875,6 +875,29 @@ enum class AliasingMode ...@@ -875,6 +875,29 @@ enum class AliasingMode
Disallowed, Disallowed,
}; };
// Stores clear value In packed attachment index
class PackedClearValuesArray final
{
public:
PackedClearValuesArray();
~PackedClearValuesArray();
PackedClearValuesArray(const PackedClearValuesArray &other);
PackedClearValuesArray &operator=(const PackedClearValuesArray &rhs);
void store(PackedAttachmentIndex index,
VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue);
void storeNoDepthStencil(PackedAttachmentIndex index, const VkClearValue &clearValue);
const VkClearValue &operator[](PackedAttachmentIndex index) const
{
return mValues[index.get()];
}
const VkClearValue *data() const { return mValues.data(); }
private:
gl::AttachmentArray<VkClearValue> mValues;
};
// The following are used to help track the state of an invalidated attachment. // The following are used to help track the state of an invalidated attachment.
// This value indicates an "infinite" CmdSize that is not valid for comparing // This value indicates an "infinite" CmdSize that is not valid for comparing
...@@ -946,8 +969,8 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -946,8 +969,8 @@ class CommandBufferHelper : angle::NonCopyable
const gl::Rectangle &renderArea, const gl::Rectangle &renderArea,
const RenderPassDesc &renderPassDesc, const RenderPassDesc &renderPassDesc,
const AttachmentOpsArray &renderPassAttachmentOps, const AttachmentOpsArray &renderPassAttachmentOps,
const uint32_t depthStencilAttachmentIndex, const PackedAttachmentIndex depthStencilAttachmentIndex,
const ClearValuesArray &clearValues, const PackedClearValuesArray &clearValues,
CommandBuffer **commandBufferOut); CommandBuffer **commandBufferOut);
void endRenderPass(ContextVk *contextVk); void endRenderPass(ContextVk *contextVk);
...@@ -961,7 +984,7 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -961,7 +984,7 @@ class CommandBufferHelper : angle::NonCopyable
void endTransformFeedback(); void endTransformFeedback();
void invalidateRenderPassColorAttachment(size_t attachmentIndex) void invalidateRenderPassColorAttachment(PackedAttachmentIndex attachmentIndex)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE); SetBitField(mAttachmentOps[attachmentIndex].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
...@@ -1005,13 +1028,15 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1005,13 +1028,15 @@ class CommandBufferHelper : angle::NonCopyable
cmdCountInvalidated; cmdCountInvalidated;
} }
void updateRenderPassAttachmentFinalLayout(size_t attachmentIndex, ImageLayout finalLayout) void updateRenderPassAttachmentFinalLayout(PackedAttachmentIndex attachmentIndex,
ImageLayout finalLayout)
{ {
ASSERT(mIsRenderPassCommandBuffer); ASSERT(mIsRenderPassCommandBuffer);
SetBitField(mAttachmentOps[attachmentIndex].finalLayout, finalLayout); SetBitField(mAttachmentOps[attachmentIndex].finalLayout, finalLayout);
} }
void updateRenderPassColorClear(size_t colorIndex, const VkClearValue &colorClearValue); void updateRenderPassColorClear(PackedAttachmentIndex colorIndex,
const VkClearValue &colorClearValue);
void updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags, void updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,
const VkClearValue &clearValue); const VkClearValue &clearValue);
...@@ -1081,7 +1106,7 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1081,7 +1106,7 @@ class CommandBufferHelper : angle::NonCopyable
AttachmentOpsArray mAttachmentOps; AttachmentOpsArray mAttachmentOps;
Framebuffer mFramebuffer; Framebuffer mFramebuffer;
gl::Rectangle mRenderArea; gl::Rectangle mRenderArea;
ClearValuesArray mClearValues; PackedClearValuesArray mClearValues;
bool mRenderPassStarted; bool mRenderPassStarted;
bool mForceIndividualBarriers; bool mForceIndividualBarriers;
...@@ -1103,7 +1128,7 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1103,7 +1128,7 @@ class CommandBufferHelper : angle::NonCopyable
uint32_t mStencilCmdSizeDisabled; uint32_t mStencilCmdSizeDisabled;
// Keep track of the depth/stencil attachment index // Keep track of the depth/stencil attachment index
uint32_t mDepthStencilAttachmentIndex; PackedAttachmentIndex mDepthStencilAttachmentIndex;
// Tracks resources used in the command buffer. // Tracks resources used in the command buffer.
// For Buffers, we track the read/write access type so we can enable simuntaneous reads. // For Buffers, we track the read/write access type so we can enable simuntaneous reads.
...@@ -1112,8 +1137,6 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1112,8 +1137,6 @@ class CommandBufferHelper : angle::NonCopyable
angle::FastIntegerSet mRenderPassUsedImages; angle::FastIntegerSet mRenderPassUsedImages;
}; };
static constexpr uint32_t kInvalidAttachmentIndex = -1;
// Imagine an image going through a few layout transitions: // Imagine an image going through a few layout transitions:
// //
// srcStage 1 dstStage 2 srcStage 2 dstStage 3 // srcStage 1 dstStage 2 srcStage 2 dstStage 3
......
...@@ -107,6 +107,35 @@ namespace vk ...@@ -107,6 +107,35 @@ namespace vk
{ {
struct Format; struct Format;
// A packed attachment index interface with vulkan API
class PackedAttachmentIndex final
{
public:
explicit constexpr PackedAttachmentIndex(uint32_t index) : mAttachmentIndex(index) {}
constexpr PackedAttachmentIndex(const PackedAttachmentIndex &other) = default;
constexpr PackedAttachmentIndex &operator=(const PackedAttachmentIndex &other) = default;
constexpr uint32_t get() const { return mAttachmentIndex; }
PackedAttachmentIndex &operator++()
{
++mAttachmentIndex;
return *this;
}
constexpr bool operator==(const PackedAttachmentIndex &other) const
{
return mAttachmentIndex == other.mAttachmentIndex;
}
constexpr bool operator!=(const PackedAttachmentIndex &other) const
{
return mAttachmentIndex != other.mAttachmentIndex;
}
private:
uint32_t mAttachmentIndex;
};
static constexpr PackedAttachmentIndex kAttachmentIndexInvalid = PackedAttachmentIndex(-1);
static constexpr PackedAttachmentIndex kAttachmentIndexZero = PackedAttachmentIndex(0);
// Prepend ptr to the pNext chain at chainStart // Prepend ptr to the pNext chain at chainStart
template <typename VulkanStruct1, typename VulkanStruct2> template <typename VulkanStruct1, typename VulkanStruct2>
void AddToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr) void AddToPNextChain(VulkanStruct1 *chainStart, VulkanStruct2 *ptr)
...@@ -683,11 +712,6 @@ class ClearValuesArray final ...@@ -683,11 +712,6 @@ class ClearValuesArray final
bool empty() const { return mEnabled.none(); } bool empty() const { return mEnabled.none(); }
bool any() const { return mEnabled.any(); } bool any() const { return mEnabled.any(); }
gl::DrawBufferMask getEnabledColorAttachmentsMask() const
{
return gl::DrawBufferMask(static_cast<gl::DrawBufferMask::value_type>(mEnabled.to_ulong()));
}
private: private:
gl::AttachmentArray<VkClearValue> mValues; gl::AttachmentArray<VkClearValue> mValues;
gl::AttachmentsMask mEnabled; gl::AttachmentsMask mEnabled;
......
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