diff options
Diffstat (limited to 'host-common')
-rw-r--r-- | host-common/RenderDoc.h | 54 | ||||
-rw-r--r-- | host-common/RenderDoc_unittest.cpp | 89 |
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 |