diff options
author | Kaiyi Li <kaiyili@google.com> | 2022-02-11 14:52:47 -0800 |
---|---|---|
committer | Kaiyi Li <kaiyili@google.com> | 2022-03-17 10:48:02 -0700 |
commit | 291904d272552a684286390fd5c235fc6c50208d (patch) | |
tree | b7ea8d2f890662a88d4a95361f9b1a9f8e97bbef /host-common | |
parent | ec3396fe1eb5e3ffb410583f475e65c0bae7617a (diff) | |
download | vulkan-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.txt | 3 | ||||
-rw-r--r-- | host-common/RenderDoc.h | 75 | ||||
-rw-r--r-- | host-common/RenderDoc_unittest.cpp | 89 |
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 |