diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index d82c46108..b896d6874 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -1066,6 +1066,10 @@ void CaptureContext::LoadCaptureThreaded(const QString &captureFile, const Repla for(BufferDescription &b : m_BufferList) m_Buffers[b.resourceId] = &b; + m_DescriptorStoreList = r->GetDescriptorStores(); + for(DescriptorStoreDescription &d : m_DescriptorStoreList) + m_DescriptorStores[d.resourceId] = &d; + m_PostloadProgress = 0.8f; m_TextureList = r->GetTextures(); diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index f9b32cba8..381fbe1a1 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -177,6 +177,10 @@ public: TextureDescription *GetTexture(ResourceId id) override { return m_Textures[id]; } const rdcarray &GetTextures() override { return m_TextureList; } BufferDescription *GetBuffer(ResourceId id) override { return m_Buffers[id]; } + DescriptorStoreDescription *GetDescriptorStore(ResourceId id) override + { + return m_DescriptorStores[id]; + } const rdcarray &GetBuffers() const override { return m_BufferList; } const ActionDescription *GetAction(uint32_t eventId) override { @@ -374,6 +378,8 @@ private: rdcarray m_TextureList; QMap m_Buffers; rdcarray m_BufferList; + QMap m_DescriptorStores; + rdcarray m_DescriptorStoreList; QMap m_Resources; rdcarray m_ResourceList; diff --git a/qrenderdoc/Code/Interface/QRDInterface.h b/qrenderdoc/Code/Interface/QRDInterface.h index f4d355635..e8d62b1b6 100644 --- a/qrenderdoc/Code/Interface/QRDInterface.h +++ b/qrenderdoc/Code/Interface/QRDInterface.h @@ -1271,6 +1271,25 @@ protected: DECLARE_REFLECTION_STRUCT(IShaderMessageViewer); +DOCUMENT("A descriptor viewer window."); +struct IDescriptorViewer +{ + DOCUMENT(R"(Retrieves the PySide2 QWidget for this :class:`DescriptorViewer` if PySide2 is available, or otherwise +returns a unique opaque pointer that can be passed back to any RenderDoc functions expecting a +QWidget. + +:return: Return the widget handle, either a PySide2 handle or an opaque handle. +:rtype: QWidget +)"); + virtual QWidget *Widget() = 0; + +protected: + IDescriptorViewer() = default; + ~IDescriptorViewer() = default; +}; + +DECLARE_REFLECTION_STRUCT(IDescriptorViewer); + DOCUMENT("A pixel history window."); struct IPixelHistoryView { @@ -2141,6 +2160,15 @@ considered out of date )"); virtual const rdcarray &GetBuffers() const = 0; + DOCUMENT(R"(Retrieve the information about a particular descriptor store. + +:param renderdoc.ResourceId id: The ID of the buffer to query about. +:return: The information about a descriptor store, or ``None`` if the ID does not correspond to a + descriptor store. +:rtype: renderdoc.DescriptorStoreDescription +)"); + virtual DescriptorStoreDescription *GetDescriptorStore(ResourceId id) = 0; + DOCUMENT(R"(Retrieve the information about an action at a given :data:`eventId `. diff --git a/qrenderdoc/Code/pyrenderdoc/renderdoc.i b/qrenderdoc/Code/pyrenderdoc/renderdoc.i index 9712e3d15..6b7f8df73 100644 --- a/qrenderdoc/Code/pyrenderdoc/renderdoc.i +++ b/qrenderdoc/Code/pyrenderdoc/renderdoc.i @@ -365,6 +365,7 @@ TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ActionDescription) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, GPUCounter) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, CounterResult) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, APIEvent) +TEMPLATE_ARRAY_INSTANTIATE(rdcarray, DescriptorStoreDescription) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, BufferDescription) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, CaptureFileFormat) TEMPLATE_ARRAY_INSTANTIATE(rdcarray, ConstantBlock) @@ -433,6 +434,9 @@ TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, ResourceData) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, ResourceState) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, StreamOutBind) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, VertexBuffer) +TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, RootTableRange) +TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, RootParam) +TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, D3D12Pipe, StaticSampler) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, GLPipe, VertexBuffer) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, GLPipe, VertexAttribute) TEMPLATE_NAMESPACE_ARRAY_INSTANTIATE(rdcarray, GLPipe, TextureCompleteness) diff --git a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp index 0ae413cbd..12afcecb6 100644 --- a/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/D3D12PipelineStateViewer.cpp @@ -1136,7 +1136,7 @@ void D3D12PipelineStateViewer::setShaderState(const D3D12Pipe::Shader &stage, RD ShaderReflection *shaderDetails = stage.reflection; const D3D12Pipe::State &state = *m_Ctx.CurD3D12PipelineState(); - rootSig->setText(ToQStr(state.rootSignatureResourceId)); + rootSig->setText(ToQStr(state.rootSignature.resourceId)); QString shText = ToQStr(stage.resourceId); diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index d5837cb68..a6200b9cf 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -519,6 +519,10 @@ struct CaptureContextInvoker : ObjectForwarder virtual TextureDescription *GetTexture(ResourceId id) override { return m_Obj.GetTexture(id); } virtual const rdcarray &GetTextures() override { return m_Obj.GetTextures(); } virtual BufferDescription *GetBuffer(ResourceId id) override { return m_Obj.GetBuffer(id); } + virtual DescriptorStoreDescription *GetDescriptorStore(ResourceId id) override + { + return m_Obj.GetDescriptorStore(id); + } virtual const rdcarray &GetBuffers() const override { return m_Obj.GetBuffers(); diff --git a/renderdoc/api/replay/d3d12_pipestate.h b/renderdoc/api/replay/d3d12_pipestate.h index 65bd8f5bb..4b2c2c55c 100644 --- a/renderdoc/api/replay/d3d12_pipestate.h +++ b/renderdoc/api/replay/d3d12_pipestate.h @@ -550,6 +550,219 @@ struct ResourceData rdcarray states; }; +DOCUMENT("Contains the structure of a single range within a root table definition."); +struct RootTableRange +{ + DOCUMENT(""); + RootTableRange() = default; + RootTableRange(const RootTableRange &) = default; + RootTableRange &operator=(const RootTableRange &) = default; + + bool operator==(const RootTableRange &o) const + { + return category == o.category && space == o.space && baseRegister == o.baseRegister && + count == o.count && tableByteOffset == o.tableByteOffset; + } + bool operator<(const RootTableRange &o) const + { + if(!(category == o.category)) + return category < o.category; + if(!(space == o.space)) + return space < o.space; + if(!(baseRegister == o.baseRegister)) + return baseRegister < o.baseRegister; + if(!(count == o.count)) + return count < o.count; + if(!(tableByteOffset == o.tableByteOffset)) + return tableByteOffset < o.tableByteOffset; + return false; + } + DOCUMENT(R"(The descriptor category specified in this range. + +:type: DescriptorCategory +)"); + DescriptorCategory category = DescriptorCategory::Unknown; + + DOCUMENT(R"(The register space of this range. + +:type: int +)"); + uint32_t space = 0; + + DOCUMENT(R"(The first register in this range. + +:type: int +)"); + uint32_t baseRegister = 0; + + DOCUMENT(R"(The number of registers in this range. + +:type: int +)"); + uint32_t count = 0; + + DOCUMENT(R"(The offset in bytes from the start of the table as defined in :class:`D3D12RootParam`. + +:type: int +)"); + uint32_t tableByteOffset = 0; + + DOCUMENT(R"(Whether or not this table was appended after the previous, leading to an auto-calculated +offset in :data:`tableByteOffset`. + +:type: bool +)"); + bool appended = false; +}; + +DOCUMENT("Contains the structure and content of a single root parameter."); +struct RootParam +{ + DOCUMENT(""); + RootParam() = default; + RootParam(const RootParam &) = default; + RootParam &operator=(const RootParam &) = default; + + bool operator==(const RootParam &o) const + { + return visibility == o.visibility && heap == o.heap && heapByteOffset == o.heapByteOffset && + tableRanges == o.tableRanges && descriptor == o.descriptor && constants == o.constants; + } + bool operator<(const RootParam &o) const + { + if(!(visibility == o.visibility)) + return visibility < o.visibility; + if(!(heap == o.heap)) + return heap < o.heap; + if(!(heapByteOffset == o.heapByteOffset)) + return heapByteOffset < o.heapByteOffset; + if(!(tableRanges == o.tableRanges)) + return tableRanges < o.tableRanges; + if(!(descriptor == o.descriptor)) + return descriptor < o.descriptor; + if(!(constants == o.constants)) + return constants < o.constants; + return false; + } + + DOCUMENT(R"(The shader stage that can access this parameter. + +:type: ShaderStageMask +)"); + ShaderStageMask visibility; + + DOCUMENT(R"(For a root constant parameter, the words defined. + +:type: bytes +)"); + bytebuf constants; + + DOCUMENT(R"(For a root descriptor parameter, the descriptor itself. + +:type: Descriptor +)"); + Descriptor descriptor; + + DOCUMENT(R"(For a root table parameter, the descriptor heap bound to this parameter. See +:data:`heapByteOffset` and :data:`tableRanges`. + +:type: ResourceId +)"); + ResourceId heap; + + DOCUMENT(R"(For a root table parameter, the byte offset into the descriptor heap bound to this +parameter. See :data:`heap` and :data:`tableRanges`. + +:type: ResourceId +)"); + uint32_t heapByteOffset = 0; + + DOCUMENT(R"(For a root table parameter, the descriptor ranges that define this table. See +:data:`heap` and :data:`heapByteOffset`. + +:type: List[D3D12RootTableRange] +)"); + rdcarray tableRanges; +}; + +DOCUMENT("Contains the details of a single static sampler in a root signature."); +struct StaticSampler +{ + DOCUMENT(""); + StaticSampler() = default; + StaticSampler(const StaticSampler &) = default; + StaticSampler &operator=(const StaticSampler &) = default; + + bool operator==(const StaticSampler &o) const + { + return visibility == o.visibility && space == o.space && reg == o.reg && + descriptor == o.descriptor; + } + bool operator<(const StaticSampler &o) const + { + if(!(visibility == o.visibility)) + return visibility < o.visibility; + if(!(space == o.space)) + return space < o.space; + if(!(reg == o.reg)) + return reg < o.reg; + if(!(descriptor == o.descriptor)) + return descriptor < o.descriptor; + return false; + } + + DOCUMENT(R"(The shader stage that can access this sampler. + +:type: ShaderStageMask +)"); + ShaderStageMask visibility; + + DOCUMENT(R"(The register space of this sampler. + +:type: int +)"); + uint32_t space = 0; + + DOCUMENT(R"(The register number of this sampler. + +:type: int +)"); + uint32_t reg = 0; + + DOCUMENT(R"(The details of the sampler descriptor itself. + +:type: SamplerDescriptor +)"); + SamplerDescriptor descriptor; +}; + +DOCUMENT("Contains the root signature structure and root parameters."); +struct RootSignature +{ + DOCUMENT(""); + RootSignature() = default; + RootSignature(const RootSignature &) = default; + RootSignature &operator=(const RootSignature &) = default; + + DOCUMENT(R"(The :class:`ResourceId` of the root signature object. + +:type: ResourceId +)"); + ResourceId resourceId; + + DOCUMENT(R"(The parameters in this root signature. + +:type: List[D3D12RootParam] +)"); + rdcarray parameters; + + DOCUMENT(R"(The static samplers defined in this root signature. + +:type: List[SamplerDescriptor] +)"); + rdcarray staticSamplers; +}; + DOCUMENT("The full current D3D12 pipeline state."); struct State { @@ -562,15 +775,18 @@ struct State DOCUMENT("The :class:`ResourceId` of the pipeline state object."); ResourceId pipelineResourceId; - DOCUMENT("The :class:`ResourceId` of the root signature object."); - ResourceId rootSignatureResourceId; - DOCUMENT(R"(The descriptor heaps currently bound. :type: List[ResourceId] )"); rdcarray descriptorHeaps; + DOCUMENT(R"(Details of the root signature structure and root parameters. + +:type: D3D12RootSignature +)"); + RootSignature rootSignature; + DOCUMENT(R"(The input assembly pipeline stage. :type: D3D12InputAssembly @@ -659,4 +875,8 @@ DECLARE_REFLECTION_STRUCT(D3D12Pipe::BlendState); DECLARE_REFLECTION_STRUCT(D3D12Pipe::OM); DECLARE_REFLECTION_STRUCT(D3D12Pipe::ResourceState); DECLARE_REFLECTION_STRUCT(D3D12Pipe::ResourceData); +DECLARE_REFLECTION_STRUCT(D3D12Pipe::RootTableRange); +DECLARE_REFLECTION_STRUCT(D3D12Pipe::RootParam); +DECLARE_REFLECTION_STRUCT(D3D12Pipe::StaticSampler); +DECLARE_REFLECTION_STRUCT(D3D12Pipe::RootSignature); DECLARE_REFLECTION_STRUCT(D3D12Pipe::State); diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index e84a25bae..8aeab899c 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -596,6 +596,50 @@ typically it is one parent to many derived. DECLARE_REFLECTION_STRUCT(ResourceDescription); +DOCUMENT("A description of a descriptor store."); +struct DescriptorStoreDescription +{ + DOCUMENT(""); + DescriptorStoreDescription() = default; + DescriptorStoreDescription(const DescriptorStoreDescription &) = default; + DescriptorStoreDescription &operator=(const DescriptorStoreDescription &) = default; + + bool operator==(const DescriptorStoreDescription &o) const { return resourceId == o.resourceId; } + bool operator<(const DescriptorStoreDescription &o) const + { + if(!(resourceId == o.resourceId)) + return resourceId < o.resourceId; + return false; + } + + DOCUMENT(R"(The unique :class:`ResourceId` that identifies this descriptor store. + +:type: ResourceId +)"); + ResourceId resourceId; + + DOCUMENT(R"(For descriptor stores which contain desriptors all of identical size, the size of each +descriptor. Descriptors are assumed to be tightly packed so stride is equal to size. + +:type: int +)"); + uint32_t descriptorByteSize = 1; + + DOCUMENT(R"(The byte offset within the store to the first descriptor. + +:type: int +)"); + uint32_t firstDescriptorOffset = 0; + + DOCUMENT(R"(The number of descriptors within this storage object. + +:type: int +)"); + uint32_t descriptorCount = 0; +}; + +DECLARE_REFLECTION_STRUCT(DescriptorStoreDescription); + DOCUMENT("A description of a buffer resource."); struct BufferDescription { diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 118a31031..4846bc564 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -850,6 +850,13 @@ are only used as intermediary elements. )"); virtual const rdcarray &GetBuffers() = 0; + DOCUMENT(R"(Retrieve the list of descriptor storage objects alive in the capture. + +:return: The list of descriptor storage objects in the capture. +:rtype: List[DescriptorStoreDescription] +)"); + virtual const rdcarray &GetDescriptorStores() = 0; + DOCUMENT(R"(Retrieve a list of any newly generated diagnostic messages. Every time this function is called, any debug messages returned will not be returned again. Only diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 7b979ff99..0df734aea 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -250,6 +250,7 @@ public: void RenderMesh(uint32_t eventId, const rdcarray &secondaryDraws, const MeshDisplay &cfg) { } + rdcarray GetDescriptorStores() { return {}; } rdcarray GetBuffers() { return {}; } rdcarray GetDebugMessages() { return rdcarray(); } BufferDescription GetBuffer(ResourceId id) diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 223db9524..bd7927bcc 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -102,6 +102,7 @@ rdcstr DoStringise(const ReplayProxyPacket &el) STRINGISE_ENUM_NAMED(eReplayProxy_GetSamplerDescriptors, "GetSamplerDescriptors"); STRINGISE_ENUM_NAMED(eReplayProxy_GetDescriptorAccess, "GetDescriptorAccess"); STRINGISE_ENUM_NAMED(eReplayProxy_GetDescriptorLocations, "GetDescriptorLocations"); + STRINGISE_ENUM_NAMED(eReplayProxy_GetDescriptorStores, "GetDescriptorStores"); } END_ENUM_STRINGISE(); } @@ -530,6 +531,35 @@ TextureDescription ReplayProxy::GetTexture(ResourceId id) PROXY_FUNCTION(GetTexture, id); } +template +rdcarray ReplayProxy::Proxied_GetDescriptorStores( + ParamSerialiser ¶mser, ReturnSerialiser &retser) +{ + const ReplayProxyPacket expectedPacket = eReplayProxy_GetDescriptorStores; + ReplayProxyPacket packet = eReplayProxy_GetDescriptorStores; + rdcarray ret; + + { + BEGIN_PARAMS(); + END_PARAMS(); + } + + { + REMOTE_EXECUTION(); + if(paramser.IsReading() && !paramser.IsErrored() && !m_IsErrored) + ret = m_Remote->GetDescriptorStores(); + } + + SERIALISE_RETURN(ret); + + return ret; +} + +rdcarray ReplayProxy::GetDescriptorStores() +{ + PROXY_FUNCTION(GetDescriptorStores); +} + template rdcarray ReplayProxy::Proxied_GetBuffers(ParamSerialiser ¶mser, ReturnSerialiser &retser) @@ -3046,6 +3076,7 @@ bool ReplayProxy::Tick(int type) case eReplayProxy_GetSamplerDescriptors: GetSamplerDescriptors(ResourceId(), {}); break; case eReplayProxy_GetDescriptorAccess: GetDescriptorAccess(0); break; case eReplayProxy_GetDescriptorLocations: GetDescriptorLocations(ResourceId(), {}); break; + case eReplayProxy_GetDescriptorStores: GetDescriptorStores(); break; case eReplayProxy_GetUsage: GetUsage(ResourceId()); break; case eReplayProxy_GetLiveID: GetLiveID(ResourceId()); break; case eReplayProxy_GetFrameRecord: GetFrameRecord(); break; diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index 4b4190075..014227e8a 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -110,6 +110,7 @@ enum ReplayProxyPacket eReplayProxy_GetSamplerDescriptors, eReplayProxy_GetDescriptorAccess, eReplayProxy_GetDescriptorLocations, + eReplayProxy_GetDescriptorStores, }; DECLARE_REFLECTION_ENUM(ReplayProxyPacket); @@ -469,6 +470,8 @@ public: IMPLEMENT_FUNCTION_PROXIED(rdcarray, GetResources); + IMPLEMENT_FUNCTION_PROXIED(rdcarray, GetDescriptorStores); + IMPLEMENT_FUNCTION_PROXIED(rdcarray, GetBuffers); IMPLEMENT_FUNCTION_PROXIED(BufferDescription, GetBuffer, ResourceId id); diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 1b59e961f..dbb1f4058 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -157,6 +157,8 @@ public: ResourceDescription &GetResourceDesc(ResourceId id); rdcarray GetResources(); + rdcarray GetDescriptorStores() { return {}; } + rdcarray GetBuffers(); BufferDescription GetBuffer(ResourceId id); diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index b28b0b061..d4018ce51 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -29,6 +29,7 @@ #include "driver/ihv/amd/official/DXExt/AmdExtD3DCommandListMarkerApi.h" #include "d3d12_command_list.h" #include "d3d12_command_queue.h" +#include "d3d12_replay.h" #include "d3d12_resources.h" #include "d3d12_shader_cache.h" @@ -963,6 +964,13 @@ bool WrappedID3D12Device::Serialise_CreateDescriptorHeap( GetResourceManager()->AddLiveResource(pHeap, ret); AddResource(pHeap, ResourceType::DescriptorStore, "Descriptor Heap"); + + DescriptorStoreDescription desc; + desc.resourceId = pHeap; + desc.descriptorByteSize = 1; + desc.firstDescriptorOffset = 0; + desc.descriptorCount = Descriptor.NumDescriptors; + GetReplay()->RegisterDescriptorStore(desc); } } diff --git a/renderdoc/driver/d3d12/d3d12_replay.cpp b/renderdoc/driver/d3d12/d3d12_replay.cpp index fbf8829ab..0a8b5ac1d 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.cpp +++ b/renderdoc/driver/d3d12/d3d12_replay.cpp @@ -350,6 +350,16 @@ rdcarray D3D12Replay::GetResources() return m_Resources; } +rdcarray D3D12Replay::GetDescriptorStores() +{ + return m_DescriptorStores; +} + +void D3D12Replay::RegisterDescriptorStore(const DescriptorStoreDescription &desc) +{ + m_DescriptorStores.push_back(desc); +} + rdcarray D3D12Replay::GetBuffers() { rdcarray ret; @@ -1049,19 +1059,58 @@ void D3D12Replay::FillSamplerDescriptor(SamplerDescriptor &dst, const D3D12_SAMP dst.mipBias = src.MipLODBias; } -ShaderStageMask ToShaderStageMask(D3D12_SHADER_VISIBILITY vis) +void D3D12Replay::FillRootDescriptor(Descriptor &dst, const D3D12RenderState::SignatureElement &src) { - switch(vis) + D3D12ResourceManager *rm = m_pDevice->GetResourceManager(); + + if(src.type == eRootCBV) { - case D3D12_SHADER_VISIBILITY_ALL: return ShaderStageMask::All; - case D3D12_SHADER_VISIBILITY_VERTEX: return ShaderStageMask::Vertex; - case D3D12_SHADER_VISIBILITY_HULL: return ShaderStageMask::Hull; - case D3D12_SHADER_VISIBILITY_DOMAIN: return ShaderStageMask::Domain; - case D3D12_SHADER_VISIBILITY_GEOMETRY: return ShaderStageMask::Geometry; - case D3D12_SHADER_VISIBILITY_PIXEL: return ShaderStageMask::Pixel; - case D3D12_SHADER_VISIBILITY_AMPLIFICATION: return ShaderStageMask::Amplification; - case D3D12_SHADER_VISIBILITY_MESH: return ShaderStageMask::Mesh; - default: return ShaderStageMask::Unknown; + dst.type = DescriptorType::ConstantBuffer; + + ID3D12Resource *buf = rm->GetCurrentAs(src.id); + + dst.resource = rm->GetOriginalID(src.id); + dst.byteOffset = src.offset; + if(buf) + dst.byteSize = uint32_t(buf->GetDesc().Width - dst.byteOffset); + else + dst.byteSize = 0; + } + else if(src.type == eRootSRV) + { + dst.type = DescriptorType::Buffer; + + ID3D12Resource *buf = rm->GetCurrentAs(src.id); + + // parameters from resource/view + dst.resource = rm->GetOriginalID(src.id); + dst.textureType = TextureType::Buffer; + dst.format = MakeResourceFormat(DXGI_FORMAT_R32_UINT); + + dst.elementByteSize = sizeof(uint32_t); + dst.byteOffset = src.offset; + if(buf) + dst.byteSize = uint32_t(buf->GetDesc().Width - src.offset); + else + dst.byteSize = 0; + } + else if(src.type == eRootUAV) + { + dst.type = DescriptorType::ReadWriteBuffer; + + ID3D12Resource *buf = rm->GetCurrentAs(src.id); + + // parameters from resource/view + dst.resource = rm->GetOriginalID(src.id); + dst.textureType = TextureType::Buffer; + dst.format = MakeResourceFormat(DXGI_FORMAT_R32_UINT); + + dst.elementByteSize = sizeof(uint32_t); + dst.byteOffset = src.offset; + if(buf) + dst.byteSize = uint32_t(buf->GetDesc().Width - src.offset); + else + dst.byteSize = 0; } } @@ -1211,10 +1260,136 @@ void D3D12Replay::SavePipelineState(uint32_t eventId) // Root Signature ///////////////////////////////////////////////// { - if(pipe && pipe->IsCompute()) - state.rootSignatureResourceId = rm->GetOriginalID(rs.compute.rootsig); - else if(pipe) - state.rootSignatureResourceId = rm->GetOriginalID(rs.graphics.rootsig); + const D3D12RenderState::RootSignature &sig = + (pipe && pipe->IsCompute()) ? rs.compute : rs.graphics; + const rdcarray &rootElems = sig.sigelems; + + WrappedID3D12RootSignature *rootSig = rm->GetCurrentAs(sig.rootsig); + + state.rootSignature.resourceId = rm->GetOriginalID(GetResID(rootSig)); + state.rootSignature.parameters.clear(); + state.rootSignature.staticSamplers.clear(); + + if(rootSig) + { + state.rootSignature.parameters.reserve(rootSig->sig.Parameters.size()); + for(size_t i = 0; i < rootSig->sig.Parameters.size(); i++) + { + const D3D12RootSignatureParameter &src = rootSig->sig.Parameters[i]; + D3D12Pipe::RootParam dst; + dst.visibility = ConvertVisibility(src.ShaderVisibility); + + switch(src.ParameterType) + { + case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE: + { + if(i < rootElems.size()) + { + dst.heap = rm->GetOriginalID(rootElems[i].id); + dst.heapByteOffset = (uint32_t)rootElems[i].offset; + } + + UINT prevTableOffset = 0; + + dst.tableRanges.reserve(src.DescriptorTable.NumDescriptorRanges); + for(UINT r = 0; r < src.DescriptorTable.NumDescriptorRanges; r++) + { + const D3D12_DESCRIPTOR_RANGE1 &srcRange = src.DescriptorTable.pDescriptorRanges[r]; + + D3D12Pipe::RootTableRange range; + + switch(srcRange.RangeType) + { + case D3D12_DESCRIPTOR_RANGE_TYPE_CBV: + range.category = DescriptorCategory::ConstantBlock; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER: + range.category = DescriptorCategory::Sampler; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_SRV: + range.category = DescriptorCategory::ReadOnlyResource; + break; + case D3D12_DESCRIPTOR_RANGE_TYPE_UAV: + range.category = DescriptorCategory::ReadWriteResource; + break; + } + + UINT offset = srcRange.OffsetInDescriptorsFromTableStart; + + if(srcRange.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + { + range.appended = true; + offset = prevTableOffset; + } + + range.space = srcRange.RegisterSpace; + range.baseRegister = srcRange.BaseShaderRegister; + range.count = srcRange.NumDescriptors; + range.tableByteOffset = offset; + + prevTableOffset = offset + srcRange.NumDescriptors; + + dst.tableRanges.push_back(range); + } + + break; + } + case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS: + { + dst.constants.resize(src.Constants.Num32BitValues * 4); + + if(i < rootElems.size()) + { + memcpy(dst.constants.data(), rootElems[i].constants.data(), + RDCMIN(rootElems[i].constants.byteSize(), dst.constants.byteSize())); + } + + break; + } + case D3D12_ROOT_PARAMETER_TYPE_CBV: + { + dst.descriptor.type = DescriptorType::ConstantBuffer; + + if(i < rootElems.size()) + FillRootDescriptor(dst.descriptor, rootElems[i]); + break; + + case D3D12_ROOT_PARAMETER_TYPE_SRV: + { + dst.descriptor.type = DescriptorType::Buffer; + + if(i < rootElems.size()) + FillRootDescriptor(dst.descriptor, rootElems[i]); + break; + } + case D3D12_ROOT_PARAMETER_TYPE_UAV: + { + dst.descriptor.type = DescriptorType::ReadWriteBuffer; + + if(i < rootElems.size()) + FillRootDescriptor(dst.descriptor, rootElems[i]); + break; + } + } + } + + state.rootSignature.parameters.push_back(std::move(dst)); + } + + state.rootSignature.staticSamplers.reserve(rootSig->sig.StaticSamplers.size()); + for(const D3D12_STATIC_SAMPLER_DESC1 &src : rootSig->sig.StaticSamplers) + { + D3D12Pipe::StaticSampler dst; + dst.visibility = ConvertVisibility(src.ShaderVisibility); + + dst.space = src.RegisterSpace; + dst.reg = src.ShaderRegister; + + FillSamplerDescriptor(dst.descriptor, ConvertStaticSampler(src)); + + state.rootSignature.staticSamplers.push_back(std::move(dst)); + } + } } state.descriptorHeaps.clear(); @@ -1488,6 +1663,8 @@ rdcarray D3D12Replay::GetDescriptors(ResourceId descriptorStore, if(WrappedID3D12RootSignature::IsAlloc(res)) { // root signature descriptor storage is for static samplers + for(Descriptor &d : ret) + d.type = DescriptorType::Sampler; return ret; } @@ -1532,54 +1709,9 @@ rdcarray D3D12Replay::GetDescriptors(ResourceId descriptorStore, d.byteOffset += rootElems[root].constants.byteSize(); d.byteSize = rootEl.constants.byteSize(); } - else if(rootEl.type == eRootCBV) + else { - d.type = DescriptorType::ConstantBuffer; - - ID3D12Resource *buf = rm->GetCurrentAs(rootEl.id); - - d.resource = rm->GetOriginalID(rootEl.id); - d.byteOffset = rootEl.offset; - if(buf) - d.byteSize = uint32_t(buf->GetDesc().Width - d.byteOffset); - else - d.byteSize = 0; - } - else if(rootEl.type == eRootSRV) - { - d.type = DescriptorType::Buffer; - - ID3D12Resource *buf = rm->GetCurrentAs(rootEl.id); - - // parameters from resource/view - d.resource = rm->GetOriginalID(rootEl.id); - d.textureType = TextureType::Buffer; - d.format = MakeResourceFormat(DXGI_FORMAT_R32_UINT); - - d.elementByteSize = sizeof(uint32_t); - d.byteOffset = rootEl.offset; - if(buf) - d.byteSize = uint32_t(buf->GetDesc().Width - rootEl.offset); - else - d.byteSize = 0; - } - else if(rootEl.type == eRootUAV) - { - d.type = DescriptorType::ReadWriteBuffer; - - ID3D12Resource *buf = rm->GetCurrentAs(rootEl.id); - - // parameters from resource/view - d.resource = rm->GetOriginalID(rootEl.id); - d.textureType = TextureType::Buffer; - d.format = MakeResourceFormat(DXGI_FORMAT_R32_UINT); - - d.elementByteSize = sizeof(uint32_t); - d.byteOffset = rootEl.offset; - if(buf) - d.byteSize = uint32_t(buf->GetDesc().Width - rootEl.offset); - else - d.byteSize = 0; + FillRootDescriptor(d, rootEl); } } } @@ -1618,7 +1750,11 @@ rdcarray D3D12Replay::GetDescriptors(ResourceId descriptorStore, ret[dst].resource = rm->GetOriginalID(ret[dst].resource); ret[dst].byteSize = cbv.SizeInBytes; } - else if(desc->GetType() != D3D12DescriptorType::Sampler) + else if(desc->GetType() == D3D12DescriptorType::Sampler) + { + ret[dst].type = DescriptorType::Sampler; + } + else { FillDescriptor(ret[dst], desc); } @@ -1834,7 +1970,7 @@ rdcarray D3D12Replay::GetDescriptorLocations( else { ret[dst].fixedBindNumber = ~0U - 2048 + staticIdx; - ret[dst].stageMask = ToShaderStageMask(sig->sig.StaticSamplers[staticIdx].ShaderVisibility); + ret[dst].stageMask = ConvertVisibility(sig->sig.StaticSamplers[staticIdx].ShaderVisibility); ret[dst].category = DescriptorCategory::Sampler; ret[dst].logicalBindName = StringFormat::Fmt("Static #%u", staticIdx); } @@ -1867,7 +2003,7 @@ rdcarray D3D12Replay::GetDescriptorLocations( DescriptorLogicalLocation &l = ret[dst]; l.fixedBindNumber = ~0U - 2048 - 64 + rootIndex; - l.stageMask = ToShaderStageMask(param.ShaderVisibility); + l.stageMask = ConvertVisibility(param.ShaderVisibility); if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS) { @@ -3238,7 +3374,7 @@ void D3D12Replay::FillCBufferVariables(ResourceId pipeline, ResourceId shader, S const D3D12RootSignatureParameter &p = sig->sig.Parameters[i]; if(p.ParameterType == D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS && - (ToShaderStageMask(p.ShaderVisibility) & reflMask) && + (ConvertVisibility(p.ShaderVisibility) & reflMask) && p.Constants.RegisterSpace == c.fixedBindSetOrSpace && p.Constants.ShaderRegister == c.fixedBindNumber) { diff --git a/renderdoc/driver/d3d12/d3d12_replay.h b/renderdoc/driver/d3d12/d3d12_replay.h index 54e3e3dcb..cda71e91e 100644 --- a/renderdoc/driver/d3d12/d3d12_replay.h +++ b/renderdoc/driver/d3d12/d3d12_replay.h @@ -114,6 +114,9 @@ public: ResourceDescription &GetResourceDesc(ResourceId id); rdcarray GetResources(); + rdcarray GetDescriptorStores(); + void RegisterDescriptorStore(const DescriptorStoreDescription &desc); + rdcarray GetBuffers(); BufferDescription GetBuffer(ResourceId id); @@ -269,6 +272,7 @@ public: private: void FillDescriptor(Descriptor &dst, const D3D12Descriptor *src); + void FillRootDescriptor(Descriptor &dst, const D3D12RenderState::SignatureElement &src); void FillSamplerDescriptor(SamplerDescriptor &dst, const D3D12_SAMPLER_DESC2 &src); bool CreateSOBuffers(); @@ -541,6 +545,7 @@ private: } m_Histogram; rdcarray m_Resources; + rdcarray m_DescriptorStores; std::map m_ResourceIdx; bool m_ISAChecked = false; diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index b91ad0db7..152f39f40 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -136,6 +136,8 @@ public: ResourceDescription &GetResourceDesc(ResourceId id); rdcarray GetResources(); + rdcarray GetDescriptorStores() { return {}; } + rdcarray GetBuffers(); BufferDescription GetBuffer(ResourceId id); diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 1410ad117..66bbda291 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -304,6 +304,16 @@ rdcarray VulkanReplay::GetResources() return m_Resources; } +rdcarray VulkanReplay::GetDescriptorStores() +{ + return m_DescriptorStores; +} + +void VulkanReplay::RegisterDescriptorStore(const DescriptorStoreDescription &desc) +{ + m_DescriptorStores.push_back(desc); +} + rdcarray VulkanReplay::GetTextures() { rdcarray texs; @@ -2436,7 +2446,11 @@ rdcarray VulkanReplay::GetDescriptors(ResourceId descriptorStore, { // silently drop out of bounds descriptor reads } - else if(desc->type != DescriptorSlotType::Sampler) + else if(desc->type == DescriptorSlotType::Sampler) + { + ret[dst].type = DescriptorType::Sampler; + } + else { FillDescriptor(ret[dst], *desc); diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index 1726903c4..10d131cae 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -324,6 +324,9 @@ public: ResourceDescription &GetResourceDesc(ResourceId id); rdcarray GetResources(); + rdcarray GetDescriptorStores(); + void RegisterDescriptorStore(const DescriptorStoreDescription &desc); + rdcarray GetBuffers(); BufferDescription GetBuffer(ResourceId id); @@ -823,6 +826,7 @@ private: ShaderDebugData m_ShaderDebugData; rdcarray m_Resources; + rdcarray m_DescriptorStores; std::map m_ResourceIdx; VKPipe::State *m_VulkanPipelineState = NULL; diff --git a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp index d1c30c1ce..7816fdc5c 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_descriptor_funcs.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include "../vk_core.h" +#include "../vk_replay.h" #include "core/settings.h" RDOC_DEBUG_CONFIG(bool, Vulkan_Debug_AllowDescriptorSetReuse, true, @@ -469,12 +470,12 @@ bool WrappedVulkan::Serialise_vkAllocateDescriptorSets(SerialiserType &ser, VkDe // if we got here we must have succeeded RDCASSERTEQUAL(ret, VK_SUCCESS); + ResourceId layoutId = GetResID(AllocateInfo.pSetLayouts[0]); + { ResourceId live = GetResourceManager()->WrapResource(Unwrap(device), descset); GetResourceManager()->AddLiveResource(DescriptorSet, descset); - ResourceId layoutId = GetResID(AllocateInfo.pSetLayouts[0]); - // this is stored in the resource record on capture, we need to be able to look to up m_DescriptorSetState[live].layout = layoutId; @@ -506,6 +507,15 @@ bool WrappedVulkan::Serialise_vkAllocateDescriptorSets(SerialiserType &ser, VkDe DerivedResource(device, DescriptorSet); DerivedResource(AllocateInfo.pSetLayouts[0], DescriptorSet); DerivedResource(AllocateInfo.descriptorPool, DescriptorSet); + + DescriptorStoreDescription desc; + desc.resourceId = DescriptorSet; + desc.descriptorByteSize = 1; + // descriptors are stored after all the inline bytes + desc.firstDescriptorOffset = m_CreationInfo.m_DescSetLayout[layoutId].inlineByteSize; + desc.descriptorCount = + (uint32_t)m_DescriptorSetState[GetResID(descset)].data.totalDescriptorCount(); + GetReplay()->RegisterDescriptorStore(desc); } return true; diff --git a/renderdoc/replay/dummy_driver.cpp b/renderdoc/replay/dummy_driver.cpp index 98eb28b30..d6202ad89 100644 --- a/renderdoc/replay/dummy_driver.cpp +++ b/renderdoc/replay/dummy_driver.cpp @@ -32,6 +32,7 @@ DummyDriver::DummyDriver(IReplayDriver *original, const rdcarrayGetAPIProperties(); m_Resources = original->GetResources(); + m_DescriptorStores = original->GetDescriptorStores(); m_Buffers = original->GetBuffers(); m_Textures = original->GetTextures(); m_FrameRecord = original->GetFrameRecord(); @@ -70,6 +71,11 @@ rdcarray DummyDriver::GetResources() return m_Resources; } +rdcarray DummyDriver::GetDescriptorStores() +{ + return m_DescriptorStores; +} + rdcarray DummyDriver::GetBuffers() { return m_Buffers; diff --git a/renderdoc/replay/dummy_driver.h b/renderdoc/replay/dummy_driver.h index e98b7e5bb..2ec6c3b1b 100644 --- a/renderdoc/replay/dummy_driver.h +++ b/renderdoc/replay/dummy_driver.h @@ -41,6 +41,8 @@ public: rdcarray GetResources(); + rdcarray GetDescriptorStores(); + rdcarray GetBuffers(); BufferDescription GetBuffer(ResourceId id); @@ -193,6 +195,7 @@ private: APIProperties m_Props; rdcarray m_Resources; + rdcarray m_DescriptorStores; rdcarray m_Buffers; rdcarray m_Textures; FrameRecord m_FrameRecord; diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index ec4df38f7..bf0ea0a9a 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -475,6 +475,17 @@ void DoSerialise(SerialiserType &ser, BufferDescription &el) SIZE_CHECK(32); } +template +void DoSerialise(SerialiserType &ser, DescriptorStoreDescription &el) +{ + SERIALISE_MEMBER(resourceId); + SERIALISE_MEMBER(descriptorByteSize); + SERIALISE_MEMBER(firstDescriptorOffset); + SERIALISE_MEMBER(descriptorCount); + + SIZE_CHECK(24); +} + template void DoSerialise(SerialiserType &ser, APIProperties &el) { @@ -1579,12 +1590,59 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::ResourceData &el) SIZE_CHECK(32); } +template +void DoSerialise(SerialiserType &ser, D3D12Pipe::RootTableRange &el) +{ + SERIALISE_MEMBER(category); + SERIALISE_MEMBER(space); + SERIALISE_MEMBER(baseRegister); + SERIALISE_MEMBER(count); + SERIALISE_MEMBER(tableByteOffset); + SERIALISE_MEMBER(appended); + + SIZE_CHECK(24); +} + +template +void DoSerialise(SerialiserType &ser, D3D12Pipe::RootParam &el) +{ + SERIALISE_MEMBER(visibility); + SERIALISE_MEMBER(constants); + SERIALISE_MEMBER(descriptor); + SERIALISE_MEMBER(heap); + SERIALISE_MEMBER(heapByteOffset); + SERIALISE_MEMBER(tableRanges); + + SIZE_CHECK(152); +} + +template +void DoSerialise(SerialiserType &ser, D3D12Pipe::StaticSampler &el) +{ + SERIALISE_MEMBER(visibility); + SERIALISE_MEMBER(space); + SERIALISE_MEMBER(reg); + SERIALISE_MEMBER(descriptor); + + SIZE_CHECK(88); +} + +template +void DoSerialise(SerialiserType &ser, D3D12Pipe::RootSignature &el) +{ + SERIALISE_MEMBER(resourceId); + SERIALISE_MEMBER(parameters); + SERIALISE_MEMBER(staticSamplers); + + SIZE_CHECK(56); +} + template void DoSerialise(SerialiserType &ser, D3D12Pipe::State &el) { SERIALISE_MEMBER(pipelineResourceId); - SERIALISE_MEMBER(rootSignatureResourceId); SERIALISE_MEMBER(descriptorHeaps); + SERIALISE_MEMBER(rootSignature); SERIALISE_MEMBER(inputAssembly); @@ -1605,7 +1663,7 @@ void DoSerialise(SerialiserType &ser, D3D12Pipe::State &el) SERIALISE_MEMBER(resourceStates); - SIZE_CHECK(728); + SIZE_CHECK(776); } #pragma endregion D3D12 pipeline state @@ -2254,6 +2312,7 @@ INSTANTIATE_SERIALISE_TYPE(ShaderDebugTrace) INSTANTIATE_SERIALISE_TYPE(ResourceDescription) INSTANTIATE_SERIALISE_TYPE(TextureDescription) INSTANTIATE_SERIALISE_TYPE(BufferDescription) +INSTANTIATE_SERIALISE_TYPE(DescriptorStoreDescription) INSTANTIATE_SERIALISE_TYPE(APIProperties) INSTANTIATE_SERIALISE_TYPE(DriverInformation) INSTANTIATE_SERIALISE_TYPE(DebugMessage) diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 2a32d768f..51aff5300 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -481,6 +481,13 @@ const rdcarray &ReplayController::GetBuffers() return m_Buffers; } +const rdcarray &ReplayController::GetDescriptorStores() +{ + CHECK_REPLAY_THREAD(); + + return m_DescriptorStores; +} + const rdcarray &ReplayController::GetTextures() { CHECK_REPLAY_THREAD(); @@ -2207,6 +2214,8 @@ RDResult ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rdc) FatalErrorCheck(); m_Resources = m_pDevice->GetResources(); FatalErrorCheck(); + m_DescriptorStores = m_pDevice->GetDescriptorStores(); + FatalErrorCheck(); m_FrameRecord = m_pDevice->GetFrameRecord(); FatalErrorCheck(); diff --git a/renderdoc/replay/replay_controller.h b/renderdoc/replay/replay_controller.h index a9a9c5fed..fbd15b468 100644 --- a/renderdoc/replay/replay_controller.h +++ b/renderdoc/replay/replay_controller.h @@ -188,6 +188,7 @@ public: CounterDescription DescribeCounter(GPUCounter counterID); const rdcarray &GetTextures(); const rdcarray &GetBuffers(); + const rdcarray &GetDescriptorStores(); const rdcarray &GetResources(); rdcarray GetDebugMessages(); ResultDetails GetFatalErrorStatus() @@ -283,6 +284,7 @@ private: rdcarray m_Resources; rdcarray m_Buffers; + rdcarray m_DescriptorStores; rdcarray m_Textures; IReplayDriver *m_pDevice; diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index a90cb6cde..1e7b7f7fa 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -140,6 +140,8 @@ public: virtual rdcarray GetResources() = 0; + virtual rdcarray GetDescriptorStores() = 0; + virtual rdcarray GetBuffers() = 0; virtual BufferDescription GetBuffer(ResourceId id) = 0;