Commit 887b1346 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Add resolve/unresolve counters

With this change, render-pass-related counters are calculated at render pass creation time and stored alongside the render pass handle (and serial) in the render pass cache. On every use, the render pass' counters are accumulated over the global counters. Additionally, this change adds MSRTT resolve and unresolve counters to render pass counters. Bug: angleproject:4836 Change-Id: If15a789e5a7d66c7ea5a2315bc76fe045ce57491 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2444099 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 102074d1
...@@ -731,12 +731,141 @@ angle::Result CreateRenderPass2(Context *context, ...@@ -731,12 +731,141 @@ angle::Result CreateRenderPass2(Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
angle::Result InitializeRenderPassFromDesc(Context *context, void UpdateRenderPassColorPerfCounters(const VkRenderPassCreateInfo &createInfo,
const VkSubpassDescription &subpass,
vk::RenderPassPerfCounters *countersOut)
{
// Color resolve counters.
if (subpass.pResolveAttachments == nullptr)
{
return;
}
for (uint32_t colorSubpassIndex = 0; colorSubpassIndex < subpass.colorAttachmentCount;
++colorSubpassIndex)
{
uint32_t resolveRenderPassIndex = subpass.pResolveAttachments[colorSubpassIndex].attachment;
if (resolveRenderPassIndex == VK_ATTACHMENT_UNUSED)
{
continue;
}
++countersOut->colorAttachmentResolves;
}
}
void UpdateRenderPassDepthStencilPerfCounters(const VkRenderPassCreateInfo &createInfo,
size_t renderPassIndex,
vk::RenderPassPerfCounters *countersOut)
{
ASSERT(renderPassIndex != VK_ATTACHMENT_UNUSED);
// Depth/stencil ops counters.
const VkAttachmentDescription &ds = createInfo.pAttachments[renderPassIndex];
countersOut->depthClears += ds.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
countersOut->depthLoads += ds.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
countersOut->depthStores += ds.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
countersOut->stencilClears += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
countersOut->stencilLoads += ds.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
countersOut->stencilStores += ds.stencilStoreOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
// Depth/stencil read-only mode.
countersOut->readOnlyDepthStencil +=
ds.finalLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ? 1 : 0;
}
void UpdateRenderPassDepthStencilResolvePerfCounters(
const VkRenderPassCreateInfo &createInfo,
const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
vk::RenderPassPerfCounters *countersOut)
{
if (depthStencilResolve.pDepthStencilResolveAttachment == nullptr)
{
return;
}
uint32_t resolveRenderPassIndex =
depthStencilResolve.pDepthStencilResolveAttachment->attachment;
if (resolveRenderPassIndex == VK_ATTACHMENT_UNUSED)
{
return;
}
const VkAttachmentDescription &dsResolve = createInfo.pAttachments[resolveRenderPassIndex];
// Resolve depth/stencil ops counters.
countersOut->depthClears += dsResolve.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
countersOut->depthLoads += dsResolve.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
countersOut->depthStores += dsResolve.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
countersOut->stencilClears += dsResolve.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
countersOut->stencilLoads += dsResolve.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
countersOut->stencilStores += dsResolve.stencilStoreOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
// Depth/stencil resolve counters.
countersOut->depthAttachmentResolves +=
depthStencilResolve.depthResolveMode != VK_RESOLVE_MODE_NONE ? 1 : 0;
countersOut->stencilAttachmentResolves +=
depthStencilResolve.stencilResolveMode != VK_RESOLVE_MODE_NONE ? 1 : 0;
}
void UpdateRenderPassPerfCounters(
const RenderPassDesc &desc,
const VkRenderPassCreateInfo &createInfo,
const VkSubpassDescriptionDepthStencilResolve &depthStencilResolve,
vk::RenderPassPerfCounters *countersOut)
{
// Accumulate depth/stencil attachment indices in all subpasses to avoid double-counting
// counters.
vk::FramebufferAttachmentMask depthStencilAttachmentIndices;
for (uint32_t subpassIndex = 0; subpassIndex < createInfo.subpassCount; ++subpassIndex)
{
const VkSubpassDescription &subpass = createInfo.pSubpasses[subpassIndex];
// Color counters. Note: currently there are no counters for load/store ops of color
// attachments, so there's no risk of double counting.
UpdateRenderPassColorPerfCounters(createInfo, subpass, countersOut);
// Record index of depth/stencil attachment.
if (subpass.pDepthStencilAttachment != nullptr)
{
uint32_t attachmentRenderPassIndex = subpass.pDepthStencilAttachment->attachment;
if (attachmentRenderPassIndex != VK_ATTACHMENT_UNUSED)
{
depthStencilAttachmentIndices.set(attachmentRenderPassIndex);
}
}
}
// Depth/stencil counters. Currently, both subpasses use the same depth/stencil attachment (if
// any).
ASSERT(depthStencilAttachmentIndices.count() <= 1);
for (size_t attachmentRenderPassIndex : depthStencilAttachmentIndices)
{
UpdateRenderPassDepthStencilPerfCounters(createInfo, attachmentRenderPassIndex,
countersOut);
}
UpdateRenderPassDepthStencilResolvePerfCounters(createInfo, depthStencilResolve, countersOut);
// Determine unresolve counters from the render pass desc, to avoid making guesses from subpass
// count etc.
countersOut->colorAttachmentUnresolves += desc.getColorUnresolveAttachmentMask().count();
countersOut->depthAttachmentUnresolves += desc.hasDepthUnresolveAttachment() ? 1 : 0;
countersOut->stencilAttachmentUnresolves += desc.hasStencilUnresolveAttachment() ? 1 : 0;
}
angle::Result InitializeRenderPassFromDesc(ContextVk *contextVk,
const RenderPassDesc &desc, const RenderPassDesc &desc,
const AttachmentOpsArray &ops, const AttachmentOpsArray &ops,
RenderPass *renderPass) vk::RenderPassHelper *renderPassHelper)
{ {
RendererVk *renderer = context->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
constexpr VkAttachmentReference kUnusedAttachment = {VK_ATTACHMENT_UNUSED, constexpr VkAttachmentReference kUnusedAttachment = {VK_ATTACHMENT_UNUSED,
VK_IMAGE_LAYOUT_UNDEFINED}; VK_IMAGE_LAYOUT_UNDEFINED};
...@@ -940,17 +1069,54 @@ angle::Result InitializeRenderPassFromDesc(Context *context, ...@@ -940,17 +1069,54 @@ angle::Result InitializeRenderPassFromDesc(Context *context,
// vkCreateRenderPass2KHR. // vkCreateRenderPass2KHR.
if (desc.hasDepthStencilResolveAttachment()) if (desc.hasDepthStencilResolveAttachment())
{ {
ANGLE_TRY(CreateRenderPass2(context, createInfo, depthStencilResolve, ANGLE_TRY(CreateRenderPass2(
desc.hasDepthUnresolveAttachment(), contextVk, createInfo, depthStencilResolve, desc.hasDepthUnresolveAttachment(),
desc.hasStencilUnresolveAttachment(), renderPass)); desc.hasStencilUnresolveAttachment(), &renderPassHelper->getRenderPass()));
} }
else else
{ {
ANGLE_VK_TRY(context, renderPass->init(context->getDevice(), createInfo)); ANGLE_VK_TRY(contextVk,
renderPassHelper->getRenderPass().init(contextVk->getDevice(), createInfo));
} }
// Calculate perf counters associated with this render pass, such as load/store ops, unresolve
// and resolve operations etc. This information is taken out of the render pass create info.
// Depth/stencil resolve attachment uses RenderPass2 structures, so it's passed in separately.
UpdateRenderPassPerfCounters(desc, createInfo, depthStencilResolve,
&renderPassHelper->getPerfCounters());
return angle::Result::Continue; return angle::Result::Continue;
} }
void GetRenderPassAndUpdateSerial(ContextVk *contextVk,
Serial serial,
bool updatePerfCounters,
vk::RenderPassHelper *renderPassHelper,
vk::RenderPass **renderPassOut)
{
renderPassHelper->updateSerial(serial);
*renderPassOut = &renderPassHelper->getRenderPass();
if (updatePerfCounters)
{
PerfCounters &counters = contextVk->getPerfCounters();
const RenderPassPerfCounters &rpCounters = renderPassHelper->getPerfCounters();
counters.depthClears += rpCounters.depthClears;
counters.depthLoads += rpCounters.depthLoads;
counters.depthStores += rpCounters.depthStores;
counters.stencilClears += rpCounters.stencilClears;
counters.stencilLoads += rpCounters.stencilLoads;
counters.stencilStores += rpCounters.stencilStores;
counters.colorAttachmentUnresolves += rpCounters.colorAttachmentUnresolves;
counters.colorAttachmentResolves += rpCounters.colorAttachmentResolves;
counters.depthAttachmentUnresolves += rpCounters.depthAttachmentUnresolves;
counters.depthAttachmentResolves += rpCounters.depthAttachmentResolves;
counters.stencilAttachmentUnresolves += rpCounters.stencilAttachmentUnresolves;
counters.stencilAttachmentResolves += rpCounters.stencilAttachmentResolves;
counters.readOnlyDepthStencilRenderPasses += rpCounters.readOnlyDepthStencil;
}
}
void InitializeSpecializationInfo( void InitializeSpecializationInfo(
vk::SpecializationConstantBitSet specConsts, vk::SpecializationConstantBitSet specConsts,
vk::SpecializationConstantMap<VkSpecializationMapEntry> *specializationEntriesOut, vk::SpecializationConstantMap<VkSpecializationMapEntry> *specializationEntriesOut,
...@@ -2823,6 +2989,55 @@ SamplerHelper &SamplerHelper::operator=(SamplerHelper &&rhs) ...@@ -2823,6 +2989,55 @@ SamplerHelper &SamplerHelper::operator=(SamplerHelper &&rhs)
std::swap(mSamplerSerial, rhs.mSamplerSerial); std::swap(mSamplerSerial, rhs.mSamplerSerial);
return *this; return *this;
} }
// RenderPassHelper implementation.
RenderPassHelper::RenderPassHelper() : mPerfCounters{} {}
RenderPassHelper::~RenderPassHelper() = default;
RenderPassHelper::RenderPassHelper(RenderPassHelper &&other)
{
*this = std::move(other);
}
RenderPassHelper &RenderPassHelper::operator=(RenderPassHelper &&other)
{
mRenderPass = std::move(other.mRenderPass);
mSerial = std::move(other.mSerial);
mPerfCounters = std::move(other.mPerfCounters);
return *this;
}
void RenderPassHelper::destroy(VkDevice device)
{
mRenderPass.destroy(device);
mSerial = Serial();
}
const RenderPass &RenderPassHelper::getRenderPass() const
{
return mRenderPass;
}
RenderPass &RenderPassHelper::getRenderPass()
{
return mRenderPass;
}
void RenderPassHelper::updateSerial(Serial serial)
{
mSerial = serial;
}
const RenderPassPerfCounters &RenderPassHelper::getPerfCounters() const
{
return mPerfCounters;
}
RenderPassPerfCounters &RenderPassHelper::getPerfCounters()
{
return mPerfCounters;
}
} // namespace vk } // namespace vk
// RenderPassCache implementation. // RenderPassCache implementation.
...@@ -2839,7 +3054,7 @@ void RenderPassCache::destroy(VkDevice device) ...@@ -2839,7 +3054,7 @@ void RenderPassCache::destroy(VkDevice device)
{ {
for (auto &innerIt : outerIt.second) for (auto &innerIt : outerIt.second)
{ {
innerIt.second.get().destroy(device); innerIt.second.destroy(device);
} }
} }
mPayload.clear(); mPayload.clear();
...@@ -2882,15 +3097,25 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk, ...@@ -2882,15 +3097,25 @@ angle::Result RenderPassCache::addRenderPass(ContextVk *contextVk,
ops.initWithLoadStore(colorIndexVk, imageLayout, imageLayout); ops.initWithLoadStore(colorIndexVk, imageLayout, imageLayout);
} }
return getRenderPassWithOps(contextVk, serial, desc, ops, renderPassOut); return getRenderPassWithOpsImpl(contextVk, serial, desc, ops, false, renderPassOut);
} }
angle::Result RenderPassCache::getRenderPassWithOps(vk::Context *context, angle::Result RenderPassCache::getRenderPassWithOps(ContextVk *contextVk,
Serial serial, Serial serial,
const vk::RenderPassDesc &desc, const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps, const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut) vk::RenderPass **renderPassOut)
{ {
return getRenderPassWithOpsImpl(contextVk, serial, desc, attachmentOps, true, renderPassOut);
}
angle::Result RenderPassCache::getRenderPassWithOpsImpl(ContextVk *contextVk,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
bool updatePerfCounters,
vk::RenderPass **renderPassOut)
{
auto outerIt = mPayload.find(desc); auto outerIt = mPayload.find(desc);
if (outerIt != mPayload.end()) if (outerIt != mPayload.end())
{ {
...@@ -2901,8 +3126,8 @@ angle::Result RenderPassCache::getRenderPassWithOps(vk::Context *context, ...@@ -2901,8 +3126,8 @@ angle::Result RenderPassCache::getRenderPassWithOps(vk::Context *context,
{ {
// Update the serial before we return. // Update the serial before we return.
// TODO(jmadill): Could possibly use an MRU cache here. // TODO(jmadill): Could possibly use an MRU cache here.
innerIt->second.updateSerial(serial); vk::GetRenderPassAndUpdateSerial(contextVk, serial, updatePerfCounters,
*renderPassOut = &innerIt->second.get(); &innerIt->second, renderPassOut);
return angle::Result::Continue; return angle::Result::Continue;
} }
} }
...@@ -2912,14 +3137,13 @@ angle::Result RenderPassCache::getRenderPassWithOps(vk::Context *context, ...@@ -2912,14 +3137,13 @@ angle::Result RenderPassCache::getRenderPassWithOps(vk::Context *context,
outerIt = emplaceResult.first; outerIt = emplaceResult.first;
} }
vk::RenderPass newRenderPass; vk::RenderPassHelper newRenderPass;
ANGLE_TRY(vk::InitializeRenderPassFromDesc(context, desc, attachmentOps, &newRenderPass)); ANGLE_TRY(vk::InitializeRenderPassFromDesc(contextVk, desc, attachmentOps, &newRenderPass));
vk::RenderPassAndSerial withSerial(std::move(newRenderPass), serial);
InnerCache &innerCache = outerIt->second; InnerCache &innerCache = outerIt->second;
auto insertPos = innerCache.emplace(attachmentOps, std::move(withSerial)); auto insertPos = innerCache.emplace(attachmentOps, std::move(newRenderPass));
*renderPassOut = &insertPos.first->second.get(); vk::GetRenderPassAndUpdateSerial(contextVk, serial, updatePerfCounters,
&insertPos.first->second, renderPassOut);
// TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup. // TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -56,8 +56,7 @@ class DynamicDescriptorPool; ...@@ -56,8 +56,7 @@ class DynamicDescriptorPool;
class ImageHelper; class ImageHelper;
enum class ImageLayout; enum class ImageLayout;
using RenderPassAndSerial = ObjectAndSerial<RenderPass>; using PipelineAndSerial = ObjectAndSerial<Pipeline>;
using PipelineAndSerial = ObjectAndSerial<Pipeline>;
using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>; using RefCountedDescriptorSetLayout = RefCounted<DescriptorSetLayout>;
using RefCountedPipelineLayout = RefCounted<PipelineLayout>; using RefCountedPipelineLayout = RefCounted<PipelineLayout>;
...@@ -114,6 +113,7 @@ template <typename T> ...@@ -114,6 +113,7 @@ template <typename T>
using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>; using FramebufferAttachmentArray = std::array<T, kMaxFramebufferAttachments>;
template <typename T> template <typename T>
using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttachments>; using FramebufferAttachmentsVector = angle::FixedVector<T, kMaxFramebufferAttachments>;
using FramebufferAttachmentMask = angle::BitSet<kMaxFramebufferAttachments>;
constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1; constexpr size_t kMaxFramebufferNonResolveAttachments = gl::IMPLEMENTATION_MAX_DRAW_BUFFERS + 1;
template <typename T> template <typename T>
...@@ -1139,6 +1139,31 @@ class SamplerHelper final : angle::NonCopyable ...@@ -1139,6 +1139,31 @@ class SamplerHelper final : angle::NonCopyable
using RefCountedSampler = RefCounted<SamplerHelper>; using RefCountedSampler = RefCounted<SamplerHelper>;
using SamplerBinding = BindingPointer<SamplerHelper>; using SamplerBinding = BindingPointer<SamplerHelper>;
class RenderPassHelper final : angle::NonCopyable
{
public:
RenderPassHelper();
~RenderPassHelper();
RenderPassHelper(RenderPassHelper &&other);
RenderPassHelper &operator=(RenderPassHelper &&other);
void destroy(VkDevice device);
const RenderPass &getRenderPass() const;
RenderPass &getRenderPass();
void updateSerial(Serial serial);
const RenderPassPerfCounters &getPerfCounters() const;
RenderPassPerfCounters &getPerfCounters();
private:
RenderPass mRenderPass;
Serial mSerial;
RenderPassPerfCounters mPerfCounters;
};
} // namespace vk } // namespace vk
} // namespace rx } // namespace rx
...@@ -1235,20 +1260,27 @@ class RenderPassCache final : angle::NonCopyable ...@@ -1235,20 +1260,27 @@ class RenderPassCache final : angle::NonCopyable
// Find the first element and return it. // Find the first element and return it.
innerCache.begin()->second.updateSerial(serial); innerCache.begin()->second.updateSerial(serial);
*renderPassOut = &innerCache.begin()->second.get(); *renderPassOut = &innerCache.begin()->second.getRenderPass();
return angle::Result::Continue; return angle::Result::Continue;
} }
return addRenderPass(contextVk, serial, desc, renderPassOut); return addRenderPass(contextVk, serial, desc, renderPassOut);
} }
angle::Result getRenderPassWithOps(vk::Context *context, angle::Result getRenderPassWithOps(ContextVk *contextVk,
Serial serial, Serial serial,
const vk::RenderPassDesc &desc, const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps, const vk::AttachmentOpsArray &attachmentOps,
vk::RenderPass **renderPassOut); vk::RenderPass **renderPassOut);
private: private:
angle::Result getRenderPassWithOpsImpl(ContextVk *contextVk,
Serial serial,
const vk::RenderPassDesc &desc,
const vk::AttachmentOpsArray &attachmentOps,
bool updatePerfCounters,
vk::RenderPass **renderPassOut);
angle::Result addRenderPass(ContextVk *contextVk, angle::Result addRenderPass(ContextVk *contextVk,
Serial serial, Serial serial,
const vk::RenderPassDesc &desc, const vk::RenderPassDesc &desc,
...@@ -1256,7 +1288,7 @@ class RenderPassCache final : angle::NonCopyable ...@@ -1256,7 +1288,7 @@ class RenderPassCache final : angle::NonCopyable
// Use a two-layer caching scheme. The top level matches the "compatible" RenderPass elements. // 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. // The second layer caches the attachment load/store ops and initial/final layout.
using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassAndSerial>; using InnerCache = std::unordered_map<vk::AttachmentOpsArray, vk::RenderPassHelper>;
using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>; using OuterCache = std::unordered_map<vk::RenderPassDesc, InnerCache>;
OuterCache mPayload; OuterCache mPayload;
......
...@@ -1032,19 +1032,6 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk) ...@@ -1032,19 +1032,6 @@ void CommandBufferHelper::endRenderPass(ContextVk *contextVk)
// Ensure we don't write to a read-only RenderPass. (ReadOnly -> !Write) // Ensure we don't write to a read-only RenderPass. (ReadOnly -> !Write)
ASSERT(!mReadOnlyDepthStencilMode || mDepthAccess != ResourceAccess::Write); ASSERT(!mReadOnlyDepthStencilMode || mDepthAccess != ResourceAccess::Write);
// Fill out perf counters
PerfCounters &counters = contextVk->getPerfCounters();
counters.depthClears += dsOps.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
counters.depthLoads += dsOps.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
counters.depthStores += dsOps.storeOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
counters.stencilClears += dsOps.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR ? 1 : 0;
counters.stencilLoads += dsOps.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD ? 1 : 0;
counters.stencilStores += dsOps.stencilStoreOp == VK_ATTACHMENT_STORE_OP_STORE ? 1 : 0;
counters.readOnlyDepthStencilRenderPasses +=
static_cast<ImageLayout>(dsOps.finalLayout) == vk::ImageLayout::DepthStencilReadOnly ? 1
: 0;
} }
void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount, void CommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
......
...@@ -1215,7 +1215,7 @@ class CommandBufferHelper : angle::NonCopyable ...@@ -1215,7 +1215,7 @@ class CommandBufferHelper : angle::NonCopyable
enum class ImageLayout enum class ImageLayout
{ {
Undefined = 0, Undefined = 0,
// Framebuffer attachment layouts are placed first, so they could fit in fewer bits in // Framebuffer attachment layouts are placed first, so they can fit in fewer bits in
// PackedAttachmentOpsDesc. // PackedAttachmentOpsDesc.
ColorAttachment, ColorAttachment,
DepthStencilReadOnly, DepthStencilReadOnly,
......
...@@ -773,6 +773,27 @@ class ResourceSerialFactory final : angle::NonCopyable ...@@ -773,6 +773,27 @@ class ResourceSerialFactory final : angle::NonCopyable
}; };
// Performance and resource counters. // Performance and resource counters.
struct RenderPassPerfCounters
{
// load/storeOps. Includes ops for resolve attachment. Maximum value = 2.
uint8_t depthClears;
uint8_t depthLoads;
uint8_t depthStores;
uint8_t stencilClears;
uint8_t stencilLoads;
uint8_t stencilStores;
// Number of unresolve and resolve operations. Maximum value for color =
// gl::IMPLEMENTATION_MAX_DRAW_BUFFERS and for depth/stencil = 1 each.
uint8_t colorAttachmentUnresolves;
uint8_t colorAttachmentResolves;
uint8_t depthAttachmentUnresolves;
uint8_t depthAttachmentResolves;
uint8_t stencilAttachmentUnresolves;
uint8_t stencilAttachmentResolves;
// Whether the depth/stencil attachment is using a read-only layout.
uint8_t readOnlyDepthStencil;
};
struct PerfCounters struct PerfCounters
{ {
uint32_t primaryBuffers; uint32_t primaryBuffers;
...@@ -786,6 +807,12 @@ struct PerfCounters ...@@ -786,6 +807,12 @@ struct PerfCounters
uint32_t stencilClears; uint32_t stencilClears;
uint32_t stencilLoads; uint32_t stencilLoads;
uint32_t stencilStores; uint32_t stencilStores;
uint32_t colorAttachmentUnresolves;
uint32_t depthAttachmentUnresolves;
uint32_t stencilAttachmentUnresolves;
uint32_t colorAttachmentResolves;
uint32_t depthAttachmentResolves;
uint32_t stencilAttachmentResolves;
uint32_t readOnlyDepthStencilRenderPasses; uint32_t readOnlyDepthStencilRenderPasses;
}; };
......
...@@ -94,15 +94,6 @@ class VulkanPerformanceCounterTest : public ANGLETest ...@@ -94,15 +94,6 @@ class VulkanPerformanceCounterTest : public ANGLETest
expected->stencilStores = counters.stencilStores + incrementalStencilStores; expected->stencilStores = counters.stencilStores + incrementalStencilStores;
} }
void setAndIncrementLoadCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
uint32_t incrementalDepthLoads,
uint32_t incrementalStencilLoads,
rx::vk::PerfCounters *expected)
{
expected->depthLoads = counters.depthLoads + incrementalDepthLoads;
expected->stencilLoads = counters.stencilLoads + incrementalStencilLoads;
}
void compareDepthStencilCountersForInvalidateTest(const rx::vk::PerfCounters &counters, void compareDepthStencilCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
const rx::vk::PerfCounters &expected) const rx::vk::PerfCounters &expected)
{ {
...@@ -114,12 +105,60 @@ class VulkanPerformanceCounterTest : public ANGLETest ...@@ -114,12 +105,60 @@ class VulkanPerformanceCounterTest : public ANGLETest
EXPECT_EQ(expected.stencilStores, counters.stencilStores); EXPECT_EQ(expected.stencilStores, counters.stencilStores);
} }
void setAndIncrementLoadCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
uint32_t incrementalDepthLoads,
uint32_t incrementalStencilLoads,
rx::vk::PerfCounters *expected)
{
expected->depthLoads = counters.depthLoads + incrementalDepthLoads;
expected->stencilLoads = counters.stencilLoads + incrementalStencilLoads;
}
void compareLoadCountersForInvalidateTest(const rx::vk::PerfCounters &counters, void compareLoadCountersForInvalidateTest(const rx::vk::PerfCounters &counters,
const rx::vk::PerfCounters &expected) const rx::vk::PerfCounters &expected)
{ {
EXPECT_EQ(expected.depthLoads, counters.depthLoads); EXPECT_EQ(expected.depthLoads, counters.depthLoads);
EXPECT_EQ(expected.stencilLoads, counters.stencilLoads); EXPECT_EQ(expected.stencilLoads, counters.stencilLoads);
} }
void setExpectedCountersForUnresolveResolveTest(const rx::vk::PerfCounters &counters,
uint32_t incrementalColorAttachmentUnresolves,
uint32_t incrementalDepthAttachmentUnresolves,
uint32_t incrementalStencilAttachmentUnresolves,
uint32_t incrementalColorAttachmentResolves,
uint32_t incrementalDepthAttachmentResolves,
uint32_t incrementalStencilAttachmentResolves,
rx::vk::PerfCounters *expected)
{
expected->colorAttachmentUnresolves =
counters.colorAttachmentUnresolves + incrementalColorAttachmentUnresolves;
expected->depthAttachmentUnresolves =
counters.depthAttachmentUnresolves + incrementalDepthAttachmentUnresolves;
expected->stencilAttachmentUnresolves =
counters.stencilAttachmentUnresolves + incrementalStencilAttachmentUnresolves;
expected->colorAttachmentResolves =
counters.colorAttachmentResolves + incrementalColorAttachmentResolves;
expected->depthAttachmentResolves =
counters.depthAttachmentResolves + incrementalDepthAttachmentResolves;
expected->stencilAttachmentResolves =
counters.stencilAttachmentResolves + incrementalStencilAttachmentResolves;
}
void compareCountersForUnresolveResolveTest(const rx::vk::PerfCounters &counters,
const rx::vk::PerfCounters &expected)
{
EXPECT_EQ(expected.colorAttachmentUnresolves, counters.colorAttachmentUnresolves);
EXPECT_EQ(expected.depthAttachmentUnresolves, counters.depthAttachmentUnresolves);
if (counters.stencilAttachmentUnresolves != 0)
{
// Allow stencil unresolves to be 0. If VK_EXT_shader_stencil_export is not supported,
// stencil unresolve is impossible.
EXPECT_EQ(expected.stencilAttachmentUnresolves, counters.stencilAttachmentUnresolves);
}
EXPECT_EQ(expected.colorAttachmentResolves, counters.colorAttachmentResolves);
EXPECT_EQ(expected.depthAttachmentResolves, counters.depthAttachmentResolves);
EXPECT_EQ(expected.stencilAttachmentResolves, counters.stencilAttachmentResolves);
}
}; };
class VulkanPerformanceCounterTest_ES31 : public VulkanPerformanceCounterTest class VulkanPerformanceCounterTest_ES31 : public VulkanPerformanceCounterTest
...@@ -1700,11 +1739,19 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou ...@@ -1700,11 +1739,19 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou
ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture")); ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multisampled_render_to_texture"));
const rx::vk::PerfCounters &counters = hackANGLE(); const rx::vk::PerfCounters &counters = hackANGLE();
uint32_t expectedDepthClearCount = counters.depthClears + 1; rx::vk::PerfCounters expected;
uint32_t expectedDepthLoadCount = counters.depthLoads;
uint32_t expectedStencilClearCount = counters.stencilClears + 1; // This test creates 4 render passes. In the first render pass, color, depth and stencil are
uint32_t expectedStencilLoadCountMin = counters.stencilLoads; // cleared. In the following render passes, they must be loaded. However, given that the
uint32_t expectedStencilLoadCountMax = counters.stencilLoads + 4; // attachments are multisampled-render-to-texture, loads are done through an unresolve
// operation. All 4 render passes resolve the attachments.
// Expect rpCount+4, depth(Clears+1, Loads+3, Stores+3), stencil(Clears+1, Load+3, Stores+3).
// Note that the Loads and Stores are from the resolve attachments.
setExpectedCountersForInvalidateTest(counters, 4, 1, 3, 3, 1, 3, 3, &expected);
// Additionally, expect 4 resolves and 3 unresolves.
setExpectedCountersForUnresolveResolveTest(counters, 3, 3, 3, 4, 4, 4, &expected);
GLFramebuffer FBO; GLFramebuffer FBO;
glBindFramebuffer(GL_FRAMEBUFFER, FBO); glBindFramebuffer(GL_FRAMEBUFFER, FBO);
...@@ -1733,11 +1780,11 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou ...@@ -1733,11 +1780,11 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou
glBindTexture(GL_TEXTURE_2D, copyTex); glBindTexture(GL_TEXTURE_2D, copyTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Set viewport and clear depth // Set viewport and clear color, depth and stencil
glViewport(0, 0, kSize, kSize); glViewport(0, 0, kSize, kSize);
glClearDepthf(1); glClearDepthf(1);
glClearStencil(0x55); glClearStencil(0x55);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
// If depth is not cleared to 1, rendering would fail. // If depth is not cleared to 1, rendering would fail.
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
...@@ -1793,11 +1840,8 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou ...@@ -1793,11 +1840,8 @@ TEST_P(VulkanPerformanceCounterTest, RenderToTextureDepthStencilRenderbufferShou
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Verify the counters // Verify the counters
EXPECT_EQ(counters.depthClears, expectedDepthClearCount); compareLoadCountersForInvalidateTest(counters, expected);
EXPECT_EQ(counters.depthLoads, expectedDepthLoadCount); compareCountersForUnresolveResolveTest(counters, expected);
EXPECT_EQ(counters.stencilClears, expectedStencilClearCount);
EXPECT_GE(counters.stencilLoads, expectedStencilLoadCountMin);
EXPECT_LE(counters.stencilLoads, expectedStencilLoadCountMax);
// Verify that copies were done correctly. // Verify that copies were done correctly.
GLFramebuffer verifyFBO; GLFramebuffer verifyFBO;
......
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