summaryrefslogtreecommitdiff
path: root/host-common
diff options
context:
space:
mode:
authorKaiyi Li <kaiyili@google.com>2022-03-17 20:37:12 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-03-17 20:37:12 +0000
commit8162a818d11c8a76c27663af57f4f9a873e7fdfe (patch)
tree9dc914f1ac8c32243d561b66c9de97a12869579b /host-common
parent843b91d5f83805dbdd60b1451a3c42c62c0fe095 (diff)
parente4159ae89caa28fd8bf2593aa9098f30b5e9c822 (diff)
downloadvulkan-cereal-8162a818d11c8a76c27663af57f4f9a873e7fdfe.tar.gz
Merge "Integrate RenderDoc with guest VkInstances"
Diffstat (limited to 'host-common')
-rw-r--r--host-common/RenderDoc.h54
-rw-r--r--host-common/RenderDoc_unittest.cpp89
2 files changed, 141 insertions, 2 deletions
diff --git a/host-common/RenderDoc.h b/host-common/RenderDoc.h
index e141f727..e3b128f3 100644
--- a/host-common/RenderDoc.h
+++ b/host-common/RenderDoc.h
@@ -18,10 +18,14 @@
#include <renderdoc_app.h>
+#include <algorithm>
#include <cstring>
#include <memory>
#include <mutex>
+#include <string>
#include <type_traits>
+#include <unordered_map>
+#include <vector>
#include "base/SharedLibrary.h"
#include "host-common/logging.h"
@@ -56,10 +60,13 @@ class RenderDoc {
static constexpr auto kSetActiveWindow = &RenderDocApi::SetActiveWindow;
static constexpr auto kGetCaptureOptionU32 = &RenderDocApi::GetCaptureOptionU32;
+ static constexpr auto kIsFrameCapturing = &RenderDocApi::IsFrameCapturing;
+ static constexpr auto kStartFrameCapture = &RenderDocApi::StartFrameCapture;
+ static constexpr auto kEndFrameCapture = &RenderDocApi::EndFrameCapture;
template <class F, class... Args, typename = std::enable_if_t<std::is_invocable_v<F, Args...>>>
// Call a RenderDoc in-application API given the function pointer and parameters, and guard the
// API call with a mutex.
- auto call(F(RenderDocApi::*function), Args... args) {
+ auto call(F(RenderDocApi::*function), Args... args) const {
std::lock_guard<std::mutex> guard(mMutex);
return (mRdocApi->*function)(args...);
}
@@ -67,9 +74,52 @@ class RenderDoc {
private:
RenderDoc(RenderDocApi* rdocApi) : mRdocApi(rdocApi) {}
- std::mutex mMutex;
+ mutable std::mutex mMutex;
RenderDocApi* mRdocApi = nullptr;
};
+
+template <class RenderDocT>
+class RenderDocWithMultipleVkInstancesBase {
+ public:
+ RenderDocWithMultipleVkInstancesBase(RenderDocT& renderDoc) : mRenderDoc(renderDoc) {}
+
+ void onFrameDelimiter(VkInstance vkInstance) {
+ std::lock_guard<std::mutex> guard(mMutex);
+ mCaptureContexts.erase(vkInstance);
+ if (mRenderDoc.call(RenderDoc::kIsFrameCapturing)) {
+ mCaptureContexts.emplace(vkInstance,
+ std::make_unique<CaptureContext>(mRenderDoc, vkInstance));
+ }
+ }
+
+ void removeVkInstance(VkInstance vkInstance) {
+ std::lock_guard<std::mutex> guard(mMutex);
+ mCaptureContexts.erase(vkInstance);
+ }
+
+ private:
+ class CaptureContext {
+ public:
+ CaptureContext(RenderDocT& renderDoc, VkInstance vkInstance)
+ : mRenderDoc(renderDoc), mVkInstance(vkInstance) {
+ mRenderDoc.call(RenderDoc::kStartFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(mVkInstance), nullptr);
+ }
+ ~CaptureContext() {
+ mRenderDoc.call(RenderDoc::kEndFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(mVkInstance), nullptr);
+ }
+
+ private:
+ const RenderDocT& mRenderDoc;
+ const VkInstance mVkInstance;
+ };
+ std::mutex mMutex;
+ std::unordered_map<VkInstance, std::unique_ptr<CaptureContext>> mCaptureContexts;
+ RenderDocT& mRenderDoc;
+};
+
+using RenderDocWithMultipleVkInstances = RenderDocWithMultipleVkInstancesBase<RenderDoc>;
} // namespace emugl
#endif
diff --git a/host-common/RenderDoc_unittest.cpp b/host-common/RenderDoc_unittest.cpp
index 8c1fa432..16a34481 100644
--- a/host-common/RenderDoc_unittest.cpp
+++ b/host-common/RenderDoc_unittest.cpp
@@ -85,5 +85,94 @@ TEST(RenderDocTest, CreateSuccessfully) {
EXPECT_EQ(renderDoc->call(RenderDoc::kGetCaptureOptionU32, eRENDERDOC_Option_DebugOutputMute),
1);
}
+
+class RenderDocMock {
+ public:
+ // For StartFrameCapture
+ MOCK_METHOD(void, call,
+ (void (*RenderDocApi::*function)(RENDERDOC_DevicePointer, RENDERDOC_WindowHandle),
+ RENDERDOC_DevicePointer, RENDERDOC_WindowHandle),
+ (const));
+ // For EndFrameCapture
+ MOCK_METHOD(uint32_t, call,
+ (uint32_t(*RenderDocApi::*function)(RENDERDOC_DevicePointer,
+ RENDERDOC_WindowHandle),
+ RENDERDOC_DevicePointer, RENDERDOC_WindowHandle),
+ (const));
+ // For IsFrameCapturing
+ MOCK_METHOD(uint32_t, call, (uint32_t(*RenderDocApi::*function)()), (const));
+};
+
+using RenderDocWithMultipleVkInstances = RenderDocWithMultipleVkInstancesBase<RenderDocMock>;
+
+TEST(RenderDocWithMultipleVkInstancesTest,
+ ShouldNotStartFrameCaptureOnFrameDelimiterWhenNotCapturing) {
+ RenderDocMock renderDocMock;
+ RenderDocWithMultipleVkInstances renderDocWithMultipleVkInstances(renderDocMock);
+ int vkInstanceInternal = 0x1234;
+ VkInstance vkInstance = reinterpret_cast<VkInstance>(&vkInstanceInternal);
+
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kIsFrameCapturing)).WillRepeatedly(Return(0));
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kStartFrameCapture, _, _)).Times(0);
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kEndFrameCapture, _, _)).Times(0);
+
+ renderDocWithMultipleVkInstances.onFrameDelimiter(vkInstance);
+}
+
+TEST(RenderDocWithMultipleVkInstancesTest, ShouldStartAndEndFrameCaptureOnFrameDelimiter) {
+ RenderDocMock renderDocMock;
+ RenderDocWithMultipleVkInstances renderDocWithMultipleVkInstances(renderDocMock);
+ int vkInstanceInternal = 0x4321;
+ VkInstance vkInstance = reinterpret_cast<VkInstance>(&vkInstanceInternal);
+
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kIsFrameCapturing)).WillRepeatedly(Return(1));
+ {
+ InSequence s;
+
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kStartFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(1);
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kEndFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(1)
+ .WillRepeatedly(Return(1));
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kStartFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(1);
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kEndFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(1)
+ .WillRepeatedly(Return(1));
+ }
+
+ renderDocWithMultipleVkInstances.onFrameDelimiter(vkInstance);
+ renderDocWithMultipleVkInstances.onFrameDelimiter(vkInstance);
+}
+
+TEST(RenderDocWithMultipleVkInstancesTest, ShouldEndFrameCaptureOnVkInstanceRemoved) {
+ RenderDocMock renderDocMock;
+ RenderDocWithMultipleVkInstances renderDocWithMultipleVkInstances(renderDocMock);
+ int vkInstanceInternal = 0x4321;
+ VkInstance vkInstance = reinterpret_cast<VkInstance>(&vkInstanceInternal);
+
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kIsFrameCapturing)).WillRepeatedly(Return(1));
+ {
+ InSequence s;
+
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kStartFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(1);
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kEndFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(1)
+ .WillRepeatedly(Return(1));
+ }
+
+ renderDocWithMultipleVkInstances.onFrameDelimiter(vkInstance);
+ renderDocWithMultipleVkInstances.removeVkInstance(vkInstance);
+ EXPECT_CALL(renderDocMock, call(RenderDoc::kEndFrameCapture,
+ RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vkInstance), NULL))
+ .Times(0);
+}
} // namespace
} // namespace emugl