Skip to content

Commit fbbb566

Browse files
committed
Always promote only the first inline constant to push constants.
1 parent e35714e commit fbbb566

File tree

1 file changed

+64
-63
lines changed

1 file changed

+64
-63
lines changed

Graphics/GraphicsEngineVulkan/src/PipelineStateVkImpl.cpp

Lines changed: 64 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -824,8 +824,41 @@ void PipelineStateVkImpl::RemapOrVerifyShaderResources(
824824
bool PipelineStateVkImpl::InitPushConstantInfoFromSignatures(PushConstantInfoVk& PushConstant,
825825
TShaderStages& ShaderStages) const noexcept(false)
826826
{
827-
// Step 1: Check if any shader already has a push constant declared in SPIR-V
828-
// This happens when the shader source uses layout(push_constant) explicitly
827+
// Vulkan allows only one push constant range per pipeline layout.
828+
// DiligentCore allows multiple inline constant resources, so we promote only the first inline constant
829+
// from resource signatures to push constants. Other inline constants remain uniform buffers.
830+
const PipelineResourceDesc* pResDesc = nullptr;
831+
const char* PushConstantName = nullptr;
832+
Uint32 PushConstantSize = 0;
833+
Uint32 PushConstantSignIdx = INVALID_PUSH_CONSTANT_INDEX;
834+
Uint32 PushConstantResIdx = INVALID_PUSH_CONSTANT_INDEX;
835+
836+
for (Uint32 s = 0; s < m_SignatureCount; ++s)
837+
{
838+
const PipelineResourceSignatureVkImpl* pSignature = m_Signatures[s];
839+
if (pSignature == nullptr)
840+
continue;
841+
842+
for (Uint32 r = 0; r < pSignature->GetTotalResourceCount(); ++r)
843+
{
844+
const PipelineResourceDesc& ResDesc = pSignature->GetResourceDesc(r);
845+
if ((ResDesc.Flags & PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS) == 0)
846+
continue;
847+
848+
// For inline constants, ArraySize contains the number of 32-bit constants.
849+
PushConstantSize = ResDesc.ArraySize * sizeof(Uint32);
850+
PushConstantSignIdx = s;
851+
PushConstantResIdx = r;
852+
PushConstantName = ResDesc.Name;
853+
pResDesc = &ResDesc;
854+
break;
855+
}
856+
857+
if (pResDesc != nullptr)
858+
break;
859+
}
860+
861+
// Validate shader-declared push constants against the selected inline constant (if any).
829862
for (const ShaderStageInfo& Stage : ShaderStages)
830863
{
831864
for (const ShaderVkImpl* pShader : Stage.Shaders)
@@ -834,82 +867,50 @@ bool PipelineStateVkImpl::InitPushConstantInfoFromSignatures(PushConstantInfoVk&
834867
if (!pShaderResources)
835868
continue;
836869

837-
// Check for push constants in shader resources
838870
for (Uint32 pc = 0; pc < pShaderResources->GetNumPushConstants(); ++pc)
839871
{
840872
const SPIRVShaderResourceAttribs& PCAttribs = pShaderResources->GetPushConstant(pc);
841873

842-
// Find matching resource in signatures
843-
for (Uint32 s = 0; s < m_SignatureCount; ++s)
874+
if (pResDesc == nullptr)
844875
{
845-
const PipelineResourceSignatureVkImpl* pSignature = m_Signatures[s];
846-
if (pSignature == nullptr)
847-
continue;
876+
LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' defines push constants block '", PCAttribs.Name,
877+
"', but the pipeline resource signatures define no inline constant resource to promote to push constants.");
878+
}
848879

849-
for (Uint32 r = 0; r < pSignature->GetTotalResourceCount(); ++r)
850-
{
851-
const PipelineResourceDesc& ResDesc = pSignature->GetResourceDesc(r);
852-
if (strcmp(ResDesc.Name, PCAttribs.Name) == 0)
853-
{
854-
// Found matching resource - this is the push constant
855-
const Uint32 PCSize = PCAttribs.BufferStaticSize;
856-
857-
PushConstant.Size = PCSize;
858-
PushConstant.SignatureIndex = s;
859-
PushConstant.ResourceIndex = r;
860-
861-
// Add shader stages
862-
for (SHADER_TYPE ShaderTypes = ResDesc.ShaderStages; ShaderTypes != SHADER_TYPE_UNKNOWN;)
863-
{
864-
const SHADER_TYPE ShaderType = ExtractLSB(ShaderTypes);
865-
PushConstant.StageFlags |= ShaderTypeToVkShaderStageFlagBit(ShaderType);
866-
}
867-
868-
// Found push constant from SPIR-V
869-
return true;
870-
}
871-
}
880+
if (strcmp(PushConstantName, PCAttribs.Name) != 0)
881+
{
882+
LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' defines push constants block '", PCAttribs.Name,
883+
"', but the pipeline resource signatures select inline constant resource '", PushConstantName,
884+
"' as push constants (only the first inline constant is promoted in Vulkan).");
885+
}
886+
887+
if (PCAttribs.BufferStaticSize != PushConstantSize)
888+
{
889+
LOG_ERROR_AND_THROW("Push constants block size mismatch for resource '", PushConstantName, "' in shader '",
890+
pShader->GetDesc().Name, "': SPIR-V declares ", PCAttribs.BufferStaticSize,
891+
" bytes, but the pipeline resource signature defines ", PushConstantSize, " bytes.");
872892
}
873893
}
874894
}
875895
}
876896

877-
// Step 2: No explicit push constant in SPIR-V, select first inline constant from signatures
878-
for (Uint32 s = 0; s < m_SignatureCount; ++s)
897+
if (pResDesc == nullptr)
879898
{
880-
const PipelineResourceSignatureVkImpl* pSignature = m_Signatures[s];
881-
if (pSignature == nullptr)
882-
continue;
883-
884-
for (Uint32 r = 0; r < pSignature->GetTotalResourceCount(); ++r)
885-
{
886-
const PipelineResourceDesc& ResDesc = pSignature->GetResourceDesc(r);
887-
888-
// Check if this resource is marked as inline constant
889-
if ((ResDesc.Flags & PIPELINE_RESOURCE_FLAG_INLINE_CONSTANTS) != 0)
890-
{
891-
// For inline constants, ArraySize contains the number of 32-bit constants
892-
const Uint32 PCSize = ResDesc.ArraySize * sizeof(Uint32);
893-
894-
PushConstant.Size = PCSize;
895-
PushConstant.SignatureIndex = s;
896-
PushConstant.ResourceIndex = r;
899+
// No inline constants found - PushConstant remains empty.
900+
return false;
901+
}
897902

898-
// Add shader stages
899-
for (SHADER_TYPE ShaderTypes = ResDesc.ShaderStages; ShaderTypes != SHADER_TYPE_UNKNOWN;)
900-
{
901-
const SHADER_TYPE ShaderType = ExtractLSB(ShaderTypes);
902-
PushConstant.StageFlags |= ShaderTypeToVkShaderStageFlagBit(ShaderType);
903-
}
903+
PushConstant.Size = PushConstantSize;
904+
PushConstant.SignatureIndex = PushConstantSignIdx;
905+
PushConstant.ResourceIndex = PushConstantResIdx;
904906

905-
// Found first inline constant
906-
return true;
907-
}
908-
}
907+
for (SHADER_TYPE ShaderTypes = pResDesc->ShaderStages; ShaderTypes != SHADER_TYPE_UNKNOWN;)
908+
{
909+
const SHADER_TYPE ShaderType = ExtractLSB(ShaderTypes);
910+
PushConstant.StageFlags |= ShaderTypeToVkShaderStageFlagBit(ShaderType);
909911
}
910912

911-
// No inline constants found - PushConstant remains empty
912-
return false;
913+
return true;
913914
}
914915

915916
void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& CreateInfo, TShaderStages& ShaderStages) noexcept(false)
@@ -927,7 +928,7 @@ void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& Crea
927928
#endif
928929

929930
// Vulkan allows only one push constant block per pipeline, but it can be accessed from multiple shader stages.
930-
// First check if SPIR-V already has a push constant, otherwise select the first inline constant and promote it to push constant.
931+
// Promote the first inline constant from signatures to push constants (and validate any shader-declared push constants).
931932
PushConstantInfoVk PushConstant;
932933
InitPushConstantInfoFromSignatures(PushConstant, ShaderStages);
933934

0 commit comments

Comments
 (0)