Skip to content

Commit 3cfb920

Browse files
committed
1. extend the test a bit - test all variable types by specifying
PsoCI.PSODesc.ResourceLayout.DefaultVariableType 2. add a test similar to InlineConstants.ResourceLayout, but for compute shaders
1 parent 70b0382 commit 3cfb920

1 file changed

Lines changed: 247 additions & 73 deletions

File tree

Tests/DiligentCoreAPITest/src/InlineConstantsTest.cpp

Lines changed: 247 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ const std::string VulkanPushConstants_VS{
105105
struct PushConstants_t
106106
{
107107
float4 g_Positions[6];
108-
float4 g_Colors[4];
108+
float4 g_Colors[3];
109109
};
110110
111111
[[vk::push_constant]] ConstantBuffer<PushConstants_t> PushConstants;
@@ -128,7 +128,7 @@ const std::string VulkanPushConstants_PS{
128128
struct PushConstants_t
129129
{
130130
float4 g_Positions[6];
131-
float4 g_Colors[4];
131+
float4 g_Colors[3];
132132
};
133133
134134
[[vk::push_constant]] ConstantBuffer<PushConstants_t> PushConstants;
@@ -141,9 +141,32 @@ struct PSInput
141141
142142
float4 main(in PSInput PSIn) : SV_Target
143143
{
144-
// Use push constants from PS to apply alpha modulation
144+
// Use push constants from PS to apply color modulation
145145
// This ensures both VS and PS access the same PushConstants
146-
return PSIn.Color * PushConstants.g_Colors[3];
146+
return float4(
147+
PSIn.Color.r * PushConstants.g_Colors[0].r,
148+
PSIn.Color.g * PushConstants.g_Colors[1].g,
149+
PSIn.Color.b * PushConstants.g_Colors[2].b,
150+
PSIn.Color.a);
151+
}
152+
)"};
153+
154+
const std::string InlineConstantsTest_CS{
155+
R"(
156+
cbuffer cbInlineData
157+
{
158+
float4 g_Data[4];
159+
}
160+
161+
RWTexture2D<float4> g_Output;
162+
163+
[numthreads(16, 16, 1)]
164+
void main(uint3 DTid : SV_DispatchThreadID)
165+
{
166+
// Use inline constants to write to output texture
167+
// Index into g_Data based on position to verify all constants are correctly set
168+
uint idx = (DTid.x / 64 + DTid.y / 64 * 2) % 4;
169+
g_Output[DTid.xy] = g_Data[idx];
147170
}
148171
)"};
149172

@@ -165,8 +188,18 @@ float4 g_Colors[] = {
165188
float4{0.f, 0.f, 1.f, 1.f},
166189
};
167190

168-
constexpr Uint32 kNumPosConstants = sizeof(g_Positions) / 4;
169-
constexpr Uint32 kNumColConstants = sizeof(g_Colors) / 4;
191+
float4 g_ColorPSFactor = float4{1.f, 1.f, 1.f, 1.f};
192+
193+
float4 g_ComputeData[] = {
194+
float4{1.f, 0.f, 0.f, 1.f}, // Red
195+
float4{0.f, 1.f, 0.f, 1.f}, // Green
196+
float4{0.f, 0.f, 1.f, 1.f}, // Blue
197+
float4{1.f, 1.f, 0.f, 1.f}, // Yellow
198+
};
199+
200+
constexpr Uint32 kNumPosConstants = sizeof(g_Positions) / 4;
201+
constexpr Uint32 kNumColConstants = sizeof(g_Colors) / 4;
202+
constexpr Uint32 kNumComputeConstants = sizeof(g_ComputeData) / 4;
170203

171204
class InlineConstants : public ::testing::Test
172205
{
@@ -360,6 +393,139 @@ TEST_F(InlineConstants, ResourceLayout)
360393
}
361394

362395

396+
TEST_F(InlineConstants, ComputeResourceLayout)
397+
{
398+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
399+
IRenderDevice* pDevice = pEnv->GetDevice();
400+
IDeviceContext* pContext = pEnv->GetDeviceContext();
401+
ISwapChain* pSwapChain = pEnv->GetSwapChain();
402+
403+
// Check compute shader support
404+
if (!pDevice->GetDeviceInfo().Features.ComputeShaders)
405+
{
406+
GTEST_SKIP() << "Compute shaders are not supported by this device";
407+
}
408+
409+
const SwapChainDesc& SCDesc = pSwapChain->GetDesc();
410+
411+
// Create compute shader
412+
RefCntAutoPtr<IShader> pCS;
413+
{
414+
ShaderCreateInfo ShaderCI;
415+
ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_HLSL;
416+
ShaderCI.ShaderCompiler = pEnv->GetDefaultCompiler(ShaderCI.SourceLanguage);
417+
ShaderCI.Desc = {"Inline constants compute test", SHADER_TYPE_COMPUTE, true};
418+
ShaderCI.EntryPoint = "main";
419+
ShaderCI.Source = HLSL::InlineConstantsTest_CS.c_str();
420+
pDevice->CreateShader(ShaderCI, &pCS);
421+
ASSERT_NE(pCS, nullptr);
422+
}
423+
424+
// Create output UAV texture
425+
RefCntAutoPtr<ITexture> pOutputTex;
426+
{
427+
TextureDesc TexDesc;
428+
TexDesc.Name = "Inline constants compute output";
429+
TexDesc.Type = RESOURCE_DIM_TEX_2D;
430+
TexDesc.Width = SCDesc.Width;
431+
TexDesc.Height = SCDesc.Height;
432+
TexDesc.Format = TEX_FORMAT_RGBA8_UNORM;
433+
TexDesc.BindFlags = BIND_UNORDERED_ACCESS | BIND_SHADER_RESOURCE;
434+
pDevice->CreateTexture(TexDesc, nullptr, &pOutputTex);
435+
ASSERT_NE(pOutputTex, nullptr);
436+
}
437+
ITextureView* pOutputUAV = pOutputTex->GetDefaultView(TEXTURE_VIEW_UNORDERED_ACCESS);
438+
ASSERT_NE(pOutputUAV, nullptr);
439+
440+
for (Uint32 resType = 0; resType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++resType)
441+
{
442+
SHADER_RESOURCE_VARIABLE_TYPE ResType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(resType);
443+
444+
// Create PSO with inline constants
445+
ComputePipelineStateCreateInfoX PsoCI{"Inline constants compute test"};
446+
447+
PipelineResourceLayoutDescX ResLayoutDesc;
448+
ResLayoutDesc.AddVariable(SHADER_TYPE_COMPUTE, "cbInlineData", ResType, SHADER_VARIABLE_FLAG_INLINE_CONSTANTS);
449+
450+
PsoCI
451+
.AddShader(pCS)
452+
.SetResourceLayout(ResLayoutDesc)
453+
.SetSRBAllocationGranularity(4);
454+
455+
RefCntAutoPtr<IPipelineState> pPSO;
456+
pDevice->CreateComputePipelineState(PsoCI, &pPSO);
457+
ASSERT_TRUE(pPSO);
458+
459+
// Set static inline constants on PSO before creating SRB
460+
if (ResType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
461+
{
462+
IShaderResourceVariable* pVar = pPSO->GetStaticVariableByName(SHADER_TYPE_COMPUTE, "cbInlineData");
463+
ASSERT_TRUE(pVar);
464+
pVar->SetInlineConstants(g_ComputeData, 0, kNumComputeConstants);
465+
}
466+
467+
// Set static UAV on PSO
468+
{
469+
IShaderResourceVariable* pVar = pPSO->GetStaticVariableByName(SHADER_TYPE_COMPUTE, "g_Output");
470+
if (pVar != nullptr)
471+
{
472+
pVar->Set(pOutputUAV);
473+
}
474+
}
475+
476+
// Create SRB
477+
RefCntAutoPtr<IShaderResourceBinding> pSRB;
478+
pPSO->CreateShaderResourceBinding(&pSRB, true);
479+
ASSERT_TRUE(pSRB);
480+
481+
// Set UAV on SRB if not static
482+
{
483+
IShaderResourceVariable* pVar = pSRB->GetVariableByName(SHADER_TYPE_COMPUTE, "g_Output");
484+
if (pVar != nullptr)
485+
{
486+
pVar->Set(pOutputUAV);
487+
}
488+
}
489+
490+
// Set mutable/dynamic inline constants on SRB
491+
IShaderResourceVariable* pDataVar = nullptr;
492+
if (ResType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
493+
{
494+
pDataVar = pSRB->GetVariableByName(SHADER_TYPE_COMPUTE, "cbInlineData");
495+
ASSERT_TRUE(pDataVar);
496+
}
497+
498+
pContext->SetPipelineState(pPSO);
499+
500+
if (pDataVar != nullptr)
501+
{
502+
// Set first half of constants before committing SRB
503+
pDataVar->SetInlineConstants(g_ComputeData, 0, kNumComputeConstants / 2);
504+
}
505+
506+
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
507+
508+
if (pDataVar != nullptr)
509+
{
510+
// Set second half of constants after committing SRB
511+
pDataVar->SetInlineConstants(g_ComputeData[0].Data() + kNumComputeConstants / 2, kNumComputeConstants / 2, kNumComputeConstants / 2);
512+
}
513+
514+
// Dispatch
515+
DispatchComputeAttribs DispatchAttribs;
516+
DispatchAttribs.ThreadGroupCountX = (SCDesc.Width + 15) / 16;
517+
DispatchAttribs.ThreadGroupCountY = (SCDesc.Height + 15) / 16;
518+
pContext->DispatchCompute(DispatchAttribs);
519+
520+
pContext->Flush();
521+
pContext->InvalidateState();
522+
523+
std::cout << TestingEnvironment::GetCurrentTestStatusString() << ' '
524+
<< " ResType " << GetShaderVariableTypeLiteralName(ResType) << std::endl;
525+
}
526+
}
527+
528+
363529
void InlineConstants::TestSignatures(Uint32 NumSignatures)
364530
{
365531
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
@@ -855,95 +1021,103 @@ TEST_F(InlineConstants, VulkanPushConstantsBlock)
8551021
ASSERT_NE(pPS, nullptr);
8561022
}
8571023

858-
// Create pipeline without explicit resource layout
859-
// Let the system automatically extract push constants from shaders
860-
GraphicsPipelineStateCreateInfoX PsoCI{"Vulkan Push Constants Test"};
861-
PsoCI
862-
.AddRenderTarget(pSwapChain->GetDesc().ColorBufferFormat)
863-
.SetPrimitiveTopology(PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
864-
.AddShader(pVS)
865-
.AddShader(pPS);
866-
PsoCI.GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
1024+
for (Uint32 resType = 0; resType < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++resType)
1025+
{
1026+
SHADER_RESOURCE_VARIABLE_TYPE ResType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(resType);
8671027

868-
RefCntAutoPtr<IPipelineState> pPSO;
869-
pDevice->CreateGraphicsPipelineState(PsoCI, &pPSO);
870-
ASSERT_TRUE(pPSO);
1028+
// Create pipeline without explicit resource layout
1029+
// Let the system automatically extract push constants from shaders
1030+
GraphicsPipelineStateCreateInfoX PsoCI{"Vulkan Push Constants Test"};
8711031

872-
// Verify that resource signature was created with correct ArraySize
873-
ASSERT_EQ(pPSO->GetResourceSignatureCount(), 1u);
874-
IPipelineResourceSignature* pSign = pPSO->GetResourceSignature(0);
875-
ASSERT_TRUE(pSign);
1032+
PsoCI.PSODesc.ResourceLayout.DefaultVariableType = ResType;
8761033

877-
const PipelineResourceSignatureDesc& SignDesc = pSign->GetDesc();
1034+
PsoCI
1035+
.AddRenderTarget(pSwapChain->GetDesc().ColorBufferFormat)
1036+
.SetPrimitiveTopology(PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
1037+
.AddShader(pVS)
1038+
.AddShader(pPS);
1039+
PsoCI.GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
8781040

879-
// Find VS and PS push constants in the resource signature
880-
const PipelineResourceDesc* PushConstantsDesc = nullptr;
1041+
RefCntAutoPtr<IPipelineState> pPSO;
1042+
pDevice->CreateGraphicsPipelineState(PsoCI, &pPSO);
1043+
ASSERT_TRUE(pPSO);
8811044

882-
for (Uint32 i = 0; i < SignDesc.NumResources; ++i)
883-
{
884-
const auto& Res = SignDesc.Resources[i];
885-
if (Res.ShaderStages == SHADER_TYPE_VS_PS &&
886-
strcmp(Res.Name, "PushConstants") == 0)
1045+
// Verify that resource signature was created with correct ArraySize
1046+
ASSERT_EQ(pPSO->GetResourceSignatureCount(), 1u);
1047+
IPipelineResourceSignature* pSign = pPSO->GetResourceSignature(0);
1048+
ASSERT_TRUE(pSign);
1049+
1050+
const PipelineResourceSignatureDesc& SignDesc = pSign->GetDesc();
1051+
1052+
// Find VS and PS push constants in the resource signature
1053+
const PipelineResourceDesc* PushConstantsDesc = nullptr;
1054+
1055+
for (Uint32 i = 0; i < SignDesc.NumResources; ++i)
8871056
{
888-
PushConstantsDesc = &Res;
1057+
const auto& Res = SignDesc.Resources[i];
1058+
if (strcmp(Res.Name, "PushConstants") == 0)
1059+
{
1060+
PushConstantsDesc = &Res;
1061+
}
8891062
}
890-
}
8911063

892-
float4 PushConstants_Positions[] = {
893-
float4{-1.0f, -0.5f, 0.f, 1.f},
894-
float4{-0.5f, +0.5f, 0.f, 1.f},
895-
float4{0.0f, -0.5f, 0.f, 1.f},
896-
float4{+0.0f, -0.5f, 0.f, 1.f},
897-
float4{+0.5f, +0.5f, 0.f, 1.f},
898-
float4{+1.0f, -0.5f, 0.f, 1.f},
899-
};
1064+
ASSERT_TRUE(PushConstantsDesc != nullptr) << "PushConstants not found in resource signature";
9001065

901-
float4 PushConstants_Colors[] = {
902-
float4{1.f, 0.f, 0.f, 1.f},
903-
float4{0.f, 1.f, 0.f, 1.f},
904-
float4{0.f, 0.f, 1.f, 1.f},
905-
float4{1.f, 1.f, 1.f, 1.f},
906-
};
1066+
// Verify inline constants flag
1067+
EXPECT_EQ(PushConstantsDesc->Flags, PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS);
9071068

908-
ASSERT_TRUE(PushConstantsDesc != nullptr) << "PushConstants not found in resource signature";
1069+
// Verify ArraySize
1070+
EXPECT_EQ(PushConstantsDesc->ArraySize, kNumPosConstants + kNumColConstants);
9091071

910-
// Verify inline constants flag
911-
EXPECT_EQ(PushConstantsDesc->Flags, PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS);
1072+
// Verify ShaderStages
1073+
EXPECT_EQ(PushConstantsDesc->ShaderStages, SHADER_TYPE_VS_PS);
9121074

913-
// Verify ArraySize matches
914-
EXPECT_EQ(PushConstantsDesc->ArraySize, (sizeof(PushConstants_Positions) + sizeof(PushConstants_Colors)) / (sizeof(Uint32)))
915-
<< "VS push constants should have 24 + 12 = 36 constants (6 float4 for PushConstants.g_Positions, 4 float4 for PushConstants.g_Colors)";
1075+
// Now test runtime usage
1076+
const float ClearColor[] = {sm_Rnd(), sm_Rnd(), sm_Rnd(), sm_Rnd()};
1077+
RenderDrawCommandReference(pSwapChain, ClearColor);
9161078

917-
// Now test runtime usage
918-
const float ClearColor[] = {sm_Rnd(), sm_Rnd(), sm_Rnd(), sm_Rnd()};
919-
RenderDrawCommandReference(pSwapChain, ClearColor);
1079+
ITextureView* pRTVs[] = {pSwapChain->GetCurrentBackBufferRTV()};
1080+
pContext->SetRenderTargets(1, pRTVs, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
1081+
pContext->ClearRenderTarget(pRTVs[0], ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
9201082

921-
ITextureView* pRTVs[] = {pSwapChain->GetCurrentBackBufferRTV()};
922-
pContext->SetRenderTargets(1, pRTVs, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
923-
pContext->ClearRenderTarget(pRTVs[0], ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
1083+
//They should all goes with resource[0] ("PushConstants") under the hood:
1084+
if (ResType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
1085+
{
1086+
IShaderResourceVariable* pVSVar = pPSO->GetStaticVariableByName(SHADER_TYPE_VERTEX, "PushConstants");
1087+
ASSERT_TRUE(pVSVar);
9241088

925-
//They should all goes with resource[0] ("PushConstants") under the hood:
1089+
pVSVar->SetInlineConstants(g_Positions, 0, kNumPosConstants);
9261090

927-
IShaderResourceVariable* pVSVar = pPSO->GetStaticVariableByName(SHADER_TYPE_VERTEX, "PushConstants");
928-
ASSERT_TRUE(pVSVar);
1091+
IShaderResourceVariable* pPSVar = pPSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "PushConstants");
1092+
ASSERT_TRUE(pPSVar);
9291093

930-
pVSVar->SetInlineConstants(PushConstants_Positions, 0, sizeof(PushConstants_Positions) / (sizeof(Uint32)));
1094+
pPSVar->SetInlineConstants(g_Colors, kNumPosConstants, kNumColConstants);
1095+
}
9311096

932-
IShaderResourceVariable* pPSVar = pPSO->GetStaticVariableByName(SHADER_TYPE_PIXEL, "PushConstants");
933-
ASSERT_TRUE(pPSVar);
1097+
RefCntAutoPtr<IShaderResourceBinding> pSRB;
1098+
pPSO->CreateShaderResourceBinding(&pSRB, true);
1099+
ASSERT_TRUE(pSRB);
9341100

935-
pPSVar->SetInlineConstants(PushConstants_Colors, sizeof(PushConstants_Positions) / (sizeof(Uint32)), sizeof(PushConstants_Colors) / (sizeof(Uint32)));
1101+
if (ResType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
1102+
{
1103+
IShaderResourceVariable* pVSVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "PushConstants");
1104+
ASSERT_TRUE(pVSVar);
9361105

937-
RefCntAutoPtr<IShaderResourceBinding> pSRB;
938-
pPSO->CreateShaderResourceBinding(&pSRB, true);
939-
ASSERT_TRUE(pSRB);
1106+
pVSVar->SetInlineConstants(g_Positions, 0, kNumPosConstants);
9401107

941-
// Render
942-
pContext->SetPipelineState(pPSO);
943-
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
944-
pContext->Draw({6, DRAW_FLAG_VERIFY_ALL});
1108+
IShaderResourceVariable* pPSVar = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "PushConstants");
1109+
ASSERT_TRUE(pPSVar);
9451110

946-
Present();
1111+
pPSVar->SetInlineConstants(g_Colors, kNumPosConstants, kNumColConstants);
1112+
}
1113+
1114+
// Render
1115+
pContext->SetPipelineState(pPSO);
1116+
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
1117+
pContext->Draw({6, DRAW_FLAG_VERIFY_ALL});
1118+
1119+
Present();
1120+
}
9471121
}
9481122

9491123
} // namespace

0 commit comments

Comments
 (0)