Skip to content

Commit f541575

Browse files
committed
Add InlineConstants CrossSignatureSRB test.
1 parent 08d88fd commit f541575

1 file changed

Lines changed: 174 additions & 0 deletions

File tree

Tests/DiligentCoreAPITest/src/InlineConstantsTest.cpp

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,180 @@ TEST_F(InlineConstants, TwoResourceSignatures)
839839
TestSignatures(2);
840840
}
841841

842+
// Test for "Inline Constants Cross-Signature Commit Inconsistency" fix.
843+
//
844+
// This test verifies that inline constants work correctly when an SRB created
845+
// from one signature is used with a PSO created from a different but compatible
846+
// signature instance.
847+
//
848+
// Bug scenario:
849+
// 1. PSO is created with Signature A
850+
// 2. SRB is created from Signature B (compatible but different instance)
851+
// 3. Inline constants are set through SRB
852+
// 4. BindResources() binds buffers from SRB cache (pointing to Signature B's buffers)
853+
// 5. BUG (fixed): UpdateInlineConstantBuffers() was updating Signature A's buffers
854+
// instead of the buffers from SRB cache
855+
//
856+
// The fix ensures that UpdateInlineConstantBuffers() updates the buffer from
857+
// SRB cache - the same buffer that was bound during BindResources().
858+
//
859+
// In Vulkan, only the first inline constant uses push constants (always works).
860+
// The second inline constant uses buffer-emulated path where this bug manifested.
861+
// Therefore, this test uses TWO inline constant buffers to ensure we test both paths.
862+
TEST_F(InlineConstants, CrossSignatureSRB)
863+
{
864+
GPUTestingEnvironment* pEnv = GPUTestingEnvironment::GetInstance();
865+
IRenderDevice* pDevice = pEnv->GetDevice();
866+
IDeviceContext* pContext = pEnv->GetDeviceContext();
867+
ISwapChain* pSwapChain = pEnv->GetSwapChain();
868+
869+
// Test all variable types to ensure complete coverage
870+
for (Uint32 pos_type = 0; pos_type < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++pos_type)
871+
{
872+
for (Uint32 col_type = 0; col_type < SHADER_RESOURCE_VARIABLE_TYPE_NUM_TYPES; ++col_type)
873+
{
874+
const float ClearColor[] = {sm_Rnd(), sm_Rnd(), sm_Rnd(), sm_Rnd()};
875+
RenderDrawCommandReference(pSwapChain, ClearColor);
876+
877+
SHADER_RESOURCE_VARIABLE_TYPE PosType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(pos_type);
878+
SHADER_RESOURCE_VARIABLE_TYPE ColType = static_cast<SHADER_RESOURCE_VARIABLE_TYPE>(col_type);
879+
880+
// Create TWO IDENTICAL but SEPARATE signature instances
881+
// This is the key to reproducing the cross-signature issue:
882+
// - pSign1 and pSign2 are compatible (same resources)
883+
// - But they are different instances with separate internal buffers
884+
RefCntAutoPtr<IPipelineResourceSignature> pSign1, pSign2;
885+
886+
PipelineResourceSignatureDescX SignDesc{"Cross-Signature Test"};
887+
SignDesc
888+
// First inline constant (Vulkan: push constants path)
889+
.AddResource(SHADER_TYPE_VERTEX, "cbInlinePositions", kNumPosConstants,
890+
SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, PosType,
891+
PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS)
892+
// Second inline constant (Vulkan: buffer-emulated path - where the bug was)
893+
.AddResource(SHADER_TYPE_VS_PS, "cbInlineColors", kNumColConstants,
894+
SHADER_RESOURCE_TYPE_CONSTANT_BUFFER, ColType,
895+
PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS);
896+
SignDesc.SetSRBAllocationGranularity(4);
897+
898+
// Create first signature instance
899+
pDevice->CreatePipelineResourceSignature(SignDesc, &pSign1);
900+
ASSERT_TRUE(pSign1);
901+
902+
// Create second signature instance with identical descriptor
903+
// This creates a separate instance with its own internal buffers
904+
pDevice->CreatePipelineResourceSignature(SignDesc, &pSign2);
905+
ASSERT_TRUE(pSign2);
906+
907+
// IMPORTANT: pSign1 and pSign2 are compatible but have separate buffer allocations
908+
// Using an SRB from pSign2 with a PSO from pSign1 tests the cross-signature path
909+
910+
// Create PSO using signature 1
911+
GraphicsPipelineStateCreateInfoX PsoCI{"Cross-Signature Test"};
912+
PsoCI
913+
.AddRenderTarget(pSwapChain->GetDesc().ColorBufferFormat)
914+
.SetPrimitiveTopology(PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
915+
.AddShader(sm_Res.pVS)
916+
.AddShader(sm_Res.pPS)
917+
.AddSignature(pSign1); // PSO uses signature 1
918+
PsoCI.GraphicsPipeline.DepthStencilDesc.DepthEnable = False;
919+
920+
RefCntAutoPtr<IPipelineState> pPSO;
921+
pDevice->CreateGraphicsPipelineState(PsoCI, &pPSO);
922+
ASSERT_TRUE(pPSO);
923+
924+
// For STATIC variables, set on signature 2 (which will be used for SRB)
925+
if (PosType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
926+
{
927+
IShaderResourceVariable* pVar = pSign2->GetStaticVariableByName(SHADER_TYPE_VERTEX, "cbInlinePositions");
928+
ASSERT_TRUE(pVar);
929+
pVar->SetInlineConstants(g_Positions, 0, kNumPosConstants);
930+
}
931+
932+
if (ColType == SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
933+
{
934+
IShaderResourceVariable* pVar = pSign2->GetStaticVariableByName(SHADER_TYPE_VERTEX, "cbInlineColors");
935+
ASSERT_TRUE(pVar);
936+
pVar->SetInlineConstants(g_Colors, 0, kNumColConstants);
937+
}
938+
939+
// Create SRB from signature 2 (DIFFERENT from PSO's signature!)
940+
// This is the critical part: SRB is from pSign2, PSO is from pSign1
941+
RefCntAutoPtr<IShaderResourceBinding> pSRB;
942+
pSign2->CreateShaderResourceBinding(&pSRB, true);
943+
ASSERT_TRUE(pSRB);
944+
945+
// Verify the SRB is compatible with PSO (they should be, since signatures are identical)
946+
// Note: IsCompatibleWith checks signature compatibility
947+
EXPECT_TRUE(pPSO->IsCompatibleWith(pSign2));
948+
949+
IShaderResourceVariable* pPosVar = nullptr;
950+
IShaderResourceVariable* pColVarVS = nullptr;
951+
IShaderResourceVariable* pColVarPS = nullptr;
952+
953+
if (PosType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
954+
{
955+
pPosVar = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbInlinePositions");
956+
ASSERT_TRUE(pPosVar);
957+
}
958+
959+
if (ColType != SHADER_RESOURCE_VARIABLE_TYPE_STATIC)
960+
{
961+
pColVarVS = pSRB->GetVariableByName(SHADER_TYPE_VERTEX, "cbInlineColors");
962+
ASSERT_TRUE(pColVarVS);
963+
pColVarPS = pSRB->GetVariableByName(SHADER_TYPE_PIXEL, "cbInlineColors");
964+
ASSERT_TRUE(pColVarPS);
965+
}
966+
967+
ITextureView* pRTVs[] = {pSwapChain->GetCurrentBackBufferRTV()};
968+
pContext->SetRenderTargets(1, pRTVs, nullptr, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
969+
pContext->ClearRenderTarget(pRTVs[0], ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
970+
971+
// Set first half of color constants BEFORE CommitShaderResources
972+
if (pColVarVS != nullptr)
973+
{
974+
pColVarVS->SetInlineConstants(g_Colors, 0, kNumColConstants / 2);
975+
}
976+
977+
pContext->SetPipelineState(pPSO);
978+
pContext->CommitShaderResources(pSRB, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
979+
980+
// Set second half of color constants AFTER CommitShaderResources but BEFORE Draw
981+
// This is the specific timing that triggered the original bug:
982+
// - CommitShaderResources binds buffers from SRB cache
983+
// - SetInlineConstants writes to CPU staging
984+
// - Draw triggers UpdateInlineConstantBuffers which must update the CORRECT buffer
985+
if (pColVarPS != nullptr)
986+
{
987+
pColVarPS->SetInlineConstants(g_Colors[0].Data() + kNumColConstants / 2,
988+
kNumColConstants / 2, kNumColConstants / 2);
989+
}
990+
991+
if (pPosVar == nullptr)
992+
{
993+
// Draw both triangles as positions are static
994+
pContext->Draw({6, DRAW_FLAG_VERIFY_ALL});
995+
}
996+
else
997+
{
998+
// Draw first triangle
999+
pPosVar->SetInlineConstants(g_Positions, 0, kNumPosConstants / 2);
1000+
pContext->Draw({3, DRAW_FLAG_VERIFY_ALL});
1001+
1002+
// Draw second triangle - also tests update after CommitShaderResources
1003+
pPosVar->SetInlineConstants(g_Positions[0].Data() + kNumPosConstants / 2, 0, kNumPosConstants / 2);
1004+
pContext->Draw({3, DRAW_FLAG_VERIFY_ALL});
1005+
}
1006+
1007+
Present();
1008+
1009+
std::cout << TestingEnvironment::GetCurrentTestStatusString() << ' '
1010+
<< " Pos " << GetShaderVariableTypeLiteralName(PosType) << ','
1011+
<< " Col " << GetShaderVariableTypeLiteralName(ColType) << std::endl;
1012+
}
1013+
}
1014+
}
1015+
8421016
constexpr Uint32 kCacheContentVersion = 7;
8431017

8441018
RefCntAutoPtr<IRenderStateCache> CreateCache(IRenderDevice* pDevice,

0 commit comments

Comments
 (0)