Commit bef918cb by Jamie Madill Committed by Commit Bot

Vulkan: Add packed RenderPass descriptions.

This change is two-fold: it splits the compatible parts from the RenderPass description, which allows for correct caching. It also will allow the pipeline state cache to cache the compatible RenderPass bits. In order to do this we introduce a packed version of the RenderPass description, which uses carefully aligned bit representations so we can hash the descriptions easily using MurmurHash, and compare them with memcmp. Bug: angleproject:2163 Change-Id: I4179c0ff8762df81f29082168bd6e3056ceb1318 Reviewed-on: https://chromium-review.googlesource.com/815816 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarFrank Henigman <fjhenigman@chromium.org>
parent ece12535
......@@ -30,7 +30,6 @@ namespace rx
namespace
{
gl::ErrorOrResult<const gl::InternalFormat *> GetReadAttachmentInfo(
const gl::Context *context,
const gl::FramebufferAttachment *readAttachment)
......@@ -41,30 +40,6 @@ gl::ErrorOrResult<const gl::InternalFormat *> GetReadAttachmentInfo(
GLenum implFormat = renderTarget->format->textureFormat().fboImplementationInternalFormat;
return &gl::GetSizedInternalFormatInfo(implFormat);
}
VkSampleCountFlagBits ConvertSamples(GLint sampleCount)
{
switch (sampleCount)
{
case 0:
case 1:
return VK_SAMPLE_COUNT_1_BIT;
case 2:
return VK_SAMPLE_COUNT_2_BIT;
case 4:
return VK_SAMPLE_COUNT_4_BIT;
case 8:
return VK_SAMPLE_COUNT_8_BIT;
case 16:
return VK_SAMPLE_COUNT_16_BIT;
case 32:
return VK_SAMPLE_COUNT_32_BIT;
default:
UNREACHABLE();
return VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
}
}
} // anonymous namespace
// static
......@@ -386,24 +361,7 @@ const vk::RenderPassDesc &FramebufferVk::getRenderPassDesc(const gl::Context *co
{
RenderTargetVk *renderTarget = nullptr;
ANGLE_SWALLOW_ERR(colorAttachment.getRenderTarget(context, &renderTarget));
VkAttachmentDescription *colorDesc = desc.nextColorAttachment();
// TODO(jmadill): We would only need this flag for duplicated attachments.
colorDesc->flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
colorDesc->format = renderTarget->format->vkTextureFormat;
colorDesc->samples = ConvertSamples(colorAttachment.getSamples());
// The load op controls the prior existing depth/color attachment data.
// TODO(jmadill): Proper load ops. Should not be hard coded to clear.
colorDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
// We might want to transition directly to PRESENT_SRC for Surface attachments.
colorDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
desc.packColorAttachment(*renderTarget->format, colorAttachment.getSamples());
}
}
......@@ -413,18 +371,8 @@ const vk::RenderPassDesc &FramebufferVk::getRenderPassDesc(const gl::Context *co
{
RenderTargetVk *renderTarget = nullptr;
ANGLE_SWALLOW_ERR(depthStencilAttachment->getRenderTarget(context, &renderTarget));
VkAttachmentDescription *depthStencilDesc = desc.nextDepthStencilAttachment();
depthStencilDesc->flags = 0;
depthStencilDesc->format = renderTarget->format->vkTextureFormat;
depthStencilDesc->samples = ConvertSamples(depthStencilAttachment->getSamples());
depthStencilDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthStencilDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthStencilDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
depthStencilDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
depthStencilDesc->initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencilDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
desc.packDepthStencilAttachment(*renderTarget->format,
depthStencilAttachment->getSamples());
}
mRenderPassDesc = desc;
......@@ -512,6 +460,9 @@ gl::Error FramebufferVk::beginRenderPass(const gl::Context *context,
vk::CommandBuffer *commandBuffer,
Serial queueSerial)
{
uint32_t attachmentIndex = 0;
vk::AttachmentOpsArray attachmentOps;
// TODO(jmadill): Cache render targets.
for (const auto &colorAttachment : mState.getColorAttachments())
{
......@@ -520,6 +471,9 @@ gl::Error FramebufferVk::beginRenderPass(const gl::Context *context,
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(colorAttachment.getRenderTarget<RenderTargetVk>(context, &renderTarget));
renderTarget->resource->setQueueSerial(queueSerial);
// Fill in some default load and store ops.
attachmentOps.initDummyOp(attachmentIndex++, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
}
......@@ -529,6 +483,10 @@ gl::Error FramebufferVk::beginRenderPass(const gl::Context *context,
RenderTargetVk *renderTarget = nullptr;
ANGLE_TRY(depthStencilAttachment->getRenderTarget<RenderTargetVk>(context, &renderTarget));
renderTarget->resource->setQueueSerial(queueSerial);
// Fill in some default load and store ops.
attachmentOps.initDummyOp(attachmentIndex++,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
vk::Framebuffer *framebuffer = nullptr;
......@@ -538,7 +496,7 @@ gl::Error FramebufferVk::beginRenderPass(const gl::Context *context,
const vk::RenderPassDesc &desc = getRenderPassDesc(context);
vk::RenderPass *renderPass = nullptr;
ANGLE_TRY(rendererVk->getMatchingRenderPass(desc, &renderPass));
ANGLE_TRY(rendererVk->getRenderPassWithOps(desc, attachmentOps, &renderPass));
ASSERT(renderPass && renderPass->valid());
// TODO(jmadill): Proper clear value implementation.
......
......@@ -96,9 +96,12 @@ RenderPassCache::~RenderPassCache()
void RenderPassCache::destroy(VkDevice device)
{
for (auto &renderPassIt : mPayload)
for (auto &outerIt : mPayload)
{
renderPassIt.second.get().destroy(device);
for (auto &innerIt : outerIt.second)
{
innerIt.second.get().destroy(device);
}
}
mPayload.clear();
}
......@@ -108,32 +111,68 @@ vk::Error RenderPassCache::getCompatibleRenderPass(VkDevice device,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)
{
// TODO(jmadill): Return compatible RenderPass when possible.
return getMatchingRenderPass(device, serial, desc, renderPassOut);
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
InnerCache &innerCache = outerIt->second;
ASSERT(!innerCache.empty());
// Find the first element and return it.
*renderPassOut = &innerCache.begin()->second.get();
return vk::NoError();
}
// Insert some dummy attachment ops.
// TODO(jmadill): Pre-populate the cache in the Renderer so we rarely miss here.
vk::AttachmentOpsArray ops;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
ops.initDummyOp(colorIndex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
if (desc.depthStencilAttachmentCount() > 0)
{
ops.initDummyOp(desc.colorAttachmentCount(),
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
}
return getRenderPassWithOps(device, serial, desc, ops, renderPassOut);
}
vk::Error RenderPassCache::getMatchingRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)
vk::Error RenderPassCache::getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut)
{
auto it = mPayload.find(desc);
if (it != mPayload.end())
auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end())
{
// Update the serial before we return.
// TODO(jmadill): Could possibly use an MRU cache here.
it->second.updateSerial(serial);
InnerCache &innerCache = outerIt->second;
*renderPassOut = &it->second.get();
return vk::NoError();
auto innerIt = innerCache.find(attachmentOps);
if (innerIt != innerCache.end())
{
// Update the serial before we return.
// TODO(jmadill): Could possibly use an MRU cache here.
innerIt->second.updateSerial(serial);
*renderPassOut = &innerIt->second.get();
return vk::NoError();
}
}
else
{
auto emplaceResult = mPayload.emplace(desc, InnerCache());
outerIt = emplaceResult.first;
}
vk::RenderPass newRenderPass;
ANGLE_TRY(vk::InitializeRenderPassFromDesc(device, desc, &newRenderPass));
ANGLE_TRY(vk::InitializeRenderPassFromDesc(device, desc, attachmentOps, &newRenderPass));
vk::RenderPassAndSerial withSerial(std::move(newRenderPass), serial);
auto insertPos = mPayload.emplace(desc, std::move(withSerial));
InnerCache &innerCache = outerIt->second;
auto insertPos = innerCache.emplace(attachmentOps, std::move(withSerial));
*renderPassOut = &insertPos.first->second.get();
// TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
......@@ -897,11 +936,12 @@ vk::Error RendererVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
renderPassOut);
}
vk::Error RendererVk::getMatchingRenderPass(const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut)
vk::Error RendererVk::getRenderPassWithOps(const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &ops,
vk::RenderPass **renderPassOut)
{
return mRenderPassCache.getMatchingRenderPass(mDevice, mCurrentQueueSerial, desc,
renderPassOut);
return mRenderPassCache.getRenderPassWithOps(mDevice, mCurrentQueueSerial, desc, ops,
renderPassOut);
}
} // namespace rx
......@@ -46,13 +46,19 @@ class RenderPassCache
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut);
vk::Error getMatchingRenderPass(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut);
vk::Error getRenderPassWithOps(VkDevice device,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut);
private:
std::unordered_map<vk::RenderPassDesc, vk::RenderPassAndSerial> mPayload;
// Use a two-layer caching scheme. The top level matches the "compatible" RenderPass elements.
// The second layer caches the attachment load/store ops and initial/final layout.
using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassAndSerial>;
using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>;
OuterCache mPayload;
};
class RendererVk : angle::NonCopyable
......@@ -139,7 +145,9 @@ class RendererVk : angle::NonCopyable
vk::Error getCompatibleRenderPass(const vk::RenderPassDesc &desc,
vk::RenderPass **renderPassOut);
vk::Error getMatchingRenderPass(const vk::RenderPassDesc &desc, vk::RenderPass **renderPassOut);
vk::Error getRenderPassWithOps(const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &ops,
vk::RenderPass **renderPassOut);
private:
void ensureCapsInitialized() const;
......
......@@ -105,6 +105,44 @@ VkImageUsageFlags GetStagingBufferUsageFlags(vk::StagingUsage usage)
}
}
VkSampleCountFlagBits ConvertSamples(GLint sampleCount)
{
switch (sampleCount)
{
case 0:
case 1:
return VK_SAMPLE_COUNT_1_BIT;
case 2:
return VK_SAMPLE_COUNT_2_BIT;
case 4:
return VK_SAMPLE_COUNT_4_BIT;
case 8:
return VK_SAMPLE_COUNT_8_BIT;
case 16:
return VK_SAMPLE_COUNT_16_BIT;
case 32:
return VK_SAMPLE_COUNT_32_BIT;
default:
UNREACHABLE();
return VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM;
}
}
void UnpackAttachmentDesc(VkAttachmentDescription *desc,
const vk::PackedAttachmentDesc &packedDesc,
const vk::PackedAttachmentOpsDesc &ops)
{
desc->flags = static_cast<VkAttachmentDescriptionFlags>(packedDesc.flags);
desc->format = static_cast<VkFormat>(packedDesc.format);
desc->samples = ConvertSamples(packedDesc.samples);
desc->loadOp = static_cast<VkAttachmentLoadOp>(ops.loadOp);
desc->storeOp = static_cast<VkAttachmentStoreOp>(ops.storeOp);
desc->stencilLoadOp = static_cast<VkAttachmentLoadOp>(ops.stencilLoadOp);
desc->stencilStoreOp = static_cast<VkAttachmentStoreOp>(ops.stencilStoreOp);
desc->initialLayout = static_cast<VkImageLayout>(ops.initialLayout);
desc->finalLayout = static_cast<VkImageLayout>(ops.finalLayout);
}
} // anonymous namespace
// Mirrors std_validation_str in loader.h
......@@ -1256,9 +1294,8 @@ Error CommandBufferAndState::ensureFinished()
// RenderPassDesc implementation.
RenderPassDesc::RenderPassDesc()
: colorAttachmentCount(0), depthStencilAttachmentCount(0), attachmentDescs{}
{
memset(attachmentDescs.data(), 0, sizeof(VkAttachmentDescription) * attachmentDescs.size());
memset(this, 0, sizeof(RenderPassDesc));
}
RenderPassDesc::~RenderPassDesc()
......@@ -1270,44 +1307,124 @@ RenderPassDesc::RenderPassDesc(const RenderPassDesc &other)
memcpy(this, &other, sizeof(RenderPassDesc));
}
void RenderPassDesc::packAttachment(uint32_t index, const vk::Format &format, GLsizei samples)
{
PackedAttachmentDesc &desc = mAttachmentDescs[index];
// TODO(jmadill): We would only need this flag for duplicated attachments.
desc.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
ASSERT(desc.samples < std::numeric_limits<uint8_t>::max());
desc.samples = static_cast<uint8_t>(samples);
ASSERT(format.vkTextureFormat < std::numeric_limits<uint16_t>::max());
desc.format = static_cast<uint16_t>(format.vkTextureFormat);
}
void RenderPassDesc::packColorAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
ASSERT(mColorAttachmentCount < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
packAttachment(mColorAttachmentCount++, format, samples);
}
void RenderPassDesc::packDepthStencilAttachment(const vk::Format &format, GLsizei samples)
{
ASSERT(mDepthStencilAttachmentCount == 0);
packAttachment(mDepthStencilAttachmentCount++, format, samples);
}
RenderPassDesc &RenderPassDesc::operator=(const RenderPassDesc &other)
{
memcpy(this, &other, sizeof(RenderPassDesc));
return *this;
}
VkAttachmentDescription *RenderPassDesc::nextColorAttachment()
size_t RenderPassDesc::hash() const
{
ASSERT(colorAttachmentCount < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS);
return &attachmentDescs[colorAttachmentCount++];
return angle::ComputeGenericHash(*this);
}
VkAttachmentDescription *RenderPassDesc::nextDepthStencilAttachment()
uint32_t RenderPassDesc::attachmentCount() const
{
ASSERT(depthStencilAttachmentCount == 0);
return &attachmentDescs[depthStencilAttachmentCount++];
return (mColorAttachmentCount + mDepthStencilAttachmentCount);
}
size_t RenderPassDesc::hash() const
uint32_t RenderPassDesc::colorAttachmentCount() const
{
return angle::ComputeGenericHash(*this);
return mColorAttachmentCount;
}
bool RenderPassDesc::operator==(const RenderPassDesc &other) const
uint32_t RenderPassDesc::depthStencilAttachmentCount() const
{
return colorAttachmentCount == other.colorAttachmentCount &&
depthStencilAttachmentCount == other.depthStencilAttachmentCount &&
(memcmp(attachmentDescs.data(), other.attachmentDescs.data(),
sizeof(VkAttachmentDescription) * attachmentDescs.size()) == 0);
return mDepthStencilAttachmentCount;
}
uint32_t RenderPassDesc::attachmentCount() const
const PackedAttachmentDesc &RenderPassDesc::operator[](size_t index) const
{
ASSERT(index < mAttachmentDescs.size());
return mAttachmentDescs[index];
}
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(RenderPassDesc)) == 0);
}
// AttachmentOpsArray implementation.
AttachmentOpsArray::AttachmentOpsArray()
{
return (colorAttachmentCount + depthStencilAttachmentCount);
memset(&mOps, 0, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray::~AttachmentOpsArray()
{
}
AttachmentOpsArray::AttachmentOpsArray(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
}
AttachmentOpsArray &AttachmentOpsArray::operator=(const AttachmentOpsArray &other)
{
memcpy(&mOps, &other.mOps, sizeof(PackedAttachmentOpsDesc) * mOps.size());
return *this;
}
const PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index) const
{
return mOps[index];
}
PackedAttachmentOpsDesc &AttachmentOpsArray::operator[](size_t index)
{
return mOps[index];
}
void AttachmentOpsArray::initDummyOp(size_t index, VkImageLayout finalLayout)
{
PackedAttachmentOpsDesc &ops = mOps[index];
ops.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
ops.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
ops.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ops.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
ops.initialLayout = static_cast<uint16_t>(VK_IMAGE_LAYOUT_UNDEFINED);
ops.finalLayout = static_cast<uint16_t>(finalLayout);
}
size_t AttachmentOpsArray::hash() const
{
return angle::ComputeGenericHash(mOps);
}
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs)
{
return (memcmp(&lhs, &rhs, sizeof(AttachmentOpsArray)) == 0);
}
Error InitializeRenderPassFromDesc(VkDevice device,
const RenderPassDesc &desc,
const AttachmentOpsArray &ops,
RenderPass *renderPass)
{
uint32_t attachmentCount = desc.attachmentCount();
......@@ -1315,7 +1432,7 @@ Error InitializeRenderPassFromDesc(VkDevice device,
gl::DrawBuffersArray<VkAttachmentReference> colorAttachmentRefs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount; ++colorIndex)
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
VkAttachmentReference &colorRef = colorAttachmentRefs[colorIndex];
colorRef.attachment = colorIndex;
......@@ -1323,10 +1440,10 @@ Error InitializeRenderPassFromDesc(VkDevice device,
}
VkAttachmentReference depthStencilAttachmentRef;
if (desc.depthStencilAttachmentCount > 0)
if (desc.depthStencilAttachmentCount() > 0)
{
ASSERT(desc.depthStencilAttachmentCount == 1);
depthStencilAttachmentRef.attachment = desc.colorAttachmentCount;
ASSERT(desc.depthStencilAttachmentCount() == 1);
depthStencilAttachmentRef.attachment = desc.colorAttachmentCount();
depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
......@@ -1336,20 +1453,34 @@ Error InitializeRenderPassFromDesc(VkDevice device,
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDesc.inputAttachmentCount = 0;
subpassDesc.pInputAttachments = nullptr;
subpassDesc.colorAttachmentCount = desc.colorAttachmentCount;
subpassDesc.colorAttachmentCount = desc.colorAttachmentCount();
subpassDesc.pColorAttachments = colorAttachmentRefs.data();
subpassDesc.pResolveAttachments = nullptr;
subpassDesc.pDepthStencilAttachment =
(desc.depthStencilAttachmentCount > 0 ? &depthStencilAttachmentRef : nullptr);
(desc.depthStencilAttachmentCount() > 0 ? &depthStencilAttachmentRef : nullptr);
subpassDesc.preserveAttachmentCount = 0;
subpassDesc.pPreserveAttachments = nullptr;
// Unpack the packed and split representation into the format required by Vulkan.
gl::AttachmentArray<VkAttachmentDescription> attachmentDescs;
for (uint32_t colorIndex = 0; colorIndex < desc.colorAttachmentCount(); ++colorIndex)
{
UnpackAttachmentDesc(&attachmentDescs[colorIndex], desc[colorIndex], ops[colorIndex]);
}
if (desc.depthStencilAttachmentCount() > 0)
{
uint32_t depthStencilIndex = desc.colorAttachmentCount();
UnpackAttachmentDesc(&attachmentDescs[depthStencilIndex], desc[depthStencilIndex],
ops[depthStencilIndex]);
}
VkRenderPassCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.attachmentCount = attachmentCount;
createInfo.pAttachments = desc.attachmentDescs.data();
createInfo.pAttachments = attachmentDescs.data();
createInfo.subpassCount = 1;
createInfo.pSubpasses = &subpassDesc;
createInfo.dependencyCount = 0;
......
......@@ -93,6 +93,8 @@ class ResourceVk
namespace vk
{
struct Format;
template <typename T>
struct ImplTypeHelper;
......@@ -680,31 +682,84 @@ using CommandBufferAndSerial = ObjectAndSerial<CommandBufferAndState>;
using FenceAndSerial = ObjectAndSerial<Fence>;
using RenderPassAndSerial = ObjectAndSerial<RenderPass>;
struct RenderPassDesc final
struct alignas(4) PackedAttachmentDesc
{
uint8_t flags;
uint8_t samples;
uint16_t format;
};
struct alignas(8) PackedAttachmentOpsDesc final
{
uint8_t loadOp;
uint8_t storeOp;
uint8_t stencilLoadOp;
uint8_t stencilStoreOp;
// 16-bits to force pad the structure to exactly 8 bytes.
uint16_t initialLayout;
uint16_t finalLayout;
};
class RenderPassDesc final
{
public:
RenderPassDesc();
~RenderPassDesc();
RenderPassDesc(const RenderPassDesc &other);
RenderPassDesc &operator=(const RenderPassDesc &other);
// These also increment the attachment counts. DS attachments are limited to a count of 1.
VkAttachmentDescription *nextColorAttachment();
VkAttachmentDescription *nextDepthStencilAttachment();
uint32_t attachmentCount() const;
// Depth stencil attachments must be packed after color attachments.
void packColorAttachment(const Format &format, GLsizei samples);
void packDepthStencilAttachment(const Format &format, GLsizei samples);
size_t hash() const;
bool operator==(const RenderPassDesc &other) const;
// Fully padded out, with no bools, to avoid any undefined behaviour.
uint32_t colorAttachmentCount;
uint32_t depthStencilAttachmentCount;
uint32_t attachmentCount() const;
uint32_t colorAttachmentCount() const;
uint32_t depthStencilAttachmentCount() const;
const PackedAttachmentDesc &operator[](size_t index) const;
private:
void packAttachment(uint32_t index, const vk::Format &format, GLsizei samples);
uint32_t mColorAttachmentCount;
uint32_t mDepthStencilAttachmentCount;
gl::AttachmentArray<PackedAttachmentDesc> mAttachmentDescs;
};
bool operator==(const RenderPassDesc &lhs, const RenderPassDesc &rhs);
class AttachmentOpsArray final
{
public:
AttachmentOpsArray();
~AttachmentOpsArray();
AttachmentOpsArray(const AttachmentOpsArray &other);
AttachmentOpsArray &operator=(const AttachmentOpsArray &other);
const PackedAttachmentOpsDesc &operator[](size_t index) const;
PackedAttachmentOpsDesc &operator[](size_t index);
// Initializes an attachment op with whatever values. Used for compatible RenderPass checks.
void initDummyOp(size_t index, VkImageLayout finalLayout);
size_t hash() const;
// The last element in this array is the depth/stencil attachment, if present.
gl::AttachmentArray<VkAttachmentDescription> attachmentDescs;
private:
gl::AttachmentArray<PackedAttachmentOpsDesc> mOps;
};
bool operator==(const AttachmentOpsArray &lhs, const AttachmentOpsArray &rhs);
static_assert(sizeof(PackedAttachmentDesc) == 4, "Size check failed");
static_assert(sizeof(PackedAttachmentOpsDesc) == 8, "Size check failed");
static_assert(sizeof(RenderPassDesc) == 48, "Size check failed");
static_assert(sizeof(AttachmentOpsArray) == 80, "Size check failed");
Error InitializeRenderPassFromDesc(VkDevice device,
const RenderPassDesc &desc,
const AttachmentOpsArray &ops,
RenderPass *renderPass);
} // namespace vk
......@@ -740,6 +795,12 @@ struct hash<rx::vk::RenderPassDesc>
{
size_t operator()(const rx::vk::RenderPassDesc &key) const { return key.hash(); }
};
template <>
struct hash<rx::vk::AttachmentOpsArray>
{
size_t operator()(const rx::vk::AttachmentOpsArray &key) const { return key.hash(); }
};
} // namespace std
#endif // LIBANGLE_RENDERER_VULKAN_RENDERERVK_UTILS_H_
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