summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2021-03-10 22:26:04 +0000
committerassiduous <assiduous@diligentgraphics.com>2021-03-19 00:38:20 +0000
commit515588c5ca0eb091ca8f0e59608bc72637daae83 (patch)
tree3a94b839218b2e7bd7b1be23a52d745ea3ef6189 /Graphics/GraphicsEngineD3D12
parentFixed issue with destruction of ShaderResourceBindingBase (diff)
downloadDiligentCore-515588c5ca0eb091ca8f0e59608bc72637daae83.tar.gz
DiligentCore-515588c5ca0eb091ca8f0e59608bc72637daae83.zip
D3D12 backend: moved resource binding logic to shader variable manger
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
-rw-r--r--Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp11
-rw-r--r--Graphics/GraphicsEngineD3D12/include/ShaderVariableManagerD3D12.hpp30
-rw-r--r--Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp457
-rw-r--r--Graphics/GraphicsEngineD3D12/src/ShaderVariableManagerD3D12.cpp440
4 files changed, 471 insertions, 467 deletions
diff --git a/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp
index 921e1bbb..773d0879 100644
--- a/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp
+++ b/Graphics/GraphicsEngineD3D12/include/PipelineResourceSignatureD3D12Impl.hpp
@@ -134,17 +134,6 @@ public:
void CopyStaticResources(ShaderResourceCacheD3D12& ResourceCache) const;
- // Binds object pObj to resource with index ResIndex in m_Desc.Resources and
- // array index ArrayIndex.
- void BindResource(IDeviceObject* pObj,
- Uint32 ArrayIndex,
- Uint32 ResIndex,
- ShaderResourceCacheD3D12& ResourceCache) const;
-
- bool IsBound(Uint32 ArrayIndex,
- Uint32 ResIndex,
- const ShaderResourceCacheD3D12& ResourceCache) const;
-
struct CommitCacheResourcesAttribs
{
const ShaderResourceCacheD3D12& ResourceCache;
diff --git a/Graphics/GraphicsEngineD3D12/include/ShaderVariableManagerD3D12.hpp b/Graphics/GraphicsEngineD3D12/include/ShaderVariableManagerD3D12.hpp
index 7fc3c6dc..a067592e 100644
--- a/Graphics/GraphicsEngineD3D12/include/ShaderVariableManagerD3D12.hpp
+++ b/Graphics/GraphicsEngineD3D12/include/ShaderVariableManagerD3D12.hpp
@@ -98,6 +98,14 @@ public:
ShaderVariableD3D12Impl* GetVariable(const Char* Name) const;
ShaderVariableD3D12Impl* GetVariable(Uint32 Index) const;
+ // Binds object pObj to resource with index ResIndex and array index ArrayIndex.
+ void BindResource(IDeviceObject* pObj,
+ Uint32 ArrayIndex,
+ Uint32 ResIndex);
+
+ bool IsBound(Uint32 ArrayIndex,
+ Uint32 ResIndex) const;
+
void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags);
static size_t GetRequiredMemorySize(const PipelineResourceSignatureD3D12Impl& Signature,
@@ -198,8 +206,10 @@ public:
return m_ParentManager.GetVariableIndex(*this);
}
- // This method can't be defined in the header due to dependency on PipelineResourceSignatureD3D12Impl
- virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final;
+ virtual bool DILIGENT_CALL_TYPE IsBound(Uint32 ArrayIndex) const override final
+ {
+ return m_ParentManager.IsBound(ArrayIndex, m_ResIndex);
+ }
virtual void DILIGENT_CALL_TYPE GetHLSLResourceDesc(HLSLShaderResourceDesc& HLSLResDesc) const override final
{
@@ -207,14 +217,22 @@ public:
HLSLResDesc.ShaderRegister = GetAttribs().Register;
}
- const PipelineResourceDesc& GetDesc() const { return m_ParentManager.GetResourceDesc(m_ResIndex); }
+ const PipelineResourceDesc& GetDesc() const
+ {
+ return m_ParentManager.GetResourceDesc(m_ResIndex);
+ }
- // This method can't be defined in the header due to dependency on PipelineResourceSignatureD3D12Impl
- void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const;
+ void BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const
+ {
+ m_ParentManager.BindResource(pObj, ArrayIndex, m_ResIndex);
+ }
private:
using ResourceAttribs = PipelineResourceAttribsD3D12;
- const ResourceAttribs& GetAttribs() const { return m_ParentManager.GetResourceAttribs(m_ResIndex); }
+ const ResourceAttribs& GetAttribs() const
+ {
+ return m_ParentManager.GetResourceAttribs(m_ResIndex);
+ }
private:
const Uint32 m_ResIndex;
diff --git a/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp
index 8aa19bec..24b696d2 100644
--- a/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp
@@ -34,13 +34,12 @@
#include "RenderDeviceD3D12Impl.hpp"
#include "BufferD3D12Impl.hpp"
#include "BufferViewD3D12Impl.hpp"
-#include "SamplerD3D12Impl.hpp"
#include "TextureD3D12Impl.hpp"
#include "TextureViewD3D12Impl.hpp"
-#include "TopLevelASD3D12Impl.hpp"
-#include "D3D12TypeConversions.hpp"
#include "ShaderVariableD3D.hpp"
+#include "D3D12TypeConversions.hpp"
+
namespace Diligent
{
@@ -706,443 +705,6 @@ bool PipelineResourceSignatureD3D12Impl::HasImmutableSamplerArray(SHADER_TYPE Sh
return false;
}
-
-namespace
-{
-
-class BindResourceHelper
-{
-public:
- BindResourceHelper(const PipelineResourceSignatureD3D12Impl& Signature,
- ShaderResourceCacheD3D12& ResourceCache,
- Uint32 ResIndex,
- Uint32 ArrayIndex);
-
- void operator()(IDeviceObject* pObj) const;
-
-private:
- void CacheCB(IDeviceObject* pBuffer) const;
- void CacheSampler(IDeviceObject* pBuffer) const;
- void CacheAccelStruct(IDeviceObject* pBuffer) const;
- void BindCombinedSampler(TextureViewD3D12Impl* pTexView) const;
- void BindCombinedSampler(BufferViewD3D12Impl* pTexView) const {}
-
- template <typename TResourceViewType, ///< The type of the view (TextureViewD3D12Impl or BufferViewD3D12Impl)
- typename TViewTypeEnum ///< The type of the expected view type enum (TEXTURE_VIEW_TYPE or BUFFER_VIEW_TYPE)
- >
- void CacheResourceView(IDeviceObject* pBufferView,
- TViewTypeEnum dbgExpectedViewType) const;
-
- ID3D12Device* GetD3D12Device() const { return m_Signature.GetDevice()->GetD3D12Device(); }
-
- void SetResource(D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle, RefCntAutoPtr<IDeviceObject>&& pObject) const
- {
- if (m_DstTableCPUDescriptorHandle.ptr != 0)
- {
- VERIFY(CPUDescriptorHandle.ptr != 0, "CPU descriptor handle must not be null for resources allocated in descriptor tables");
- DEV_CHECK_ERR(m_ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC || m_DstRes.pObject == nullptr, "Static and mutable resource descriptors should only be copied once");
- const auto d3d12HeapType = m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER ?
- D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER :
- D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
- GetD3D12Device()->CopyDescriptorsSimple(1, m_DstTableCPUDescriptorHandle, CPUDescriptorHandle, d3d12HeapType);
- }
-
- m_ResourceCache.SetResource(m_RootIndex, m_OffsetFromTableStart, m_ResDesc.ResourceType, CPUDescriptorHandle, std::move(pObject));
- }
-
-private:
- using ResourceAttribs = PipelineResourceSignatureD3D12Impl::ResourceAttribs;
-
- const PipelineResourceSignatureD3D12Impl& m_Signature;
- ShaderResourceCacheD3D12& m_ResourceCache;
-
- const PipelineResourceDesc& m_ResDesc;
- const ResourceAttribs& m_Attribs; // Must go before m_RootIndex, m_OffsetFromTableStart
-
- const ResourceCacheContentType m_CacheType; // Must go before m_RootIndex, m_OffsetFromTableStart
- const Uint32 m_RootIndex; // Must go before m_DstRes
- const Uint32 m_ArrayIndex;
- const Uint32 m_OffsetFromTableStart; // Must go before m_DstRes
-
- const ShaderResourceCacheD3D12::Resource& m_DstRes;
-
- D3D12_CPU_DESCRIPTOR_HANDLE m_DstTableCPUDescriptorHandle{};
-};
-
-BindResourceHelper::BindResourceHelper(const PipelineResourceSignatureD3D12Impl& Signature,
- ShaderResourceCacheD3D12& ResourceCache,
- Uint32 ResIndex,
- Uint32 ArrayIndex) :
- // clang-format off
- m_Signature {Signature},
- m_ResourceCache {ResourceCache},
- m_ResDesc {Signature.GetResourceDesc(ResIndex)},
- m_Attribs {Signature.GetResourceAttribs(ResIndex)},
- m_CacheType {ResourceCache.GetContentType()},
- m_RootIndex {m_Attribs.RootIndex(m_CacheType)},
- m_ArrayIndex {ArrayIndex},
- m_OffsetFromTableStart{m_Attribs.OffsetFromTableStart(m_CacheType) + ArrayIndex},
- m_DstRes {const_cast<const ShaderResourceCacheD3D12&>(ResourceCache).GetRootTable(m_RootIndex).GetResource(m_OffsetFromTableStart)}
-// clang-format on
-{
- VERIFY(ArrayIndex < m_ResDesc.ArraySize, "Array index is out of range");
-
- if (m_CacheType != ResourceCacheContentType::Signature && !m_Attribs.IsRootView())
- {
- const auto IsSampler = (m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
- const auto RootParamGroup = VariableTypeToRootParameterGroup(m_ResDesc.VarType);
- // Static/mutable resources are allocated in GPU-visible descriptor heap, while dynamic resources - in CPU-only heap.
- m_DstTableCPUDescriptorHandle =
- ResourceCache.GetDescriptorTableHandle<D3D12_CPU_DESCRIPTOR_HANDLE>(
- IsSampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
- RootParamGroup, m_RootIndex, m_OffsetFromTableStart);
- }
-
-#ifdef DILIGENT_DEBUG
- if (m_CacheType == ResourceCacheContentType::Signature)
- {
- VERIFY(m_DstTableCPUDescriptorHandle.ptr == 0, "Static shader resource cache should never be assigned descriptor space.");
- }
- else if (m_CacheType == ResourceCacheContentType::SRB)
- {
- if (m_Attribs.GetD3D12RootParamType() == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
- {
- VERIFY(m_DstTableCPUDescriptorHandle.ptr != 0, "Shader resources allocated in descriptor tables must be assigned descriptor space.");
- }
- else
- {
- VERIFY_EXPR(m_Attribs.IsRootView());
- VERIFY((m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER ||
- m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV ||
- m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV),
- "Only constant buffers and dynamic buffer views can be allocated as root views");
- VERIFY(m_DstTableCPUDescriptorHandle.ptr == 0, "Resources allocated as root views should never be assigned descriptor space.");
- }
- }
- else
- {
- UNEXPECTED("Unknown content type");
- }
-#endif
-}
-
-void BindResourceHelper::CacheCB(IDeviceObject* pBuffer) const
-{
- // We cannot use ValidatedCast<> here as the resource retrieved from the
- // resource mapping can be of wrong type
- RefCntAutoPtr<BufferD3D12Impl> pBuffD3D12{pBuffer, IID_BufferD3D12};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyConstantBufferBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ResDesc.Flags, m_ArrayIndex,
- pBuffer, pBuffD3D12.RawPtr(), m_DstRes.pObject.RawPtr());
- if (m_ResDesc.ArraySize != 1 && pBuffD3D12 && pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC && pBuffD3D12->GetD3D12Resource() == nullptr)
- {
- LOG_ERROR_MESSAGE("Attempting to bind dynamic buffer '", pBuffD3D12->GetDesc().Name, "' that doesn't have backing d3d12 resource to array variable '", m_ResDesc.Name,
- "[", m_ResDesc.ArraySize, "]', which is currently not supported in Direct3D12 backend. Either use non-array variable, or bind non-dynamic buffer.");
- }
-#endif
- if (pBuffD3D12)
- {
- if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
- {
- // Do not update resource if one is already bound unless it is dynamic. This may be
- // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
- return;
- }
-
- const auto CPUDescriptorHandle = pBuffD3D12->GetCBVHandle();
- VERIFY(CPUDescriptorHandle.ptr != 0 || pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC,
- "Only dynamic constant buffers may have null CPU descriptor");
-
- SetResource(CPUDescriptorHandle, std::move(pBuffD3D12));
- }
-}
-
-
-void BindResourceHelper::CacheSampler(IDeviceObject* pSampler) const
-{
- RefCntAutoPtr<ISamplerD3D12> pSamplerD3D12{pSampler, IID_SamplerD3D12};
- if (pSamplerD3D12)
- {
- if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
- {
- if (m_DstRes.pObject != pSampler)
- {
- auto VarTypeStr = GetShaderVariableTypeLiteralName(m_ResDesc.VarType);
- LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex),
- "'. Attempting to bind another sampler is an error and will be ignored. ",
- "Use another shader resource binding instance or label the variable as dynamic.");
- }
-
- // Do not update resource if one is already bound unless it is dynamic. This may be
- // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
- return;
- }
-
- const auto CPUDescriptorHandle = pSamplerD3D12->GetCPUDescriptorHandle();
- VERIFY(CPUDescriptorHandle.ptr != 0, "Samplers must always have valid CPU descriptors");
- VERIFY(m_CacheType == ResourceCacheContentType::Signature || m_DstTableCPUDescriptorHandle.ptr != 0,
- "Samplers in SRB cache must always be allocated in root tables and thus assigned descriptor in the table");
-
- SetResource(CPUDescriptorHandle, std::move(pSamplerD3D12));
- }
- else
- {
- LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '",
- GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), "'. Incorect object type: sampler is expected.");
- }
-}
-
-
-void BindResourceHelper::CacheAccelStruct(IDeviceObject* pTLAS) const
-{
- RefCntAutoPtr<ITopLevelASD3D12> pTLASD3D12{pTLAS, IID_TopLevelASD3D12};
- if (pTLASD3D12)
- {
- if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
- {
- // Do not update resource if one is already bound unless it is dynamic. This may be
- // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
- return;
- }
-
- const auto CPUDescriptorHandle = pTLASD3D12->GetCPUDescriptorHandle();
- VERIFY(CPUDescriptorHandle.ptr != 0, "Acceleration structures must always have valid CPU descriptor handles");
- VERIFY(m_CacheType == ResourceCacheContentType::Signature || m_DstTableCPUDescriptorHandle.ptr != 0,
- "Acceleration structures in SRB cache are always allocated in root tables and thus must have a descriptor");
-
- SetResource(CPUDescriptorHandle, std::move(pTLASD3D12));
- }
-}
-
-
-template <typename TResourceViewType>
-struct ResourceViewTraits
-{};
-
-template <>
-struct ResourceViewTraits<TextureViewD3D12Impl>
-{
- static const INTERFACE_ID& IID;
-
- static bool VerifyView(const TextureViewD3D12Impl* pViewD3D12, const PipelineResourceDesc& ResDesc)
- {
- return true;
- }
-};
-const INTERFACE_ID& ResourceViewTraits<TextureViewD3D12Impl>::IID = IID_TextureViewD3D12;
-
-template <>
-struct ResourceViewTraits<BufferViewD3D12Impl>
-{
- static const INTERFACE_ID& IID;
-
- static bool VerifyView(const BufferViewD3D12Impl* pViewD3D12, const PipelineResourceDesc& ResDesc)
- {
- if (pViewD3D12 != nullptr)
- {
- const auto* const pBuffer = pViewD3D12->GetBuffer<BufferD3D12Impl>();
- if (ResDesc.ArraySize != 1 && pBuffer->GetDesc().Usage == USAGE_DYNAMIC && pBuffer->GetD3D12Resource() == nullptr)
- {
- LOG_ERROR_MESSAGE("Attempting to bind dynamic buffer '", pBuffer->GetDesc().Name, "' that doesn't have backing d3d12 resource to array variable '", ResDesc.Name,
- "[", ResDesc.ArraySize, "]', which is currently not supported in Direct3D12 backend. Either use non-array variable, or bind non-dynamic buffer.");
- return false;
- }
- }
-
- return true;
- }
-};
-const INTERFACE_ID& ResourceViewTraits<BufferViewD3D12Impl>::IID = IID_BufferViewD3D12;
-
-
-template <typename TResourceViewType,
- typename TViewTypeEnum>
-void BindResourceHelper::CacheResourceView(IDeviceObject* pView,
- TViewTypeEnum dbgExpectedViewType) const
-{
- // We cannot use ValidatedCast<> here as the resource retrieved from the
- // resource mapping can be of wrong type
- RefCntAutoPtr<TResourceViewType> pViewD3D12{pView, ResourceViewTraits<TResourceViewType>::IID};
-#ifdef DILIGENT_DEVELOPMENT
- VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex,
- pView, pViewD3D12.RawPtr(),
- {dbgExpectedViewType}, RESOURCE_DIM_UNDEFINED,
- false, // IsMultisample
- m_DstRes.pObject.RawPtr());
- ResourceViewTraits<TResourceViewType>::VerifyView(pViewD3D12, m_ResDesc);
-#endif
- if (pViewD3D12)
- {
- if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
- {
- // Do not update resource if one is already bound unless it is dynamic. This may be
- // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
- return;
- }
-
- const auto CPUDescriptorHandle = pViewD3D12->GetCPUDescriptorHandle();
- // Note that for dynamic structured buffers we still create SRV even though we don't really use it.
- VERIFY(CPUDescriptorHandle.ptr != 0, "Texture/buffer views should always have valid CPU descriptor handles");
-
- BindCombinedSampler(pViewD3D12);
-
- SetResource(CPUDescriptorHandle, std::move(pViewD3D12));
- }
-}
-
-
-void BindResourceHelper::BindCombinedSampler(TextureViewD3D12Impl* pTexView) const
-{
- if (m_ResDesc.ResourceType != SHADER_RESOURCE_TYPE_TEXTURE_SRV)
- {
- VERIFY(!m_Attribs.IsCombinedWithSampler(), "Only texture SRVs can be combined with sampler");
- return;
- }
-
- if (!m_Attribs.IsCombinedWithSampler())
- return;
-
- const auto& SamplerResDesc = m_Signature.GetResourceDesc(m_Attribs.SamplerInd);
- const auto& SamplerAttribs = m_Signature.GetResourceAttribs(m_Attribs.SamplerInd);
- VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
-
- if (SamplerAttribs.IsImmutableSamplerAssigned())
- {
- // Immutable samplers should not be assigned cache space
- VERIFY_EXPR(SamplerAttribs.RootIndex(ResourceCacheContentType::Signature) == ResourceAttribs::InvalidSigRootIndex);
- VERIFY_EXPR(SamplerAttribs.RootIndex(ResourceCacheContentType::SRB) == ResourceAttribs::InvalidSRBRootIndex);
- VERIFY_EXPR(SamplerAttribs.SigOffsetFromTableStart == ResourceAttribs::InvalidOffset);
- VERIFY_EXPR(SamplerAttribs.SRBOffsetFromTableStart == ResourceAttribs::InvalidOffset);
- return;
- }
-
- auto* const pSampler = pTexView->GetSampler();
- if (pSampler == nullptr)
- {
- LOG_ERROR_MESSAGE("Failed to bind sampler to variable '", SamplerResDesc.Name, ". Sampler is not set in the texture view '", pTexView->GetDesc().Name, '\'');
- return;
- }
-
- VERIFY_EXPR(m_ResDesc.ArraySize == SamplerResDesc.ArraySize || SamplerResDesc.ArraySize == 1);
- const auto SamplerArrInd = SamplerResDesc.ArraySize > 1 ? m_ArrayIndex : 0;
-
- BindResourceHelper BindSampler{m_Signature, m_ResourceCache, m_Attribs.SamplerInd, SamplerArrInd};
- BindSampler(pSampler);
-}
-
-void BindResourceHelper::operator()(IDeviceObject* pObj) const
-{
- if (pObj)
- {
- static_assert(SHADER_RESOURCE_TYPE_LAST == 8, "Please update this function to handle the new resource type");
- switch (m_ResDesc.ResourceType)
- {
- case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER:
- CacheCB(pObj);
- break;
-
- case SHADER_RESOURCE_TYPE_TEXTURE_SRV:
- case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT:
- CacheResourceView<TextureViewD3D12Impl>(pObj, TEXTURE_VIEW_SHADER_RESOURCE);
- break;
-
- case SHADER_RESOURCE_TYPE_TEXTURE_UAV:
- CacheResourceView<TextureViewD3D12Impl>(pObj, TEXTURE_VIEW_UNORDERED_ACCESS);
- break;
-
- case SHADER_RESOURCE_TYPE_BUFFER_SRV:
- CacheResourceView<BufferViewD3D12Impl>(pObj, BUFFER_VIEW_SHADER_RESOURCE);
- break;
-
- case SHADER_RESOURCE_TYPE_BUFFER_UAV:
- CacheResourceView<BufferViewD3D12Impl>(pObj, BUFFER_VIEW_UNORDERED_ACCESS);
- break;
-
- case SHADER_RESOURCE_TYPE_SAMPLER:
- CacheSampler(pObj);
- break;
-
- case SHADER_RESOURCE_TYPE_ACCEL_STRUCT:
- CacheAccelStruct(pObj);
- break;
-
- default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(m_ResDesc.ResourceType));
- }
- }
- else
- {
- if (m_DstRes.pObject != nullptr && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- LOG_ERROR_MESSAGE("Shader variable '", m_ResDesc.Name, "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. ",
- "Use another shader resource binding instance or label the variable as dynamic if you need to bind another resource.");
- }
-
- m_ResourceCache.ResetResource(m_RootIndex, m_OffsetFromTableStart);
- if (m_Attribs.IsCombinedWithSampler())
- {
- auto& SamplerResDesc = m_Signature.GetResourceDesc(m_Attribs.SamplerInd);
- auto& SamplerAttribs = m_Signature.GetResourceAttribs(m_Attribs.SamplerInd);
- VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
-
- if (!SamplerAttribs.IsImmutableSamplerAssigned())
- {
- const auto SamplerArrInd = SamplerResDesc.ArraySize > 1 ? m_ArrayIndex : 0;
- const auto SamRootIndex = SamplerAttribs.RootIndex(m_CacheType);
- const auto SamOffsetFromTableStart = SamplerAttribs.OffsetFromTableStart(m_CacheType) + SamplerArrInd;
- const auto& DstSam = const_cast<const ShaderResourceCacheD3D12&>(m_ResourceCache).GetRootTable(SamRootIndex).GetResource(SamOffsetFromTableStart);
-
- if (DstSam.pObject != nullptr && SamplerResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
- {
- LOG_ERROR_MESSAGE("Sampler variable '", SamplerResDesc.Name, "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. ",
- "Use another shader resource binding instance or label the variable as dynamic if you need to bind another sampler.");
- }
-
- m_ResourceCache.ResetResource(SamRootIndex, SamOffsetFromTableStart);
- }
- }
- }
-}
-
-} // namespace
-
-
-void PipelineResourceSignatureD3D12Impl::BindResource(IDeviceObject* pObj,
- Uint32 ArrayIndex,
- Uint32 ResIndex,
- ShaderResourceCacheD3D12& ResourceCache) const
-{
- VERIFY(IsUsingSeparateSamplers() || GetResourceDesc(ResIndex).ResourceType != SHADER_RESOURCE_TYPE_SAMPLER,
- "Samplers should not be set directly when using combined texture samplers");
- BindResourceHelper BindResHelper{*this, ResourceCache, ResIndex, ArrayIndex};
- BindResHelper(pObj);
-}
-
-bool PipelineResourceSignatureD3D12Impl::IsBound(Uint32 ArrayIndex,
- Uint32 ResIndex,
- const ShaderResourceCacheD3D12& ResourceCache) const
-{
- const auto& ResDesc = GetResourceDesc(ResIndex);
- const auto& Attribs = GetResourceAttribs(ResIndex);
- const auto CacheType = ResourceCache.GetContentType();
- const auto RootIndex = Attribs.RootIndex(CacheType);
- const auto OffsetFromTableStart = Attribs.OffsetFromTableStart(CacheType) + ArrayIndex;
-
- VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
-
- if (RootIndex < ResourceCache.GetNumRootTables())
- {
- const auto& RootTable = ResourceCache.GetRootTable(RootIndex);
- if (OffsetFromTableStart < RootTable.GetSize())
- {
- const auto& CachedRes = RootTable.GetResource(OffsetFromTableStart);
- return !CachedRes.IsNull();
- }
- }
-
- return false;
-}
-
-
#ifdef DILIGENT_DEVELOPMENT
bool PipelineResourceSignatureD3D12Impl::DvpValidateCommittedResource(const D3DShaderResourceAttribs& D3DAttribs,
Uint32 ResIndex,
@@ -1167,7 +729,8 @@ bool PipelineResourceSignatureD3D12Impl::DvpValidateCommittedResource(const D3DS
bool BindingsOK = true;
for (Uint32 ArrIndex = 0; ArrIndex < D3DAttribs.BindCount; ++ArrIndex)
{
- if (!IsBound(ArrIndex, ResIndex, ResourceCache))
+ const auto& CachedRes = RootTable.GetResource(OffsetFromTableStart + ArrIndex);
+ if (CachedRes.IsNull())
{
LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(D3DAttribs.Name, D3DAttribs.BindCount, ArrIndex),
"' in shader '", ShaderName, "' of PSO '", PSOName, "'.");
@@ -1177,15 +740,19 @@ bool PipelineResourceSignatureD3D12Impl::DvpValidateCommittedResource(const D3DS
if (ResAttribs.IsCombinedWithSampler())
{
- auto& SamplerResDesc = GetResourceDesc(ResAttribs.SamplerInd);
- auto& SamplerAttribs = GetResourceAttribs(ResAttribs.SamplerInd);
+ const auto& SamplerResDesc = GetResourceDesc(ResAttribs.SamplerInd);
+ const auto& SamplerAttribs = GetResourceAttribs(ResAttribs.SamplerInd);
VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
VERIFY_EXPR(SamplerResDesc.ArraySize == 1 || SamplerResDesc.ArraySize == ResDesc.ArraySize);
if (!SamplerAttribs.IsImmutableSamplerAssigned())
{
if (ArrIndex < SamplerResDesc.ArraySize)
{
- if (!IsBound(ArrIndex, ResAttribs.SamplerInd, ResourceCache))
+ const auto SamRootIndex = SamplerAttribs.RootIndex(CacheType);
+ const auto SamOffsetFromTableStart = SamplerAttribs.OffsetFromTableStart(CacheType);
+ const auto& SamRootTable = ResourceCache.GetRootTable(RootIndex);
+ const auto& CachedSam = SamRootTable.GetResource(SamOffsetFromTableStart + ArrIndex);
+ if (CachedSam.IsNull())
{
LOG_ERROR_MESSAGE("No sampler is bound to sampler variable '", GetShaderResourcePrintName(SamplerResDesc, ArrIndex),
"' combined with texture '", D3DAttribs.Name, "' in shader '", ShaderName, "' of PSO '", PSOName, "'.");
@@ -1195,8 +762,6 @@ bool PipelineResourceSignatureD3D12Impl::DvpValidateCommittedResource(const D3DS
}
}
- const auto& CachedRes = RootTable.GetResource(OffsetFromTableStart);
-
switch (ResDesc.ResourceType)
{
case SHADER_RESOURCE_TYPE_TEXTURE_SRV:
diff --git a/Graphics/GraphicsEngineD3D12/src/ShaderVariableManagerD3D12.cpp b/Graphics/GraphicsEngineD3D12/src/ShaderVariableManagerD3D12.cpp
index b8e33cb0..a47583a1 100644
--- a/Graphics/GraphicsEngineD3D12/src/ShaderVariableManagerD3D12.cpp
+++ b/Graphics/GraphicsEngineD3D12/src/ShaderVariableManagerD3D12.cpp
@@ -31,6 +31,14 @@
#include "RenderDeviceD3D12Impl.hpp"
#include "PipelineResourceSignatureD3D12Impl.hpp"
+#include "BufferD3D12Impl.hpp"
+#include "BufferViewD3D12Impl.hpp"
+#include "SamplerD3D12Impl.hpp"
+#include "TextureD3D12Impl.hpp"
+#include "TextureViewD3D12Impl.hpp"
+#include "TopLevelASD3D12Impl.hpp"
+
+#include "ShaderVariableD3D.hpp"
#include "ShaderResourceCacheD3D12.hpp"
namespace Diligent
@@ -203,14 +211,438 @@ void ShaderVariableD3D12Impl::SetArray(IDeviceObject* const* ppObjects, Uint32 F
BindResource(ppObjects[Elem], FirstElement + Elem);
}
-bool ShaderVariableD3D12Impl::IsBound(Uint32 ArrayIndex) const
+
+namespace
+{
+
+class BindResourceHelper
+{
+public:
+ BindResourceHelper(const PipelineResourceSignatureD3D12Impl& Signature,
+ ShaderResourceCacheD3D12& ResourceCache,
+ Uint32 ResIndex,
+ Uint32 ArrayIndex);
+
+ void operator()(IDeviceObject* pObj) const;
+
+private:
+ void CacheCB(IDeviceObject* pBuffer) const;
+ void CacheSampler(IDeviceObject* pBuffer) const;
+ void CacheAccelStruct(IDeviceObject* pBuffer) const;
+ void BindCombinedSampler(TextureViewD3D12Impl* pTexView) const;
+ void BindCombinedSampler(BufferViewD3D12Impl* pTexView) const {}
+
+ template <typename TResourceViewType, ///< The type of the view (TextureViewD3D12Impl or BufferViewD3D12Impl)
+ typename TViewTypeEnum ///< The type of the expected view type enum (TEXTURE_VIEW_TYPE or BUFFER_VIEW_TYPE)
+ >
+ void CacheResourceView(IDeviceObject* pBufferView,
+ TViewTypeEnum dbgExpectedViewType) const;
+
+ ID3D12Device* GetD3D12Device() const { return m_Signature.GetDevice()->GetD3D12Device(); }
+
+ void SetResource(D3D12_CPU_DESCRIPTOR_HANDLE CPUDescriptorHandle, RefCntAutoPtr<IDeviceObject>&& pObject) const
+ {
+ if (m_DstTableCPUDescriptorHandle.ptr != 0)
+ {
+ VERIFY(CPUDescriptorHandle.ptr != 0, "CPU descriptor handle must not be null for resources allocated in descriptor tables");
+ DEV_CHECK_ERR(m_ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC || m_DstRes.pObject == nullptr, "Static and mutable resource descriptors should only be copied once");
+ const auto d3d12HeapType = m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER ?
+ D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER :
+ D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
+ GetD3D12Device()->CopyDescriptorsSimple(1, m_DstTableCPUDescriptorHandle, CPUDescriptorHandle, d3d12HeapType);
+ }
+
+ m_ResourceCache.SetResource(m_RootIndex, m_OffsetFromTableStart, m_ResDesc.ResourceType, CPUDescriptorHandle, std::move(pObject));
+ }
+
+private:
+ using ResourceAttribs = PipelineResourceSignatureD3D12Impl::ResourceAttribs;
+
+ const PipelineResourceSignatureD3D12Impl& m_Signature;
+ ShaderResourceCacheD3D12& m_ResourceCache;
+
+ const PipelineResourceDesc& m_ResDesc;
+ const ResourceAttribs& m_Attribs; // Must go before m_RootIndex, m_OffsetFromTableStart
+
+ const ResourceCacheContentType m_CacheType; // Must go before m_RootIndex, m_OffsetFromTableStart
+ const Uint32 m_RootIndex; // Must go before m_DstRes
+ const Uint32 m_ArrayIndex;
+ const Uint32 m_OffsetFromTableStart; // Must go before m_DstRes
+
+ const ShaderResourceCacheD3D12::Resource& m_DstRes;
+
+ D3D12_CPU_DESCRIPTOR_HANDLE m_DstTableCPUDescriptorHandle{};
+};
+
+BindResourceHelper::BindResourceHelper(const PipelineResourceSignatureD3D12Impl& Signature,
+ ShaderResourceCacheD3D12& ResourceCache,
+ Uint32 ResIndex,
+ Uint32 ArrayIndex) :
+ // clang-format off
+ m_Signature {Signature},
+ m_ResourceCache {ResourceCache},
+ m_ResDesc {Signature.GetResourceDesc(ResIndex)},
+ m_Attribs {Signature.GetResourceAttribs(ResIndex)},
+ m_CacheType {ResourceCache.GetContentType()},
+ m_RootIndex {m_Attribs.RootIndex(m_CacheType)},
+ m_ArrayIndex {ArrayIndex},
+ m_OffsetFromTableStart{m_Attribs.OffsetFromTableStart(m_CacheType) + ArrayIndex},
+ m_DstRes {const_cast<const ShaderResourceCacheD3D12&>(ResourceCache).GetRootTable(m_RootIndex).GetResource(m_OffsetFromTableStart)}
+// clang-format on
+{
+ VERIFY(ArrayIndex < m_ResDesc.ArraySize, "Array index is out of range");
+
+ if (m_CacheType != ResourceCacheContentType::Signature && !m_Attribs.IsRootView())
+ {
+ const auto IsSampler = (m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
+ const auto RootParamGroup = VariableTypeToRootParameterGroup(m_ResDesc.VarType);
+ // Static/mutable resources are allocated in GPU-visible descriptor heap, while dynamic resources - in CPU-only heap.
+ m_DstTableCPUDescriptorHandle =
+ ResourceCache.GetDescriptorTableHandle<D3D12_CPU_DESCRIPTOR_HANDLE>(
+ IsSampler ? D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER : D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
+ RootParamGroup, m_RootIndex, m_OffsetFromTableStart);
+ }
+
+#ifdef DILIGENT_DEBUG
+ if (m_CacheType == ResourceCacheContentType::Signature)
+ {
+ VERIFY(m_DstTableCPUDescriptorHandle.ptr == 0, "Static shader resource cache should never be assigned descriptor space.");
+ }
+ else if (m_CacheType == ResourceCacheContentType::SRB)
+ {
+ if (m_Attribs.GetD3D12RootParamType() == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE)
+ {
+ VERIFY(m_DstTableCPUDescriptorHandle.ptr != 0, "Shader resources allocated in descriptor tables must be assigned descriptor space.");
+ }
+ else
+ {
+ VERIFY_EXPR(m_Attribs.IsRootView());
+ VERIFY((m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER ||
+ m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_SRV ||
+ m_ResDesc.ResourceType == SHADER_RESOURCE_TYPE_BUFFER_UAV),
+ "Only constant buffers and dynamic buffer views can be allocated as root views");
+ VERIFY(m_DstTableCPUDescriptorHandle.ptr == 0, "Resources allocated as root views should never be assigned descriptor space.");
+ }
+ }
+ else
+ {
+ UNEXPECTED("Unknown content type");
+ }
+#endif
+}
+
+void BindResourceHelper::CacheCB(IDeviceObject* pBuffer) const
+{
+ // We cannot use ValidatedCast<> here as the resource retrieved from the
+ // resource mapping can be of wrong type
+ RefCntAutoPtr<BufferD3D12Impl> pBuffD3D12{pBuffer, IID_BufferD3D12};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyConstantBufferBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ResDesc.Flags, m_ArrayIndex,
+ pBuffer, pBuffD3D12.RawPtr(), m_DstRes.pObject.RawPtr());
+ if (m_ResDesc.ArraySize != 1 && pBuffD3D12 && pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC && pBuffD3D12->GetD3D12Resource() == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Attempting to bind dynamic buffer '", pBuffD3D12->GetDesc().Name, "' that doesn't have backing d3d12 resource to array variable '", m_ResDesc.Name,
+ "[", m_ResDesc.ArraySize, "]', which is currently not supported in Direct3D12 backend. Either use non-array variable, or bind non-dynamic buffer.");
+ }
+#endif
+ if (pBuffD3D12)
+ {
+ if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
+ {
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ const auto CPUDescriptorHandle = pBuffD3D12->GetCBVHandle();
+ VERIFY(CPUDescriptorHandle.ptr != 0 || pBuffD3D12->GetDesc().Usage == USAGE_DYNAMIC,
+ "Only dynamic constant buffers may have null CPU descriptor");
+
+ SetResource(CPUDescriptorHandle, std::move(pBuffD3D12));
+ }
+}
+
+
+void BindResourceHelper::CacheSampler(IDeviceObject* pSampler) const
+{
+ RefCntAutoPtr<ISamplerD3D12> pSamplerD3D12{pSampler, IID_SamplerD3D12};
+ if (pSamplerD3D12)
+ {
+ if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
+ {
+ if (m_DstRes.pObject != pSampler)
+ {
+ auto VarTypeStr = GetShaderVariableTypeLiteralName(m_ResDesc.VarType);
+ LOG_ERROR_MESSAGE("Non-null sampler is already bound to ", VarTypeStr, " shader variable '", GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex),
+ "'. Attempting to bind another sampler is an error and will be ignored. ",
+ "Use another shader resource binding instance or label the variable as dynamic.");
+ }
+
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ const auto CPUDescriptorHandle = pSamplerD3D12->GetCPUDescriptorHandle();
+ VERIFY(CPUDescriptorHandle.ptr != 0, "Samplers must always have valid CPU descriptors");
+ VERIFY(m_CacheType == ResourceCacheContentType::Signature || m_DstTableCPUDescriptorHandle.ptr != 0,
+ "Samplers in SRB cache must always be allocated in root tables and thus assigned descriptor in the table");
+
+ SetResource(CPUDescriptorHandle, std::move(pSamplerD3D12));
+ }
+ else
+ {
+ LOG_ERROR_MESSAGE("Failed to bind object '", pSampler->GetDesc().Name, "' to variable '",
+ GetShaderResourcePrintName(m_ResDesc, m_ArrayIndex), "'. Incorect object type: sampler is expected.");
+ }
+}
+
+
+void BindResourceHelper::CacheAccelStruct(IDeviceObject* pTLAS) const
{
- return m_ParentManager.m_pSignature->IsBound(ArrayIndex, m_ResIndex, m_ParentManager.m_ResourceCache);
+ RefCntAutoPtr<ITopLevelASD3D12> pTLASD3D12{pTLAS, IID_TopLevelASD3D12};
+ if (pTLASD3D12)
+ {
+ if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
+ {
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ const auto CPUDescriptorHandle = pTLASD3D12->GetCPUDescriptorHandle();
+ VERIFY(CPUDescriptorHandle.ptr != 0, "Acceleration structures must always have valid CPU descriptor handles");
+ VERIFY(m_CacheType == ResourceCacheContentType::Signature || m_DstTableCPUDescriptorHandle.ptr != 0,
+ "Acceleration structures in SRB cache are always allocated in root tables and thus must have a descriptor");
+
+ SetResource(CPUDescriptorHandle, std::move(pTLASD3D12));
+ }
}
-void ShaderVariableD3D12Impl::BindResource(IDeviceObject* pObj, Uint32 ArrayIndex) const
+
+template <typename TResourceViewType>
+struct ResourceViewTraits
+{};
+
+template <>
+struct ResourceViewTraits<TextureViewD3D12Impl>
{
- m_ParentManager.m_pSignature->BindResource(pObj, ArrayIndex, m_ResIndex, m_ParentManager.m_ResourceCache);
+ static const INTERFACE_ID& IID;
+
+ static bool VerifyView(const TextureViewD3D12Impl* pViewD3D12, const PipelineResourceDesc& ResDesc)
+ {
+ return true;
+ }
+};
+const INTERFACE_ID& ResourceViewTraits<TextureViewD3D12Impl>::IID = IID_TextureViewD3D12;
+
+template <>
+struct ResourceViewTraits<BufferViewD3D12Impl>
+{
+ static const INTERFACE_ID& IID;
+
+ static bool VerifyView(const BufferViewD3D12Impl* pViewD3D12, const PipelineResourceDesc& ResDesc)
+ {
+ if (pViewD3D12 != nullptr)
+ {
+ const auto* const pBuffer = pViewD3D12->GetBuffer<BufferD3D12Impl>();
+ if (ResDesc.ArraySize != 1 && pBuffer->GetDesc().Usage == USAGE_DYNAMIC && pBuffer->GetD3D12Resource() == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Attempting to bind dynamic buffer '", pBuffer->GetDesc().Name, "' that doesn't have backing d3d12 resource to array variable '", ResDesc.Name,
+ "[", ResDesc.ArraySize, "]', which is currently not supported in Direct3D12 backend. Either use non-array variable, or bind non-dynamic buffer.");
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+const INTERFACE_ID& ResourceViewTraits<BufferViewD3D12Impl>::IID = IID_BufferViewD3D12;
+
+
+template <typename TResourceViewType,
+ typename TViewTypeEnum>
+void BindResourceHelper::CacheResourceView(IDeviceObject* pView,
+ TViewTypeEnum dbgExpectedViewType) const
+{
+ // We cannot use ValidatedCast<> here as the resource retrieved from the
+ // resource mapping can be of wrong type
+ RefCntAutoPtr<TResourceViewType> pViewD3D12{pView, ResourceViewTraits<TResourceViewType>::IID};
+#ifdef DILIGENT_DEVELOPMENT
+ VerifyResourceViewBinding(m_ResDesc.Name, m_ResDesc.ArraySize, m_ResDesc.VarType, m_ArrayIndex,
+ pView, pViewD3D12.RawPtr(),
+ {dbgExpectedViewType}, RESOURCE_DIM_UNDEFINED,
+ false, // IsMultisample
+ m_DstRes.pObject.RawPtr());
+ ResourceViewTraits<TResourceViewType>::VerifyView(pViewD3D12, m_ResDesc);
+#endif
+ if (pViewD3D12)
+ {
+ if (m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC && m_DstRes.pObject != nullptr)
+ {
+ // Do not update resource if one is already bound unless it is dynamic. This may be
+ // dangerous as CopyDescriptorsSimple() may interfere with GPU reading the same descriptor.
+ return;
+ }
+
+ const auto CPUDescriptorHandle = pViewD3D12->GetCPUDescriptorHandle();
+ // Note that for dynamic structured buffers we still create SRV even though we don't really use it.
+ VERIFY(CPUDescriptorHandle.ptr != 0, "Texture/buffer views should always have valid CPU descriptor handles");
+
+ BindCombinedSampler(pViewD3D12);
+
+ SetResource(CPUDescriptorHandle, std::move(pViewD3D12));
+ }
+}
+
+
+void BindResourceHelper::BindCombinedSampler(TextureViewD3D12Impl* pTexView) const
+{
+ if (m_ResDesc.ResourceType != SHADER_RESOURCE_TYPE_TEXTURE_SRV)
+ {
+ VERIFY(!m_Attribs.IsCombinedWithSampler(), "Only texture SRVs can be combined with sampler");
+ return;
+ }
+
+ if (!m_Attribs.IsCombinedWithSampler())
+ return;
+
+ const auto& SamplerResDesc = m_Signature.GetResourceDesc(m_Attribs.SamplerInd);
+ const auto& SamplerAttribs = m_Signature.GetResourceAttribs(m_Attribs.SamplerInd);
+ VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
+
+ if (SamplerAttribs.IsImmutableSamplerAssigned())
+ {
+ // Immutable samplers should not be assigned cache space
+ VERIFY_EXPR(SamplerAttribs.RootIndex(ResourceCacheContentType::Signature) == ResourceAttribs::InvalidSigRootIndex);
+ VERIFY_EXPR(SamplerAttribs.RootIndex(ResourceCacheContentType::SRB) == ResourceAttribs::InvalidSRBRootIndex);
+ VERIFY_EXPR(SamplerAttribs.SigOffsetFromTableStart == ResourceAttribs::InvalidOffset);
+ VERIFY_EXPR(SamplerAttribs.SRBOffsetFromTableStart == ResourceAttribs::InvalidOffset);
+ return;
+ }
+
+ auto* const pSampler = pTexView->GetSampler();
+ if (pSampler == nullptr)
+ {
+ LOG_ERROR_MESSAGE("Failed to bind sampler to variable '", SamplerResDesc.Name, ". Sampler is not set in the texture view '", pTexView->GetDesc().Name, '\'');
+ return;
+ }
+
+ VERIFY_EXPR(m_ResDesc.ArraySize == SamplerResDesc.ArraySize || SamplerResDesc.ArraySize == 1);
+ const auto SamplerArrInd = SamplerResDesc.ArraySize > 1 ? m_ArrayIndex : 0;
+
+ BindResourceHelper BindSampler{m_Signature, m_ResourceCache, m_Attribs.SamplerInd, SamplerArrInd};
+ BindSampler(pSampler);
+}
+
+void BindResourceHelper::operator()(IDeviceObject* pObj) const
+{
+ if (pObj)
+ {
+ static_assert(SHADER_RESOURCE_TYPE_LAST == 8, "Please update this function to handle the new resource type");
+ switch (m_ResDesc.ResourceType)
+ {
+ case SHADER_RESOURCE_TYPE_CONSTANT_BUFFER:
+ CacheCB(pObj);
+ break;
+
+ case SHADER_RESOURCE_TYPE_TEXTURE_SRV:
+ case SHADER_RESOURCE_TYPE_INPUT_ATTACHMENT:
+ CacheResourceView<TextureViewD3D12Impl>(pObj, TEXTURE_VIEW_SHADER_RESOURCE);
+ break;
+
+ case SHADER_RESOURCE_TYPE_TEXTURE_UAV:
+ CacheResourceView<TextureViewD3D12Impl>(pObj, TEXTURE_VIEW_UNORDERED_ACCESS);
+ break;
+
+ case SHADER_RESOURCE_TYPE_BUFFER_SRV:
+ CacheResourceView<BufferViewD3D12Impl>(pObj, BUFFER_VIEW_SHADER_RESOURCE);
+ break;
+
+ case SHADER_RESOURCE_TYPE_BUFFER_UAV:
+ CacheResourceView<BufferViewD3D12Impl>(pObj, BUFFER_VIEW_UNORDERED_ACCESS);
+ break;
+
+ case SHADER_RESOURCE_TYPE_SAMPLER:
+ CacheSampler(pObj);
+ break;
+
+ case SHADER_RESOURCE_TYPE_ACCEL_STRUCT:
+ CacheAccelStruct(pObj);
+ break;
+
+ default: UNEXPECTED("Unknown resource type ", static_cast<Int32>(m_ResDesc.ResourceType));
+ }
+ }
+ else
+ {
+ if (m_DstRes.pObject != nullptr && m_ResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ LOG_ERROR_MESSAGE("Shader variable '", m_ResDesc.Name, "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. ",
+ "Use another shader resource binding instance or label the variable as dynamic if you need to bind another resource.");
+ }
+
+ m_ResourceCache.ResetResource(m_RootIndex, m_OffsetFromTableStart);
+ if (m_Attribs.IsCombinedWithSampler())
+ {
+ auto& SamplerResDesc = m_Signature.GetResourceDesc(m_Attribs.SamplerInd);
+ auto& SamplerAttribs = m_Signature.GetResourceAttribs(m_Attribs.SamplerInd);
+ VERIFY_EXPR(SamplerResDesc.ResourceType == SHADER_RESOURCE_TYPE_SAMPLER);
+
+ if (!SamplerAttribs.IsImmutableSamplerAssigned())
+ {
+ const auto SamplerArrInd = SamplerResDesc.ArraySize > 1 ? m_ArrayIndex : 0;
+ const auto SamRootIndex = SamplerAttribs.RootIndex(m_CacheType);
+ const auto SamOffsetFromTableStart = SamplerAttribs.OffsetFromTableStart(m_CacheType) + SamplerArrInd;
+ const auto& DstSam = const_cast<const ShaderResourceCacheD3D12&>(m_ResourceCache).GetRootTable(SamRootIndex).GetResource(SamOffsetFromTableStart);
+
+ if (DstSam.pObject != nullptr && SamplerResDesc.VarType != SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC)
+ {
+ LOG_ERROR_MESSAGE("Sampler variable '", SamplerResDesc.Name, "' is not dynamic but is being reset to null. This is an error and may cause unpredicted behavior. ",
+ "Use another shader resource binding instance or label the variable as dynamic if you need to bind another sampler.");
+ }
+
+ m_ResourceCache.ResetResource(SamRootIndex, SamOffsetFromTableStart);
+ }
+ }
+ }
+}
+
+} // namespace
+
+
+void ShaderVariableManagerD3D12::BindResource(IDeviceObject* pObj,
+ Uint32 ArrayIndex,
+ Uint32 ResIndex)
+{
+ VERIFY(m_pSignature->IsUsingSeparateSamplers() || GetResourceDesc(ResIndex).ResourceType != SHADER_RESOURCE_TYPE_SAMPLER,
+ "Samplers should not be set directly when using combined texture samplers");
+ BindResourceHelper BindResHelper{*m_pSignature, m_ResourceCache, ResIndex, ArrayIndex};
+ BindResHelper(pObj);
+}
+
+bool ShaderVariableManagerD3D12::IsBound(Uint32 ArrayIndex,
+ Uint32 ResIndex) const
+{
+ const auto& ResDesc = GetResourceDesc(ResIndex);
+ const auto& Attribs = GetResourceAttribs(ResIndex);
+ const auto CacheType = m_ResourceCache.GetContentType();
+ const auto RootIndex = Attribs.RootIndex(CacheType);
+ const auto OffsetFromTableStart = Attribs.OffsetFromTableStart(CacheType) + ArrayIndex;
+
+ VERIFY_EXPR(ArrayIndex < ResDesc.ArraySize);
+
+ if (RootIndex < m_ResourceCache.GetNumRootTables())
+ {
+ const auto& RootTable = const_cast<const ShaderResourceCacheD3D12&>(m_ResourceCache).GetRootTable(RootIndex);
+ if (OffsetFromTableStart < RootTable.GetSize())
+ {
+ const auto& CachedRes = RootTable.GetResource(OffsetFromTableStart);
+ return !CachedRes.IsNull();
+ }
+ }
+
+ return false;
}
} // namespace Diligent