@@ -824,8 +824,41 @@ void PipelineStateVkImpl::RemapOrVerifyShaderResources(
824824bool 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
915916void 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