diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index 5b00b0822..e0bf4c419 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -1088,6 +1088,9 @@ worked around by re-sorting bindings. )"); bool shadersMutable = false; + DOCUMENT("``True`` if the driver and system are configured to allow creating RGP captures."); + bool RGPCapture = false; + #if !defined(SWIG) // flags about edge-case parts of the APIs that might be used in the capture. bool ShaderLinkage = false; diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 4d1e04e2e..0389398f6 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -747,6 +747,14 @@ function must be called from another thread. )"); virtual void ReplayLoop(WindowingData window, ResourceId texid) = 0; + DOCUMENT(R"(Uses the given output window to create an RGP Profile. + +:param WindowingData window: A :class:`WindowingData` describing the native window. +:return: The path to the created RGP profile, or empty on failure +:rtype: str +)"); + virtual rdcstr CreateRGPProfile(WindowingData window) = 0; + DOCUMENT("Cancels a replay loop begun in :meth:`ReplayLoop`. Does nothing if no loop is active."); virtual void CancelReplayLoop() = 0; diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 4c653797e..9d91376d4 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -74,6 +74,7 @@ public: { return m_Proxy->GetSupportedWindowSystems(); } + AMDRGPControl *GetRGPControl() { return NULL; } uint64_t MakeOutputWindow(WindowingData window, bool depth) { return m_Proxy->MakeOutputWindow(window, depth); diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 4f757adbf..73038ad47 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -149,6 +149,7 @@ public: { return ReplayStatus::Succeeded; } + AMDRGPControl *GetRGPControl() { return NULL; } vector GetSupportedWindowSystems() { if(m_Proxy) diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index dae165c55..d4cb85323 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -147,6 +147,7 @@ public: return ret; } + AMDRGPControl *GetRGPControl() { return NULL; } uint64_t MakeOutputWindow(WindowingData window, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index d1077415e..f5f0450e6 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -26,6 +26,7 @@ #include "driver/dx/official/d3dcompiler.h" #include "driver/dxgi/dxgi_common.h" #include "driver/ihv/amd/amd_counters.h" +#include "driver/ihv/amd/amd_rgp.h" #include "maths/camera.h" #include "maths/matrix.h" #include "serialise/rdcfile.h" @@ -70,6 +71,8 @@ void D3D12Replay::Shutdown() m_ProxyResources[i]->Release(); m_ProxyResources.clear(); + SAFE_DELETE(m_RGP); + m_pDevice->Release(); } @@ -175,6 +178,7 @@ APIProperties D3D12Replay::GetAPIProperties() ret.vendor = m_Vendor; ret.degraded = false; ret.shadersMutable = false; + ret.RGPCapture = m_RGP != NULL && m_RGP->DriverSupportsInterop(); return ret; } @@ -3361,6 +3365,11 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) if(initParams.MinimumFeatureLevel < D3D_FEATURE_LEVEL_11_0) initParams.MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0; + AMDRGPControl *rgp = new AMDRGPControl(); + + if(!rgp->Initialised()) + SAFE_DELETE(rgp); + ID3D12Device *dev = NULL; HRESULT hr = RENDERDOC_CreateWrappedD3D12Device(NULL, initParams.MinimumFeatureLevel, __uuidof(ID3D12Device), (void **)&dev); @@ -3369,6 +3378,8 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) { RDCERR("Couldn't create a d3d12 device :(."); + SAFE_DELETE(rgp); + return ReplayStatus::APIHardwareUnsupported; } @@ -3379,6 +3390,7 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) D3D12Replay *replay = wrappedDev->GetReplay(); replay->SetProxy(rdc == NULL); + replay->SetRGP(rgp); *driver = (IReplayDriver *)replay; return ReplayStatus::Succeeded; diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index fc21c80fb..89222225f 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -53,6 +53,7 @@ public: D3D12Replay(); D3D12DebugManager *GetDebugManager() { return m_DebugManager; } + void SetRGP(AMDRGPControl *rgp) { m_RGP = rgp; } void SetProxy(bool proxy) { m_Proxy = proxy; } bool IsRemoteProxy() { return m_Proxy; } void Shutdown(); @@ -104,6 +105,7 @@ public: return ret; } + AMDRGPControl *GetRGPControl() { return m_RGP; } uint64_t MakeOutputWindow(WindowingData window, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); @@ -398,6 +400,7 @@ private: IDXGIFactory4 *m_pFactory = NULL; AMDCounters *m_pAMDCounters = NULL; + AMDRGPControl *m_RGP = NULL; D3D12AMDDrawCallback *m_pAMDDrawCallback = NULL; diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 48de95fe4..99dad3981 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -140,6 +140,7 @@ public: return ret; } + AMDRGPControl *GetRGPControl() { return NULL; } uint64_t MakeOutputWindow(WindowingData window, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 23ff840e7..84545bbb4 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -24,6 +24,7 @@ #include "vk_replay.h" #include +#include "driver/ihv/amd/amd_rgp.h" #include "maths/camera.h" #include "maths/matrix.h" #include "serialise/rdcfile.h" @@ -65,6 +66,8 @@ VulkanResourceManager *VulkanReplay::GetResourceManager() void VulkanReplay::Shutdown() { + SAFE_DELETE(m_RGP); + m_pDriver->Shutdown(); delete m_pDriver; } @@ -77,6 +80,7 @@ APIProperties VulkanReplay::GetAPIProperties() ret.localRenderer = GraphicsAPI::Vulkan; ret.degraded = false; ret.shadersMutable = false; + ret.RGPCapture = m_RGP != NULL && m_RGP->DriverSupportsInterop(); return ret; } @@ -3467,11 +3471,18 @@ ReplayStatus Vulkan_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) InitReplayTables(module); + AMDRGPControl *rgp = new AMDRGPControl(); + + if(!rgp->Initialised()) + SAFE_DELETE(rgp); + WrappedVulkan *vk = new WrappedVulkan(); ReplayStatus status = vk->Initialise(initParams, ver); if(status != ReplayStatus::Succeeded) { + SAFE_DELETE(rgp); + delete vk; return status; } @@ -3479,6 +3490,7 @@ ReplayStatus Vulkan_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) RDCLOG("Created device."); VulkanReplay *replay = vk->GetReplay(); replay->SetProxy(rdc == NULL); + replay->SetRGP(rgp); *driver = (IReplayDriver *)replay; diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index fe37a9985..6d4d07ff4 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -176,6 +176,7 @@ class VulkanReplay : public IReplayDriver public: VulkanReplay(); + void SetRGP(AMDRGPControl *rgp) { m_RGP = rgp; } void SetProxy(bool p) { m_Proxy = p; } bool IsRemoteProxy() { return m_Proxy; } void Shutdown(); @@ -221,6 +222,7 @@ public: vector GetSupportedWindowSystems(); + AMDRGPControl *GetRGPControl() { return m_RGP; } uint64_t MakeOutputWindow(WindowingData window, bool depth); void DestroyOutputWindow(uint64_t id); bool CheckResizeOutputWindow(uint64_t id); @@ -585,6 +587,7 @@ private: vector FetchCountersAMD(const vector &counters); AMDCounters *m_pAMDCounters = NULL; + AMDRGPControl *m_RGP = NULL; VulkanAMDDrawCallback *m_pAMDDrawCallback = NULL; }; diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index ab7b1bcaf..0a1c218d0 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -28,6 +28,7 @@ #include #include "common/dds_readwrite.h" #include "driver/ihv/amd/amd_isa.h" +#include "driver/ihv/amd/amd_rgp.h" #include "jpeg-compressor/jpgd.h" #include "jpeg-compressor/jpge.h" #include "maths/formatpacking.h" @@ -1398,6 +1399,75 @@ rdcarray ReplayController::GetSupportedWindowSystems() return m_pDevice->GetSupportedWindowSystems(); } +rdcstr ReplayController::CreateRGPProfile(WindowingData window) +{ + AMDRGPControl *rgp = m_pDevice->GetRGPControl(); + + if(!rgp) + { + RDCERR("RGP Capture is not supported on this API implementation"); + return ""; + } + + std::string path = FileIO::GetTempFolderFilename() + "/renderdoc_rgp_capture.rgp"; + + ReplayOutput *output = CreateOutput(window, ReplayOutputType::Texture); + + TextureDisplay d = {}; + output->SetTextureDisplay(d); + + // prime the pump + for(int i = 0; i < 5; i++) + { + m_pDevice->ReplayLog(10000000, eReplay_Full); + output->Display(); + } + + bool captureTriggered = rgp->TriggerCapture(path); + if(!captureTriggered) + { + RDCERR("Failed to trigger an RGP Capture."); + return ""; + } + + // delay a while to make sure the profiling is ready to go + Threading::Sleep(5000); + + // replay for capture. We do this a few times since doing it only once doesn't seem to pick up + // (6-7 runs needed) + for(int i = 0; i < 10; i++) + { + if(rgp->HasCapture()) + { + RDCDEBUG("Got profile after %d runs", i); + break; + } + + output->Display(); + m_pDevice->ReplayLog(10000000, eReplay_Full); + } + + output->Display(); + + // restore back to where we were + m_pDevice->ReplayLog(m_EventID, eReplay_Full); + + ShutdownOutput(output); + + // wait for 5 seconds for the capture to become ready + for(int i = 0; i < 50; i++) + { + if(rgp->HasCapture()) + return path; + + Threading::Sleep(100); + } + + RDCERR("Didn't get capture after 5 seconds"); + + return ""; +} + void ReplayController::ReplayLoop(WindowingData window, ResourceId texid) { ReplayOutput *output = CreateOutput(window, ReplayOutputType::Texture); diff --git a/renderdoc/replay/replay_controller.h b/renderdoc/replay/replay_controller.h index a6a79edea..5c72e5131 100644 --- a/renderdoc/replay/replay_controller.h +++ b/renderdoc/replay/replay_controller.h @@ -196,6 +196,8 @@ public: void ReplayLoop(WindowingData window, ResourceId texid); void CancelReplayLoop(); + rdcstr CreateRGPProfile(WindowingData window); + ReplayOutput *CreateOutput(WindowingData window, ReplayOutputType type); void ShutdownOutput(IReplayOutput *output); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index e09990fac..b493e7081 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -73,6 +73,8 @@ DECLARE_REFLECTION_STRUCT(GetTextureDataParams); class RDCFile; +class AMDRGPControl; + // these two interfaces define what an API driver implementation must provide // to the replay. At minimum it must implement IRemoteDriver which contains // all of the functionality that cannot be achieved elsewhere. An IReplayDriver @@ -174,6 +176,8 @@ public: virtual vector GetSupportedWindowSystems() = 0; + virtual AMDRGPControl *GetRGPControl() = 0; + virtual uint64_t MakeOutputWindow(WindowingData window, bool depth) = 0; virtual void DestroyOutputWindow(uint64_t id) = 0; virtual bool CheckResizeOutputWindow(uint64_t id) = 0;