Skip to content

Commit 36006c1

Browse files
D3D12: commit root constants; add inline constants test (#672)
1 parent 98c8cda commit 36006c1

File tree

4 files changed

+279
-0
lines changed

4 files changed

+279
-0
lines changed

Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,22 @@ void DeviceContextD3D12Impl::CommitRootTablesAndViews(RootTableInfo& RootInfo, U
418418
"There are no dynamic root buffers in the cache, but the bit in DynamicSRBMask is set. This may indicate that resources "
419419
"in the cache have changed, but the SRB has not been committed before the draw/dispatch command.");
420420
}
421+
422+
if (Uint64 RootConstantsMask = pResourceCache->GetRootConstantsMask())
423+
{
424+
VERIFY((RootInfo.InlineConstantsSRBMask & SignBit) != 0,
425+
"There are root constants in the cache, but the bit in InlineConstantsSRBMask is not set. "
426+
"This may be a bug because root constants mask in the cache never changes after SRB creation, "
427+
"while RootInfo.InlineConstantsSRBMask is initialized when SRB is committed.");
428+
pSignature->CommitRootConstants(CommitAttribs, RootConstantsMask);
429+
}
430+
else
431+
{
432+
VERIFY((RootInfo.InlineConstantsSRBMask & SignBit) == 0,
433+
"There are no root constants in the cache, but the bit in InlineConstantsSRBMask is set. "
434+
"This may be a bug because root constants mask in the cache never changes after SRB creation, "
435+
"while RootInfo.InlineConstantsSRBMask is initialized when SRB is committed.");
436+
}
421437
}
422438

423439
VERIFY_EXPR((CommitSRBMask & RootInfo.ActiveSRBMask) == 0);

Graphics/GraphicsEngineD3D12/src/PipelineResourceSignatureD3D12Impl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,14 @@ bool PipelineResourceSignatureD3D12Impl::DvpValidateCommittedResource(const Devi
830830
for (Uint32 ArrIndex = 0; ArrIndex < D3DAttribs.BindCount; ++ArrIndex)
831831
{
832832
const ShaderResourceCacheD3D12::Resource& CachedRes = RootTable.GetResource(OffsetFromTableStart + ArrIndex);
833+
if (ResDesc.Flags & PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS)
834+
{
835+
VERIFY(CachedRes.IsNull(), "Inline constants should not have any resource bound to them.");
836+
VERIFY(CachedRes.CPUDescriptorHandle.ptr != 0, "Inline constant resource must have valid CPU descriptor handle.");
837+
// Inline constants are not actual resources
838+
continue;
839+
}
840+
833841
if (CachedRes.IsNull())
834842
{
835843
LOG_ERROR_MESSAGE("No resource is bound to variable '", GetShaderResourcePrintName(D3DAttribs.Name, D3DAttribs.BindCount, ArrIndex),

Graphics/GraphicsEngineD3D12/src/ShaderResourceCacheD3D12.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ void ShaderResourceCacheD3D12::Initialize(IMemoryAllocator& Me
178178
// Store the number of constant values in BufferRangeSize
179179
Res.BufferRangeSize = InlineConstInfo.NumValues;
180180
pCurrInlineConstValueStorage += InlineConstInfo.NumValues;
181+
182+
m_RootConstantsMask |= (Uint64{1} << Uint64{InlineConstInfo.RootIndex});
181183
}
182184
VERIFY_EXPR(pCurrInlineConstValueStorage == GetInlineConstantStorage() + TotalInlineConstantValues);
183185
}
@@ -284,6 +286,8 @@ void ShaderResourceCacheD3D12::Initialize(IMemoryAllocator& MemAllocator,
284286
};
285287
++ResIdx;
286288

289+
m_RootConstantsMask |= (Uint64{1} << Uint64{RootConsts.RootIndex});
290+
287291
#ifdef DILIGENT_DEBUG
288292
RootTableInitFlags[RootConsts.RootIndex] = true;
289293
#endif
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
/*
2+
* Copyright 2025 Diligent Graphics LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* In no event and under no legal theory, whether in tort (including negligence),
17+
* contract, or otherwise, unless required by applicable law (such as deliberate
18+
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
19+
* liable for any damages, including any direct, indirect, special, incidental,
20+
* or consequential damages of any character arising as a result of this License or
21+
* out of the use or inability to use the software (including but not limited to damages
22+
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
23+
* all other commercial damages or losses), even if such Contributor has been advised
24+
* of the possibility of such damages.
25+
*/
26+
27+
#include "GPUTestingEnvironment.hpp"
28+
29+
#include "gtest/gtest.h"
30+
31+
#include "GraphicsTypesX.hpp"
32+
#include "FastRand.hpp"
33+
34+
35+
namespace Diligent
36+
{
37+
namespace Testing
38+
{
39+
void RenderDrawCommandReference(ISwapChain* pSwapChain, const float* pClearColor = nullptr);
40+
}
41+
} // namespace Diligent
42+
43+
44+
using namespace Diligent;
45+
using namespace Diligent::Testing;
46+
47+
#include "InlineShaders/DrawCommandTestHLSL.h"
48+
49+
50+
namespace
51+
{
52+
53+
namespace HLSL
54+
{
55+
56+
const std::string InlineConstantsTest_VS{
57+
R"(
58+
cbuffer cbInlinePositions
59+
{
60+
float4 g_Positions[6];
61+
}
62+
63+
cbuffer cbInlineColors
64+
{
65+
float4 g_Colors[3];
66+
}
67+
68+
struct PSInput
69+
{
70+
float4 Pos : SV_POSITION;
71+
float3 Color : COLOR;
72+
};
73+
74+
void main(uint VertexId : SV_VertexId,
75+
out PSInput PSIn)
76+
{
77+
PSIn.Pos = g_Positions[VertexId];
78+
PSIn.Color = g_Colors[VertexId % 3].rgb;
79+
}
80+
)"};
81+
82+
}
83+
84+
float4 g_Positions[] = {
85+
float4{-1.0f, -0.5f, 0.f, 1.f},
86+
float4{-0.5f, +0.5f, 0.f, 1.f},
87+
float4{0.0f, -0.5f, 0.f, 1.f},
88+
89+
float4{+0.0f, -0.5f, 0.f, 1.f},
90+
float4{+0.5f, +0.5f, 0.f, 1.f},
91+
float4{+1.0f, -0.5f, 0.f, 1.f},
92+
};
93+
94+
float4 g_Colors[] = {
95+
float4{1.f, 0.f, 0.f, 1.f},
96+
float4{0.f, 1.f, 0.f, 1.f},
97+
float4{0.f, 0.f, 1.f, 1.f},
98+
};
99+
100+
class InlineConstants : public ::testing::Test
101+
{
102+
protected:
103+
static void SetUpTestSuite()
104+
{
105+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
106+
IRenderDevice* pDevice = pEnv->GetDevice();
107+
108+
ShaderCreateInfo ShaderCI;
109+
ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
110+
ShaderCI.ShaderCompiler = pEnv->GetDefaultCompiler(ShaderCI.SourceLanguage);
111+
112+
{
113+
ShaderCI.Desc = {"Inline constants test", SHADER_TYPE_VERTEX, true};
114+
ShaderCI.EntryPoint = "main";
115+
ShaderCI.Source = HLSL::InlineConstantsTest_VS.c_str();
116+
pDevice->CreateShader(ShaderCI, &sm_Res.pVS);
117+
ASSERT_NE(sm_Res.pVS, nullptr);
118+
}
119+
120+
{
121+
ShaderCI.Desc = {"Inline constants test", SHADER_TYPE_PIXEL, true};
122+
ShaderCI.EntryPoint = "main";
123+
ShaderCI.Source = HLSL::DrawTest_PS.c_str();
124+
pDevice->CreateShader(ShaderCI, &sm_Res.pPS);
125+
ASSERT_NE(sm_Res.pPS, nullptr);
126+
}
127+
}
128+
129+
static void TearDownTestSuite()
130+
{
131+
sm_Res = {};
132+
133+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
134+
pEnv->Reset();
135+
}
136+
137+
static void Present()
138+
{
139+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
140+
ISwapChain* pSwapChain = pEnv->GetSwapChain();
141+
IDeviceContext* pContext = pEnv->GetDeviceContext();
142+
143+
pSwapChain->Present();
144+
145+
pContext->Flush();
146+
pContext->InvalidateState();
147+
}
148+
149+
struct Resources
150+
{
151+
RefCntAutoPtr<IShader> pVS;
152+
RefCntAutoPtr<IShader> pPS;
153+
};
154+
static Resources sm_Res;
155+
156+
static FastRandFloat sm_Rnd;
157+
};
158+
159+
InlineConstants::Resources InlineConstants::sm_Res;
160+
FastRandFloat InlineConstants::sm_Rnd{0, 0.f, 1.f};
161+
162+
163+
TEST_F(InlineConstants, ResourceSignature)
164+
{
165+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
166+
IRenderDevice* pDevice = pEnv->GetDevice();
167+
IDeviceContext* pContext = pEnv->GetDeviceContext();
168+
ISwapChain* pSwapChain = pEnv->GetSwapChain();
169+
if (pDevice->GetDeviceInfo().Type != RENDER_DEVICE_TYPE_D3D12)
170+
{
171+
GTEST_SKIP();
172+
}
173+
174+
for (Uint32 pos_type = 0; pos_type < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++pos_type)
175+
{
176+
for (Uint32 col_type = 0; col_type < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++col_type)
177+
{
178+
const float ClearColor[] = {sm_Rnd(), sm_Rnd(), sm_Rnd(), sm_Rnd()};
179+
RenderDrawCommandReference(pSwapChain, ClearColor);
180+
181+
SHADER_RESOURCE_VARIABLE_TYPE PosType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(pos_type);
182+
SHADER_RESOURCE_VARIABLE_TYPE ColType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(col_type);
183+
184+
PipelineResourceSignatureDescX SignDesc;
185+
SignDesc
186+
.AddResource(SHADER_TYPE_VERTEX, "cbInlinePositions", Uint32{sizeof(g_Positions) / 4}, SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, PosType, PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS)
187+
.AddResource(SHADER_TYPE_VERTEX, "cbInlineColors", Uint32{sizeof(g_Colors) / 4}, SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, ColType, PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS);
188+
RefCntAutoPtr<IPipelineResourceSignature> pSign;
189+
pDevice->CreatePipelineResourceSignature(SignDesc, &pSign);
190+
ASSERT_TRUE(pSign);
191+
192+
GraphicsPipelineStateCreateInfoX PsoCI{"Inline constants test"};
193+
PsoCI
194+
.AddRenderTarget(pSwapChain->GetDesc().ColorBufferFormat)
195+
.SetPrimitiveTopology(PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
196+
.AddShader(sm_Res.pVS)
197+
.AddShader(sm_Res.pPS)
198+
.AddSignature(pSign);
199+
PsoCI.GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
200+
201+
RefCntAutoPtr<IPipelineState> pPSO;
202+
pDevice->CreateGraphicsPipelineState(PsoCI, &pPSO);
203+
ASSERT_TRUE(pPSO);
204+
205+
if (PosType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
206+
{
207+
IShaderResourceVariable* pVar = pSign->GetStaticVariableByName(SHADER_TYPE_VERTEX, "cbInlinePositions");
208+
ASSERT_TRUE(pVar);
209+
pVar->SetInlineConstants(g_Positions, 0, sizeof(g_Positions) / 4);
210+
}
211+
212+
if (ColType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
213+
{
214+
IShaderResourceVariable* pVar = pSign->GetStaticVariableByName(SHADER_TYPE_VERTEX, "cbInlineColors");
215+
ASSERT_TRUE(pVar);
216+
pVar->SetInlineConstants(g_Colors, 0, sizeof(g_Colors) / 4);
217+
}
218+
219+
RefCntAutoPtr<IShaderResourceBinding> pSRB;
220+
pSign->CreateShaderResourceBinding(&pSRB, true);
221+
ASSERT_TRUE(pSRB);
222+
223+
if (PosType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
224+
{
225+
IShaderResourceVariable* pVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbInlinePositions");
226+
ASSERT_TRUE(pVar);
227+
pVar->SetInlineConstants(g_Positions, 0, sizeof(g_Positions) / 4);
228+
}
229+
230+
if (ColType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
231+
{
232+
IShaderResourceVariable* pVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbInlineColors");
233+
ASSERT_TRUE(pVar);
234+
pVar->SetInlineConstants(g_Colors, 0, sizeof(g_Colors) / 4);
235+
}
236+
237+
ITextureView* pRTVs[] = {pSwapChain->GetCurrentBackBufferRTV()};
238+
pContext->SetRenderTargets(1, pRTVs, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
239+
pContext->ClearRenderTarget(pRTVs[0], ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
240+
241+
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
242+
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_VERIFY);
243+
pContext->SetPipelineState(pPSO);
244+
pContext->Draw({6, DRAW_FLAG_VERIFY_ALL});
245+
246+
Present();
247+
}
248+
}
249+
}
250+
251+
} // namespace

0 commit comments

Comments
 (0)