summaryrefslogtreecommitdiff
path: root/host-common
diff options
context:
space:
mode:
authorKaiyi Li <kaiyili@google.com>2022-02-11 14:52:47 -0800
committerKaiyi Li <kaiyili@google.com>2022-03-17 10:48:02 -0700
commit291904d272552a684286390fd5c235fc6c50208d (patch)
treeb7ea8d2f890662a88d4a95361f9b1a9f8e97bbef /host-common
parentec3396fe1eb5e3ffb410583f475e65c0bae7617a (diff)
downloadvulkan-cereal-291904d272552a684286390fd5c235fc6c50208d.tar.gz
Add basic renderdoc integration
Set the ANDROID_EMU_RENDERDOC environment varaible will load the renderdoc DLL in FrameBuffer::initialize(). Test: run the emulator with and without ANDROID_EMU_RENDERDOC set, and use renderdoc to capture some Asphalt 9 frames Change-Id: I1e9b4abf1477f1ecdd8f3deea74c311478293578
Diffstat (limited to 'host-common')
-rw-r--r--host-common/CMakeLists.txt3
-rw-r--r--host-common/RenderDoc.h75
-rw-r--r--host-common/RenderDoc_unittest.cpp89
3 files changed, 166 insertions, 1 deletions
diff --git a/host-common/CMakeLists.txt b/host-common/CMakeLists.txt
index 423d8fd0..00f81430 100644
--- a/host-common/CMakeLists.txt
+++ b/host-common/CMakeLists.txt
@@ -132,7 +132,8 @@ add_executable(
HostAddressSpace_unittest.cpp
HostmemIdMapping_unittest.cpp
logging_unittest.cpp
- GfxstreamFatalError_unittest.cpp)
+ GfxstreamFatalError_unittest.cpp
+ RenderDoc_unittest.cpp)
target_include_directories(
gfxstream-host-common_unittests
diff --git a/host-common/RenderDoc.h b/host-common/RenderDoc.h
new file mode 100644
index 00000000..e141f727
--- /dev/null
+++ b/host-common/RenderDoc.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011-2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef RENDER_DOC_H
+#define RENDER_DOC_H
+
+#include <renderdoc_app.h>
+
+#include <cstring>
+#include <memory>
+#include <mutex>
+#include <type_traits>
+
+#include "base/SharedLibrary.h"
+#include "host-common/logging.h"
+#include "vulkan/vulkan.h"
+
+using android::base::SharedLibrary;
+
+namespace emugl {
+class RenderDoc {
+ public:
+ using RenderDocApi = RENDERDOC_API_1_4_2;
+ static std::unique_ptr<RenderDoc> create(const SharedLibrary* renderDocLib) {
+ if (!renderDocLib) {
+ ERR("The renderdoc shared library is null.");
+ return nullptr;
+ }
+ pRENDERDOC_GetAPI RENDERDOC_GetAPI =
+ reinterpret_cast<pRENDERDOC_GetAPI>(renderDocLib->findSymbol("RENDERDOC_GetAPI"));
+ if (!RENDERDOC_GetAPI) {
+ ERR("Failed to find the RENDERDOC_GetAPI symbol.");
+ return nullptr;
+ }
+ RenderDocApi* rdocApi = nullptr;
+ int ret =
+ RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_4_2, reinterpret_cast<void**>(&rdocApi));
+ if (ret != 1 || rdocApi == nullptr) {
+ ERR("Failed to load renderdoc API. %d is returned from RENDERDOC_GetAPI.");
+ return nullptr;
+ }
+ return std::unique_ptr<RenderDoc>(new RenderDoc(rdocApi));
+ }
+
+ static constexpr auto kSetActiveWindow = &RenderDocApi::SetActiveWindow;
+ static constexpr auto kGetCaptureOptionU32 = &RenderDocApi::GetCaptureOptionU32;
+ 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) {
+ std::lock_guard<std::mutex> guard(mMutex);
+ return (mRdocApi->*function)(args...);
+ }
+
+ private:
+ RenderDoc(RenderDocApi* rdocApi) : mRdocApi(rdocApi) {}
+
+ std::mutex mMutex;
+ RenderDocApi* mRdocApi = nullptr;
+};
+} // namespace emugl
+
+#endif
diff --git a/host-common/RenderDoc_unittest.cpp b/host-common/RenderDoc_unittest.cpp
new file mode 100644
index 00000000..8c1fa432
--- /dev/null
+++ b/host-common/RenderDoc_unittest.cpp
@@ -0,0 +1,89 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "RenderDoc.h"
+
+#include <type_traits>
+
+#include "base/SharedLibrary.h"
+
+namespace emugl {
+namespace {
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MockFunction;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+using FunctionPtr = android::base::SharedLibrary::FunctionPtr;
+using RenderDocApi = RenderDoc::RenderDocApi;
+
+class MockSharedLibrary : public android::base::SharedLibrary {
+ public:
+ MockSharedLibrary() : SharedLibrary(NULL) {}
+ MOCK_METHOD(FunctionPtr, findSymbol, (const char*), (const, override));
+};
+
+TEST(RenderDocTest, InitializeWithNullSharedLibrary) {
+ EXPECT_EQ(RenderDoc::create(nullptr), nullptr);
+}
+
+TEST(RenderDocTest, CantFindRENDERDOC_GetAPI) {
+ MockSharedLibrary sharedLibrary;
+ EXPECT_CALL(sharedLibrary, findSymbol(_)).WillRepeatedly(Return(nullptr));
+ EXPECT_EQ(RenderDoc::create(&sharedLibrary), nullptr);
+}
+
+TEST(RenderDocTest, RENDERDOC_GetAPIFails) {
+ MockSharedLibrary sharedLibrary;
+ static MockFunction<std::remove_pointer_t<pRENDERDOC_GetAPI>> mockRENDERDOC_GetAPI;
+ static pRENDERDOC_GetAPI fpMockRENDERDOC_GetAPI = [](RENDERDOC_Version version,
+ void** outAPIPointers) {
+ return mockRENDERDOC_GetAPI.Call(version, outAPIPointers);
+ };
+ RenderDocApi rdocApi;
+
+ EXPECT_CALL(sharedLibrary, findSymbol(_)).WillRepeatedly(Return(nullptr));
+ EXPECT_CALL(sharedLibrary, findSymbol("RENDERDOC_GetAPI"))
+ .WillRepeatedly(Return(reinterpret_cast<FunctionPtr>(fpMockRENDERDOC_GetAPI)));
+
+ EXPECT_CALL(mockRENDERDOC_GetAPI, Call(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(&rdocApi), Return(0)));
+ EXPECT_EQ(RenderDoc::create(&sharedLibrary), nullptr);
+
+ EXPECT_CALL(mockRENDERDOC_GetAPI, Call(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(nullptr), Return(1)));
+ EXPECT_EQ(RenderDoc::create(&sharedLibrary), nullptr);
+}
+
+TEST(RenderDocTest, CreateSuccessfully) {
+ MockSharedLibrary sharedLibrary;
+ static MockFunction<std::remove_pointer_t<pRENDERDOC_GetAPI>> mockRENDERDOC_GetAPI;
+ static pRENDERDOC_GetAPI fpMockRENDERDOC_GetAPI = [](RENDERDOC_Version version,
+ void** outAPIPointers) {
+ return mockRENDERDOC_GetAPI.Call(version, outAPIPointers);
+ };
+ RenderDocApi rdocApiMock;
+ static MockFunction<std::remove_pointer_t<pRENDERDOC_GetCaptureOptionU32>>
+ getCaptureOptionU32Mock;
+ rdocApiMock.GetCaptureOptionU32 = [](RENDERDOC_CaptureOption option) {
+ return getCaptureOptionU32Mock.Call(option);
+ };
+
+ EXPECT_CALL(sharedLibrary, findSymbol(_)).WillRepeatedly(Return(nullptr));
+ EXPECT_CALL(sharedLibrary, findSymbol("RENDERDOC_GetAPI"))
+ .WillRepeatedly(Return(reinterpret_cast<FunctionPtr>(fpMockRENDERDOC_GetAPI)));
+ EXPECT_CALL(mockRENDERDOC_GetAPI, Call(_, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(&rdocApiMock), Return(1)));
+ std::unique_ptr<RenderDoc> renderDoc = RenderDoc::create(&sharedLibrary);
+ EXPECT_NE(renderDoc, nullptr);
+
+ EXPECT_CALL(getCaptureOptionU32Mock, Call(eRENDERDOC_Option_DebugOutputMute))
+ .WillRepeatedly(Return(1));
+ EXPECT_EQ(renderDoc->call(RenderDoc::kGetCaptureOptionU32, eRENDERDOC_Option_DebugOutputMute),
+ 1);
+}
+} // namespace
+} // namespace emugl