511 lines
16 KiB
C++
511 lines
16 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
D3D12RootSignature.h: D3D12 Root Signatures
|
|
=============================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "D3D12RootSignatureDefinitions.h"
|
|
#include "D3D12Util.h"
|
|
|
|
// Root parameter keys grouped by visibility.
|
|
enum ERootParameterKeys
|
|
{
|
|
PS_SRVs,
|
|
PS_CBVs,
|
|
PS_RootCBVs,
|
|
PS_Samplers,
|
|
VS_SRVs,
|
|
VS_CBVs,
|
|
VS_RootCBVs,
|
|
VS_Samplers,
|
|
VS_UAVs,
|
|
GS_SRVs,
|
|
GS_CBVs,
|
|
GS_RootCBVs,
|
|
GS_Samplers,
|
|
MS_SRVs,
|
|
MS_CBVs,
|
|
MS_RootCBVs,
|
|
MS_Samplers,
|
|
AS_SRVs,
|
|
AS_CBVs,
|
|
AS_RootCBVs,
|
|
AS_Samplers,
|
|
ALL_SRVs,
|
|
ALL_CBVs,
|
|
ALL_RootCBVs,
|
|
ALL_Samplers,
|
|
ALL_UAVs, // non-VS stages (PS, CS, etc.)
|
|
RPK_RootParameterKeyCount,
|
|
};
|
|
|
|
class FD3D12RootSignature;
|
|
|
|
class FD3D12RootSignatureDesc
|
|
{
|
|
public:
|
|
explicit FD3D12RootSignatureDesc(const FD3D12QuantizedBoundShaderState& QBSS, const D3D12_RESOURCE_BINDING_TIER ResourceBindingTier);
|
|
|
|
inline const D3D12_VERSIONED_ROOT_SIGNATURE_DESC& GetDesc() const { return RootDesc; }
|
|
|
|
static constexpr uint32 MaxRootParameters = 32; // Arbitrary max, increase as needed.
|
|
|
|
inline int8 GetRootConstantsSlot() const { return RootConstantsSlot; }
|
|
inline int8 GetDiagnosticBufferSlot() const { return DiagnosticBufferSlot; }
|
|
inline int8 GetStaticShaderBindingSlot() const { return StaticShaderBindingSlot; }
|
|
inline int8 GetStaticShaderBindingCount() const { return StaticShaderBindingCount; }
|
|
|
|
private:
|
|
|
|
uint32 RootParametersSize; // The size of all root parameters in the root signature. Size in DWORDs, the limit is 64.
|
|
int8 RootConstantsSlot = -1;
|
|
int8 DiagnosticBufferSlot = -1;
|
|
int8 StaticShaderBindingSlot = -1;
|
|
int8 StaticShaderBindingCount = -1;
|
|
CD3DX12_ROOT_PARAMETER1 TableSlots[MaxRootParameters];
|
|
CD3DX12_DESCRIPTOR_RANGE1 DescriptorRanges[MaxRootParameters];
|
|
CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC RootDesc;
|
|
};
|
|
|
|
class FD3D12RootSignature : public FD3D12AdapterChild
|
|
{
|
|
private:
|
|
// Struct for all the useful info we want per shader stage.
|
|
struct ShaderStage
|
|
{
|
|
// TODO: Make these arrays and index into them by type instead of individual variables.
|
|
uint8 MaxCBVCount = 0;
|
|
uint8 MaxSRVCount = 0;
|
|
uint8 MaxSamplerCount = 0;
|
|
uint8 MaxUAVCount = 0;
|
|
CBVSlotMask CBVRegisterMask = 0;
|
|
bool bVisible = false;
|
|
};
|
|
|
|
public:
|
|
explicit FD3D12RootSignature(FD3D12Adapter* InParent)
|
|
: FD3D12AdapterChild(InParent)
|
|
{}
|
|
explicit FD3D12RootSignature(FD3D12Adapter* InParent, const FD3D12QuantizedBoundShaderState& InQBSS)
|
|
: FD3D12AdapterChild(InParent)
|
|
{
|
|
Init(InQBSS);
|
|
}
|
|
|
|
void Init(const FD3D12QuantizedBoundShaderState& InQBSS);
|
|
void Init(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC& InDesc, ERootSignatureType InRootSignatureType);
|
|
|
|
void InitStaticGraphicsRootSignature(EShaderBindingLayoutFlags InFlags);
|
|
void InitStaticComputeRootSignatureDesc(EShaderBindingLayoutFlags InFlags);
|
|
#if D3D12_RHI_RAYTRACING
|
|
void InitStaticRayTracingGlobalRootSignatureDesc(EShaderBindingLayoutFlags InFlags);
|
|
void InitStaticRayTracingLocalRootSignatureDesc(EShaderBindingLayoutFlags InFlags);
|
|
#endif
|
|
|
|
ID3D12RootSignature* GetRootSignature() const { return RootSignature.GetReference(); }
|
|
ID3DBlob* GetRootSignatureBlob() const { return RootSignatureBlob.GetReference(); }
|
|
|
|
inline uint32 SamplerRDTBindSlot(EShaderFrequency ShaderStage) const
|
|
{
|
|
switch (ShaderStage)
|
|
{
|
|
case SF_Vertex: return BindSlotMap[VS_Samplers];
|
|
case SF_Mesh: return BindSlotMap[MS_Samplers];
|
|
case SF_Amplification: return BindSlotMap[AS_Samplers];
|
|
case SF_Pixel: return BindSlotMap[PS_Samplers];
|
|
case SF_Geometry: return BindSlotMap[GS_Samplers];
|
|
case SF_Compute: return BindSlotMap[ALL_Samplers];
|
|
|
|
default: check(false);
|
|
return UINT_MAX;
|
|
}
|
|
}
|
|
|
|
inline uint32 SRVRDTBindSlot(EShaderFrequency ShaderStage) const
|
|
{
|
|
switch (ShaderStage)
|
|
{
|
|
case SF_Vertex: return BindSlotMap[VS_SRVs];
|
|
case SF_Mesh: return BindSlotMap[MS_SRVs];
|
|
case SF_Amplification: return BindSlotMap[AS_SRVs];
|
|
case SF_Pixel: return BindSlotMap[PS_SRVs];
|
|
case SF_Geometry: return BindSlotMap[GS_SRVs];
|
|
case SF_Compute: return BindSlotMap[ALL_SRVs];
|
|
|
|
default: check(false);
|
|
return UINT_MAX;
|
|
}
|
|
}
|
|
|
|
inline uint32 CBVRDTBindSlot(EShaderFrequency ShaderStage) const
|
|
{
|
|
switch (ShaderStage)
|
|
{
|
|
case SF_Vertex: return BindSlotMap[VS_CBVs];
|
|
case SF_Mesh: return BindSlotMap[MS_CBVs];
|
|
case SF_Amplification: return BindSlotMap[AS_CBVs];
|
|
case SF_Pixel: return BindSlotMap[PS_CBVs];
|
|
case SF_Geometry: return BindSlotMap[GS_CBVs];
|
|
case SF_Compute: return BindSlotMap[ALL_CBVs];
|
|
|
|
default: check(false);
|
|
return UINT_MAX;
|
|
}
|
|
}
|
|
|
|
inline uint32 CBVRDBaseBindSlot(EShaderFrequency ShaderStage) const
|
|
{
|
|
switch (ShaderStage)
|
|
{
|
|
case SF_Vertex: return BindSlotMap[VS_RootCBVs];
|
|
case SF_Mesh: return BindSlotMap[MS_RootCBVs];
|
|
case SF_Amplification: return BindSlotMap[AS_RootCBVs];
|
|
case SF_Pixel: return BindSlotMap[PS_RootCBVs];
|
|
case SF_Geometry: return BindSlotMap[GS_RootCBVs];
|
|
|
|
case SF_NumFrequencies:
|
|
case SF_Compute: return BindSlotMap[ALL_RootCBVs];
|
|
|
|
default: check(false);
|
|
return UINT_MAX;
|
|
}
|
|
}
|
|
|
|
inline uint32 CBVRDBindSlot(EShaderFrequency ShaderStage, uint32 BufferIndex) const
|
|
{
|
|
// This code assumes that all Root CBVs for a particular stage are contiguous in the root signature (thus indexable by the buffer index).
|
|
return CBVRDBaseBindSlot(ShaderStage) + BufferIndex;
|
|
}
|
|
|
|
inline uint32 UAVRDTBindSlot(EShaderFrequency ShaderStage) const
|
|
{
|
|
check(ShaderStage == SF_Pixel || ShaderStage == SF_Vertex || ShaderStage == SF_Compute);
|
|
const uint32 MapSlotIndex = ShaderStage == SF_Vertex ? VS_UAVs : ALL_UAVs;
|
|
return BindSlotMap[MapSlotIndex];
|
|
}
|
|
|
|
inline static bool IsValidBindSlot(uint32 BindSlotMapIndex)
|
|
{
|
|
return BindSlotMapIndex < InvalidBindSlotMapIndex;
|
|
}
|
|
|
|
inline bool HasUAVs() const { return bHasUAVs; }
|
|
inline bool HasSRVs() const { return bHasSRVs; }
|
|
inline bool HasCBVs() const { return bHasCBVs; }
|
|
inline bool HasRootCBs() const { return bHasRootCBs; }
|
|
inline bool HasTableResources() const { return bHasUAVs || bHasSRVs; }
|
|
inline bool HasTableConstants() const { return bHasCBVs; }
|
|
inline bool HasSamplers() const { return bHasSamplers; }
|
|
|
|
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
|
|
bool UsesDynamicResources() const { return bUsesDynamicResources; }
|
|
bool UsesDynamicSamplers() const { return bUsesDynamicSamplers; }
|
|
#else
|
|
constexpr bool UsesDynamicResources() const { return false; }
|
|
constexpr bool UsesDynamicSamplers() const { return false; }
|
|
#endif
|
|
|
|
inline bool HasVS() const { return Stage[SF_Vertex].bVisible; }
|
|
inline bool HasMS() const { return Stage[SF_Mesh].bVisible; }
|
|
inline bool HasAS() const { return Stage[SF_Amplification].bVisible; }
|
|
inline bool HasGS() const { return Stage[SF_Geometry].bVisible; }
|
|
inline bool HasPS() const { return Stage[SF_Pixel].bVisible; }
|
|
inline bool HasCS() const { return Stage[SF_Compute].bVisible; } // Root signatures can be used for Graphics and/or Compute because they exist in separate bind spaces.
|
|
inline uint32 MaxSamplerCount(uint32 ShaderStage) const { check(ShaderStage != SF_NumFrequencies); return Stage[ShaderStage].MaxSamplerCount; }
|
|
inline uint32 MaxSRVCount(uint32 ShaderStage) const { check(ShaderStage != SF_NumFrequencies); return Stage[ShaderStage].MaxSRVCount; }
|
|
inline uint32 MaxCBVCount(uint32 ShaderStage) const { check(ShaderStage != SF_NumFrequencies); return Stage[ShaderStage].MaxCBVCount; }
|
|
inline uint32 MaxUAVCount(uint32 ShaderStage) const { check(ShaderStage != SF_NumFrequencies); return Stage[ShaderStage].MaxUAVCount; }
|
|
inline CBVSlotMask CBVRegisterMask(uint32 ShaderStage) const { check(ShaderStage != SF_NumFrequencies); return Stage[ShaderStage].CBVRegisterMask; }
|
|
|
|
uint32 GetBindSlotOffsetInBytes(uint8 BindSlotIndex) const { check(BindSlotIndex < UE_ARRAY_COUNT(BindSlotOffsetsInDWORDs)); return 4 * BindSlotOffsetsInDWORDs[BindSlotIndex]; }
|
|
uint32 GetTotalRootSignatureSizeInBytes() const { return 4 * TotalRootSignatureSizeInDWORDs; }
|
|
|
|
inline int8 GetRootConstantsSlot() const { return RootConstantsSlot; }
|
|
inline int8 GetStaticShaderBindingSlot() const { return StaticShaderBindingSlot; }
|
|
inline int8 GetStaticShaderBindingCount() const { return StaticShaderBindingCount; }
|
|
|
|
// Returns root parameter slot for the internal shader diagnostic buffer (used for asserts, etc.) or -1 if not available.
|
|
inline int8 GetDiagnosticBufferSlot() const { return DiagnosticBufferSlot; }
|
|
|
|
private:
|
|
void AnalyzeSignature(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC& Desc, ERootSignatureType InRootSignatureType);
|
|
|
|
template<typename RootSignatureDescType>
|
|
void InternalAnalyzeSignature(const RootSignatureDescType& Desc, ERootSignatureType InRootSignatureType);
|
|
|
|
inline bool HasVisibility(const D3D12_SHADER_VISIBILITY& ParameterVisibility, const D3D12_SHADER_VISIBILITY& Visibility) const
|
|
{
|
|
return ParameterVisibility == D3D12_SHADER_VISIBILITY_ALL || ParameterVisibility == Visibility;
|
|
}
|
|
|
|
inline void SetSamplersRDTBindSlot(EShaderFrequency SF, uint8 RootParameterIndex)
|
|
{
|
|
uint8* pBindSlot = nullptr;
|
|
switch (SF)
|
|
{
|
|
case SF_Vertex: pBindSlot = &BindSlotMap[VS_Samplers]; break;
|
|
case SF_Mesh: pBindSlot = &BindSlotMap[MS_Samplers]; break;
|
|
case SF_Amplification: pBindSlot = &BindSlotMap[AS_Samplers]; break;
|
|
case SF_Pixel: pBindSlot = &BindSlotMap[PS_Samplers]; break;
|
|
case SF_Geometry: pBindSlot = &BindSlotMap[GS_Samplers]; break;
|
|
|
|
case SF_Compute:
|
|
case SF_NumFrequencies: pBindSlot = &BindSlotMap[ALL_Samplers]; break;
|
|
|
|
default: check(false);
|
|
return;
|
|
}
|
|
|
|
check(*pBindSlot == InvalidBindSlotMapIndex);
|
|
*pBindSlot = RootParameterIndex;
|
|
|
|
bHasSamplers = true;
|
|
}
|
|
|
|
inline void SetSRVRDTBindSlot(EShaderFrequency SF, uint8 RootParameterIndex)
|
|
{
|
|
uint8* pBindSlot = nullptr;
|
|
switch (SF)
|
|
{
|
|
case SF_Vertex: pBindSlot = &BindSlotMap[VS_SRVs]; break;
|
|
case SF_Mesh: pBindSlot = &BindSlotMap[MS_SRVs]; break;
|
|
case SF_Amplification: pBindSlot = &BindSlotMap[AS_SRVs]; break;
|
|
case SF_Pixel: pBindSlot = &BindSlotMap[PS_SRVs]; break;
|
|
case SF_Geometry: pBindSlot = &BindSlotMap[GS_SRVs]; break;
|
|
|
|
case SF_Compute:
|
|
case SF_NumFrequencies: pBindSlot = &BindSlotMap[ALL_SRVs]; break;
|
|
|
|
default: check(false);
|
|
return;
|
|
}
|
|
|
|
check(*pBindSlot == InvalidBindSlotMapIndex);
|
|
*pBindSlot = RootParameterIndex;
|
|
|
|
bHasSRVs = true;
|
|
}
|
|
|
|
inline void SetCBVRDTBindSlot(EShaderFrequency SF, uint8 RootParameterIndex)
|
|
{
|
|
uint8* pBindSlot = nullptr;
|
|
switch (SF)
|
|
{
|
|
case SF_Vertex: pBindSlot = &BindSlotMap[VS_CBVs]; break;
|
|
case SF_Mesh: pBindSlot = &BindSlotMap[MS_CBVs]; break;
|
|
case SF_Amplification: pBindSlot = &BindSlotMap[AS_CBVs]; break;
|
|
case SF_Pixel: pBindSlot = &BindSlotMap[PS_CBVs]; break;
|
|
case SF_Geometry: pBindSlot = &BindSlotMap[GS_CBVs]; break;
|
|
|
|
case SF_Compute:
|
|
case SF_NumFrequencies: pBindSlot = &BindSlotMap[ALL_CBVs]; break;
|
|
|
|
default: check(false);
|
|
return;
|
|
}
|
|
|
|
check(*pBindSlot == InvalidBindSlotMapIndex);
|
|
*pBindSlot = RootParameterIndex;
|
|
|
|
bHasCBVs = true;
|
|
}
|
|
|
|
inline void SetCBVRDBindSlot(EShaderFrequency SF, uint8 RootParameterIndex)
|
|
{
|
|
uint8* pBindSlot = nullptr;
|
|
switch (SF)
|
|
{
|
|
case SF_Vertex: pBindSlot = &BindSlotMap[VS_RootCBVs]; break;
|
|
case SF_Mesh: pBindSlot = &BindSlotMap[MS_RootCBVs]; break;
|
|
case SF_Amplification: pBindSlot = &BindSlotMap[AS_RootCBVs]; break;
|
|
case SF_Pixel: pBindSlot = &BindSlotMap[PS_RootCBVs]; break;
|
|
case SF_Geometry: pBindSlot = &BindSlotMap[GS_RootCBVs]; break;
|
|
|
|
case SF_Compute:
|
|
case SF_NumFrequencies: pBindSlot = &BindSlotMap[ALL_RootCBVs]; break;
|
|
|
|
default: check(false);
|
|
return;
|
|
}
|
|
|
|
check(*pBindSlot == InvalidBindSlotMapIndex);
|
|
*pBindSlot = RootParameterIndex;
|
|
|
|
bHasRootCBs = true;
|
|
}
|
|
|
|
inline void SetUAVRDTBindSlot(EShaderFrequency SF, uint8 RootParameterIndex)
|
|
{
|
|
check(SF == SF_Pixel || SF == SF_Vertex || SF == SF_Compute || SF == SF_NumFrequencies);
|
|
|
|
const uint32 MapSlotIndex = SF == SF_Vertex ? VS_UAVs : ALL_UAVs;
|
|
uint8* pBindSlot = &BindSlotMap[MapSlotIndex];
|
|
|
|
check(*pBindSlot == InvalidBindSlotMapIndex);
|
|
*pBindSlot = RootParameterIndex;
|
|
|
|
bHasUAVs = true;
|
|
}
|
|
|
|
inline void SetMaxSamplerCount(EShaderFrequency SF, uint8 Count)
|
|
{
|
|
if (SF == SF_NumFrequencies)
|
|
{
|
|
// Update all counts for all stages.
|
|
for (uint32 s = SF_Vertex; s <= SF_Compute; s++)
|
|
{
|
|
Stage[s].MaxSamplerCount = Count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Stage[SF].MaxSamplerCount = Count;
|
|
}
|
|
}
|
|
|
|
inline void SetMaxSRVCount(EShaderFrequency SF, uint8 Count)
|
|
{
|
|
if (SF == SF_NumFrequencies)
|
|
{
|
|
// Update all counts for all stages.
|
|
for (uint32 s = SF_Vertex; s <= SF_Compute; s++)
|
|
{
|
|
Stage[s].MaxSRVCount = Count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Stage[SF].MaxSRVCount = Count;
|
|
}
|
|
}
|
|
|
|
// Update the mask that indicates what shader registers are used in the descriptor table.
|
|
template<typename DescriptorRangeType>
|
|
inline void UpdateCBVRegisterMaskWithDescriptorRange(EShaderFrequency SF, const DescriptorRangeType& Range)
|
|
{
|
|
const uint32 StartRegister = Range.BaseShaderRegister;
|
|
const uint32 EndRegister = StartRegister + Range.NumDescriptors;
|
|
const uint32 StartStage = (SF == SF_NumFrequencies) ? SF_Vertex : SF;
|
|
const uint32 EndStage = (SF == SF_NumFrequencies) ? SF_Compute : SF;
|
|
for (uint32 CurrentStage = StartStage; CurrentStage <= EndStage; CurrentStage++)
|
|
{
|
|
for (uint32 Register = StartRegister; Register < EndRegister; Register++)
|
|
{
|
|
// The bit shouldn't already be set for the current register.
|
|
check((Stage[CurrentStage].CBVRegisterMask & (1 << Register)) == 0);
|
|
Stage[CurrentStage].CBVRegisterMask |= (1 << Register);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the mask that indicates what shader registers are used in the root descriptor.
|
|
template<typename DescriptorType>
|
|
inline void UpdateCBVRegisterMaskWithDescriptor(EShaderFrequency SF, const DescriptorType& Descriptor)
|
|
{
|
|
const uint32 StartStage = (SF == SF_NumFrequencies) ? SF_Vertex : SF;
|
|
const uint32 EndStage = (SF == SF_NumFrequencies) ? SF_Compute : SF;
|
|
const uint32& Register = Descriptor.ShaderRegister;
|
|
for (uint32 CurrentStage = StartStage; CurrentStage <= EndStage; CurrentStage++)
|
|
{
|
|
// The bit shouldn't already be set for the current register.
|
|
check((Stage[CurrentStage].CBVRegisterMask & (1 << Register)) == 0);
|
|
Stage[CurrentStage].CBVRegisterMask |= (1 << Register);
|
|
}
|
|
}
|
|
|
|
inline void SetMaxCBVCount(EShaderFrequency SF, uint8 Count)
|
|
{
|
|
if (SF == SF_NumFrequencies)
|
|
{
|
|
// Update all counts for all stages.
|
|
for (uint32 s = SF_Vertex; s <= SF_Compute; s++)
|
|
{
|
|
Stage[s].MaxCBVCount = Count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Stage[SF].MaxCBVCount = Count;
|
|
}
|
|
}
|
|
|
|
inline void IncrementMaxCBVCount(EShaderFrequency SF, uint8 Count)
|
|
{
|
|
if (SF == SF_NumFrequencies)
|
|
{
|
|
// Update all counts for all stages.
|
|
for (uint32 s = SF_Vertex; s <= SF_Compute; s++)
|
|
{
|
|
Stage[s].MaxCBVCount += Count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Stage[SF].MaxCBVCount += Count;
|
|
}
|
|
}
|
|
|
|
inline void SetMaxUAVCount(EShaderFrequency SF, uint8 Count)
|
|
{
|
|
if (SF == SF_NumFrequencies)
|
|
{
|
|
// Update all counts for all stages.
|
|
for (uint32 s = SF_Vertex; s <= SF_Compute; s++)
|
|
{
|
|
Stage[s].MaxUAVCount = Count;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Stage[SF].MaxUAVCount = Count;
|
|
}
|
|
}
|
|
|
|
TRefCountPtr<ID3D12RootSignature> RootSignature;
|
|
uint8 BindSlotMap[RPK_RootParameterKeyCount]; // This map uses an enum as a key to lookup the root parameter index
|
|
static constexpr uint8 InvalidBindSlotMapIndex = 0xFF;
|
|
ShaderStage Stage[SF_NumFrequencies];
|
|
TRefCountPtr<ID3DBlob> RootSignatureBlob;
|
|
|
|
uint8 BindSlotOffsetsInDWORDs[FD3D12RootSignatureDesc::MaxRootParameters] = {};
|
|
uint8 TotalRootSignatureSizeInDWORDs = 0;
|
|
int8 RootConstantsSlot = -1;
|
|
int8 DiagnosticBufferSlot = -1;
|
|
int8 StaticShaderBindingSlot = -1;
|
|
int8 StaticShaderBindingCount = -1;
|
|
|
|
uint8 bHasUAVs : 1;
|
|
uint8 bHasSRVs : 1;
|
|
uint8 bHasCBVs : 1;
|
|
uint8 bHasRootCBs : 1;
|
|
uint8 bHasSamplers : 1;
|
|
#if PLATFORM_SUPPORTS_BINDLESS_RENDERING
|
|
uint8 bUsesDynamicResources : 1;
|
|
uint8 bUsesDynamicSamplers : 1;
|
|
#endif
|
|
};
|
|
|
|
class FD3D12RootSignatureManager : public FD3D12AdapterChild
|
|
{
|
|
public:
|
|
explicit FD3D12RootSignatureManager(FD3D12Adapter* InParent)
|
|
: FD3D12AdapterChild(InParent)
|
|
{
|
|
}
|
|
~FD3D12RootSignatureManager()
|
|
{
|
|
check(RootSignatureMap.Num() == 0);
|
|
}
|
|
void Destroy();
|
|
|
|
FD3D12RootSignature* GetRootSignature(const FD3D12QuantizedBoundShaderState& QBSS);
|
|
FD3D12QuantizedBoundShaderState GetQuantizedBoundShaderState(const FD3D12RootSignature* const RootSignature);
|
|
|
|
private:
|
|
FCriticalSection CS;
|
|
FD3D12RootSignature* CreateRootSignature(const FD3D12QuantizedBoundShaderState& QBSS);
|
|
|
|
TMap<FD3D12QuantizedBoundShaderState, FD3D12RootSignature*> RootSignatureMap;
|
|
}; |