Vulkan: Implement a RenderPass cache.
This cache replaces the RenderPass-per-Framebuffer approach. Although
the concepts of a RenderPass are closely associated with rendering to
a Framebuffer, there can be multiple RenderPasses used with a single
FBO, especially considering the nature of Load and Store operations.
This code will then lend itself to the implementation of the deferred
RenderPasses, which are created on flush. These RenderPasses won't
be owned by a Framebuffer.
Bug: angleproject:2264
Change-Id: I4dce07c302118f7e05f5225e2a3b0569ad1e52bf
Reviewed-on: https://chromium-review.googlesource.com/789534
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index f98f242..affb372 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -84,6 +84,63 @@
} // anonymous namespace
+// RenderPassCache implementation.
+RenderPassCache::RenderPassCache()
+{
+}
+
+RenderPassCache::~RenderPassCache()
+{
+ ASSERT(mPayload.empty());
+}
+
+void RenderPassCache::destroy(VkDevice device)
+{
+ for (auto &renderPassIt : mPayload)
+ {
+ renderPassIt.second.get().destroy(device);
+ }
+ mPayload.clear();
+}
+
+vk::Error RenderPassCache::getCompatibleRenderPass(VkDevice device,
+ Serial serial,
+ const vk::RenderPassDesc &desc,
+ vk::RenderPass **renderPassOut)
+{
+ // TODO(jmadill): Return compatible RenderPass when possible.
+ return getMatchingRenderPass(device, serial, desc, renderPassOut);
+}
+
+vk::Error RenderPassCache::getMatchingRenderPass(VkDevice device,
+ Serial serial,
+ const vk::RenderPassDesc &desc,
+ vk::RenderPass **renderPassOut)
+{
+ auto it = mPayload.find(desc);
+ if (it != mPayload.end())
+ {
+ // Update the serial before we return.
+ // TODO(jmadill): Could possibly use an MRU cache here.
+ it->second.updateSerial(serial);
+
+ *renderPassOut = &it->second.get();
+ return vk::NoError();
+ }
+
+ vk::RenderPass newRenderPass;
+ ANGLE_TRY(vk::InitializeRenderPassFromDesc(device, desc, &newRenderPass));
+
+ vk::RenderPassAndSerial withSerial(std::move(newRenderPass), serial);
+
+ auto insertPos = mPayload.emplace(desc, std::move(withSerial));
+ *renderPassOut = &insertPos.first->second.get();
+
+ // TODO(jmadill): Trim cache, and pre-populate with the most common RPs on startup.
+ return vk::NoError();
+}
+
+// RendererVk implementation.
RendererVk::RendererVk()
: mCapsInitialized(false),
mInstance(VK_NULL_HANDLE),
@@ -112,6 +169,8 @@
}
}
+ mRenderPassCache.destroy(mDevice);
+
if (mGlslangWrapper)
{
GlslangWrapper::ReleaseReference();
@@ -798,8 +857,7 @@
{
endRenderPass();
}
- ANGLE_TRY(
- framebufferVk->beginRenderPass(context, mDevice, &mCommandBuffer, mCurrentQueueSerial));
+ ANGLE_TRY(framebufferVk->beginRenderPass(context, this, &mCommandBuffer, mCurrentQueueSerial));
mCurrentRenderPassFramebuffer = framebufferVk;
return gl::NoError();
}
@@ -832,4 +890,18 @@
return serial > mLastCompletedQueueSerial;
}
+vk::Error RendererVk::getCompatibleRenderPass(const vk::RenderPassDesc &desc,
+ vk::RenderPass **renderPassOut)
+{
+ return mRenderPassCache.getCompatibleRenderPass(mDevice, mCurrentQueueSerial, desc,
+ renderPassOut);
+}
+
+vk::Error RendererVk::getMatchingRenderPass(const vk::RenderPassDesc &desc,
+ vk::RenderPass **renderPassOut)
+{
+ return mRenderPassCache.getMatchingRenderPass(mDevice, mCurrentQueueSerial, desc,
+ renderPassOut);
+}
+
} // namespace rx