Skip to content

Commit 686f151

Browse files
D3D11/D3D12: clean up code and update documentation for inline constants
1 parent 93af1da commit 686f151

File tree

12 files changed

+112
-70
lines changed

12 files changed

+112
-70
lines changed

Graphics/GraphicsAccessories/src/GraphicsAccessories.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,6 +1644,10 @@ String GetPipelineResourceFlagsString(PIPELINE_RESOURCE_FLAGS Flags, bool GetFul
16441644
Str.append(GetFullName ? "PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS" : "NO_DYNAMIC_BUFFERS");
16451645
break;
16461646

1647+
case PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS:
1648+
Str.append(GetFullName ? "PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS" : "INLINE_CONSTANTS");
1649+
break;
1650+
16471651
case PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER:
16481652
Str.append(GetFullName ? "PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER" : "COMBINED_SAMPLER");
16491653
break;
@@ -1660,10 +1664,6 @@ String GetPipelineResourceFlagsString(PIPELINE_RESOURCE_FLAGS Flags, bool GetFul
16601664
Str.append(GetFullName ? "PIPELINE_RESOURCE_FLAG_GENERAL_INPUT_ATTACHMENT" : "GENERAL_INPUT_ATTACHMENT");
16611665
break;
16621666

1663-
case PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS:
1664-
Str.append(GetFullName ? "PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS" : "INLINE_CONSTANTS");
1665-
break;
1666-
16671667
default:
16681668
UNEXPECTED("Unexpected pipeline resource flag");
16691669
}
@@ -1852,16 +1852,16 @@ PIPELINE_RESOURCE_FLAGS ShaderVariableFlagsToPipelineResourceFlags(SHADER_VARIAB
18521852
case SHADER_VARIABLE_FLAG_NO_DYNAMIC_BUFFERS:
18531853
return PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS;
18541854

1855+
case SHADER_VARIABLE_FLAG_INLINE_CONSTANTS:
1856+
return PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS;
1857+
18551858
case SHADER_VARIABLE_FLAG_GENERAL_INPUT_ATTACHMENT_VK:
18561859
return PIPELINE_RESOURCE_FLAG_GENERAL_INPUT_ATTACHMENT;
18571860

18581861
case SHADER_VARIABLE_FLAG_UNFILTERABLE_FLOAT_TEXTURE_WEBGPU:
18591862
case SHADER_VARIABLE_FLAG_NON_FILTERING_SAMPLER_WEBGPU:
18601863
return PIPELINE_RESOURCE_FLAG_NONE;
18611864

1862-
case SHADER_VARIABLE_FLAG_INLINE_CONSTANTS:
1863-
return PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS;
1864-
18651865
default:
18661866
UNEXPECTED("Unexpected shader variable flag");
18671867
return PIPELINE_RESOURCE_FLAG_NONE;

Graphics/GraphicsEngine/interface/PipelineResourceSignature.h

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,28 @@ DILIGENT_TYPED_ENUM(PIPELINE_RESOURCE_FLAGS, Uint8)
105105
/// PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS flag.
106106
PIPELINE_RESOURCE_FLAG_NO_DYNAMIC_BUFFERS = 1u << 0,
107107

108+
/// Indicates that the resource consists of inline constants (also
109+
/// known as push constants in Vulkan or root constants in Direct3D12).
110+
///
111+
/// Applies to SHADER_RESOURCE_TYPE_CONSTANT_BUFFER only.
112+
///
113+
/// Use this flag if you have a buffer of frequently changing constants
114+
/// - that are small in size (typically up to 128 bytes) and
115+
/// - change often (e.g. per-draw or per-dispatch).
116+
///
117+
/// Inline constants are set directly using IShaderResourceVariable::SetInlineConstants.
118+
///
119+
/// This flag cannot be combined with any other flags.
120+
///
121+
/// In Vulkan and Direct3D12, inline constants are not bound via descriptor sets or root
122+
/// signatures, but are set directly in command buffers or command lists and are very cheap.
123+
/// In legacy APIs (Direct3D11 and OpenGL), inline constants are emulated using regular
124+
/// constant buffers and thus have higher overhead.
125+
PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS = 1u << 1,
126+
108127
/// Indicates that a texture SRV will be combined with a sampler.
109128
/// Applies to SHADER_RESOURCE_TYPE_TEXTURE_SRV resources.
110-
PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER = 1u << 1,
129+
PIPELINE_RESOURCE_FLAG_COMBINED_SAMPLER = 1u << 2,
111130

112131
/// Indicates that this variable will be used to bind formatted buffers.
113132
/// Applies to SHADER_RESOURCE_TYPE_BUFFER_UAV and SHADER_RESOURCE_TYPE_BUFFER_SRV
@@ -117,35 +136,19 @@ DILIGENT_TYPED_ENUM(PIPELINE_RESOURCE_FLAGS, Uint8)
117136
/// as opposed to structured buffers. If an application will be using
118137
/// formatted buffers with buffer UAVs and SRVs, it must specify the
119138
/// PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER flag.
120-
PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER = 1u << 2,
139+
PIPELINE_RESOURCE_FLAG_FORMATTED_BUFFER = 1u << 3,
121140

122141
/// Indicates that resource is a run-time sized shader array (e.g. an array without a specific size).
123-
PIPELINE_RESOURCE_FLAG_RUNTIME_ARRAY = 1u << 3,
142+
PIPELINE_RESOURCE_FLAG_RUNTIME_ARRAY = 1u << 4,
124143

125144
/// Indicates that the resource is an input attachment in general layout, which allows simultaneously
126145
/// reading from the resource through the input attachment and writing to it via color or depth-stencil
127146
/// attachment.
128147
///
129148
/// \note This flag is only valid in Vulkan.
130-
PIPELINE_RESOURCE_FLAG_GENERAL_INPUT_ATTACHMENT = 1u << 4,
131-
132-
/// Indicates that the resource consists of inline constants (also known as push constants in Vulkan or root constants in Direct3D12).
133-
134-
/// Applies to SHADER_RESOURCE_TYPE_CONSTANT_BUFFER only.
135-
///
136-
/// Inline constants are set directly using IShaderResourceVariable::SetInlineConstants.
137-
///
138-
/// This flag cannot be combined with any other flags.
139-
///
140-
/// In Vulkan and Direct3D12, inline constants are not bound via descriptor sets or root
141-
/// signatures, but are set directly in command buffers or command lists. As such, they
142-
/// are very cheap to set and are intended for small pieces of frequently changing data.
143-
///
144-
/// In legacy APIs (Direct3D11 and OpenGL), inline constants are emulated using regular
145-
/// constant buffers and thus have higher overhead.
146-
PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS = 1u << 5,
149+
PIPELINE_RESOURCE_FLAG_GENERAL_INPUT_ATTACHMENT = 1u << 5,
147150

148-
PIPELINE_RESOURCE_FLAG_LAST = PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS
151+
PIPELINE_RESOURCE_FLAG_LAST = PIPELINE_RESOURCE_FLAG_GENERAL_INPUT_ATTACHMENT
149152
};
150153
DEFINE_FLAG_ENUM_OPERATORS(PIPELINE_RESOURCE_FLAGS);
151154

Graphics/GraphicsEngine/interface/PipelineState.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ DILIGENT_TYPED_ENUM(SHADER_VARIABLE_FLAGS, Uint8)
109109
///
110110
/// \remarks This flag directly translates to the Diligent::PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS
111111
/// flag in the internal pipeline resource signature.
112+
///
113+
/// See Diligent::PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS for more details.
112114
SHADER_VARIABLE_FLAG_INLINE_CONSTANTS = 1u << 1,
113115

114116
/// Indicates that the resource is an input attachment in general layout, which allows simultaneously

Graphics/GraphicsEngine/interface/ShaderResourceVariable.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ DILIGENT_BEGIN_INTERFACE(IShaderResourceVariable, IObject)
252252

253253
/// For inline constant variables, sets the constant values
254254

255+
/// Inline constant variables are defined using Diligent::SHADER_RESOURCE_VARIABLE_FLAG_INLINE_CONSTANTS
256+
/// or Diligent::PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS flags.
257+
///
255258
/// \param [in] pConstants - pointer to the array of 32-bit constant values.
256259
/// \param [in] FirstConstant - index of the first 32-bit constant to set.
257260
/// \param [in] NumConstants - number of 32-bit constants to set.

Graphics/GraphicsEngineD3D11/include/ShaderResourceCacheD3D11.hpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ __forceinline void ShaderResourceCacheD3D11::SetInlineConstants(const D3D11Resou
776776
Uint32 FirstConstant,
777777
Uint32 NumConstants)
778778
{
779+
// Since all shader stages share the same inline constant data, we can just set it for one stage
779780
SHADER_TYPE ActiveStages = BindPoints.GetActiveStages();
780781
VERIFY_EXPR(ActiveStages != SHADER_TYPE_UNKNOWN);
781782
const Uint32 ShaderInd0 = ExtractFirstShaderStageIndex(ActiveStages);
@@ -793,9 +794,9 @@ __forceinline void ShaderResourceCacheD3D11::SetInlineConstants(const D3D11Resou
793794

794795
const auto ResArrays = GetResourceArrays<D3D11_RESOURCE_RANGE_CBV>(ShaderInd);
795796
VERIFY(ResArrays.first[Binding].pInlineConstantData == ResArrays0.first[Binding0].pInlineConstantData,
796-
"All active shader stages must share the same inline constant data");
797+
"All shader stages must share the same inline constant data (ensured by InitInlineConstantBuffer)");
797798
VERIFY(ResArrays.first[Binding] == ResArrays0.first[Binding0],
798-
"All active shader stages must share the same inline constant data attributes");
799+
"All shader stages must share the same inline constant data attributes (ensured by InitInlineConstantBuffer)");
799800
}
800801
#endif
801802
}
@@ -859,6 +860,7 @@ bool ShaderResourceCacheD3D11::CopyResource(const ShaderResourceCacheD3D11& SrcC
859860

860861
inline void ShaderResourceCacheD3D11::CopyInlineConstants(const ShaderResourceCacheD3D11& SrcCache, const D3D11ResourceBindPoints& BindPoints, Uint32 NumConstants)
861862
{
863+
// Since all shader stages share the same inline constant data, we can just copy from one stage
862864
SHADER_TYPE ActiveStages = BindPoints.GetActiveStages();
863865
VERIFY_EXPR(ActiveStages != SHADER_TYPE_UNKNOWN);
864866

@@ -889,12 +891,14 @@ inline void ShaderResourceCacheD3D11::CopyInlineConstants(const ShaderResourceCa
889891
const Uint32 Binding = BindPoints[ShaderInd];
890892
VERIFY(Binding < GetResourceCount<D3D11_RESOURCE_RANGE_CBV>(ShaderInd), "Index is out of range");
891893
VERIFY(Binding < SrcCache.GetResourceCount<D3D11_RESOURCE_RANGE_CBV>(ShaderInd), "Index is out of range");
892-
VERIFY(SrcResArrays0.first[Binding0] == SrcResArrays.first[Binding], "All shader stages must share the same inline constant data attributes");
893-
VERIFY(DstResArrays0.first[Binding0] == DstResArrays.first[Binding], "All shader stages must share the same inline constant data attributes");
894+
VERIFY(SrcResArrays0.first[Binding0] == SrcResArrays.first[Binding],
895+
"All shader stages must share the same inline constant data attributes (ensured by InitInlineConstantBuffer)");
896+
VERIFY(DstResArrays0.first[Binding0] == DstResArrays.first[Binding],
897+
"All shader stages must share the same inline constant data attributes (ensured by InitInlineConstantBuffer)");
894898
VERIFY(SrcResArrays0.first[Binding0].pInlineConstantData == SrcResArrays.first[Binding].pInlineConstantData,
895-
"All active shader stages must share the same inline constant data");
899+
"All shader stages must share the same inline constant data (ensured by InitInlineConstantBuffer)");
896900
VERIFY(DstResArrays0.first[Binding0].pInlineConstantData == DstResArrays.first[Binding].pInlineConstantData,
897-
"All active shader stages must share the same inline constant data");
901+
"All shader stages must share the same inline constant data (ensured by InitInlineConstantBuffer)");
898902
}
899903
#endif
900904
}

Graphics/GraphicsEngineD3D11/src/DeviceContextD3D11Impl.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,8 @@ void DeviceContextD3D11Impl::BindShaderResources(Uint32 BindSRBMask,
454454
continue;
455455
}
456456

457-
if (m_BindInfo.StaleSRBMask & SignBit)
457+
const bool SRBStale = (m_BindInfo.StaleSRBMask & SignBit) != 0;
458+
if (SRBStale)
458459
{
459460
// Bind all cache resources
460461
BindCacheResources(*pResourceCache, BaseBindings, PsUavBindMode);
@@ -494,7 +495,8 @@ void DeviceContextD3D11Impl::BindShaderResources(Uint32 BindSRBMask,
494495
"Shader resource cache does not contain inline constants, but the corresponding bit in InlineConstantsSRBMask is set. "
495496
"This may be a bug because inline constants flag in the cache never changes after SRB creation, "
496497
"while m_BindInfo.InlineConstantsSRBMask is initialized when SRB is committed.");
497-
if ((m_BindInfo.StaleSRBMask & SignBit) != 0 || !InlineConstantsIntact)
498+
// Always update inline constant buffers if the SRB is stale
499+
if (SRBStale || !InlineConstantsIntact)
498500
{
499501
if (PipelineResourceSignatureD3D11Impl* pSign = m_pPipelineState->GetResourceSignature(SignIdx))
500502
{
@@ -715,7 +717,7 @@ void DeviceContextD3D11Impl::PrepareForDraw(DRAW_FLAGS Flags)
715717

716718
const bool DynamicBuffersIntact = (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) != 0;
717719
const bool InlineConstantsIntact = (Flags & DRAW_FLAG_INLINE_CONSTANTS_INTACT) != 0;
718-
if (Uint32 BindSRBMask = m_BindInfo.GetCommitMask(Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT, Flags & DRAW_FLAG_INLINE_CONSTANTS_INTACT))
720+
if (Uint32 BindSRBMask = m_BindInfo.GetCommitMask(DynamicBuffersIntact, InlineConstantsIntact))
719721
{
720722
BindShaderResources(BindSRBMask, DynamicBuffersIntact, InlineConstantsIntact);
721723
}

Graphics/GraphicsEngineD3D11/src/PipelineResourceSignatureD3D11Impl.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ void PipelineResourceSignatureD3D11Impl::CreateLayout(const bool IsSerialized)
212212

213213
VERIFY((ResDesc.Flags & PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS) == 0 || ResDesc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER,
214214
"Only constant buffers can have inline constants flag");
215-
// For inline constants, ArraySize holds the number of 4-byte constants
215+
// For inline constants, ArraySize holds the number of 4-byte constants, while
216+
// the resource occupies a single constant buffer slot.
216217
const Uint32 ArraySize = ResDesc.GetArraySize();
217218
AllocBindPoints(m_ResourceCounters, BindPoints, ResDesc.ShaderStages, ArraySize, Range);
218219
if (ResDesc.VarType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
@@ -246,10 +247,20 @@ void PipelineResourceSignatureD3D11Impl::CreateLayout(const bool IsSerialized)
246247

247248
if (ResDesc.Flags & PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS)
248249
{
250+
// Inline constant buffers are handled mostly like regular constant buffers. The only
251+
// difference is that the buffer is created internally here and is not expected to be bound.
252+
// It is updated by UpdateInlineConstantBuffers() method.
253+
249254
VERIFY(ResDesc.ResourceType == SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, "Only constant buffers can have INLINE_CONSTANTS flag");
250255
InlineConstantBufferAttribsD3D11& InlineCBAttribs{m_InlineConstantBuffers[InlineConstantBufferIdx++]};
251256
InlineCBAttribs.BindPoints = BindPoints;
252257
InlineCBAttribs.NumConstants = ResDesc.ArraySize;
258+
259+
// All SRBs created from this signature will share the same inline constant buffer.
260+
// An alternative design is to have a separate inline constant buffer for each SRB,
261+
// which will allow skipping buffer update if the inline constants are not changed.
262+
// However, this will increase memory consumption as each SRB will have its own copy of the inline CB.
263+
// Besides, inline constants are expected to change frequently, so skipping updates is unlikely.
253264
if (m_pDevice)
254265
{
255266
std::string Name = m_Desc.Name;
@@ -437,7 +448,8 @@ void PipelineResourceSignatureD3D11Impl::UpdateShaderResourceBindingMap(Resource
437448
{
438449
Uint32{BaseBindings[Range][ShaderInd]} + Uint32{ResAttr.BindPoints[ShaderInd]},
439450
0u, // register space is not supported
440-
ResDesc.GetArraySize(), // For inline constants, ArraySize holds the number of 4-byte constants
451+
ResDesc.GetArraySize(), // For inline constants, ArraySize holds the number of 4-byte constants,
452+
// while the resource occupies a single constant buffer slot.
441453
ResDesc.ResourceType,
442454
};
443455
bool IsUnique = ResourceMap.emplace(HashMapStringKey{ResDesc.Name}, BindInfo).second;
@@ -528,7 +540,7 @@ bool PipelineResourceSignatureD3D11Impl::DvpValidateCommittedResource(const D3DS
528540
const PipelineResourceAttribsD3D11& ResAttr = m_pResourceAttribs[ResIndex];
529541
VERIFY(strcmp(ResDesc.Name, D3DAttribs.Name) == 0, "Inconsistent resource names");
530542

531-
VERIFY_EXPR(D3DAttribs.BindCount <= ResDesc.ArraySize);
543+
VERIFY_EXPR(D3DAttribs.BindCount <= ResDesc.GetArraySize());
532544

533545
bool BindingsOK = true;
534546
switch (ShaderResourceTypeToRange(ResDesc.ResourceType))

Graphics/GraphicsEngineD3D11/src/ShaderResourceCacheD3D11.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ void ShaderResourceCacheD3D11::Initialize(const D3D11ShaderResourceCounters&
145145
SHADER_TYPE ActiveStages = InlineCBAttr.BindPoints.GetActiveStages();
146146
const Uint32 ShaderInd0 = ExtractFirstShaderStageIndex(ActiveStages);
147147
const Uint32 Binding0 = InlineCBAttr.BindPoints[ShaderInd0];
148-
const bool IsInRange = Binding0 < GetResourceCount<D3D11_RESOURCE_RANGE_CBV>(ShaderInd0);
148+
// Static resource cache may not contain all inline constant buffers.
149+
// Skip those that are out of range.
150+
const bool IsInRange = Binding0 < GetResourceCount<D3D11_RESOURCE_RANGE_CBV>(ShaderInd0);
149151

150152
#ifdef DILIGENT_DEBUG
151153
while (ActiveStages != SHADER_TYPE_UNKNOWN)
@@ -200,6 +202,7 @@ void ShaderResourceCacheD3D11::Initialize(const D3D11ShaderResourceCounters&
200202
ProcessInlineCBs([&pInlineCBData, this](const InlineConstantBufferAttribsD3D11& InlineCBAttr) {
201203
VERIFY_EXPR(InlineCBAttr.NumConstants > 0);
202204
VERIFY_EXPR(InlineCBAttr.pBuffer != nullptr);
205+
// Use the same buffer and data pointer for all active shader stages.
203206
InitInlineConstantBuffer(InlineCBAttr.BindPoints, InlineCBAttr.pBuffer, InlineCBAttr.NumConstants, pInlineCBData);
204207
pInlineCBData += InlineCBAttr.NumConstants;
205208
});
@@ -233,6 +236,7 @@ void ShaderResourceCacheD3D11::InitInlineConstantBuffer(const D3D11ResourceBindP
233236
Uint32 NumConstants,
234237
void* pInlineConstantData)
235238
{
239+
// Use the same buffer and data pointer for all shader stages.
236240
VERIFY_EXPR(pBuffer);
237241
VERIFY_EXPR(pInlineConstantData);
238242
ID3D11Buffer* pd3d11Buffer = pBuffer->GetD3D11Buffer();

0 commit comments

Comments
 (0)