From 291904d272552a684286390fd5c235fc6c50208d Mon Sep 17 00:00:00 2001 From: Kaiyi Li Date: Fri, 11 Feb 2022 14:52:47 -0800 Subject: 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 --- host-common/CMakeLists.txt | 3 +- host-common/RenderDoc.h | 75 ++++++++++++++++++++++++++++++++ host-common/RenderDoc_unittest.cpp | 89 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 host-common/RenderDoc.h create mode 100644 host-common/RenderDoc_unittest.cpp (limited to 'host-common') 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 + +#include +#include +#include +#include + +#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 create(const SharedLibrary* renderDocLib) { + if (!renderDocLib) { + ERR("The renderdoc shared library is null."); + return nullptr; + } + pRENDERDOC_GetAPI RENDERDOC_GetAPI = + reinterpret_cast(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(&rdocApi)); + if (ret != 1 || rdocApi == nullptr) { + ERR("Failed to load renderdoc API. %d is returned from RENDERDOC_GetAPI."); + return nullptr; + } + return std::unique_ptr(new RenderDoc(rdocApi)); + } + + static constexpr auto kSetActiveWindow = &RenderDocApi::SetActiveWindow; + static constexpr auto kGetCaptureOptionU32 = &RenderDocApi::GetCaptureOptionU32; + template >> + // 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 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 +#include + +#include "RenderDoc.h" + +#include + +#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> 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(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> mockRENDERDOC_GetAPI; + static pRENDERDOC_GetAPI fpMockRENDERDOC_GetAPI = [](RENDERDOC_Version version, + void** outAPIPointers) { + return mockRENDERDOC_GetAPI.Call(version, outAPIPointers); + }; + RenderDocApi rdocApiMock; + static MockFunction> + 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(fpMockRENDERDOC_GetAPI))); + EXPECT_CALL(mockRENDERDOC_GetAPI, Call(_, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(&rdocApiMock), Return(1))); + std::unique_ptr 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 -- cgit v1.2.3