git.s-ol.nu ~forks/DiligentCore / 30a65df
Unified resource signature handling by pipeline state in D3D12, Vk and GL assiduous 6 months ago
13 changed file(s) with 339 addition(s) and 447 deletion(s). Raw diff Collapse all Expand all
227227 // Note that the DoublePtrHelper is a private class, and can be created only by RefCntWeakPtr
228228 // Thus if no special effort is made, the lifetime of the instances of this class cannot be
229229 // longer than the lifetime of the creating object
230 template <typename DstType>
230231 class DoublePtrHelper
231232 {
232233 public:
233234 DoublePtrHelper(RefCntAutoPtr& AutoPtr) noexcept :
234 NewRawPtr{static_cast<T*>(AutoPtr)},
235 NewRawPtr{static_cast<DstType*>(AutoPtr)},
235236 m_pAutoPtr{std::addressof(AutoPtr)}
236237 {
237238 }
246247
247248 ~DoublePtrHelper()
248249 {
249 if (m_pAutoPtr && static_cast<T*>(*m_pAutoPtr) != NewRawPtr)
250 if (m_pAutoPtr && *m_pAutoPtr != static_cast<T*>(NewRawPtr))
250251 {
251 m_pAutoPtr->Attach(NewRawPtr);
252 m_pAutoPtr->Attach(static_cast<T*>(NewRawPtr));
252253 }
253254 }
254255
255 T*& operator*() noexcept { return NewRawPtr; }
256 const T* operator*() const noexcept { return NewRawPtr; }
256 DstType*& operator*() noexcept { return NewRawPtr; }
257 const DstType* operator*() const noexcept { return NewRawPtr; }
257258
258259 // clang-format off
259 operator T**() noexcept { return &NewRawPtr; }
260 operator const T**() const noexcept { return &NewRawPtr; }
260 operator DstType**() noexcept { return &NewRawPtr; }
261 operator const DstType**() const noexcept { return &NewRawPtr; }
261262 // clang-format on
262263
263264 private:
264 T* NewRawPtr;
265 DstType* NewRawPtr;
265266 RefCntAutoPtr* m_pAutoPtr;
266267
267268 // clang-format off
272273 };
273274
274275 public:
275 DoublePtrHelper operator&()
276 {
277 return DoublePtrHelper(*this);
278 }
279
280 const DoublePtrHelper operator&() const
281 {
282 return DoublePtrHelper(*this);
283 }
284
285 T** GetRawDblPtr() noexcept { return &m_pObject; }
286 const T** GetRawDblPtr() const noexcept { return &m_pObject; }
287
288276 template <typename DstType, typename = typename std::enable_if<std::is_convertible<T*, DstType*>::value>::type>
289 DstType** GetRawDblPtr() noexcept { return reinterpret_cast<DstType**>(&m_pObject); }
277 DoublePtrHelper<DstType> DblPtr() noexcept { return DoublePtrHelper<DstType>(*this); }
290278 template <typename DstType, typename = typename std::enable_if<std::is_convertible<T*, DstType*>::value>::type>
291 DstType** GetRawDblPtr() const noexcept { return reinterpret_cast<DstType**>(&m_pObject); }
279 DoublePtrHelper<DstType> DblPtr() const noexcept { return DoublePtrHelper<DstType>(*this); }
280
281 DoublePtrHelper<T> operator&()
282 {
283 return DblPtr<T>();
284 }
285
286 const DoublePtrHelper<T> operator&() const
287 {
288 return DblPtr<T>();
289 }
290
291 T** RawDblPtr() noexcept { return &m_pObject; }
292 const T** RawDblPtr() const noexcept { return &m_pObject; }
293
294 template <typename DstType, typename = typename std::enable_if<std::is_convertible<T*, DstType*>::value>::type>
295 DstType** RawDblPtr() noexcept { return reinterpret_cast<DstType**>(&m_pObject); }
296 template <typename DstType, typename = typename std::enable_if<std::is_convertible<T*, DstType*>::value>::type>
297 DstType** RawDblPtr() const noexcept { return reinterpret_cast<DstType**>(&m_pObject); }
292298
293299 private:
294300 template <typename OtherType>
230230 return this->m_Desc.ImmutableSamplers[SampIndex];
231231 }
232232
233 static Uint32 CalcMaxSignatureBindIndex(const Uint32 SignatureCount,
234 IPipelineResourceSignature* ppResourceSignatures[])
235 {
236 Uint32 MaxSignatureBindingIndex = 0;
237 for (Uint32 i = 0; i < SignatureCount; ++i)
238 {
239 const auto* pSignature = ppResourceSignatures[i];
240 VERIFY(pSignature != nullptr, "Pipeline resource signature at index ", i, " is null. This error should've been caught by ValidatePipelineResourceSignatures.");
241 MaxSignatureBindingIndex = std::max(MaxSignatureBindingIndex, Uint32{pSignature->GetDesc().BindingIndex});
242 }
243 return MaxSignatureBindingIndex;
244 }
245
246 template <typename TPipelineResourceSignature>
247 static Uint32 CopyResourceSignatures(PIPELINE_TYPE PipelineType,
248 const Uint32 SignatureCount,
249 IPipelineResourceSignature* ppResourceSignatures[],
250 RefCntAutoPtr<TPipelineResourceSignature> DstSignatures[],
251 const size_t MaxDstSignatureCount)
252 {
253 Uint32 MaxSignatureBindIndex = 0;
254 for (Uint32 i = 0; i < SignatureCount; ++i)
255 {
256 auto* pSignature = ValidatedCast<TPipelineResourceSignature>(ppResourceSignatures[i]);
257 VERIFY(pSignature != nullptr, "Pipeline resource signature at index ", i, " is null. This error should've been caught by ValidatePipelineResourceSignatures.");
258
259 const Uint8 Index = pSignature->GetDesc().BindingIndex;
260
261 #ifdef DILIGENT_DEBUG
262 VERIFY(Index < MaxDstSignatureCount,
263 "Pipeline resource signature specifies binding index ", Uint32{Index}, " that exceeds the limit (", MaxDstSignatureCount - 1,
264 "). This error should've been caught by ValidatePipelineResourceSignatureDesc.");
265
266 VERIFY(DstSignatures[Index] == nullptr,
267 "Pipeline resource signature '", pSignature->GetDesc().Name, "' at index ", Uint32{Index},
268 " conflicts with another resource signature '", DstSignatures[Index]->GetDesc().Name,
269 "' that uses the same index. This error should've been caught by ValidatePipelineResourceSignatures.");
270
271 for (Uint32 s = 0, StageCount = pSignature->GetNumActiveShaderStages(); s < StageCount; ++s)
272 {
273 const auto ShaderType = pSignature->GetActiveShaderStageType(s);
274 VERIFY(IsConsistentShaderType(ShaderType, PipelineType),
275 "Pipeline resource signature '", pSignature->GetDesc().Name, "' at index ", Uint32{Index},
276 " has shader stage '", GetShaderTypeLiteralName(ShaderType), "' that is not compatible with pipeline type '",
277 GetPipelineTypeString(PipelineType), "'.");
278 }
279 #endif
280
281 MaxSignatureBindIndex = std::max<Uint32>(MaxSignatureBindIndex, Index);
282 DstSignatures[Index] = pSignature;
283 }
284 return MaxSignatureBindIndex;
233 static bool SignaturesCompatible(const PipelineResourceSignatureImplType* pSign0,
234 const PipelineResourceSignatureImplType* pSign1)
235 {
236 if (pSign0 == pSign1)
237 return true;
238
239 bool IsNull0 = pSign0 == nullptr || (pSign0->GetTotalResourceCount() == 0 && pSign0->GetImmutableSamplerCount() == 0);
240 bool IsNull1 = pSign1 == nullptr || (pSign1->GetTotalResourceCount() == 0 && pSign1->GetImmutableSamplerCount() == 0);
241 if (IsNull0 && IsNull1)
242 return true;
243
244 if (IsNull0 != IsNull1)
245 return false;
246
247 VERIFY_EXPR(pSign0 != nullptr && pSign1 != nullptr);
248 return pSign0->IsCompatibleWith(pSign1);
285249 }
286250
287251 protected:
230230 m_pRayTracingPipelineData->~RayTracingPipelineData();
231231 }
232232
233 if (m_Signatures != nullptr)
234 {
235 for (Uint32 i = 0; i < m_SignatureCount; ++i)
236 m_Signatures[i].~SignatureAutoPtrType();
237 m_Signatures = nullptr;
238 }
239
233240 if (m_pPipelineDataRawMem)
234241 {
235242 GetRawAllocator().Free(m_pPipelineDataRawMem);
403410 return this->GetResourceSignature(0)->InitializeStaticSRBResources(pSRB);
404411 }
405412
413 /// Implementation of IPipelineState::GetResourceSignatureCount().
414 virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final
415 {
416 return m_SignatureCount;
417 }
418
419 /// Implementation of IPipelineState::GetResourceSignature().
420 virtual PipelineResourceSignatureImplType* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final
421 {
422 VERIFY_EXPR(Index < m_SignatureCount);
423 return m_Signatures[Index];
424 }
425
426 /// Implementation of IPipelineState::IsCompatibleWith().
427 virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override // May be overriden
428 {
429 DEV_CHECK_ERR(pPSO != nullptr, "pPSO must not be null");
430
431 if (pPSO == this)
432 return true;
433
434 const auto& lhs = *static_cast<const PipelineStateImplType*>(this);
435 const auto& rhs = *ValidatedCast<const PipelineStateImplType>(pPSO);
436
437 const auto SignCount = lhs.GetResourceSignatureCount();
438 if (SignCount != rhs.GetResourceSignatureCount())
439 return false;
440
441 for (Uint32 s = 0; s < SignCount; ++s)
442 {
443 const auto* pLhsSign = GetResourceSignature(s);
444 const auto* pRhsSign = rhs.GetResourceSignature(s);
445 if (!PipelineResourceSignatureImplType::SignaturesCompatible(pLhsSign, pRhsSign))
446 return false;
447 }
448
449 return true;
450 }
451
406452 protected:
407453 using TNameToGroupIndexMap = std::unordered_map<HashMapStringKey, Uint32, HashMapStringKey::Hasher>;
408454
411457 {
412458 MemPool.AddSpace<GraphicsPipelineData>();
413459 ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
460 ReserveResourceSignatures(CreateInfo, MemPool);
414461
415462 const auto& InputLayout = CreateInfo.GraphicsPipeline.InputLayout;
416463 Uint32 BufferSlotsUsed = 0;
428475 }
429476
430477 void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
431 FixedLinearAllocator& MemPool) const noexcept
478 FixedLinearAllocator& MemPool) noexcept
432479 {
433480 ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
481 ReserveResourceSignatures(CreateInfo, MemPool);
434482 }
435483
436484 void ReserveSpaceForPipelineDesc(const RayTracingPipelineStateCreateInfo& CreateInfo,
437 FixedLinearAllocator& MemPool) const noexcept
485 FixedLinearAllocator& MemPool) noexcept
438486 {
439487 size_t RTDataSize = sizeof(RayTracingPipelineData);
440488 // Reserve space for shader handles
458506 }
459507
460508 ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
509 ReserveResourceSignatures(CreateInfo, MemPool);
461510 }
462511
463512
603652 CorrectGraphicsPipelineDesc(GraphicsPipeline);
604653
605654 CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
655 CopyResourceSignatures(CreateInfo, MemPool);
606656
607657 pRenderPass = GraphicsPipeline.pRenderPass;
608658 if (pRenderPass)
729779 m_pPipelineDataRawMem = MemPool.ReleaseOwnership();
730780
731781 CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
782 CopyResourceSignatures(CreateInfo, MemPool);
732783 }
733784
734785 void InitializePipelineDesc(const RayTracingPipelineStateCreateInfo& CreateInfo,
755806 CopyRTShaderGroupNames(NameToGroupIndex, CreateInfo, MemPool);
756807
757808 CopyResourceLayout(CreateInfo.PSODesc.ResourceLayout, this->m_Desc.ResourceLayout, MemPool);
809 CopyResourceSignatures(CreateInfo, MemPool);
758810 }
759811
760812
889941 }
890942 }
891943
944 void ReserveResourceSignatures(const PipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool)
945 {
946 if (m_UsingImplicitSignature)
947 {
948 VERIFY_EXPR(CreateInfo.ResourceSignaturesCount == 0 || CreateInfo.ppResourceSignatures == nullptr);
949 m_SignatureCount = 1;
950 }
951 else
952 {
953 VERIFY_EXPR(CreateInfo.ResourceSignaturesCount > 0 && CreateInfo.ppResourceSignatures != nullptr);
954 Uint32 MaxSignatureBindingIndex = 0;
955 for (Uint32 i = 0; i < CreateInfo.ResourceSignaturesCount; ++i)
956 {
957 const auto* pSignature = ValidatedCast<PipelineResourceSignatureImplType>(CreateInfo.ppResourceSignatures[i]);
958 VERIFY(pSignature != nullptr, "Pipeline resource signature at index ", i, " is null. This error should've been caught by ValidatePipelineResourceSignatures.");
959
960 Uint32 Index = pSignature->GetDesc().BindingIndex;
961 VERIFY(Index < MAX_RESOURCE_SIGNATURES,
962 "Pipeline resource signature specifies binding index ", Uint32{Index}, " that exceeds the limit (", MAX_RESOURCE_SIGNATURES - 1,
963 "). This error should've been caught by ValidatePipelineResourceSignatureDesc.");
964
965 MaxSignatureBindingIndex = std::max(MaxSignatureBindingIndex, Uint32{Index});
966 }
967 VERIFY_EXPR(MaxSignatureBindingIndex < MAX_RESOURCE_SIGNATURES);
968 m_SignatureCount = static_cast<decltype(m_SignatureCount)>(MaxSignatureBindingIndex + 1);
969 VERIFY_EXPR(m_SignatureCount == MaxSignatureBindingIndex + 1);
970 }
971
972 MemPool.AddSpace<SignatureAutoPtrType>(m_SignatureCount);
973 }
974
975 void CopyResourceSignatures(const PipelineStateCreateInfo& CreateInfo, FixedLinearAllocator& MemPool)
976 {
977 m_Signatures = MemPool.ConstructArray<SignatureAutoPtrType>(m_SignatureCount);
978 if (!m_UsingImplicitSignature)
979 {
980 VERIFY_EXPR(CreateInfo.ResourceSignaturesCount != 0 && CreateInfo.ppResourceSignatures != nullptr);
981 for (Uint32 i = 0; i < CreateInfo.ResourceSignaturesCount; ++i)
982 {
983 auto* pSignature = ValidatedCast<PipelineResourceSignatureImplType>(CreateInfo.ppResourceSignatures[i]);
984 VERIFY_EXPR(pSignature != nullptr);
985
986 const Uint32 Index = pSignature->GetDesc().BindingIndex;
987
988 #ifdef DILIGENT_DEBUG
989 VERIFY_EXPR(Index < m_SignatureCount);
990
991 VERIFY(m_Signatures[Index] == nullptr,
992 "Pipeline resource signature '", pSignature->GetDesc().Name, "' at index ", Uint32{Index},
993 " conflicts with another resource signature '", m_Signatures[Index]->GetDesc().Name,
994 "' that uses the same index. This error should've been caught by ValidatePipelineResourceSignatures.");
995
996 for (Uint32 s = 0, StageCount = pSignature->GetNumActiveShaderStages(); s < StageCount; ++s)
997 {
998 const auto ShaderType = pSignature->GetActiveShaderStageType(s);
999 VERIFY(IsConsistentShaderType(ShaderType, CreateInfo.PSODesc.PipelineType),
1000 "Pipeline resource signature '", pSignature->GetDesc().Name, "' at index ", Uint32{Index},
1001 " has shader stage '", GetShaderTypeLiteralName(ShaderType), "' that is not compatible with pipeline type '",
1002 GetPipelineTypeString(CreateInfo.PSODesc.PipelineType), "'.");
1003 }
1004 #endif
1005
1006 m_Signatures[Index] = pSignature;
1007 }
1008 }
1009 }
1010
8921011 protected:
8931012 /// Shader stages that are active in this PSO.
8941013 SHADER_TYPE m_ActiveShaderStages = SHADER_TYPE_UNKNOWN;
8951014
8961015 /// True if the pipeline was created using implicit root signature.
8971016 const bool m_UsingImplicitSignature;
1017
1018 /// The number of signatures in m_Signatures array.
1019 /// Note that this is not necessarily the same as the number of signatures
1020 /// that were used to create the pipeline, because signatures are arranged
1021 /// by their binding index.
1022 Uint8 m_SignatureCount = 0;
1023
1024 /// Resource signatures arranged by their binding indices
1025 using SignatureAutoPtrType = RefCntAutoPtr<PipelineResourceSignatureImplType>;
1026 SignatureAutoPtrType* m_Signatures = nullptr; // [m_SignatureCount]
8981027
8991028 struct GraphicsPipelineData
9001029 {
5959 /// Implementation of IPipelineState::IsCompatibleWith() in Direct3D12 backend.
6060 virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final;
6161
62 /// Implementation of IPipelineState::GetResourceSignatureCount() in Direct3D12 backend.
63 virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_RootSig->GetSignatureCount(); }
64
65 /// Implementation of IPipelineState::GetResourceSignature() in Direct3D12 backend.
66 virtual PipelineResourceSignatureD3D12Impl* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final
67 {
68 VERIFY_EXPR(Index < GetResourceSignatureCount());
69 return m_ResourceSignatures[Index];
70 }
71
7262 /// Implementation of IPipelineStateD3D12::GetD3D12PipelineState().
7363 virtual ID3D12PipelineState* DILIGENT_CALL_TYPE GetD3D12PipelineState() const override final { return static_cast<ID3D12PipelineState*>(m_pd3d12PSO.p); }
7464
110100 TShaderStages& ShaderStages,
111101 LocalRootSignatureD3D12* pLocalRootSig);
112102
113 static RefCntAutoPtr<IPipelineResourceSignature> CreateDefaultResourceSignature(
103 static RefCntAutoPtr<PipelineResourceSignatureD3D12Impl> CreateDefaultResourceSignature(
114104 RenderDeviceD3D12Impl* pDevice,
115105 const PipelineStateCreateInfo& CreateInfo,
116106 TShaderStages& ShaderStages,
127117 // NB: Pipeline resource signatures used to create the PSO may NOT be the same as
128118 // pipeline resource signatures in m_RootSig, because the latter may be used from the
129119 // cache. While the two signatures may be compatible, they resource names may not be identical.
130 std::unique_ptr<RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>[]> m_ResourceSignatures;
131120
132121 #ifdef DILIGENT_DEVELOPMENT
133122 // Shader resources for all shaders in all shader stages in the pipeline.
413413 }
414414
415415
416 RefCntAutoPtr<IPipelineResourceSignature> PipelineStateD3D12Impl::CreateDefaultResourceSignature(
416 RefCntAutoPtr<PipelineResourceSignatureD3D12Impl> PipelineStateD3D12Impl::CreateDefaultResourceSignature(
417417 RenderDeviceD3D12Impl* pDevice,
418418 const PipelineStateCreateInfo& CreateInfo,
419419 TShaderStages& ShaderStages,
512512 }
513513 }
514514
515 RefCntAutoPtr<IPipelineResourceSignature> pImplicitSignature;
515 RefCntAutoPtr<PipelineResourceSignatureD3D12Impl> pImplicitSignature;
516516 if (Resources.size())
517517 {
518518 PipelineResourceSignatureDesc ResSignDesc;
525525 ResSignDesc.UseCombinedTextureSamplers = pCombinedSamplerSuffix != nullptr;
526526 ResSignDesc.CombinedSamplerSuffix = pCombinedSamplerSuffix;
527527
528 pDevice->CreatePipelineResourceSignature(ResSignDesc, &pImplicitSignature, true);
528 // Always initialize default resource signature as internal device object.
529 // This is necessary to avoud cyclic references from GenerateMips.
530 // This may never be a problem as the PSO keeps the reference to the device if necessary.
531 constexpr bool bIsDeviceInternal = true;
532 pDevice->CreatePipelineResourceSignature(ResSignDesc, pImplicitSignature.DblPtr<IPipelineResourceSignature>(), bIsDeviceInternal);
529533
530534 if (!pImplicitSignature)
531535 LOG_ERROR_AND_THROW("Failed to create implicit resource signature for pipeline state '", (CreateInfo.PSODesc.Name ? CreateInfo.PSODesc.Name : ""), "'.");
538542 TShaderStages& ShaderStages,
539543 LocalRootSignatureD3D12* pLocalRootSig)
540544 {
541 Uint32 SignatureCount = 0;
542 if (CreateInfo.ResourceSignaturesCount == 0 || CreateInfo.ppResourceSignatures == nullptr)
543 {
544 auto pImplicitSignature = CreateDefaultResourceSignature(GetDevice(), CreateInfo, ShaderStages, pLocalRootSig);
545 if (pImplicitSignature)
546 {
547 VERIFY_EXPR(pImplicitSignature->GetDesc().BindingIndex == 0);
548 SignatureCount = 1;
549 m_ResourceSignatures.reset(new RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>[SignatureCount]);
550 m_ResourceSignatures[0] = pImplicitSignature.RawPtr<PipelineResourceSignatureD3D12Impl>();
551 }
552 }
553 else
554 {
555 Uint32 MaxSignatureBindingIndex = PipelineResourceSignatureD3D12Impl::CalcMaxSignatureBindIndex(CreateInfo.ResourceSignaturesCount, CreateInfo.ppResourceSignatures);
556 SignatureCount = MaxSignatureBindingIndex + 1;
557 m_ResourceSignatures.reset(new RefCntAutoPtr<PipelineResourceSignatureD3D12Impl>[SignatureCount]);
558
559 auto DbgMaxSignatureBindingIndex =
560 PipelineResourceSignatureD3D12Impl::CopyResourceSignatures(CreateInfo.PSODesc.PipelineType, CreateInfo.ResourceSignaturesCount,
561 CreateInfo.ppResourceSignatures, m_ResourceSignatures.get(), SignatureCount);
562 VERIFY_EXPR(DbgMaxSignatureBindingIndex == MaxSignatureBindingIndex);
563 }
564
565 m_RootSig = GetDevice()->GetRootSignatureCache().GetRootSig(m_ResourceSignatures.get(), SignatureCount);
545 if (m_UsingImplicitSignature)
546 {
547 VERIFY_EXPR(m_SignatureCount == 1);
548 m_Signatures[0] = CreateDefaultResourceSignature(GetDevice(), CreateInfo, ShaderStages, pLocalRootSig);
549 VERIFY_EXPR(!m_Signatures[0] || m_Signatures[0]->GetDesc().BindingIndex == 0);
550 }
551
552 m_RootSig = GetDevice()->GetRootSignatureCache().GetRootSig(m_Signatures, m_SignatureCount);
566553 if (!m_RootSig)
567554 LOG_ERROR_AND_THROW("Failed to create root signature for pipeline '", m_Desc.Name, "'.");
568555
586573 ResourceBinding::TMap ResourceMap;
587574 // Note that we must use signatures from m_ResourceSignatures for resource binding map,
588575 // because signatures from m_RootSig may have resources with different names.
589 for (Uint32 sign = 0; sign < SignatureCount; ++sign)
590 {
591 const PipelineResourceSignatureD3D12Impl* const pSignature = m_ResourceSignatures[sign];
576 for (Uint32 sign = 0; sign < m_SignatureCount; ++sign)
577 {
578 const PipelineResourceSignatureD3D12Impl* const pSignature = m_Signatures[sign];
592579 if (pSignature == nullptr)
593580 continue;
594581
11171104
11181105 bool PipelineStateD3D12Impl::IsCompatibleWith(const IPipelineState* pPSO) const
11191106 {
1120 VERIFY_EXPR(pPSO != nullptr);
1107 DEV_CHECK_ERR(pPSO != nullptr, "pPSO must not be null");
11211108
11221109 if (pPSO == this)
11231110 return true;
11241111
1125 return (m_RootSig == ValidatedCast<const PipelineStateD3D12Impl>(pPSO)->m_RootSig);
1112 bool IsCompatible = (m_RootSig == ValidatedCast<const PipelineStateD3D12Impl>(pPSO)->m_RootSig);
1113 VERIFY_EXPR(IsCompatible == TPipelineStateBase::IsCompatibleWith(pPSO));
1114 return IsCompatible;
11261115 }
11271116
11281117 } // namespace Diligent
5959 /// Queries the specific interface, see IObject::QueryInterface() for details
6060 virtual void DILIGENT_CALL_TYPE QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override;
6161
62 /// Implementation of IPipelineState::GetResourceSignatureCount() in OpenGL backend.
63 virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_SignatureCount; }
64
65 /// Implementation of IPipelineState::GetResourceSignature() in OpenGL backend.
66 virtual PipelineResourceSignatureGLImpl* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final
67 {
68 VERIFY_EXPR(Index < m_SignatureCount);
69 return m_Signatures[Index].RawPtr<PipelineResourceSignatureGLImpl>();
70 }
71
72 /// Implementation of IPipelineState::IsCompatibleWith() in OpenGL backend.
73 virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final;
74
7562 void CommitProgram(GLContextState& State);
7663
7764 #ifdef DILIGENT_DEVELOPMENT
9178 const TShaderStages& ShaderStages,
9279 SHADER_TYPE ActiveStages);
9380
94 void CreateDefaultSignature(const PipelineStateCreateInfo& CreateInfo,
95 const TShaderStages& ShaderStages,
96 SHADER_TYPE ActiveStages,
97 IPipelineResourceSignature** ppSignature);
81 RefCntAutoPtr<PipelineResourceSignatureGLImpl> CreateDefaultSignature(
82 const PipelineStateCreateInfo& CreateInfo,
83 const TShaderStages& ShaderStages,
84 SHADER_TYPE ActiveStages);
9885
9986 void Destruct();
10087
113100 ThreadingTools::LockFlag m_ProgPipelineLockFlag;
114101
115102 std::vector<std::pair<GLContext::NativeGLContextType, GLObjectWrappers::GLPipelineObj>> m_GLProgPipelines;
116
117 using SignatureArrayType = std::array<RefCntAutoPtr<PipelineResourceSignatureGLImpl>, MAX_RESOURCE_SIGNATURES>;
118 SignatureArrayType m_Signatures = {};
119 Uint8 m_SignatureCount = 0;
120103
121104 Uint8 m_NumPrograms = 0;
122105 bool m_IsProgramPipelineSupported = false;
4040 namespace Diligent
4141 {
4242
43 void PipelineStateGLImpl::CreateDefaultSignature(const PipelineStateCreateInfo& CreateInfo,
44 const TShaderStages& ShaderStages,
45 SHADER_TYPE ActiveStages,
46 IPipelineResourceSignature** ppSignature)
43 RefCntAutoPtr<PipelineResourceSignatureGLImpl> PipelineStateGLImpl::CreateDefaultSignature(
44 const PipelineStateCreateInfo& CreateInfo,
45 const TShaderStages& ShaderStages,
46 SHADER_TYPE ActiveStages)
4747 {
4848 std::vector<PipelineResourceDesc> Resources;
4949
151151 ProgramResources.ProcessConstResources(HandleUB, HandleTexture, HandleImage, HandleSB);
152152 }
153153
154 RefCntAutoPtr<PipelineResourceSignatureGLImpl> pSignature;
154155 if (Resources.size())
155156 {
156157 String SignName = String{"Implicit signature for PSO '"} + m_Desc.Name + '\'';
166167 ResSignDesc.SRBAllocationGranularity = CreateInfo.PSODesc.SRBAllocationGranularity;
167168 ResSignDesc.UseCombinedTextureSamplers = true;
168169
169 GetDevice()->CreatePipelineResourceSignature(ResSignDesc, ppSignature, true);
170
171 if (*ppSignature == nullptr)
170 // Always initialize default resource signature as internal device object.
171 // This is necessary to avoud cyclic references from TexRegionRenderer.
172 // This may never be a problem as the PSO keeps the reference to the device if necessary.
173 constexpr bool bIsDeviceInternal = true;
174 GetDevice()->CreatePipelineResourceSignature(ResSignDesc, pSignature.DblPtr<IPipelineResourceSignature>(), bIsDeviceInternal);
175
176 if (!pSignature)
172177 LOG_ERROR_AND_THROW("Failed to create resource signature for pipeline state");
173178 }
179
180 return pSignature;
174181 }
175182
176183 void PipelineStateGLImpl::InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
177184 const TShaderStages& ShaderStages,
178185 SHADER_TYPE ActiveStages)
179186 {
180 const Uint32 SignatureCount = CreateInfo.ResourceSignaturesCount;
181 RefCntAutoPtr<IPipelineResourceSignature> pImplicitSignature;
182
183 if (SignatureCount == 0 || CreateInfo.ppResourceSignatures == nullptr)
184 {
185 CreateDefaultSignature(CreateInfo, ShaderStages, ActiveStages, &pImplicitSignature);
186 if (pImplicitSignature != nullptr)
187 {
188 VERIFY_EXPR(pImplicitSignature->GetDesc().BindingIndex == 0);
189 m_Signatures[0] = ValidatedCast<PipelineResourceSignatureGLImpl>(pImplicitSignature.RawPtr());
190 m_SignatureCount = 1;
191 }
192 }
193 else
194 {
195 const auto MaxBindingIndex =
196 PipelineResourceSignatureGLImpl::CopyResourceSignatures(CreateInfo.PSODesc.PipelineType, SignatureCount, CreateInfo.ppResourceSignatures,
197 m_Signatures.data(), m_Signatures.size());
198 m_SignatureCount = static_cast<decltype(m_SignatureCount)>(MaxBindingIndex + 1);
199 VERIFY_EXPR(m_SignatureCount == MaxBindingIndex + 1);
187 if (m_UsingImplicitSignature)
188 {
189 VERIFY_EXPR(m_SignatureCount == 1);
190 m_Signatures[0] = CreateDefaultSignature(CreateInfo, ShaderStages, ActiveStages);
191 VERIFY_EXPR(!m_Signatures[0] || m_Signatures[0]->GetDesc().BindingIndex == 0);
200192 }
201193
202194 // Apply resource bindings to programs.
392384 m_GLPrograms = nullptr;
393385 }
394386
395 m_Signatures.fill({});
396
397 m_SignatureCount = 0;
398 m_NumPrograms = 0;
387 m_NumPrograms = 0;
399388
400389 TPipelineStateBase::Destruct();
401390 }
408397 return m_ShaderTypes[Index];
409398 }
410399
411 bool PipelineStateGLImpl::IsCompatibleWith(const IPipelineState* pPSO) const
412 {
413 VERIFY_EXPR(pPSO != nullptr);
414
415 if (pPSO == this)
416 return true;
417
418 const auto& lhs = *this;
419 const auto& rhs = *ValidatedCast<const PipelineStateGLImpl>(pPSO);
420
421 if (lhs.GetResourceSignatureCount() != rhs.GetResourceSignatureCount())
422 return false;
423
424 for (Uint32 s = 0, SigCount = lhs.GetResourceSignatureCount(); s < SigCount; ++s)
425 {
426 if (!lhs.GetResourceSignature(s)->IsCompatibleWith(*rhs.GetResourceSignature(s)))
427 return false;
428 }
429 return true;
430 }
431400
432401 void PipelineStateGLImpl::CommitProgram(GLContextState& State)
433402 {
2828
2929 /// \file
3030 /// Declaration of Diligent::PipelineLayoutVk class
31
3132 #include <array>
3233
33 #include "PipelineResourceSignatureVkImpl.hpp"
3434 #include "VulkanUtilities/VulkanObjectWrappers.hpp"
3535
3636 namespace Diligent
3737 {
3838
39 class ShaderResourceCacheVk;
39 class RenderDeviceVkImpl;
40 class PipelineResourceSignatureVkImpl;
4041
4142 /// Implementation of the Diligent::PipelineLayoutVk class
4243 class PipelineLayoutVk
4546 PipelineLayoutVk();
4647 ~PipelineLayoutVk();
4748
48 void Create(RenderDeviceVkImpl* pDeviceVk, PIPELINE_TYPE PipelineType, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount);
49 void Create(RenderDeviceVkImpl* pDeviceVk, RefCntAutoPtr<PipelineResourceSignatureVkImpl> ppSignatures[], Uint32 SignatureCount);
4950 void Release(RenderDeviceVkImpl* pDeviceVkImpl, Uint64 CommandQueueMask);
5051
51 size_t GetHash() const;
52 VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
5253
53 VkPipelineLayout GetVkPipelineLayout() const { return m_VkPipelineLayout; }
54 Uint32 GetSignatureCount() const { return m_SignatureCount; }
55
56 PipelineResourceSignatureVkImpl* GetSignature(Uint32 index) const
54 // Returns the index of the first descriptor set used by the resource signature at the given bind index
55 Uint32 GetFirstDescrSetIndex(Uint32 Index) const
5756 {
58 VERIFY_EXPR(index < m_SignatureCount);
59 return m_Signatures[index].RawPtr<PipelineResourceSignatureVkImpl>();
60 }
61
62 // Returns the index of the first descriptor set used by the given resource signature
63 Uint32 GetFirstDescrSetIndex(const PipelineResourceSignatureVkImpl* pPRS) const
64 {
65 VERIFY_EXPR(pPRS != nullptr);
66 Uint32 Index = pPRS->GetDesc().BindingIndex;
67
68 VERIFY_EXPR(Index < m_SignatureCount);
69 VERIFY_EXPR(m_Signatures[Index] != nullptr);
70 VERIFY_EXPR(!m_Signatures[Index]->IsIncompatibleWith(*pPRS));
71
57 VERIFY_EXPR(Index <= m_DbgMaxBindIndex);
7258 return m_FirstDescrSetIndex[Index];
7359 }
7460
75 struct ResourceInfo
76 {
77 PipelineResourceSignatureVkImpl* Signature = nullptr;
78 SHADER_RESOURCE_TYPE Type = SHADER_RESOURCE_TYPE_UNKNOWN;
79 // Index in m_Desc.Resources for a resource, or ~0U for an immutable sampler.
80 Uint32 ResIndex = ~0U;
81 Uint32 DescrSetIndex = ~0U;
82 Uint32 BindingIndex = ~0U;
83
84 explicit operator bool() const
85 {
86 return Signature != nullptr && Type != SHADER_RESOURCE_TYPE_UNKNOWN;
87 }
88 };
89 ResourceInfo GetResourceInfo(const char* Name, SHADER_TYPE Stage) const;
90 ResourceInfo GetImmutableSamplerInfo(const char* Name, SHADER_TYPE Stage) const;
91
9261 private:
93 using SignatureArray = std::array<RefCntAutoPtr<PipelineResourceSignatureVkImpl>, MAX_RESOURCE_SIGNATURES>;
94 using FirstDescrSetIndexArrayType = std::array<Uint8, MAX_RESOURCE_SIGNATURES>;
95
9662 VulkanUtilities::PipelineLayoutWrapper m_VkPipelineLayout;
9763
64 using FirstDescrSetIndexArrayType = std::array<Uint8, MAX_RESOURCE_SIGNATURES>;
9865 // Index of the first descriptor set, for every resource signature.
9966 FirstDescrSetIndexArrayType m_FirstDescrSetIndex = {};
100
101 // The number of resource signatures used by this pipeline layout
102 // (Maximum is MAX_RESOURCE_SIGNATURES)
103 Uint8 m_SignatureCount = 0;
10467
10568 // The total number of descriptor sets used by this pipeline layout
10669 // (Maximum is MAX_RESOURCE_SIGNATURES * 2)
10770 Uint8 m_DescrSetCount = 0;
10871
109 SignatureArray m_Signatures;
72 #ifdef DILIGENT_DEBUG
73 Uint32 m_DbgMaxBindIndex = 0;
74 #endif
11075 };
11176
11277 } // namespace Diligent
4343 #include "VulkanUtilities/VulkanCommandBuffer.hpp"
4444 #include "RenderDeviceVkImpl.hpp"
4545 #include "PipelineLayoutVk.hpp"
46 #include "PipelineResourceSignatureVkImpl.hpp"
4647
4748 namespace Diligent
4849 {
6566
6667 IMPLEMENT_QUERY_INTERFACE_IN_PLACE(IID_PipelineStateVk, TPipelineStateBase)
6768
68 /// Implementation of IPipelineState::IsCompatibleWith() in Vulkan backend.
69 virtual bool DILIGENT_CALL_TYPE IsCompatibleWith(const IPipelineState* pPSO) const override final;
70
7169 /// Implementation of IPipelineStateVk::GetRenderPass().
7270 virtual IRenderPassVk* DILIGENT_CALL_TYPE GetRenderPass() const override final { return GetRenderPassPtr().RawPtr<IRenderPassVk>(); }
7371
7472 /// Implementation of IPipelineStateVk::GetVkPipeline().
7573 virtual VkPipeline DILIGENT_CALL_TYPE GetVkPipeline() const override final { return m_Pipeline; }
76
77 /// Implementation of IPipelineState::GetResourceSignatureCount() in Vulkan backend.
78 virtual Uint32 DILIGENT_CALL_TYPE GetResourceSignatureCount() const override final { return m_PipelineLayout.GetSignatureCount(); }
79
80 /// Implementation of IPipelineState::GetResourceSignature() in Vulkan backend.
81 virtual IPipelineResourceSignature* DILIGENT_CALL_TYPE GetResourceSignature(Uint32 Index) const override final { return m_PipelineLayout.GetSignature(Index); }
8274
8375 const PipelineLayoutVk& GetPipelineLayout() const { return m_PipelineLayout; }
8476
114106 // Performs validation of SRB resource parameters that are not possible to validate
115107 // when resource is bound.
116108 using SRBArray = std::array<ShaderResourceBindingVkImpl*, MAX_RESOURCE_SIGNATURES>;
117 void DvpVerifySRBResources(SRBArray& SRBs) const;
109 void DvpVerifySRBResources(const SRBArray& SRBs) const;
118110 #endif
119111
120112 private:
126118 void InitPipelineLayout(const PipelineStateCreateInfo& CreateInfo,
127119 TShaderStages& ShaderStages);
128120
129 void CreateDefaultSignature(const PipelineStateCreateInfo& CreateInfo,
130 const TShaderStages& ShaderStages,
131 IPipelineResourceSignature** ppSignature);
121 RefCntAutoPtr<PipelineResourceSignatureVkImpl> CreateDefaultSignature(
122 const PipelineStateCreateInfo& CreateInfo,
123 const TShaderStages& ShaderStages);
132124
133125 void Destruct();
134126
138130 #ifdef DILIGENT_DEVELOPMENT
139131 // Shader resources for all shaders in all shader stages
140132 std::vector<std::shared_ptr<const SPIRVShaderResources>> m_ShaderResources;
141 // Resource info for every resource in m_ShaderResources, in the same order
142 std::vector<PipelineLayoutVk::ResourceInfo> m_ResInfo;
133 // Resource attributions for every resource in m_ShaderResources, in the same order
134 std::vector<ResourceAttribution> m_ResourceAttibutions;
143135 #endif
144136 };
145137
317317
318318 const auto& Layout = pPipelineStateVk->GetPipelineLayout();
319319 auto& BindInfo = GetDescriptorSetBindInfo(PSODesc.PipelineType);
320 const auto SignCount = Layout.GetSignatureCount();
320 const auto SignCount = pPipelineStateVk->GetResourceSignatureCount();
321321
322322 BindInfo.vkPipelineLayout = Layout.GetVkPipelineLayout();
323323
324324 BindInfo.ActiveSRBMask = 0;
325325 for (Uint32 i = 0; i < SignCount; ++i)
326326 {
327 auto* pSignature = Layout.GetSignature(i);
327 auto* pSignature = pPipelineStateVk->GetResourceSignature(i);
328328 if (pSignature == nullptr || pSignature->GetNumDescriptorSets() == 0)
329329 continue;
330330
332332
333333 auto& ResInfo = BindInfo.Resources[i];
334334
335 ResInfo.DescriptorSetBaseInd = Layout.GetFirstDescrSetIndex(pSignature);
335 ResInfo.DescriptorSetBaseInd = Layout.GetFirstDescrSetIndex(pSignature->GetDesc().BindingIndex);
336336 ResInfo.DynamicOffsetCount = pSignature->GetDynamicOffsetCount();
337337 }
338338
348348 Uint32 sign = 0;
349349 for (; sign < SignCount; ++sign)
350350 {
351 const auto* pLayoutSign = Layout.GetSignature(sign);
351 const auto* pLayoutSign = pPipelineStateVk->GetResourceSignature(sign);
352352 const auto* pSRBSign = BindInfo.SRBs[sign] != nullptr ? BindInfo.SRBs[sign]->GetSignature() : nullptr;
353353
354354 if ((pLayoutSign == nullptr || pLayoutSign->GetNumDescriptorSets() == 0) != (pSRBSign == nullptr || pSRBSign->GetNumDescriptorSets() == 0))
413413 while (StaleSRBFlags != 0)
414414 {
415415 Uint32 sign = PlatformMisc::GetLSB(StaleSRBFlags);
416 VERIFY_EXPR(sign < m_pPipelineState->GetPipelineLayout().GetSignatureCount());
416 VERIFY_EXPR(sign < m_pPipelineState->GetResourceSignatureCount());
417417 StaleSRBFlags &= ~(Uint32{1} << sign);
418418
419419 auto& ResInfo = BindInfo.Resources[sign];
460460 if (m_State.CommittedResourcesValidated)
461461 return;
462462
463 const auto& Layout = m_pPipelineState->GetPipelineLayout();
464 auto& BindInfo = GetDescriptorSetBindInfo(m_pPipelineState->GetDesc().PipelineType);
465 const auto SignCount = Layout.GetSignatureCount();
463 const auto& BindInfo = GetDescriptorSetBindInfo(m_pPipelineState->GetDesc().PipelineType);
464 const auto SignCount = m_pPipelineState->GetResourceSignatureCount();
466465
467466 for (Uint32 i = 0; i < SignCount; ++i)
468467 {
469 auto* pLayoutSign = Layout.GetSignature(i);
470 if (pLayoutSign == nullptr)
468 const auto* pSign = m_pPipelineState->GetResourceSignature(i);
469 if (pSign == nullptr)
471470 continue;
472471
473 if (pLayoutSign->GetNumDescriptorSets() == 0)
472 if (pSign->GetNumDescriptorSets() == 0)
474473 {
475474 // Skip signatures without any resources
476475 continue;
486485 const auto* pSRBSign = pSRB->GetSignature();
487486 DEV_CHECK_ERR(pSRBSign != nullptr, "SRB must not be null");
488487
489 if (!pLayoutSign->IsCompatibleWith(*pSRBSign))
488 if (!pSign->IsCompatibleWith(*pSRBSign))
490489 {
491490 LOG_ERROR_MESSAGE("Shader resource binding at index ", i, " with signature '", pSRBSign->GetDesc().Name,
492491 "' is not compatible with pipeline layout in current pipeline '", m_pPipelineState->GetDesc().Name, "'.");
495494 DEV_CHECK_ERR((BindInfo.StaleSRBMask & BindInfo.ActiveSRBMask) == 0, "CommitDescriptorSets() must be called before validation.");
496495
497496 const auto& ResInfo = BindInfo.Resources[i];
498 const auto DSCount = pLayoutSign->GetNumDescriptorSets();
497 const auto DSCount = pSign->GetNumDescriptorSets();
499498 for (Uint32 s = 0; s < DSCount; ++s)
500499 {
501500 DEV_CHECK_ERR(ResInfo.vkSets[s] != VK_NULL_HANDLE,
502501 "descriptor set with index ", s, " is not bound for resource signature '",
503 pLayoutSign->GetDesc().Name, "', binding index ", i, ".");
502 pSign->GetDesc().Name, "', binding index ", i, ".");
504503 }
505504
506505 DEV_CHECK_ERR(ResInfo.LastBoundDSBaseInd == ResInfo.DescriptorSetBaseInd,
3333 #include "RenderDeviceVkImpl.hpp"
3434 #include "VulkanTypeConversions.hpp"
3535 #include "StringTools.hpp"
36 #include "PipelineResourceSignatureVkImpl.hpp"
3637
3738 namespace Diligent
3839 {
5556 }
5657 }
5758
58 void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, PIPELINE_TYPE PipelineType, IPipelineResourceSignature** ppSignatures, Uint32 SignatureCount)
59 void PipelineLayoutVk::Create(RenderDeviceVkImpl* pDeviceVk, RefCntAutoPtr<PipelineResourceSignatureVkImpl> ppSignatures[], Uint32 SignatureCount)
5960 {
60 VERIFY(m_SignatureCount == 0 && m_DescrSetCount == 0 && !m_VkPipelineLayout,
61 "This pipeline layout is already initialized");
62
63 auto MaxSignatureBindIndex =
64 PipelineResourceSignatureVkImpl::CopyResourceSignatures(PipelineType, SignatureCount, ppSignatures,
65 m_Signatures.data(), m_Signatures.size());
66 m_SignatureCount = static_cast<Uint8>(MaxSignatureBindIndex + 1);
67 VERIFY_EXPR(m_SignatureCount == MaxSignatureBindIndex + 1);
61 VERIFY(m_DescrSetCount == 0 && !m_VkPipelineLayout, "This pipeline layout is already initialized");
6862
6963 std::array<VkDescriptorSetLayout, MAX_RESOURCE_SIGNATURES * PipelineResourceSignatureVkImpl::MAX_DESCRIPTOR_SETS> DescSetLayouts;
7064
7266 Uint32 DynamicUniformBufferCount = 0;
7367 Uint32 DynamicStorageBufferCount = 0;
7468
75 for (Uint32 i = 0; i < m_SignatureCount; ++i)
69 for (Uint32 i = 0; i < SignatureCount; ++i)
7670 {
77 const auto& pSignature = m_Signatures[i];
71 const auto& pSignature = ppSignatures[i];
7872 if (pSignature == nullptr)
7973 continue;
8074
9084
9185 DynamicUniformBufferCount += pSignature->GetDynamicUniformBufferCount();
9286 DynamicStorageBufferCount += pSignature->GetDynamicStorageBufferCount();
87 #ifdef DILIGENT_DEBUG
88 m_DbgMaxBindIndex = std::max(m_DbgMaxBindIndex, Uint32{pSignature->GetDesc().BindingIndex});
89 #endif
9390 }
9491 VERIFY_EXPR(DescSetLayoutCount <= MAX_RESOURCE_SIGNATURES * 2);
9592
129126 m_DescrSetCount = static_cast<Uint8>(DescSetLayoutCount);
130127 }
131128
132 size_t PipelineLayoutVk::GetHash() const
133 {
134 if (m_SignatureCount == 0)
135 return 0;
136
137 size_t hash = 0;
138 HashCombine(hash, m_SignatureCount);
139 for (Uint32 i = 0; i < m_SignatureCount; ++i)
140 {
141 if (m_Signatures[i] != nullptr)
142 HashCombine(hash, m_Signatures[i]->GetHash());
143 else
144 HashCombine(hash, 0);
145 }
146 return hash;
147 }
148
149 PipelineLayoutVk::ResourceInfo PipelineLayoutVk::GetResourceInfo(const char* Name, SHADER_TYPE Stage) const
150 {
151 ResourceInfo Info;
152 for (Uint32 sign = 0, SignCount = GetSignatureCount(); sign < SignCount && !Info; ++sign)
153 {
154 auto* const pSignature = GetSignature(sign);
155 if (pSignature == nullptr)
156 continue;
157
158 for (Uint32 r = 0, ResCount = pSignature->GetTotalResourceCount(); r < ResCount; ++r)
159 {
160 const auto& ResDesc = pSignature->GetResourceDesc(r);
161 const auto& Attr = pSignature->GetResourceAttribs(r);
162
163 if ((ResDesc.ShaderStages & Stage) != 0 && strcmp(ResDesc.Name, Name) == 0)
164 {
165 Info.Signature = pSignature;
166 Info.Type = ResDesc.ResourceType;
167 Info.ResIndex = r;
168 Info.BindingIndex = Attr.BindingIndex;
169 Info.DescrSetIndex = m_FirstDescrSetIndex[sign] + Attr.DescrSet;
170 break;
171 }
172 }
173 }
174 return Info;
175 }
176
177 PipelineLayoutVk::ResourceInfo PipelineLayoutVk::GetImmutableSamplerInfo(const char* Name, SHADER_TYPE Stage) const
178 {
179 ResourceInfo Info;
180 for (Uint32 sign = 0, SignCount = GetSignatureCount(); sign < SignCount && !Info; ++sign)
181 {
182 auto* const pSignature = GetSignature(sign);
183 if (pSignature == nullptr)
184 continue;
185
186 for (Uint32 s = 0, SampCount = pSignature->GetImmutableSamplerCount(); s < SampCount; ++s)
187 {
188 const auto& Desc = pSignature->GetImmutableSamplerDesc(s);
189 const auto& Attr = pSignature->GetImmutableSamplerAttribs(s);
190
191 if (Attr.Ptr && (Desc.ShaderStages & Stage) != 0 && StreqSuff(Name, Desc.SamplerOrTextureName, pSignature->GetCombinedSamplerSuffix()))
192 {
193 Info.Signature = pSignature;
194 Info.Type = SHADER_RESOURCE_TYPE_SAMPLER;
195 Info.BindingIndex = Attr.BindingIndex;
196 Info.DescrSetIndex = m_FirstDescrSetIndex[sign] + Attr.DescrSet;
197 break;
198 }
199 }
200 }
201 return Info;
202 }
203
204129 } // namespace Diligent
734734 return RPDesc;
735735 }
736736
737 void PipelineStateVkImpl::CreateDefaultSignature(const PipelineStateCreateInfo& CreateInfo,
738 const TShaderStages& ShaderStages,
739 IPipelineResourceSignature** ppSignature)
737 RefCntAutoPtr<PipelineResourceSignatureVkImpl> PipelineStateVkImpl::CreateDefaultSignature(
738 const PipelineStateCreateInfo& CreateInfo,
739 const TShaderStages& ShaderStages)
740740 {
741741 struct UniqueResource
742742 {
836836 }
837837 }
838838
839 RefCntAutoPtr<PipelineResourceSignatureVkImpl> pSignature;
839840 if (Resources.size())
840841 {
841842 String SignName = String{"Implicit signature for PSO '"} + m_Desc.Name + '\'';
851852 ResSignDesc.UseCombinedTextureSamplers = pCombinedSamplerSuffix != nullptr;
852853 ResSignDesc.CombinedSamplerSuffix = pCombinedSamplerSuffix;
853854
854 GetDevice()->CreatePipelineResourceSignature(ResSignDesc, ppSignature, true);
855
856 if (*ppSignature == nullptr)
855 // Always initialize default resource signature as internal device object.
856 // This is necessary to avoud cyclic references.
857 // This may never be a problem as the PSO keeps the reference to the device if necessary.
858 constexpr bool bIsDeviceInternal = true;
859 GetDevice()->CreatePipelineResourceSignature(ResSignDesc, pSignature.DblPtr<IPipelineResourceSignature>(), bIsDeviceInternal);
860
861 if (pSignature == nullptr)
857862 LOG_ERROR_AND_THROW("Failed to create resource signature for pipeline state");
858863 }
864
865 return pSignature;
859866 }
860867
861868 void PipelineStateVkImpl::InitPipelineLayout(const PipelineStateCreateInfo& CreateInfo,
862869 TShaderStages& ShaderStages)
863870 {
864 std::array<IPipelineResourceSignature*, MAX_RESOURCE_SIGNATURES> Signatures = {};
865 RefCntAutoPtr<IPipelineResourceSignature> pImplicitSignature;
866
867 Uint32 SignatureCount = CreateInfo.ResourceSignaturesCount;
868
869 for (Uint32 i = 0; i < SignatureCount; ++i)
870 {
871 Signatures[i] = CreateInfo.ppResourceSignatures[i];
872 }
873
874 if (SignatureCount == 0 || CreateInfo.ppResourceSignatures == nullptr)
875 {
876 CreateDefaultSignature(CreateInfo, ShaderStages, &pImplicitSignature);
877 if (pImplicitSignature != nullptr)
878 {
879 VERIFY_EXPR(pImplicitSignature->GetDesc().BindingIndex == 0);
880 Signatures[0] = pImplicitSignature;
881 SignatureCount = 1;
882 }
883 }
884
885 m_PipelineLayout.Create(GetDevice(), CreateInfo.PSODesc.PipelineType, Signatures.data(), SignatureCount);
871 if (m_UsingImplicitSignature)
872 {
873 VERIFY_EXPR(m_SignatureCount == 1);
874 m_Signatures[0] = CreateDefaultSignature(CreateInfo, ShaderStages);
875 VERIFY_EXPR(!m_Signatures[0] || m_Signatures[0]->GetDesc().BindingIndex == 0);
876 }
877
878 m_PipelineLayout.Create(GetDevice(), m_Signatures, m_SignatureCount);
886879
887880 // Verify that pipeline layout is compatible with shader resources and
888881 // remap resource bindings.
907900 pShaderResources->ProcessResources(
908901 [&](const SPIRVShaderResourceAttribs& SPIRVAttribs, Uint32) //
909902 {
910 auto Info = m_PipelineLayout.GetResourceInfo(SPIRVAttribs.Name, ShaderType);
911 if (!Info && SPIRVAttribs.Type == SPIRVShaderResourceAttribs::SeparateSampler)
912 {
913 DEV_CHECK_ERR(SPIRVAttribs.ArraySize == 1, "Immutable sampler arrays must also be added to resource list");
914 Info = m_PipelineLayout.GetImmutableSamplerInfo(SPIRVAttribs.Name, ShaderType);
915 if (Info)
916 {
917 VERIFY(Info.BindingIndex != ~0u && Info.DescrSetIndex != ~0u,
918 "Binding index and/or descriptor set index are not initialized. This indicates that the immutable sampler "
919 "is also present in the list of resources, so it should've been found by GetResourceInfo().");
920 }
921 }
922 if (!Info)
903 auto ResAttribution = GetResourceAttribution(SPIRVAttribs.Name, ShaderType);
904 if (!ResAttribution)
923905 {
924906 LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' contains resource '", SPIRVAttribs.Name,
925907 "' that is not present in any pipeline resource signature used to create pipeline state '",
926908 m_Desc.Name, "'.");
927909 }
928910
911 const auto& SignDesc = ResAttribution.pSignature->GetDesc();
912
929913 SHADER_RESOURCE_TYPE Type;
930914 PIPELINE_RESOURCE_FLAGS Flags;
931915 GetShaderResourceTypeAndFlags(SPIRVAttribs.Type, Type, Flags);
932 if (Type != Info.Type)
916
917 Uint32 ResourceBinding = ~0u;
918 Uint32 DescriptorSet = ~0u;
919 if (ResAttribution.ResourceIndex != ResourceAttribution::InvalidResourceIndex)
933920 {
934 LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' contains resource with name '", SPIRVAttribs.Name,
935 "' and type '", GetShaderResourceTypeLiteralName(Type), "' that is not compatible with type '",
936 GetShaderResourceTypeLiteralName(Info.Type), "' specified in pipeline resource signature '", Info.Signature->GetDesc().Name, "'.");
921 const auto& ResDesc = ResAttribution.pSignature->GetResourceDesc(ResAttribution.ResourceIndex);
922 ValidatePipelineResourceCompatibility(ResDesc, Type, Flags, SPIRVAttribs.ArraySize,
923 pShader->GetDesc().Name, SignDesc.Name);
924
925 const auto& ResAttribs{ResAttribution.pSignature->GetResourceAttribs(ResAttribution.ResourceIndex)};
926 ResourceBinding = ResAttribs.BindingIndex;
927 DescriptorSet = ResAttribs.DescrSet;
937928 }
938
939 if (Info.ResIndex != ~0u)
929 else if (ResAttribution.ImmutableSamplerIndex != ResourceAttribution::InvalidResourceIndex)
940930 {
941 const auto& ResDesc = Info.Signature->GetResourceDesc(Info.ResIndex);
942 ValidatePipelineResourceCompatibility(ResDesc, Type, Flags, SPIRVAttribs.ArraySize,
943 pShader->GetDesc().Name, Info.Signature->GetDesc().Name);
931 if (Type != SHADER_RESOURCE_TYPE_SAMPLER)
932 {
933 LOG_ERROR_AND_THROW("Shader '", pShader->GetDesc().Name, "' contains resource with name '", SPIRVAttribs.Name,
934 "' and type '", GetShaderResourceTypeLiteralName(Type),
935 "' that is not compatible with immutable sampler defined in pipeline resource signature '",
936 SignDesc.Name, "'.");
937 }
938 const auto& SamAttribs{ResAttribution.pSignature->GetImmutableSamplerAttribs(ResAttribution.ImmutableSamplerIndex)};
939 ResourceBinding = SamAttribs.BindingIndex;
940 DescriptorSet = SamAttribs.DescrSet;
944941 }
945 SPIRV[SPIRVAttribs.BindingDecorationOffset] = Info.BindingIndex;
946 SPIRV[SPIRVAttribs.DescriptorSetDecorationOffset] = Info.DescrSetIndex;
942 else
943 {
944 UNEXPECTED("Either immutable sampler or resource index should be valid");
945 }
946
947 VERIFY_EXPR(ResourceBinding != ~0u && DescriptorSet != ~0u);
948 SPIRV[SPIRVAttribs.BindingDecorationOffset] = ResourceBinding;
949 SPIRV[SPIRVAttribs.DescriptorSetDecorationOffset] = m_PipelineLayout.GetFirstDescrSetIndex(SignDesc.BindingIndex) + DescriptorSet;
947950
948951 #ifdef DILIGENT_DEVELOPMENT
949 m_ResInfo.emplace_back(Info);
952 m_ResourceAttibutions.emplace_back(ResAttribution);
950953 #endif
951954 });
952955 }
962965 TShaderStages ShaderStages;
963966 ExtractShaders<ShaderVkImpl>(CreateInfo, ShaderStages);
964967
968 FixedLinearAllocator MemPool{GetRawAllocator()};
969
970 ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
971
972 MemPool.Reserve();
973
974 const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
975
976 InitializePipelineDesc(CreateInfo, MemPool);
977
965978 InitPipelineLayout(CreateInfo, ShaderStages);
966
967 FixedLinearAllocator MemPool{GetRawAllocator()};
968
969 ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
970
971 MemPool.Reserve();
972
973 const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
974
975 InitializePipelineDesc(CreateInfo, MemPool);
976979
977980 // Create shader modules and initialize shader stages
978981 InitPipelineShaderStages(LogicalDevice, ShaderStages, ShaderModules, vkShaderStages);
10611064 TPipelineStateBase::Destruct();
10621065 }
10631066
1064 bool PipelineStateVkImpl::IsCompatibleWith(const IPipelineState* pPSO) const
1065 {
1066 VERIFY_EXPR(pPSO != nullptr);
1067
1068 if (pPSO == this)
1069 return true;
1070
1071 const auto& lhs = m_PipelineLayout;
1072 const auto& rhs = ValidatedCast<const PipelineStateVkImpl>(pPSO)->m_PipelineLayout;
1073
1074 if (lhs.GetSignatureCount() != rhs.GetSignatureCount())
1075 return false;
1076
1077 for (Uint32 s = 0, SigCount = lhs.GetSignatureCount(); s < SigCount; ++s)
1078 {
1079 if (!lhs.GetSignature(s)->IsCompatibleWith(*rhs.GetSignature(s)))
1080 return false;
1081 }
1082 return true;
1083 }
1084
10851067 #ifdef DILIGENT_DEVELOPMENT
1086 void PipelineStateVkImpl::DvpVerifySRBResources(SRBArray& SRBs) const
1087 {
1088 auto res_info = m_ResInfo.begin();
1068 void PipelineStateVkImpl::DvpVerifySRBResources(const SRBArray& SRBs) const
1069 {
1070 auto res_info = m_ResourceAttibutions.begin();
10891071 for (const auto& pResources : m_ShaderResources)
10901072 {
10911073 pResources->ProcessResources(
10921074 [&](const SPIRVShaderResourceAttribs& ResAttribs, Uint32) //
10931075 {
1094 if (res_info->ResIndex != ~0u) // There are also immutable samplers in the list
1076 if (!res_info->IsImmutableSampler()) // There are also immutable samplers in the list
10951077 {
1096 VERIFY_EXPR(res_info->Signature != nullptr);
1097 const auto& SignDesc = res_info->Signature->GetDesc();
1078 VERIFY_EXPR(res_info->pSignature != nullptr);
1079 const auto& SignDesc = res_info->pSignature->GetDesc();
10981080 const auto SignBindIndex = SignDesc.BindingIndex;
10991081 if (auto* pSRB = SRBs[SignBindIndex])
11001082 {
1101 res_info->Signature->DvpValidateCommittedResource(ResAttribs, res_info->ResIndex, pSRB->GetResourceCache(),
1102 pResources->GetShaderName(), m_Desc.Name);
1083 res_info->pSignature->DvpValidateCommittedResource(ResAttribs, res_info->ResourceIndex, pSRB->GetResourceCache(),
1084 pResources->GetShaderName(), m_Desc.Name);
11031085 }
11041086 else
11051087 {
11101092 } //
11111093 );
11121094 }
1113 VERIFY_EXPR(res_info == m_ResInfo.end());
1095 VERIFY_EXPR(res_info == m_ResourceAttibutions.end());
11141096 }
11151097 #endif
11161098
8686 }
8787
8888 RefCntAutoPtr<RenderPassVkImpl> pRenderPass;
89 m_DeviceVkImpl.CreateRenderPass(RPDesc, pRenderPass.GetRawDblPtr<IRenderPass>(), /* IsDeviceInternal = */ true);
89 m_DeviceVkImpl.CreateRenderPass(RPDesc, pRenderPass.RawDblPtr<IRenderPass>(), /* IsDeviceInternal = */ true);
9090 VERIFY_EXPR(pRenderPass != nullptr);
9191 it = m_Cache.emplace(Key, std::move(pRenderPass)).first;
9292 }