Add runtime RenderDoc support for Windows dx12/vulkan via --enableRenderDoc option

- RenderDoc is disabled when building the monolithic build
- The installation path is inferred on Windows, but may be overridden on
  Windows/Linux via the ATOM_RENDERDOC_PATH environment variable
- Linux support may work, but I have no means to test it
- Android support shouldn't be difficult to add, but requires a
  renderdoc_android.cmake file that understands how the RenderDoc
  package is distributed as part of the Android toolchain

Signed-off-by: Jeremy Ong <jcong@amazon.com>
This commit is contained in:
Jeremy Ong
2021-07-31 17:22:51 -06:00
parent b46a80be2c
commit f9303a2eaa
7 changed files with 202 additions and 1 deletions
+23
View File
@@ -10,6 +10,23 @@ ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${P
include(${pal_dir}/AtomRHITests_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
set(RENDERDOC_CMAKE ${CMAKE_CURRENT_SOURCE_DIR}/${pal_dir}/renderdoc_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
if(EXISTS ${RENDERDOC_CMAKE})
include(${RENDERDOC_CMAKE})
endif()
if(TARGET "3rdParty::renderdoc")
message(STATUS "Renderdoc found")
set(USE_RENDERDOC_DEFINE "USE_RENDERDOC")
set(RENDERDOC_BUILD_DEPENDENCY "3rdParty::renderdoc")
set(RENDERDOC_API_DEPENDENCY "3rdParty::renderdoc_api")
else()
message(STATUS "Renderdoc missing")
set(USE_RENDERDOC_DEFINE "")
set(RENDERDOC_BUILD_DEPENDENCY "")
set(RENDERDOC_API_DEPENDENCY "")
endif()
ly_add_target(
NAME Atom_RHI.Reflect STATIC
NAMESPACE Gem
@@ -43,6 +60,12 @@ ly_add_target(
AZ::AzCore
AZ::AzFramework
Gem::Atom_RHI.Reflect
${RENDERDOC_BUILD_DEPENDENCY}
PUBLIC
${RENDERDOC_API_DEPENDENCY}
COMPILE_DEFINITIONS
PUBLIC
${USE_RENDERDOC_DEFINE}
)
ly_add_target(
+25 -1
View File
@@ -11,6 +11,11 @@
#include <Atom/RHI/PhysicalDevice.h>
#include <AzCore/Name/Name.h>
#if defined(USE_RENDERDOC)
#include <renderdoc_app.h>
#include <AzCore/AzCore_Traits_Platform.h>
#endif
namespace AZ
{
namespace RHI
@@ -66,7 +71,7 @@ namespace AZ
public:
AZ_TYPE_INFO(Factory, "{2C0231FD-DD11-4154-A4F5-177181E26D8E}");
Factory() = default;
Factory();
virtual ~Factory() = default;
// Note that you have to delete these for safety reasons, you will trip a static_assert if you do not
@@ -93,6 +98,25 @@ namespace AZ
/// Access the global factory instance.
static Factory& Get();
#if defined(USE_RENDERDOC)
#if defined(AZ_PLATFORM_WINDOWS)
static const char* RENDERDOC_MODULE = "renderdoc.dll";
#elif defined(AZ_PLATFORM_LINUX)
static const char* RENDERDOC_MODULE = "librenderdoc.so";
#elif defined(AZ_PLATFORM_ANDROID)
static const char* RENDERDOC_MODULE = "libVkLayer_GLES_RenderDoc.so"
#else
static const char* RENDERDOC_MODULE = nullptr;
#endif
/// Access the RenderDoc API pointer if available.
/// The availability of the render doc API at runtime depends on the following:
/// - You must not be building a packaged game/product (LY_MONOLITHIC_GAME not enabled in CMake)
/// - A valid renderdoc installation was found, either by auto-discovery, or by supplying ATOM_RENDERDOC_PATH as an environment variable
/// - The module loaded successfully at runtime, and the API function pointer was retrieved successfully
static RENDERDOC_API_1_1_2* GetRenderDocAPI();
#endif
/// Returns the name of the Factory.
virtual Name GetName() = 0;
@@ -37,6 +37,9 @@ namespace AZ
//! If multiple values exist it will return the last one
AZStd::string GetCommandLineValue(const AZStd::string& commandLineOption);
//! Returns true if the command line option is set
bool QueryCommandLineOption(const AZStd::string& commandLineOption);
//! Returns if the current bakcend is a null renderer
bool IsNullRenderer();
}
@@ -0,0 +1,36 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
# Prevent bundling the renderdoc dll with a packaged title
if(NOT LY_MONOLITHIC_GAME)
if(DEFINED ENV{"ATOM_RENDERDOC_PATH"})
set(RENDERDOC_PATH ENV{"ATOM_RENDERDOC_PATH"})
endif()
if(RENDERDOC_PATH)
# Normalize file path
file(TO_CMAKE_PATH "${RENDERDOC_PATH}" RENDERDOC_PATH)
if(EXISTS "${RENDERDOC_PATH}/librenderdoc.so")
ly_add_external_target(
NAME renderdoc
VERSION
3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH}
INCLUDE_DIRECTORIES "."
RUNTIME_DEPENDENCIES "${RENDERDOC_PATH}/librenderdoc.so"
)
ly_add_external_target(
NAME renderdoc_api
VERSION
3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH}
INCLUDE_DIRECTORIES "."
)
endif()
endif()
endif()
@@ -0,0 +1,38 @@
#
# Copyright (c) Contributors to the Open 3D Engine Project.
# For complete copyright and license terms please see the LICENSE at the root of this distribution.
#
# SPDX-License-Identifier: Apache-2.0 OR MIT
#
#
# Prevent bundling the renderdoc dll with a packaged title
if(NOT LY_MONOLITHIC_GAME)
# Common installation path for renderdoc path
set(RENDERDOC_PATH "C:/Program Files/RenderDoc")
if(DEFINED ENV{"ATOM_RENDERDOC_PATH"})
set(RENDERDOC_PATH ENV{"ATOM_RENDERDOC_PATH"})
endif()
if(RENDERDOC_PATH)
# Normalize file path
file(TO_CMAKE_PATH "${RENDERDOC_PATH}" RENDERDOC_PATH)
if(EXISTS "${RENDERDOC_PATH}/renderdoc.dll")
ly_add_external_target(
NAME renderdoc
VERSION
3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH}
INCLUDE_DIRECTORIES "."
RUNTIME_DEPENDENCIES "${RENDERDOC_PATH}/renderdoc.dll"
)
ly_add_external_target(
NAME renderdoc_api
VERSION
3RDPARTY_ROOT_DIRECTORY ${RENDERDOC_PATH}
INCLUDE_DIRECTORIES "."
)
endif()
endif()
endif()
+65
View File
@@ -11,6 +11,15 @@
#include <AzCore/Interface/Interface.h>
#include <AzCore/Component/TickBus.h>
#if defined(USE_RENDERDOC)
#include <AzCore/Module/DynamicModuleHandle.h>
#include <Atom/RHI/RHIUtils.h>
static AZStd::unique_ptr<AZ::DynamicModuleHandle> s_renderDocModule;
static RENDERDOC_API_1_1_2* s_renderDocApi = nullptr;
#endif
namespace AZ
{
namespace RHI
@@ -30,6 +39,48 @@ namespace AZ
return AZ_CRC("RHIPlatformService", 0xfff2cea4);
}
Factory::Factory()
{
#if defined(USE_RENDERDOC)
// If RenderDoc is requested, we need to load the library as early as possible (before device queries/factories are made)
bool enableRenderDoc = RHI::QueryCommandLineOption("enableRenderDoc");
if (enableRenderDoc && RENDERDOC_MODULE && !s_renderDocModule)
{
s_renderDocModule = DynamicModuleHandle::Create(RENDERDOC_MODULE);
if (s_renderDocModule)
{
if (s_renderDocModule->Load(false))
{
pRENDERDOC_GetAPI renderDocGetAPI = s_renderDocModule->GetFunction<pRENDERDOC_GetAPI>("RENDERDOC_GetAPI");
if (renderDocGetAPI)
{
if (!renderDocGetAPI(eRENDERDOC_API_Version_1_1_2, reinterpret_cast<void**>(&s_renderDocApi)))
{
s_renderDocApi = nullptr;
}
}
if (s_renderDocApi)
{
// Prevent RenderDoc from handling any exceptions that may interfere with the O3DE exception handler
s_renderDocApi->UnloadCrashHandler();
}
else
{
AZ_Printf("RHISystem", "RenderDoc module loaded but failed to retrieve API function pointer.\n");
}
}
else
{
AZ_Printf("RHISystem", "RenderDoc module requested but module failed to load.\n");
}
}
}
#endif // defined(USE_RENDERDOC)
}
void Factory::Register(Factory* instance)
{
Interface<Factory>::Register(instance);
@@ -58,6 +109,13 @@ namespace AZ
ResourceInvalidateBus::ClearQueuedEvents();
Interface<Factory>::Unregister(instance);
#if defined(USE_RENDERDOC)
if (s_renderDocModule)
{
s_renderDocModule->Unload();
}
#endif
}
bool Factory::IsReady()
@@ -71,5 +129,12 @@ namespace AZ
AZ_Assert(factory, "RHI::Factory is not connected to a platform. Call IsReady() to get the status of the platform. A null de-reference is imminent.");
return *factory;
}
#if defined(USE_RENDERDOC)
RENDERDOC_API_1_1_2* Factory::GetRenderDocAPI()
{
return s_renderDocApi;
}
#endif
}
}
@@ -122,5 +122,17 @@ namespace AZ
}
return commandLineValue;
}
bool QueryCommandLineOption(const AZStd::string& commandLineOption)
{
const AzFramework::CommandLine* commandLine = nullptr;
AzFramework::ApplicationRequests::Bus::BroadcastResult(commandLine, &AzFramework::ApplicationRequests::GetApplicationCommandLine);
if (commandLine)
{
return commandLine->HasSwitch(commandLineOption);
}
return false;
}
}
}