@@ -105,7 +105,7 @@ const std::string VulkanPushConstants_VS{
105105struct 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{
128128struct 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
142142float4 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
171204class 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+
363529void 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