| /* |
| * 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 <algorithm> |
| #include <cstring> |
| #include <memory> |
| #include <mutex> |
| #include <string> |
| #include <type_traits> |
| #include <unordered_map> |
| #include <vector> |
| |
| #include "aemu/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; |
| 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) const { |
| std::lock_guard<std::mutex> guard(mMutex); |
| return (mRdocApi->*function)(args...); |
| } |
| |
| private: |
| RenderDoc(RenderDocApi* rdocApi) : mRdocApi(rdocApi) {} |
| |
| 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 |