@@ -435,7 +435,15 @@ void DeviceContextVkImpl::UpdateInlineConstantBuffers(ResourceBindInfo& BindInfo
435435 continue ;
436436
437437 const ShaderResourceCacheVk* pResourceCache = BindInfo.ResourceCaches [i];
438- if (pResourceCache == nullptr || !pResourceCache->HasInlineConstants ())
438+ if (pResourceCache == nullptr )
439+ {
440+ // Each signature with inline constants must have a bound SRB with a valid resource cache
441+ DEV_CHECK_ERR (false , " Signature '" , pSign->GetDesc ().Name , " ' has inline constants but no SRB is bound. "
442+ " Did you call CommitShaderResources()?" );
443+ continue ;
444+ }
445+
446+ if (!pResourceCache->HasInlineConstants ())
439447 continue ;
440448
441449 // Update inline constant buffers
@@ -461,13 +469,14 @@ void DeviceContextVkImpl::SetPushConstants(const void* pData, Uint32 Offset, Uin
461469 " Push constant data range [" , Offset, " , " , Offset + Size, " ) exceeds the push constant block size (" , Layout.GetPushConstantSize (), " )" );
462470 }
463471 }
464-
465- if (Size > 0 )
472+ else
466473 {
467- memcpy (m_PushConstantsData.data () + Offset, pData, Size);
468- m_PushConstantsDataSize = std::max (m_PushConstantsDataSize, Offset + Size);
469- m_State.PushConstantsDirty = true ;
474+ DEV_ERROR (" A valid PipelineState must be bound before calling SetPushConstants!" );
470475 }
476+
477+ memcpy (m_PushConstantsData.data () + Offset, pData, Size);
478+ m_PushConstantsDataSize = std::max (m_PushConstantsDataSize, Offset + Size);
479+ m_State.PushConstantsDirty = true ;
471480}
472481
473482void DeviceContextVkImpl::CommitPushConstants ()
@@ -495,6 +504,27 @@ void DeviceContextVkImpl::CommitDescriptorSets(ResourceBindInfo& BindInfo, Uint3
495504{
496505 VERIFY (CommitSRBMask != 0 , " This method should not be called when there is nothing to commit" );
497506
507+ // Filter out SRBs that only have push constants (no descriptor sets)
508+ // These SRBs are included in CommitSRBMask due to InlineConstantsSRBMask, but they don't need descriptor set binding
509+ Uint32 FilteredCommitMask = CommitSRBMask;
510+ Uint32 ResourceSignaturesCount = m_pPipelineState->GetResourceSignatureCount ();
511+ for (Uint32 sign = 0 ; sign < ResourceSignaturesCount; ++sign)
512+ {
513+ if ((CommitSRBMask & (1u << sign)) != 0 )
514+ {
515+ const ShaderResourceCacheVk* pResourceCache = BindInfo.ResourceCaches [sign];
516+ if (pResourceCache != nullptr && pResourceCache->GetNumDescriptorSets () == 0 )
517+ {
518+ // This SRB only has push constants, no descriptor sets to commit
519+ FilteredCommitMask &= ~(1u << sign);
520+ }
521+ }
522+ }
523+
524+ // If all SRBs were filtered out (only push constants), nothing to commit
525+ if (FilteredCommitMask == 0 )
526+ return ;
527+
498528 const Uint32 FirstSign = PlatformMisc::GetLSB (CommitSRBMask);
499529 const Uint32 LastSign = PlatformMisc::GetMSB (CommitSRBMask);
500530 VERIFY_EXPR (LastSign < m_pPipelineState->GetResourceSignatureCount ());
@@ -563,6 +593,8 @@ void DeviceContextVkImpl::DvpValidateCommittedShaderResources(ResourceBindInfo&
563593 if (BindInfo.ResourcesValidated )
564594 return ;
565595
596+ // Use custom signature getter to skip signatures that have no resources at all
597+ // Note: Signatures with only push constants still need SRB to store push constant data
566598 DvpVerifySRBCompatibility (BindInfo);
567599
568600 const Uint32 SignCount = m_pPipelineState->GetResourceSignatureCount ();
@@ -612,9 +644,24 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR
612644
613645 ShaderResourceBindingVkImpl* pResBindingVkImpl = ClassPtrCast<ShaderResourceBindingVkImpl>(pShaderResourceBinding);
614646 ShaderResourceCacheVk& ResourceCache = pResBindingVkImpl->GetResourceCache ();
647+
648+ const Uint32 SRBIndex = pResBindingVkImpl->GetBindingIndex ();
649+ const PipelineResourceSignatureVkImpl* pSignature = pResBindingVkImpl->GetSignature ();
650+ ResourceBindInfo& BindInfo = GetBindInfo (pResBindingVkImpl->GetPipelineType ());
651+ ResourceBindInfo::DescriptorSetInfo& SetInfo = BindInfo.SetInfo [SRBIndex];
652+
653+ // Always bind the SRB, even if it has no descriptor sets (e.g., only push constants)
654+ // The resource cache is needed to store push constant data
655+ BindInfo.Set (SRBIndex, pResBindingVkImpl);
656+
657+ // If there are no descriptor sets, we're done (SRB only contains push constants)
658+ // Clear the stale flag since there are no descriptor sets to commit
615659 if (ResourceCache.GetNumDescriptorSets () == 0 )
616660 {
617- // Ignore SRBs that contain no resources
661+ // Clear the stale bit for this SRB since it has no descriptor sets to commit
662+ // The SRB is still bound and ResourceCaches[SRBIndex] is set, so push constants can be accessed
663+ const auto SRBBit = static_cast <ResourceBindInfo::SRBMaskType>(1u << SRBIndex);
664+ BindInfo.StaleSRBMask &= ~SRBBit;
618665 return ;
619666 }
620667
@@ -633,12 +680,6 @@ void DeviceContextVkImpl::CommitShaderResources(IShaderResourceBinding* pShaderR
633680 }
634681#endif
635682
636- const Uint32 SRBIndex = pResBindingVkImpl->GetBindingIndex ();
637- const PipelineResourceSignatureVkImpl* pSignature = pResBindingVkImpl->GetSignature ();
638- ResourceBindInfo& BindInfo = GetBindInfo (pResBindingVkImpl->GetPipelineType ());
639- ResourceBindInfo::DescriptorSetInfo& SetInfo = BindInfo.SetInfo [SRBIndex];
640-
641- BindInfo.Set (SRBIndex, pResBindingVkImpl);
642683 // We must not clear entire ResInfo as DescriptorSetBaseInd and DynamicOffsetCount
643684 // are set by SetPipelineState().
644685 SetInfo.vkSets = {};
@@ -836,6 +877,7 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags)
836877 ResourceBindInfo& BindInfo = GetBindInfo (PIPELINE_TYPE_GRAPHICS);
837878
838879 // Update inline constant buffers before binding descriptor sets
880+ const bool DynamicBuffersIntact = (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT) != 0 ;
839881 const bool InlineConstantsIntact = (Flags & DRAW_FLAG_INLINE_CONSTANTS_INTACT) != 0 ;
840882 if (!InlineConstantsIntact)
841883 {
@@ -845,7 +887,7 @@ void DeviceContextVkImpl::PrepareForDraw(DRAW_FLAGS Flags)
845887 // First time we must always bind descriptor sets with dynamic offsets as SRBs are stale.
846888 // If there are no dynamic buffers bound in the resource cache, for all subsequent
847889 // calls we do not need to bind the sets again.
848- if (Uint32 CommitMask = BindInfo.GetCommitMask (Flags & DRAW_FLAG_DYNAMIC_RESOURCE_BUFFERS_INTACT, Flags & DRAW_FLAG_INLINE_CONSTANTS_INTACT ))
890+ if (Uint32 CommitMask = BindInfo.GetCommitMask (DynamicBuffersIntact, InlineConstantsIntact ))
849891 {
850892 CommitDescriptorSets (BindInfo, CommitMask);
851893 }
0 commit comments