git.s-ol.nu ~forks/DiligentCore / 13b0b54
Improved exception safety of pipeline state object construction assiduous 11 months ago
31 changed file(s) with 881 addition(s) and 714 deletion(s). Raw diff Collapse all Expand all
4949 LinearAllocator& operator=(LinearAllocator&&) = delete;
5050 // clang-format on
5151
52 explicit LinearAllocator(IMemoryAllocator& Allocator) :
52 explicit LinearAllocator(IMemoryAllocator& Allocator) noexcept :
5353 m_pAllocator{&Allocator}
5454 {}
5555
56 LinearAllocator(LinearAllocator&& Other) :
56 LinearAllocator(LinearAllocator&& Other) noexcept :
5757 // clang-format off
5858 m_pDataStart {Other.m_pDataStart },
5959 m_pCurrPtr {Other.m_pCurrPtr },
8686 return Ptr;
8787 }
8888
89 void AddSpace(size_t size, size_t alignment)
89 void* ReleaseOwnership() noexcept
90 {
91 m_pAllocator = nullptr;
92 return GetDataPtr();
93 }
94
95 void* GetDataPtr() const noexcept
96 {
97 return m_pDataStart;
98 }
99
100 void AddSpace(size_t size, size_t alignment) noexcept
90101 {
91102 VERIFY(m_pDataStart == nullptr, "Memory has already been allocated");
92103 VERIFY(IsPowerOfTwo(alignment), "Alignment is not a power of two!");
116127 }
117128
118129 template <typename T>
119 void AddSpace(size_t count = 1)
130 void AddSpace(size_t count = 1) noexcept
120131 {
121132 AddSpace(sizeof(T) * count, alignof(T));
122133 }
123134
124 void AddSpaceForString(const Char* str)
135 void AddSpaceForString(const Char* str) noexcept
125136 {
126137 VERIFY_EXPR(str != nullptr);
127138 AddSpace(strlen(str) + 1, 1);
128139 }
129140
130 void AddSpaceForString(const String& str)
141 void AddSpaceForString(const String& str) noexcept
131142 {
132143 AddSpaceForString(str.c_str());
133144 }
221221
222222
223223 void ReserveSpaceForPipelineDesc(const GraphicsPipelineStateCreateInfo& CreateInfo,
224 LinearAllocator& MemPool)
224 LinearAllocator& MemPool) noexcept
225225 {
226226 MemPool.AddSpace<GraphicsPipelineDesc>();
227227 ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
239239 }
240240
241241 void ReserveSpaceForPipelineDesc(const ComputePipelineStateCreateInfo& CreateInfo,
242 LinearAllocator& MemPool) const
242 LinearAllocator& MemPool) const noexcept
243243 {
244244 ReserveResourceLayout(CreateInfo.PSODesc.ResourceLayout, MemPool);
245245 }
447447 }
448448
449449 private:
450 void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) const
450 static void ReserveResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, LinearAllocator& MemPool) noexcept
451451 {
452452 if (SrcLayout.Variables != nullptr)
453453 {
470470 }
471471 }
472472
473 void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool) const
473 static void CopyResourceLayout(const PipelineResourceLayoutDesc& SrcLayout, PipelineResourceLayoutDesc& DstLayout, LinearAllocator& MemPool)
474474 {
475475 if (SrcLayout.Variables != nullptr)
476476 {
137137
138138 private:
139139 template <typename PSOCreateInfoType>
140 LinearAllocator InitInternalObjects(const PSOCreateInfoType& CreateInfo);
140 void InitInternalObjects(const PSOCreateInfoType& CreateInfo);
141141
142142 void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
143143 const std::vector<std::pair<SHADER_TYPE, ShaderD3D11Impl*>>& ShaderStages);
144
145 void Destruct();
144146
145147 CComPtr<ID3D11BlendState> m_pd3d11BlendState;
146148 CComPtr<ID3D11RasterizerState> m_pd3d11RasterizerState;
5050 class ShaderResourceCacheD3D11
5151 {
5252 public:
53 ShaderResourceCacheD3D11()
53 ShaderResourceCacheD3D11() noexcept
5454 {}
5555
5656 ~ShaderResourceCacheD3D11();
4646 class ShaderResourceLayoutD3D11
4747 {
4848 public:
49 ShaderResourceLayoutD3D11(IObject& Owner,
50 std::shared_ptr<const ShaderResourcesD3D11> pSrcResources,
51 const PipelineResourceLayoutDesc& ResourceLayout,
52 const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes,
53 Uint32 NumVarTypes,
54 ShaderResourceCacheD3D11& ResourceCache,
55 IMemoryAllocator& ResCacheDataAllocator,
56 IMemoryAllocator& ResLayoutDataAllocator);
49 ShaderResourceLayoutD3D11(IObject& Owner,
50 ShaderResourceCacheD3D11& ResourceCache) noexcept :
51 m_Owner{Owner},
52 m_ResourceCache{ResourceCache}
53 {
54 }
55
56 void Initialize(std::shared_ptr<const ShaderResourcesD3D11> pSrcResources,
57 const PipelineResourceLayoutDesc& ResourceLayout,
58 const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes,
59 Uint32 NumVarTypes,
60 IMemoryAllocator& ResCacheDataAllocator,
61 IMemoryAllocator& ResLayoutDataAllocator);
5762 ~ShaderResourceLayoutD3D11();
5863
5964 // clang-format off
6772 static size_t GetRequiredMemorySize(const ShaderResourcesD3D11& SrcResources,
6873 const PipelineResourceLayoutDesc& ResourceLayout,
6974 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
70 Uint32 NumAllowedTypes);
75 Uint32 NumAllowedTypes) noexcept;
7176
7277 void CopyResources(ShaderResourceCacheD3D11& DstCache) const;
7378
3535 {
3636
3737 template <typename PSOCreateInfoType>
38 LinearAllocator PipelineStateD3D11Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo)
38 void PipelineStateD3D11Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo)
3939 {
4040 m_ResourceLayoutIndex.fill(-1);
4141
4242 std::vector<std::pair<SHADER_TYPE, ShaderD3D11Impl*>> ShaderStages;
4343 ExtractShaders<ShaderD3D11Impl>(CreateInfo, ShaderStages);
4444
45 // Memory must be released if an exception is thrown.
45 const auto NumShaderStages = GetNumShaderStages();
46 VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size());
47
4648 LinearAllocator MemPool{GetRawAllocator()};
4749
48 MemPool.AddSpace<ShaderResourceLayoutD3D11>(GetNumShaderStages());
49 MemPool.AddSpace<ShaderResourceCacheD3D11>(GetNumShaderStages());
50 MemPool.AddSpace<ShaderResourceCacheD3D11>(NumShaderStages);
51 MemPool.AddSpace<ShaderResourceLayoutD3D11>(NumShaderStages);
5052
5153 ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
5254
5355 MemPool.Reserve();
5456
55 m_pStaticResourceLayouts = MemPool.Allocate<ShaderResourceLayoutD3D11>(GetNumShaderStages());
56 m_pStaticResourceCaches = MemPool.Allocate<ShaderResourceCacheD3D11>(GetNumShaderStages());
57 m_pStaticResourceCaches = MemPool.ConstructArray<ShaderResourceCacheD3D11>(NumShaderStages);
58
59 // The memory is now owned by PipelineStateD3D11Impl and will be freed by Destruct().
60 auto* Ptr = MemPool.ReleaseOwnership();
61 VERIFY_EXPR(Ptr == m_pStaticResourceCaches);
62 (void)Ptr;
63
64 m_pStaticResourceLayouts = MemPool.Allocate<ShaderResourceLayoutD3D11>(NumShaderStages);
65 for (Uint32 i = 0; i < NumShaderStages; ++i)
66 new (m_pStaticResourceLayouts + i) ShaderResourceLayoutD3D11{*this, m_pStaticResourceCaches[i]}; // noexcept
5767
5868 InitializePipelineDesc(CreateInfo, MemPool);
69
70 // It is important to construct all objects before initializing them because if an exception is thrown,
71 // destructors will be called for all objects
72
5973 InitResourceLayouts(CreateInfo, ShaderStages);
60
61 return MemPool;
6274 }
6375
6476
7688 m_ImmutableSamplers (STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>"))
7789 // clang-format on
7890 {
79 auto MemPool = InitInternalObjects(CreateInfo);
80
81 auto& GraphicsPipeline = GetGraphicsPipelineDesc();
91 try
92 {
93 InitInternalObjects(CreateInfo);
94
95 auto& GraphicsPipeline = GetGraphicsPipelineDesc();
8296
8397 #define INIT_SHADER(ShortName, ExpectedType) \
8498 do \
93107 HashCombine(m_ShaderResourceLayoutHash, pShader->GetD3D11Resources()->GetHash()); \
94108 } while (false)
95109
96 INIT_SHADER(VS, SHADER_TYPE_VERTEX);
97 INIT_SHADER(PS, SHADER_TYPE_PIXEL);
98 INIT_SHADER(GS, SHADER_TYPE_GEOMETRY);
99 INIT_SHADER(DS, SHADER_TYPE_DOMAIN);
100 INIT_SHADER(HS, SHADER_TYPE_HULL);
110 INIT_SHADER(VS, SHADER_TYPE_VERTEX);
111 INIT_SHADER(PS, SHADER_TYPE_PIXEL);
112 INIT_SHADER(GS, SHADER_TYPE_GEOMETRY);
113 INIT_SHADER(DS, SHADER_TYPE_DOMAIN);
114 INIT_SHADER(HS, SHADER_TYPE_HULL);
101115 #undef INIT_SHADER
102116
103 if (m_pVS == nullptr)
104 {
105 LOG_ERROR_AND_THROW("Vertex shader is null");
106 }
107
108 auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device();
109
110 D3D11_BLEND_DESC D3D11BSDesc = {};
111 BlendStateDesc_To_D3D11_BLEND_DESC(GraphicsPipeline.BlendDesc, D3D11BSDesc);
112 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateBlendState(&D3D11BSDesc, &m_pd3d11BlendState),
113 "Failed to create D3D11 blend state object");
114
115 D3D11_RASTERIZER_DESC D3D11RSDesc = {};
116 RasterizerStateDesc_To_D3D11_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, D3D11RSDesc);
117 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateRasterizerState(&D3D11RSDesc, &m_pd3d11RasterizerState),
118 "Failed to create D3D11 rasterizer state");
119
120 D3D11_DEPTH_STENCIL_DESC D3D11DSSDesc = {};
121 DepthStencilStateDesc_To_D3D11_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, D3D11DSSDesc);
122 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateDepthStencilState(&D3D11DSSDesc, &m_pd3d11DepthStencilState),
123 "Failed to create D3D11 depth stencil state");
124
125 // Create input layout
126 const auto& InputLayout = GraphicsPipeline.InputLayout;
127 if (InputLayout.NumElements > 0)
128 {
129 std::vector<D3D11_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D11_INPUT_ELEMENT_DESC>> d311InputElements(STD_ALLOCATOR_RAW_MEM(D3D11_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<D3D11_INPUT_ELEMENT_DESC>"));
130 LayoutElements_To_D3D11_INPUT_ELEMENT_DESCs(InputLayout, d311InputElements);
131
132 ID3DBlob* pVSByteCode = m_pVS.RawPtr<ShaderD3D11Impl>()->GetBytecode();
133 if (!pVSByteCode)
134 LOG_ERROR_AND_THROW("Vertex Shader byte code does not exist");
135
136 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateInputLayout(d311InputElements.data(), static_cast<UINT>(d311InputElements.size()), pVSByteCode->GetBufferPointer(), pVSByteCode->GetBufferSize(), &m_pd3d11InputLayout),
137 "Failed to create the Direct3D11 input layout");
138 }
139
140 auto* Ptr = MemPool.Release();
141 VERIFY_EXPR(Ptr == m_pStaticResourceLayouts);
117 if (m_pVS == nullptr)
118 {
119 LOG_ERROR_AND_THROW("Vertex shader is null");
120 }
121
122 auto* pDeviceD3D11 = pRenderDeviceD3D11->GetD3D11Device();
123
124 D3D11_BLEND_DESC D3D11BSDesc = {};
125 BlendStateDesc_To_D3D11_BLEND_DESC(GraphicsPipeline.BlendDesc, D3D11BSDesc);
126 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateBlendState(&D3D11BSDesc, &m_pd3d11BlendState),
127 "Failed to create D3D11 blend state object");
128
129 D3D11_RASTERIZER_DESC D3D11RSDesc = {};
130 RasterizerStateDesc_To_D3D11_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, D3D11RSDesc);
131 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateRasterizerState(&D3D11RSDesc, &m_pd3d11RasterizerState),
132 "Failed to create D3D11 rasterizer state");
133
134 D3D11_DEPTH_STENCIL_DESC D3D11DSSDesc = {};
135 DepthStencilStateDesc_To_D3D11_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, D3D11DSSDesc);
136 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateDepthStencilState(&D3D11DSSDesc, &m_pd3d11DepthStencilState),
137 "Failed to create D3D11 depth stencil state");
138
139 // Create input layout
140 const auto& InputLayout = GraphicsPipeline.InputLayout;
141 if (InputLayout.NumElements > 0)
142 {
143 std::vector<D3D11_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D11_INPUT_ELEMENT_DESC>> d311InputElements(STD_ALLOCATOR_RAW_MEM(D3D11_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<D3D11_INPUT_ELEMENT_DESC>"));
144 LayoutElements_To_D3D11_INPUT_ELEMENT_DESCs(InputLayout, d311InputElements);
145
146 ID3DBlob* pVSByteCode = m_pVS.RawPtr<ShaderD3D11Impl>()->GetBytecode();
147 if (!pVSByteCode)
148 LOG_ERROR_AND_THROW("Vertex Shader byte code does not exist");
149
150 CHECK_D3D_RESULT_THROW(pDeviceD3D11->CreateInputLayout(d311InputElements.data(), static_cast<UINT>(d311InputElements.size()), pVSByteCode->GetBufferPointer(), pVSByteCode->GetBufferSize(), &m_pd3d11InputLayout),
151 "Failed to create the Direct3D11 input layout");
152 }
153 }
154 catch (...)
155 {
156 Destruct();
157 throw;
158 }
142159 }
143160
144161 PipelineStateD3D11Impl::PipelineStateD3D11Impl(IReferenceCounters* pRefCounters,
155172 m_ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>"))
156173 // clang-format on
157174 {
158 auto MemPool = InitInternalObjects(CreateInfo);
159
160 m_pCS = ValidatedCast<ShaderD3D11Impl>(CreateInfo.pCS);
161 if (m_pCS == nullptr)
162 {
163 LOG_ERROR_AND_THROW("Compute shader is null");
164 }
165
166 if (m_pCS->GetDesc().ShaderType != SHADER_TYPE_COMPUTE)
167 {
168 LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(SHADER_TYPE_COMPUTE), " shader is expeceted while ", GetShaderTypeLiteralName(m_pCS->GetDesc().ShaderType), " provided");
169 }
170 m_ShaderResourceLayoutHash = m_pCS->GetD3D11Resources()->GetHash();
171
172 auto* Ptr = MemPool.Release();
173 VERIFY_EXPR(Ptr == m_pStaticResourceLayouts);
175 try
176 {
177 InitInternalObjects(CreateInfo);
178
179 m_pCS = ValidatedCast<ShaderD3D11Impl>(CreateInfo.pCS);
180 if (m_pCS == nullptr)
181 {
182 LOG_ERROR_AND_THROW("Compute shader is null");
183 }
184
185 if (m_pCS->GetDesc().ShaderType != SHADER_TYPE_COMPUTE)
186 {
187 LOG_ERROR_AND_THROW(GetShaderTypeLiteralName(SHADER_TYPE_COMPUTE), " shader is expeceted while ", GetShaderTypeLiteralName(m_pCS->GetDesc().ShaderType), " provided");
188 }
189 m_ShaderResourceLayoutHash = m_pCS->GetD3D11Resources()->GetHash();
190 }
191 catch (...)
192 {
193 Destruct();
194 throw;
195 }
174196 }
175197
176198 PipelineStateD3D11Impl::~PipelineStateD3D11Impl()
177199 {
178 for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
179 {
180 m_pStaticResourceCaches[s].Destroy(GetRawAllocator());
181 m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11();
182 }
183
184 for (Uint32 l = 0; l < GetNumShaderStages(); ++l)
185 {
186 m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11();
187 }
188 // m_pStaticResourceLayouts and m_pStaticResourceCaches are allocated in contiguous chunks of memory.
189 if (auto* pRawMem = m_pStaticResourceLayouts)
200 Destruct();
201 }
202
203 void PipelineStateD3D11Impl::Destruct()
204 {
205 if (m_pStaticResourceLayouts != nullptr)
206 {
207 for (Uint32 l = 0; l < GetNumShaderStages(); ++l)
208 {
209 m_pStaticResourceLayouts[l].~ShaderResourceLayoutD3D11();
210 }
211 }
212
213 if (m_pStaticResourceCaches != nullptr)
214 {
215 for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
216 {
217 m_pStaticResourceCaches[s].Destroy(GetRawAllocator());
218 m_pStaticResourceCaches[s].~ShaderResourceCacheD3D11();
219 }
220 }
221
222 // All subobjects are allocated in contiguous chunks of memory.
223 if (auto* pRawMem = m_pStaticResourceCaches)
190224 GetRawAllocator().Free(pRawMem);
191225 }
192226
212246 }
213247 #endif
214248
215 decltype(m_ImmutableSamplers) ImmutableSamplers(STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>"));
249 decltype(m_ImmutableSamplers) ImmutableSamplers{STD_ALLOCATOR_RAW_MEM(ImmutableSamplerInfo, GetRawAllocator(), "Allocator for vector<ImmutableSamplerInfo>")};
250
216251 std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderResLayoutDataSizes = {};
217252 std::array<size_t, MAX_SHADERS_IN_PIPELINE> ShaderResCacheDataSizes = {};
218253 for (Uint32 s = 0; s < ShaderStages.size(); ++s)
219254 {
220 const auto* pShader = ShaderStages[s].second;
221 const auto& ShaderDesc = pShader->GetDesc();
222 const auto& ShaderResources = *pShader->GetD3D11Resources();
223 VERIFY_EXPR(ShaderDesc.ShaderType == ShaderResources.GetShaderType());
224
225 new (m_pStaticResourceCaches + s) ShaderResourceCacheD3D11;
226 // Do not initialize the cache as this will be performed by the resource layout
255 const auto* pShader = ShaderStages[s].second;
256 const auto& ShaderDesc = pShader->GetDesc();
257 const auto& Resources = *pShader->GetD3D11Resources();
258 VERIFY_EXPR(ShaderDesc.ShaderType == Resources.GetShaderType());
259
260 // The cache will be initialized by the resource layout
227261
228262 // Shader resource layout will only contain dynamic and mutable variables
229263 const SHADER_RESOURCE_VARIABLE_TYPE StaticVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
230 // clang-format off
231 new (m_pStaticResourceLayouts + s)
232 ShaderResourceLayoutD3D11
233 {
234 *this,
235 pShader->GetD3D11Resources(),
236 m_Desc.ResourceLayout,
237 StaticVarTypes,
238 _countof(StaticVarTypes),
239 m_pStaticResourceCaches[s],
240 GetRawAllocator(),
241 GetRawAllocator()
242 };
243 // clang-format on
264 m_pStaticResourceLayouts[s].Initialize(
265 pShader->GetD3D11Resources(),
266 m_Desc.ResourceLayout,
267 StaticVarTypes,
268 _countof(StaticVarTypes),
269 GetRawAllocator(),
270 GetRawAllocator() //
271 );
244272
245273 // Initialize immutable samplers
246 for (Uint32 sam = 0; sam < ShaderResources.GetNumSamplers(); ++sam)
247 {
248 const auto& SamplerAttribs = ShaderResources.GetSampler(sam);
274 for (Uint32 sam = 0; sam < Resources.GetNumSamplers(); ++sam)
275 {
276 const auto& SamplerAttribs = Resources.GetSampler(sam);
249277 constexpr bool LogImtblSamplerArrayError = true;
250 auto SrcImtblSamplerInd = ShaderResources.FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError);
278 auto SrcImtblSamplerInd = Resources.FindImmutableSampler(SamplerAttribs, ResourceLayout, LogImtblSamplerArrayError);
251279 if (SrcImtblSamplerInd >= 0)
252280 {
253281 const auto& SrcImtblSamplerInfo = ResourceLayout.ImmutableSamplers[SrcImtblSamplerInd];
266294 SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE,
267295 SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC //
268296 };
269 ShaderResLayoutDataSizes[s] = ShaderResourceLayoutD3D11::GetRequiredMemorySize(ShaderResources, ResourceLayout, SRBVarTypes, _countof(SRBVarTypes));
270 ShaderResCacheDataSizes[s] = ShaderResourceCacheD3D11::GetRequriedMemorySize(ShaderResources);
297 ShaderResLayoutDataSizes[s] = ShaderResourceLayoutD3D11::GetRequiredMemorySize(Resources, ResourceLayout, SRBVarTypes, _countof(SRBVarTypes));
298 ShaderResCacheDataSizes[s] = ShaderResourceCacheD3D11::GetRequriedMemorySize(Resources);
271299 }
272300
273301 auto ShaderInd = GetShaderTypePipelineIndex(ShaderDesc.ShaderType, m_Desc.PipelineType);
7676 // Shader resource layout will only contain dynamic and mutable variables
7777 // http://diligentgraphics.com/diligent-engine/architecture/d3d11/shader-resource-cache#Shader-Resource-Cache-Initialization
7878 SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
79 // clang-format off
80 new (m_pResourceLayouts + s)
81 ShaderResourceLayoutD3D11
82 {
83 *this,
84 pShaderD3D11->GetD3D11Resources(),
85 PSODesc.ResourceLayout,
86 VarTypes,
87 _countof(VarTypes),
88 m_pBoundResourceCaches[s],
89 ResCacheDataAllocator,
90 ResLayoutDataAllocator
91 };
92 // clang-format on
79 new (m_pResourceLayouts + s) ShaderResourceLayoutD3D11{*this, m_pBoundResourceCaches[s]};
80 m_pResourceLayouts[s].Initialize(
81 pShaderD3D11->GetD3D11Resources(),
82 PSODesc.ResourceLayout,
83 VarTypes,
84 _countof(VarTypes),
85 ResCacheDataAllocator,
86 ResLayoutDataAllocator //
87 );
9388
9489 const auto ShaderType = pShaderD3D11->GetDesc().ShaderType;
9590 const auto ShaderInd = GetShaderTypePipelineIndex(ShaderType, PSODesc.PipelineType);
147147
148148 void ShaderResourceCacheD3D11::Destroy(IMemoryAllocator& MemAllocator)
149149 {
150 VERIFY(IsInitialized(), "Resource cache is not initialized");
150 if (!IsInitialized())
151 return;
152
151153 VERIFY(m_pdbgMemoryAllocator == &MemAllocator, "The allocator does not match the one used to create resources");
152154
153 if (IsInitialized())
154 {
155 // Explicitly destory all objects
156 auto CBCount = GetCBCount();
157 if (CBCount != 0)
158 {
159 CachedCB* CBs = nullptr;
160 ID3D11Buffer** d3d11CBs = nullptr;
161 GetCBArrays(CBs, d3d11CBs);
162 for (size_t cb = 0; cb < CBCount; ++cb)
163 CBs[cb].~CachedCB();
164 }
165
166 auto SRVCount = GetSRVCount();
167 if (SRVCount != 0)
168 {
169 CachedResource* SRVResources = nullptr;
170 ID3D11ShaderResourceView** d3d11SRVs = nullptr;
171 GetSRVArrays(SRVResources, d3d11SRVs);
172 for (size_t srv = 0; srv < SRVCount; ++srv)
173 SRVResources[srv].~CachedResource();
174 }
175
176 auto SamplerCount = GetSamplerCount();
177 if (SamplerCount != 0)
178 {
179 CachedSampler* Samplers = nullptr;
180 ID3D11SamplerState** d3d11Samplers = nullptr;
181 GetSamplerArrays(Samplers, d3d11Samplers);
182 for (size_t sam = 0; sam < SamplerCount; ++sam)
183 Samplers[sam].~CachedSampler();
184 }
185
186 auto UAVCount = GetUAVCount();
187 if (UAVCount != 0)
188 {
189 CachedResource* UAVResources = nullptr;
190 ID3D11UnorderedAccessView** d3d11UAVs = nullptr;
191 GetUAVArrays(UAVResources, d3d11UAVs);
192 for (size_t uav = 0; uav < UAVCount; ++uav)
193 UAVResources[uav].~CachedResource();
194 }
195
196 m_SRVOffset = InvalidResourceOffset;
197 m_SamplerOffset = InvalidResourceOffset;
198 m_UAVOffset = InvalidResourceOffset;
199 m_MemoryEndOffset = InvalidResourceOffset;
200
201 if (m_pResourceData != nullptr)
202 MemAllocator.Free(m_pResourceData);
203 m_pResourceData = nullptr;
204 }
155 // Explicitly destory all objects
156 auto CBCount = GetCBCount();
157 if (CBCount != 0)
158 {
159 CachedCB* CBs = nullptr;
160 ID3D11Buffer** d3d11CBs = nullptr;
161 GetCBArrays(CBs, d3d11CBs);
162 for (size_t cb = 0; cb < CBCount; ++cb)
163 CBs[cb].~CachedCB();
164 }
165
166 auto SRVCount = GetSRVCount();
167 if (SRVCount != 0)
168 {
169 CachedResource* SRVResources = nullptr;
170 ID3D11ShaderResourceView** d3d11SRVs = nullptr;
171 GetSRVArrays(SRVResources, d3d11SRVs);
172 for (size_t srv = 0; srv < SRVCount; ++srv)
173 SRVResources[srv].~CachedResource();
174 }
175
176 auto SamplerCount = GetSamplerCount();
177 if (SamplerCount != 0)
178 {
179 CachedSampler* Samplers = nullptr;
180 ID3D11SamplerState** d3d11Samplers = nullptr;
181 GetSamplerArrays(Samplers, d3d11Samplers);
182 for (size_t sam = 0; sam < SamplerCount; ++sam)
183 Samplers[sam].~CachedSampler();
184 }
185
186 auto UAVCount = GetUAVCount();
187 if (UAVCount != 0)
188 {
189 CachedResource* UAVResources = nullptr;
190 ID3D11UnorderedAccessView** d3d11UAVs = nullptr;
191 GetUAVArrays(UAVResources, d3d11UAVs);
192 for (size_t uav = 0; uav < UAVCount; ++uav)
193 UAVResources[uav].~CachedResource();
194 }
195
196 m_SRVOffset = InvalidResourceOffset;
197 m_SamplerOffset = InvalidResourceOffset;
198 m_UAVOffset = InvalidResourceOffset;
199 m_MemoryEndOffset = InvalidResourceOffset;
200
201 if (m_pResourceData != nullptr)
202 MemAllocator.Free(m_pResourceData);
203 m_pResourceData = nullptr;
205204 }
206205
207206 ShaderResourceCacheD3D11::~ShaderResourceCacheD3D11()
8383 size_t ShaderResourceLayoutD3D11::GetRequiredMemorySize(const ShaderResourcesD3D11& SrcResources,
8484 const PipelineResourceLayoutDesc& ResourceLayout,
8585 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
86 Uint32 NumAllowedTypes)
86 Uint32 NumAllowedTypes) noexcept
8787 {
8888 // Skip immutable samplers as they are initialized directly in the resource cache by the PSO
8989 constexpr bool CountImtblSamplers = false;
100100 }
101101
102102
103 ShaderResourceLayoutD3D11::ShaderResourceLayoutD3D11(IObject& Owner,
104 std::shared_ptr<const ShaderResourcesD3D11> pSrcResources,
105 const PipelineResourceLayoutDesc& ResourceLayout,
106 const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes,
107 Uint32 NumVarTypes,
108 ShaderResourceCacheD3D11& ResourceCache,
109 IMemoryAllocator& ResCacheDataAllocator,
110 IMemoryAllocator& ResLayoutDataAllocator) :
111 // clang-format off
112 m_Owner {Owner},
113 m_pResources {std::move(pSrcResources)},
114 m_ResourceCache {ResourceCache}
115 // clang-format on
116 {
103 void ShaderResourceLayoutD3D11::Initialize(std::shared_ptr<const ShaderResourcesD3D11> pSrcResources,
104 const PipelineResourceLayoutDesc& ResourceLayout,
105 const SHADER_RESOURCE_VARIABLE_TYPE* VarTypes,
106 Uint32 NumVarTypes,
107 IMemoryAllocator& ResCacheDataAllocator,
108 IMemoryAllocator& ResLayoutDataAllocator)
109 {
110 m_pResources = std::move(pSrcResources);
111
117112 // http://diligentgraphics.com/diligent-engine/architecture/d3d11/shader-resource-layout#Shader-Resource-Layout-Initialization
118113
119114 const auto AllowedTypeBits = GetAllowedTypeBits(VarTypes, NumVarTypes);
132132 };
133133
134134 template <typename PSOCreateInfoType>
135 LinearAllocator InitInternalObjects(const PSOCreateInfoType& CreateInfo, std::vector<D3D12PipelineShaderStageInfo>& ShaderStages);
135 void InitInternalObjects(const PSOCreateInfoType& CreateInfo, std::vector<D3D12PipelineShaderStageInfo>& ShaderStages);
136136
137137 void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
138138 std::vector<D3D12PipelineShaderStageInfo>& ShaderStages);
139
140 void Destruct();
139141
140142 CComPtr<ID3D12PipelineState> m_pd3d12PSO;
141143 RootSignature m_RootSig;
109109 SRBResources
110110 };
111111
112 ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType)
112 ShaderResourceCacheD3D12(DbgCacheContentType dbgContentType) noexcept
113113 // clang-format off
114114 #ifdef DILIGENT_DEBUG
115115 : m_DbgContentType
111111 class ShaderResourceLayoutD3D12 final
112112 {
113113 public:
114 // There are two modes a layout can be constructed:
114 explicit ShaderResourceLayoutD3D12(IObject& Owner) noexcept :
115 m_Owner{Owner}
116 {}
117
118 // There are two modes a layout can be initialized:
115119 // - initialize static resource layout and initialize shader resource cache to hold static resources
116120 // - initialize reference layouts that address all types of resources (static, mutable, dynamic).
117121 // Root indices and descriptor table offsets are assigned during the initialization;
118122 // no shader resource cache is provided
119 ShaderResourceLayoutD3D12(IObject& Owner,
120 ID3D12Device* pd3d12Device,
121 PIPELINE_TYPE PipelineType,
122 const PipelineResourceLayoutDesc& ResourceLayout,
123 std::shared_ptr<const ShaderResourcesD3D12> pSrcResources,
124 IMemoryAllocator& LayoutDataAllocator,
125 const SHADER_RESOURCE_VARIABLE_TYPE* const VarTypes,
126 Uint32 NumAllowedTypes,
127 ShaderResourceCacheD3D12* pResourceCache,
128 class RootSignature* pRootSig);
123 void Initialize(ID3D12Device* pd3d12Device,
124 PIPELINE_TYPE PipelineType,
125 const PipelineResourceLayoutDesc& ResourceLayout,
126 std::shared_ptr<const ShaderResourcesD3D12> pSrcResources,
127 IMemoryAllocator& LayoutDataAllocator,
128 const SHADER_RESOURCE_VARIABLE_TYPE* const VarTypes,
129 Uint32 NumAllowedTypes,
130 ShaderResourceCacheD3D12* pResourceCache,
131 class RootSignature* pRootSig);
129132
130133 // clang-format off
131134 ShaderResourceLayoutD3D12 (const ShaderResourceLayoutD3D12&) = delete;
7575 class ShaderVariableManagerD3D12
7676 {
7777 public:
78 ShaderVariableManagerD3D12(IObject& Owner,
79 const ShaderResourceLayoutD3D12& Layout,
80 IMemoryAllocator& Allocator,
81 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
82 Uint32 NumAllowedTypes,
83 ShaderResourceCacheD3D12& ResourceCache);
78 ShaderVariableManagerD3D12(IObject& Owner,
79 ShaderResourceCacheD3D12& ResourceCache) noexcept :
80 m_Owner{Owner},
81 m_ResourceCache{ResourceCache}
82 {}
83
84 void Initialize(const ShaderResourceLayoutD3D12& Layout,
85 IMemoryAllocator& Allocator,
86 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
87 Uint32 NumAllowedTypes);
8488 ~ShaderVariableManagerD3D12();
8589
8690 void Destroy(IMemoryAllocator& Allocator);
119123 Uint32 m_NumVariables = 0;
120124
121125 #ifdef DILIGENT_DEBUG
122 IMemoryAllocator& m_DbgAllocator;
126 IMemoryAllocator* m_pDbgAllocator = nullptr;
123127 #endif
124128 // clang-format on
125129 };
9898 };
9999
100100 template <typename PSOCreateInfoType>
101 LinearAllocator PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo,
102 std::vector<D3D12PipelineShaderStageInfo>& ShaderStages)
101 void PipelineStateD3D12Impl::InitInternalObjects(const PSOCreateInfoType& CreateInfo,
102 std::vector<D3D12PipelineShaderStageInfo>& ShaderStages)
103103 {
104104 m_ResourceLayoutIndex.fill(-1);
105105
106106 ExtractShaders<ShaderD3D12Impl>(CreateInfo, ShaderStages);
107107
108 // Memory must be released if an exception is thrown.
109108 LinearAllocator MemPool{GetRawAllocator()};
110109
111 MemPool.AddSpace<ShaderResourceLayoutD3D12>(GetNumShaderStages() * 2);
112 MemPool.AddSpace<ShaderResourceCacheD3D12>(GetNumShaderStages());
113 MemPool.AddSpace<ShaderVariableManagerD3D12>(GetNumShaderStages());
110 const auto NumShaderStages = GetNumShaderStages();
111 VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size());
112
113 MemPool.AddSpace<ShaderResourceCacheD3D12>(NumShaderStages);
114 MemPool.AddSpace<ShaderResourceLayoutD3D12>(NumShaderStages * 2);
115 MemPool.AddSpace<ShaderVariableManagerD3D12>(NumShaderStages);
114116
115117 ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
116118
117119 MemPool.Reserve();
118120
121 m_pStaticResourceCaches = MemPool.ConstructArray<ShaderResourceCacheD3D12>(NumShaderStages, ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources);
122
123 // The memory is now owned by PipelineStateD3D12Impl and will be freed by Destruct().
124 auto* Ptr = MemPool.ReleaseOwnership();
125 VERIFY_EXPR(Ptr == m_pStaticResourceCaches);
126 (void)Ptr;
127
128 m_pShaderResourceLayouts = MemPool.ConstructArray<ShaderResourceLayoutD3D12>(NumShaderStages * 2, std::ref(*this));
129
130 m_pStaticVarManagers = MemPool.Allocate<ShaderVariableManagerD3D12>(NumShaderStages);
131 for (Uint32 s = 0; s < NumShaderStages; ++s)
132 new (m_pStaticVarManagers + s) ShaderVariableManagerD3D12{*this, GetStaticShaderResCache(s)};
133
134 InitializePipelineDesc(CreateInfo, MemPool);
135
119136 m_RootSig.AllocateImmutableSamplers(CreateInfo.PSODesc.ResourceLayout);
120137
121 m_pShaderResourceLayouts = MemPool.Allocate<ShaderResourceLayoutD3D12>(GetNumShaderStages() * 2);
122 m_pStaticResourceCaches = MemPool.Allocate<ShaderResourceCacheD3D12>(GetNumShaderStages());
123 m_pStaticVarManagers = MemPool.Allocate<ShaderVariableManagerD3D12>(GetNumShaderStages());
124
125 InitializePipelineDesc(CreateInfo, MemPool);
138 // It is important to construct all objects before initializing them because if an exception is thrown,
139 // destructors will be called for all objects
140
126141 InitResourceLayouts(CreateInfo, ShaderStages);
127
128 return MemPool;
129142 }
130143
131144
135148 TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc},
136149 m_SRBMemAllocator{GetRawAllocator()}
137150 {
138 std::vector<D3D12PipelineShaderStageInfo> ShaderStages;
139
140 auto MemPool = InitInternalObjects(CreateInfo, ShaderStages);
141
142 auto pd3d12Device = pDeviceD3D12->GetD3D12Device();
143 if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS)
144 {
145 const auto& GraphicsPipeline = GetGraphicsPipelineDesc();
146
147 D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {};
148
149 for (const auto& Stage : ShaderStages)
150 {
151 auto* pShaderD3D12 = Stage.pShader;
152 auto ShaderType = pShaderD3D12->GetDesc().ShaderType;
153 VERIFY_EXPR(ShaderType == Stage.Type);
154
155 D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr;
156 switch (ShaderType)
151 try
152 {
153 std::vector<D3D12PipelineShaderStageInfo> ShaderStages;
154
155 InitInternalObjects(CreateInfo, ShaderStages);
156
157 auto pd3d12Device = pDeviceD3D12->GetD3D12Device();
158 if (m_Desc.PipelineType == PIPELINE_TYPE_GRAPHICS)
159 {
160 const auto& GraphicsPipeline = GetGraphicsPipelineDesc();
161
162 D3D12_GRAPHICS_PIPELINE_STATE_DESC d3d12PSODesc = {};
163
164 for (const auto& Stage : ShaderStages)
157165 {
158 // clang-format off
166 auto* pShaderD3D12 = Stage.pShader;
167 auto ShaderType = pShaderD3D12->GetDesc().ShaderType;
168 VERIFY_EXPR(ShaderType == Stage.Type);
169
170 D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr;
171 switch (ShaderType)
172 {
173 // clang-format off
159174 case SHADER_TYPE_VERTEX: pd3d12ShaderBytecode = &d3d12PSODesc.VS; break;
160175 case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break;
161176 case SHADER_TYPE_GEOMETRY: pd3d12ShaderBytecode = &d3d12PSODesc.GS; break;
162177 case SHADER_TYPE_HULL: pd3d12ShaderBytecode = &d3d12PSODesc.HS; break;
163178 case SHADER_TYPE_DOMAIN: pd3d12ShaderBytecode = &d3d12PSODesc.DS; break;
164 // clang-format on
165 default: UNEXPECTED("Unexpected shader type");
179 // clang-format on
180 default: UNEXPECTED("Unexpected shader type");
181 }
182 auto* pByteCode = pShaderD3D12->GetShaderByteCode();
183
184 pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer();
185 pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize();
166186 }
167 auto* pByteCode = pShaderD3D12->GetShaderByteCode();
168
169 pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer();
170 pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize();
171 }
172
173 d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature();
174
175 memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput));
176
177 BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, d3d12PSODesc.BlendState);
178 // The sample mask for the blend state.
179 d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask;
180
181 RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, d3d12PSODesc.RasterizerState);
182 DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, d3d12PSODesc.DepthStencilState);
183
184 std::vector<D3D12_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D12_INPUT_ELEMENT_DESC>> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<D3D12_INPUT_ELEMENT_DESC>"));
185
186 const auto& InputLayout = GetGraphicsPipelineDesc().InputLayout;
187 if (InputLayout.NumElements > 0)
188 {
189 LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements);
190 d3d12PSODesc.InputLayout.NumElements = static_cast<UINT>(d312InputElements.size());
191 d3d12PSODesc.InputLayout.pInputElementDescs = d312InputElements.data();
192 }
193 else
194 {
195 d3d12PSODesc.InputLayout.NumElements = 0;
196 d3d12PSODesc.InputLayout.pInputElementDescs = nullptr;
197 }
198
199 d3d12PSODesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
200 static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType;
201 d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology];
202
203 d3d12PSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets;
204 for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt)
205 d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]);
206 for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormats); ++rt)
207 d3d12PSODesc.RTVFormats[rt] = DXGI_FORMAT_UNKNOWN;
208 d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat);
209
210 d3d12PSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count;
211 d3d12PSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality;
212
213 // For single GPU operation, set this to zero. If there are multiple GPU nodes,
214 // set bits to identify the nodes (the device's physical adapters) for which the
215 // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
216 d3d12PSODesc.NodeMask = 0;
217
218 d3d12PSODesc.CachedPSO.pCachedBlob = nullptr;
219 d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0;
220
221 // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
222 d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
223
224 HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO)));
225 if (FAILED(hr))
226 LOG_ERROR_AND_THROW("Failed to create pipeline state");
227 }
187
188 d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature();
189
190 memset(&d3d12PSODesc.StreamOutput, 0, sizeof(d3d12PSODesc.StreamOutput));
191
192 BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, d3d12PSODesc.BlendState);
193 // The sample mask for the blend state.
194 d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask;
195
196 RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, d3d12PSODesc.RasterizerState);
197 DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, d3d12PSODesc.DepthStencilState);
198
199 std::vector<D3D12_INPUT_ELEMENT_DESC, STDAllocatorRawMem<D3D12_INPUT_ELEMENT_DESC>> d312InputElements(STD_ALLOCATOR_RAW_MEM(D3D12_INPUT_ELEMENT_DESC, GetRawAllocator(), "Allocator for vector<D3D12_INPUT_ELEMENT_DESC>"));
200
201 const auto& InputLayout = GetGraphicsPipelineDesc().InputLayout;
202 if (InputLayout.NumElements > 0)
203 {
204 LayoutElements_To_D3D12_INPUT_ELEMENT_DESCs(InputLayout, d312InputElements);
205 d3d12PSODesc.InputLayout.NumElements = static_cast<UINT>(d312InputElements.size());
206 d3d12PSODesc.InputLayout.pInputElementDescs = d312InputElements.data();
207 }
208 else
209 {
210 d3d12PSODesc.InputLayout.NumElements = 0;
211 d3d12PSODesc.InputLayout.pInputElementDescs = nullptr;
212 }
213
214 d3d12PSODesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
215 static const PrimitiveTopology_To_D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimTopologyToD3D12TopologyType;
216 d3d12PSODesc.PrimitiveTopologyType = PrimTopologyToD3D12TopologyType[GraphicsPipeline.PrimitiveTopology];
217
218 d3d12PSODesc.NumRenderTargets = GraphicsPipeline.NumRenderTargets;
219 for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt)
220 d3d12PSODesc.RTVFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]);
221 for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormats); ++rt)
222 d3d12PSODesc.RTVFormats[rt] = DXGI_FORMAT_UNKNOWN;
223 d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat);
224
225 d3d12PSODesc.SampleDesc.Count = GraphicsPipeline.SmplDesc.Count;
226 d3d12PSODesc.SampleDesc.Quality = GraphicsPipeline.SmplDesc.Quality;
227
228 // For single GPU operation, set this to zero. If there are multiple GPU nodes,
229 // set bits to identify the nodes (the device's physical adapters) for which the
230 // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
231 d3d12PSODesc.NodeMask = 0;
232
233 d3d12PSODesc.CachedPSO.pCachedBlob = nullptr;
234 d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0;
235
236 // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
237 d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
238
239 HRESULT hr = pd3d12Device->CreateGraphicsPipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO)));
240 if (FAILED(hr))
241 LOG_ERROR_AND_THROW("Failed to create pipeline state");
242 }
228243
229244 #ifdef D3D12_H_HAS_MESH_SHADER
230 else if (m_Desc.PipelineType == PIPELINE_TYPE_MESH)
231 {
232 const auto& GraphicsPipeline = GetGraphicsPipelineDesc();
233
234 struct MESH_SHADER_PIPELINE_STATE_DESC
235 {
236 PSS_SubObject<D3D12_PIPELINE_STATE_FLAGS, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS> Flags;
237 PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK> NodeMask;
238 PSS_SubObject<ID3D12RootSignature*, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> pRootSignature;
239 PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
240 PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS> AS;
241 PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS> MS;
242 PSS_SubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> BlendState;
243 PSS_SubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> DepthStencilState;
244 PSS_SubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> RasterizerState;
245 PSS_SubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> SampleDesc;
246 PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> SampleMask;
247 PSS_SubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> DSVFormat;
248 PSS_SubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> RTVFormatArray;
249 PSS_SubObject<D3D12_CACHED_PIPELINE_STATE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO> CachedPSO;
250 };
251 MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {};
252
253 for (const auto& Stage : ShaderStages)
254 {
255 auto* pShaderD3D12 = Stage.pShader;
256 auto ShaderType = pShaderD3D12->GetDesc().ShaderType;
257 VERIFY_EXPR(ShaderType == Stage.Type);
258
259 D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr;
260 switch (ShaderType)
245 else if (m_Desc.PipelineType == PIPELINE_TYPE_MESH)
246 {
247 const auto& GraphicsPipeline = GetGraphicsPipelineDesc();
248
249 struct MESH_SHADER_PIPELINE_STATE_DESC
261250 {
262 // clang-format off
251 PSS_SubObject<D3D12_PIPELINE_STATE_FLAGS, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS> Flags;
252 PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_NODE_MASK> NodeMask;
253 PSS_SubObject<ID3D12RootSignature*, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> pRootSignature;
254 PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
255 PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS> AS;
256 PSS_SubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS> MS;
257 PSS_SubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> BlendState;
258 PSS_SubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> DepthStencilState;
259 PSS_SubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> RasterizerState;
260 PSS_SubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> SampleDesc;
261 PSS_SubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> SampleMask;
262 PSS_SubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> DSVFormat;
263 PSS_SubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> RTVFormatArray;
264 PSS_SubObject<D3D12_CACHED_PIPELINE_STATE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CACHED_PSO> CachedPSO;
265 };
266 MESH_SHADER_PIPELINE_STATE_DESC d3d12PSODesc = {};
267
268 for (const auto& Stage : ShaderStages)
269 {
270 auto* pShaderD3D12 = Stage.pShader;
271 auto ShaderType = pShaderD3D12->GetDesc().ShaderType;
272 VERIFY_EXPR(ShaderType == Stage.Type);
273
274 D3D12_SHADER_BYTECODE* pd3d12ShaderBytecode = nullptr;
275 switch (ShaderType)
276 {
277 // clang-format off
263278 case SHADER_TYPE_AMPLIFICATION: pd3d12ShaderBytecode = &d3d12PSODesc.AS; break;
264279 case SHADER_TYPE_MESH: pd3d12ShaderBytecode = &d3d12PSODesc.MS; break;
265280 case SHADER_TYPE_PIXEL: pd3d12ShaderBytecode = &d3d12PSODesc.PS; break;
266 // clang-format on
267 default: UNEXPECTED("Unexpected shader type");
281 // clang-format on
282 default: UNEXPECTED("Unexpected shader type");
283 }
284 auto* pByteCode = pShaderD3D12->GetShaderByteCode();
285
286 pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer();
287 pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize();
268288 }
269 auto* pByteCode = pShaderD3D12->GetShaderByteCode();
270
271 pd3d12ShaderBytecode->pShaderBytecode = pByteCode->GetBufferPointer();
272 pd3d12ShaderBytecode->BytecodeLength = pByteCode->GetBufferSize();
273 }
274
275 d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature();
276
277 BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState);
278 d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask;
279
280 RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, *d3d12PSODesc.RasterizerState);
281 DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, *d3d12PSODesc.DepthStencilState);
282
283 d3d12PSODesc.RTVFormatArray->NumRenderTargets = GraphicsPipeline.NumRenderTargets;
284 for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt)
285 d3d12PSODesc.RTVFormatArray->RTFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]);
286 for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormatArray->RTFormats); ++rt)
287 d3d12PSODesc.RTVFormatArray->RTFormats[rt] = DXGI_FORMAT_UNKNOWN;
288 d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat);
289
290 d3d12PSODesc.SampleDesc->Count = GraphicsPipeline.SmplDesc.Count;
291 d3d12PSODesc.SampleDesc->Quality = GraphicsPipeline.SmplDesc.Quality;
292
293 // For single GPU operation, set this to zero. If there are multiple GPU nodes,
294 // set bits to identify the nodes (the device's physical adapters) for which the
295 // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
296 d3d12PSODesc.NodeMask = 0;
297
298 d3d12PSODesc.CachedPSO->pCachedBlob = nullptr;
299 d3d12PSODesc.CachedPSO->CachedBlobSizeInBytes = 0;
300
301 // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
302 d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
303
304 D3D12_PIPELINE_STATE_STREAM_DESC streamDesc;
305 streamDesc.SizeInBytes = sizeof(d3d12PSODesc);
306 streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc;
307
308 auto* device2 = pDeviceD3D12->GetD3D12Device2();
309
310 CHECK_D3D_RESULT_THROW(device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)), "Failed to create pipeline state");
311 }
289
290 d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature();
291
292 BlendStateDesc_To_D3D12_BLEND_DESC(GraphicsPipeline.BlendDesc, *d3d12PSODesc.BlendState);
293 d3d12PSODesc.SampleMask = GraphicsPipeline.SampleMask;
294
295 RasterizerStateDesc_To_D3D12_RASTERIZER_DESC(GraphicsPipeline.RasterizerDesc, *d3d12PSODesc.RasterizerState);
296 DepthStencilStateDesc_To_D3D12_DEPTH_STENCIL_DESC(GraphicsPipeline.DepthStencilDesc, *d3d12PSODesc.DepthStencilState);
297
298 d3d12PSODesc.RTVFormatArray->NumRenderTargets = GraphicsPipeline.NumRenderTargets;
299 for (Uint32 rt = 0; rt < GraphicsPipeline.NumRenderTargets; ++rt)
300 d3d12PSODesc.RTVFormatArray->RTFormats[rt] = TexFormatToDXGI_Format(GraphicsPipeline.RTVFormats[rt]);
301 for (Uint32 rt = GraphicsPipeline.NumRenderTargets; rt < _countof(d3d12PSODesc.RTVFormatArray->RTFormats); ++rt)
302 d3d12PSODesc.RTVFormatArray->RTFormats[rt] = DXGI_FORMAT_UNKNOWN;
303 d3d12PSODesc.DSVFormat = TexFormatToDXGI_Format(GraphicsPipeline.DSVFormat);
304
305 d3d12PSODesc.SampleDesc->Count = GraphicsPipeline.SmplDesc.Count;
306 d3d12PSODesc.SampleDesc->Quality = GraphicsPipeline.SmplDesc.Quality;
307
308 // For single GPU operation, set this to zero. If there are multiple GPU nodes,
309 // set bits to identify the nodes (the device's physical adapters) for which the
310 // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
311 d3d12PSODesc.NodeMask = 0;
312
313 d3d12PSODesc.CachedPSO->pCachedBlob = nullptr;
314 d3d12PSODesc.CachedPSO->CachedBlobSizeInBytes = 0;
315
316 // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
317 d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
318
319 D3D12_PIPELINE_STATE_STREAM_DESC streamDesc;
320 streamDesc.SizeInBytes = sizeof(d3d12PSODesc);
321 streamDesc.pPipelineStateSubobjectStream = &d3d12PSODesc;
322
323 auto* device2 = pDeviceD3D12->GetD3D12Device2();
324
325 CHECK_D3D_RESULT_THROW(device2->CreatePipelineState(&streamDesc, IID_PPV_ARGS(&m_pd3d12PSO)), "Failed to create pipeline state");
326 }
312327 #endif // D3D12_H_HAS_MESH_SHADER
313 else
314 {
315 LOG_ERROR_AND_THROW("Unsupported pipeline type");
316 }
317
318 if (*m_Desc.Name != 0)
319 {
320 m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str());
321 String RootSignatureDesc("Root signature for PSO '");
322 RootSignatureDesc.append(m_Desc.Name);
323 RootSignatureDesc.push_back('\'');
324 m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str());
325 }
326
327 void* Ptr = MemPool.Release();
328 VERIFY_EXPR(Ptr == m_pShaderResourceLayouts);
328 else
329 {
330 LOG_ERROR_AND_THROW("Unsupported pipeline type");
331 }
332
333 if (*m_Desc.Name != 0)
334 {
335 m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str());
336 String RootSignatureDesc("Root signature for PSO '");
337 RootSignatureDesc.append(m_Desc.Name);
338 RootSignatureDesc.push_back('\'');
339 m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str());
340 }
341 }
342 catch (...)
343 {
344 Destruct();
345 throw;
346 }
329347 }
330348
331349 PipelineStateD3D12Impl::PipelineStateD3D12Impl(IReferenceCounters* pRefCounters,
334352 TPipelineStateBase{pRefCounters, pDeviceD3D12, CreateInfo.PSODesc},
335353 m_SRBMemAllocator{GetRawAllocator()}
336354 {
337 std::vector<D3D12PipelineShaderStageInfo> ShaderStages;
338
339 auto MemPool = InitInternalObjects(CreateInfo, ShaderStages);
340
341 auto pd3d12Device = pDeviceD3D12->GetD3D12Device();
342
343 D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {};
344
345 VERIFY_EXPR(ShaderStages[0].Type == SHADER_TYPE_COMPUTE);
346 auto* pByteCode = ShaderStages[0].pShader->GetShaderByteCode();
347 d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer();
348 d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize();
349
350 // For single GPU operation, set this to zero. If there are multiple GPU nodes,
351 // set bits to identify the nodes (the device's physical adapters) for which the
352 // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
353 d3d12PSODesc.NodeMask = 0;
354
355 d3d12PSODesc.CachedPSO.pCachedBlob = nullptr;
356 d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0;
357
358 // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
359 d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
360
361 d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature();
362
363 HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO)));
364 if (FAILED(hr))
365 LOG_ERROR_AND_THROW("Failed to create pipeline state");
366
367 if (*m_Desc.Name != 0)
368 {
369 m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str());
370 String RootSignatureDesc("Root signature for PSO '");
371 RootSignatureDesc.append(m_Desc.Name);
372 RootSignatureDesc.push_back('\'');
373 m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str());
374 }
375
376 void* Ptr = MemPool.Release();
377 VERIFY_EXPR(Ptr == m_pShaderResourceLayouts);
355 try
356 {
357 std::vector<D3D12PipelineShaderStageInfo> ShaderStages;
358
359 InitInternalObjects(CreateInfo, ShaderStages);
360
361 auto pd3d12Device = pDeviceD3D12->GetD3D12Device();
362
363 D3D12_COMPUTE_PIPELINE_STATE_DESC d3d12PSODesc = {};
364
365 VERIFY_EXPR(ShaderStages[0].Type == SHADER_TYPE_COMPUTE);
366 auto* pByteCode = ShaderStages[0].pShader->GetShaderByteCode();
367 d3d12PSODesc.CS.pShaderBytecode = pByteCode->GetBufferPointer();
368 d3d12PSODesc.CS.BytecodeLength = pByteCode->GetBufferSize();
369
370 // For single GPU operation, set this to zero. If there are multiple GPU nodes,
371 // set bits to identify the nodes (the device's physical adapters) for which the
372 // graphics pipeline state is to apply. Each bit in the mask corresponds to a single node.
373 d3d12PSODesc.NodeMask = 0;
374
375 d3d12PSODesc.CachedPSO.pCachedBlob = nullptr;
376 d3d12PSODesc.CachedPSO.CachedBlobSizeInBytes = 0;
377
378 // The only valid bit is D3D12_PIPELINE_STATE_FLAG_TOOL_DEBUG, which can only be set on WARP devices.
379 d3d12PSODesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
380
381 d3d12PSODesc.pRootSignature = m_RootSig.GetD3D12RootSignature();
382
383 HRESULT hr = pd3d12Device->CreateComputePipelineState(&d3d12PSODesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(static_cast<ID3D12PipelineState**>(&m_pd3d12PSO)));
384 if (FAILED(hr))
385 LOG_ERROR_AND_THROW("Failed to create pipeline state");
386
387 if (*m_Desc.Name != 0)
388 {
389 m_pd3d12PSO->SetName(WidenString(m_Desc.Name).c_str());
390 String RootSignatureDesc("Root signature for PSO '");
391 RootSignatureDesc.append(m_Desc.Name);
392 RootSignatureDesc.push_back('\'');
393 m_RootSig.GetD3D12RootSignature()->SetName(WidenString(RootSignatureDesc).c_str());
394 }
395 }
396 catch (...)
397 {
398 Destruct();
399 throw;
400 }
378401 }
379402
380403 PipelineStateD3D12Impl::~PipelineStateD3D12Impl()
404 {
405 Destruct();
406 }
407
408 void PipelineStateD3D12Impl::Destruct()
381409 {
382410 auto& ShaderResLayoutAllocator = GetRawAllocator();
383411 for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
384412 {
385 m_pStaticVarManagers[s].Destroy(GetRawAllocator());
386 m_pStaticVarManagers[s].~ShaderVariableManagerD3D12();
387 m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12();
388 m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12();
389 m_pShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutD3D12();
390 }
391 // m_pShaderResourceLayouts, m_pStaticResourceCaches, and m_pShaderResourceLayouts are allocated in
392 // contiguous chunks of memory.
393 auto* pRawMem = m_pShaderResourceLayouts;
394 ShaderResLayoutAllocator.Free(pRawMem);
395
396 // D3D12 object can only be destroyed when it is no longer used by the GPU
397 m_pDevice->SafeReleaseDeviceObject(std::move(m_pd3d12PSO), m_Desc.CommandQueueMask);
413 if (m_pStaticVarManagers != nullptr)
414 {
415 m_pStaticVarManagers[s].Destroy(GetRawAllocator());
416 m_pStaticVarManagers[s].~ShaderVariableManagerD3D12();
417 }
418
419 if (m_pShaderResourceLayouts != nullptr)
420 {
421 m_pShaderResourceLayouts[s].~ShaderResourceLayoutD3D12();
422 m_pShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutD3D12();
423 }
424
425 if (m_pStaticResourceCaches != nullptr)
426 {
427 m_pStaticResourceCaches[s].~ShaderResourceCacheD3D12();
428 }
429 }
430 // All internal objects are allocated in contiguous chunks of memory.
431 if (auto* pRawMem = m_pStaticResourceCaches)
432 {
433 ShaderResLayoutAllocator.Free(pRawMem);
434 }
435
436 if (m_pd3d12PSO)
437 {
438 // D3D12 object can only be destroyed when it is no longer used by the GPU
439 m_pDevice->SafeReleaseDeviceObject(std::move(m_pd3d12PSO), m_Desc.CommandQueueMask);
440 }
398441 }
399442
400443 IMPLEMENT_QUERY_INTERFACE(PipelineStateD3D12Impl, IID_PipelineStateD3D12, TPipelineStateBase)
428471
429472 m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s);
430473
431 new (m_pShaderResourceLayouts + s)
432 ShaderResourceLayoutD3D12 //
433 {
434 *this,
435 pd3d12Device,
436 m_Desc.PipelineType,
437 ResourceLayout,
438 pShaderD3D12->GetShaderResources(),
439 GetRawAllocator(),
440 nullptr,
441 0,
442 nullptr,
443 &m_RootSig //
444 };
445
446 new (m_pStaticResourceCaches + s) ShaderResourceCacheD3D12{ShaderResourceCacheD3D12::DbgCacheContentType::StaticShaderResources};
474 m_pShaderResourceLayouts[s].Initialize(
475 pd3d12Device,
476 m_Desc.PipelineType,
477 ResourceLayout,
478 pShaderD3D12->GetShaderResources(),
479 GetRawAllocator(),
480 nullptr,
481 0,
482 nullptr,
483 &m_RootSig //
484 );
447485
448486 const SHADER_RESOURCE_VARIABLE_TYPE StaticVarType[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
449 new (m_pShaderResourceLayouts + GetNumShaderStages() + s)
450 ShaderResourceLayoutD3D12 //
451 {
452 *this,
453 pd3d12Device,
454 m_Desc.PipelineType,
455 ResourceLayout,
456 pShaderD3D12->GetShaderResources(),
457 GetRawAllocator(),
458 StaticVarType,
459 _countof(StaticVarType),
460 m_pStaticResourceCaches + s,
461 nullptr //
462 };
463
464 new (m_pStaticVarManagers + s)
465 ShaderVariableManagerD3D12 //
466 {
467 *this,
468 GetStaticShaderResLayout(static_cast<Uint32>(s)),
469 GetRawAllocator(),
470 nullptr,
471 0,
472 GetStaticShaderResCache(static_cast<Uint32>(s)) //
473 };
487 m_pShaderResourceLayouts[GetNumShaderStages() + s].Initialize(
488 pd3d12Device,
489 m_Desc.PipelineType,
490 ResourceLayout,
491 pShaderD3D12->GetShaderResources(),
492 GetRawAllocator(),
493 StaticVarType,
494 _countof(StaticVarType),
495 m_pStaticResourceCaches + s,
496 nullptr //
497 );
498
499 m_pStaticVarManagers[s].Initialize(
500 GetStaticShaderResLayout(static_cast<Uint32>(s)),
501 GetRawAllocator(),
502 nullptr,
503 0 //
504 );
474505 }
475506 m_RootSig.Finalize(pd3d12Device);
476507
6666 const SHADER_RESOURCE_VARIABLE_TYPE AllowedVarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
6767 const auto& SrcLayout = pPSO->GetShaderResLayout(s);
6868 // Create shader variable manager in place
69 new (m_pShaderVarMgrs + s)
70 ShaderVariableManagerD3D12 //
71 {
72 *this,
73 SrcLayout,
74 VarDataAllocator,
75 AllowedVarTypes,
76 _countof(AllowedVarTypes),
77 m_ShaderResourceCache //
78 };
69 new (m_pShaderVarMgrs + s) ShaderVariableManagerD3D12{*this, m_ShaderResourceCache};
70 m_pShaderVarMgrs[s].Initialize(
71 SrcLayout,
72 VarDataAllocator,
73 AllowedVarTypes,
74 _countof(AllowedVarTypes) //
75 );
7976
8077 m_ResourceLayoutIndex[ShaderInd] = static_cast<Int8>(s);
8178 }
112112
113113 // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-layout#Initializing-Shader-Resource-Layouts-and-Root-Signature-in-a-Pipeline-State-Object
114114 // http://diligentgraphics.com/diligent-engine/architecture/d3d12/shader-resource-cache#Initializing-Shader-Resource-Layouts-in-a-Pipeline-State
115 ShaderResourceLayoutD3D12::ShaderResourceLayoutD3D12(IObject& Owner,
116 ID3D12Device* pd3d12Device,
117 PIPELINE_TYPE PipelineType,
118 const PipelineResourceLayoutDesc& ResourceLayout,
119 std::shared_ptr<const ShaderResourcesD3D12> pSrcResources,
120 IMemoryAllocator& LayoutDataAllocator,
121 const SHADER_RESOURCE_VARIABLE_TYPE* const AllowedVarTypes,
122 Uint32 NumAllowedTypes,
123 ShaderResourceCacheD3D12* pResourceCache,
124 RootSignature* pRootSig) :
125 // clang-format off
126 m_Owner {Owner},
127 m_pd3d12Device {pd3d12Device},
128 m_pResources {std::move(pSrcResources)}
129 // clang-format on
130 {
115 void ShaderResourceLayoutD3D12::Initialize(ID3D12Device* pd3d12Device,
116 PIPELINE_TYPE PipelineType,
117 const PipelineResourceLayoutDesc& ResourceLayout,
118 std::shared_ptr<const ShaderResourcesD3D12> pSrcResources,
119 IMemoryAllocator& LayoutDataAllocator,
120 const SHADER_RESOURCE_VARIABLE_TYPE* const AllowedVarTypes,
121 Uint32 NumAllowedTypes,
122 ShaderResourceCacheD3D12* pResourceCache,
123 RootSignature* pRootSig)
124 {
125 m_pd3d12Device = pd3d12Device;
126 m_pResources = std::move(pSrcResources);
127
131128 VERIFY_EXPR((pResourceCache != nullptr) ^ (pRootSig != nullptr));
132129
133130 const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
5353 }
5454
5555 // Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes
56 ShaderVariableManagerD3D12::ShaderVariableManagerD3D12(IObject& Owner,
57 const ShaderResourceLayoutD3D12& SrcLayout,
58 IMemoryAllocator& Allocator,
59 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
60 Uint32 NumAllowedTypes,
61 ShaderResourceCacheD3D12& ResourceCache) :
62 // clang-format off
63 m_Owner {Owner},
64 m_ResourceCache {ResourceCache}
56 void ShaderVariableManagerD3D12::Initialize(const ShaderResourceLayoutD3D12& SrcLayout,
57 IMemoryAllocator& Allocator,
58 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
59 Uint32 NumAllowedTypes)
60 {
6561 #ifdef DILIGENT_DEBUG
66 , m_DbgAllocator {Allocator}
62 m_pDbgAllocator = &Allocator;
6763 #endif
68 // clang-format on
69 {
64
7065 const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
7166 VERIFY_EXPR(m_NumVariables == 0);
7267 auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables);
112107
113108 void ShaderVariableManagerD3D12::Destroy(IMemoryAllocator& Allocator)
114109 {
115 VERIFY(&m_DbgAllocator == &Allocator, "Incosistent alloctor");
116
117110 if (m_pVariables != nullptr)
118111 {
112 VERIFY(m_pDbgAllocator == &Allocator, "Incosistent alloctor");
113
119114 for (Uint32 v = 0; v < m_NumVariables; ++v)
120115 m_pVariables[v].~ShaderVariableD3D12Impl();
121116 Allocator.Free(m_pVariables);
384384 const ShaderResources* const pShaderResources[],
385385 Uint32 NumShaders,
386386 bool VerifyVariables,
387 bool VerifyImmutableSamplers);
387 bool VerifyImmutableSamplers) noexcept;
388388 #endif
389389
390390 void GetShaderModel(Uint32& Major, Uint32& Minor) const
218218 const ShaderResources* const pShaderResources[],
219219 Uint32 NumShaders,
220220 bool VerifyVariables,
221 bool VerifyImmutableSamplers)
221 bool VerifyImmutableSamplers) noexcept
222222 {
223223 auto GetAllowedShadersString = [&](SHADER_TYPE ShaderStages) //
224224 {
4444 class GLProgramResourceCache
4545 {
4646 public:
47 GLProgramResourceCache()
47 GLProgramResourceCache() noexcept
4848 {}
4949
5050 ~GLProgramResourceCache();
113113 void InitResourceLayouts(const std::vector<GLPipelineShaderStageInfo>& ShaderStages,
114114 LinearAllocator& MemPool);
115115
116 void Destruct();
117
116118 // Linked GL programs for every shader stage. Every pipeline needs to have its own programs
117119 // because resource bindings assigned by GLProgramResources::LoadUniforms depend on other
118120 // shader stages.
9191
9292 void GLProgramResourceCache::Destroy(IMemoryAllocator& MemAllocator)
9393 {
94 VERIFY(IsInitialized(), "Resource cache is not initialized");
94 if (!IsInitialized())
95 return;
96
9597 VERIFY(m_pdbgMemoryAllocator == &MemAllocator, "The allocator does not match the one used to create resources");
9698
9799 for (Uint32 cb = 0; cb < GetUBCount(); ++cb)
3939 template <typename PSOCreateInfoType>
4040 void PipelineStateGLImpl::Initialize(const PSOCreateInfoType& CreateInfo, const std::vector<GLPipelineShaderStageInfo>& ShaderStages)
4141 {
42 // Memory must be released if an exception is thrown.
4342 LinearAllocator MemPool{GetRawAllocator()};
44
45 MemPool.AddSpace<GLProgramObj>(GetNumShaderStages());
46 MemPool.AddSpace<GLProgramResources>(GetNumShaderStages());
43 VERIFY_EXPR(m_NumShaderStages > 0 && m_NumShaderStages == ShaderStages.size());
44 if (!GetDevice()->GetDeviceCaps().Features.SeparablePrograms)
45 m_NumShaderStages = 1;
46
47 const auto NumPrograms = GetNumShaderStages();
48
49 MemPool.AddSpace<GLProgramObj>(NumPrograms);
50 MemPool.AddSpace<GLProgramResources>(NumPrograms);
4751 MemPool.AddSpace<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers);
4852
4953 ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
5054
5155 MemPool.Reserve();
56
57 m_GLPrograms = MemPool.ConstructArray<GLProgramObj>(NumPrograms, false);
58
59 // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct().
60 auto* Ptr = MemPool.ReleaseOwnership();
61 VERIFY_EXPR(Ptr == m_GLPrograms);
62 (void)Ptr;
63
64 m_ProgramResources = MemPool.ConstructArray<GLProgramResources>(NumPrograms);
65
66 m_ImmutableSamplers = MemPool.ConstructArray<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers);
67
68 // It is important to construct all objects before initializing them because if an exception is thrown,
69 // destructors will be called for all objects
5270
5371 InitResourceLayouts(ShaderStages, MemPool);
5472 InitializePipelineDesc(CreateInfo, MemPool);
55
56 void* Ptr = MemPool.Release();
57 VERIFY_EXPR(Ptr == m_GLPrograms);
5873 }
5974
6075 PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters,
7388 m_StaticResourceLayout{*this}
7489 // clang-format on
7590 {
76 std::vector<GLPipelineShaderStageInfo> ShaderStages;
77 ExtractShaders<ShaderGLImpl>(CreateInfo, ShaderStages);
78
79 RefCntAutoPtr<ShaderGLImpl> pTempPS;
80 if (CreateInfo.pPS == nullptr)
81 {
82 // Some OpenGL implementations fail if fragment shader is not present, so
83 // create a dummy one.
84 ShaderCreateInfo ShaderCI;
85 ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL;
86 ShaderCI.Source = "void main(){}";
87 ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL;
88 ShaderCI.Desc.Name = "Dummy fragment shader";
89 pDeviceGL->CreateShader(ShaderCI, reinterpret_cast<IShader**>(static_cast<ShaderGLImpl**>(&pTempPS)));
90
91 ShaderStages.emplace_back(SHADER_TYPE_PIXEL, pTempPS);
92 m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_PIXEL;
93 }
94
95 Initialize(CreateInfo, ShaderStages);
91 try
92 {
93 std::vector<GLPipelineShaderStageInfo> ShaderStages;
94 ExtractShaders<ShaderGLImpl>(CreateInfo, ShaderStages);
95
96 RefCntAutoPtr<ShaderGLImpl> pTempPS;
97 if (CreateInfo.pPS == nullptr)
98 {
99 // Some OpenGL implementations fail if fragment shader is not present, so
100 // create a dummy one.
101 ShaderCreateInfo ShaderCI;
102 ShaderCI.SourceLanguage = SHADER_SOURCE_LANGUAGE_GLSL;
103 ShaderCI.Source = "void main(){}";
104 ShaderCI.Desc.ShaderType = SHADER_TYPE_PIXEL;
105 ShaderCI.Desc.Name = "Dummy fragment shader";
106 pDeviceGL->CreateShader(ShaderCI, reinterpret_cast<IShader**>(static_cast<ShaderGLImpl**>(&pTempPS)));
107
108 ShaderStages.emplace_back(SHADER_TYPE_PIXEL, pTempPS);
109 m_ShaderStageTypes[m_NumShaderStages++] = SHADER_TYPE_PIXEL;
110 }
111
112 Initialize(CreateInfo, ShaderStages);
113 }
114 catch (...)
115 {
116 Destruct();
117 }
96118 }
97119
98120 PipelineStateGLImpl::PipelineStateGLImpl(IReferenceCounters* pRefCounters,
111133 m_StaticResourceLayout{*this}
112134 // clang-format on
113135 {
114 std::vector<GLPipelineShaderStageInfo> ShaderStages;
115 ExtractShaders<ShaderGLImpl>(CreateInfo, ShaderStages);
116
117 Initialize(CreateInfo, ShaderStages);
136 try
137 {
138 std::vector<GLPipelineShaderStageInfo> ShaderStages;
139 ExtractShaders<ShaderGLImpl>(CreateInfo, ShaderStages);
140
141 Initialize(CreateInfo, ShaderStages);
142 }
143 catch (...)
144 {
145 Destruct();
146 }
118147 }
119148
120149 PipelineStateGLImpl::~PipelineStateGLImpl()
150 {
151 Destruct();
152 }
153
154 void PipelineStateGLImpl::Destruct()
121155 {
122156 auto& RawAllocator = GetRawAllocator();
123157 m_StaticResourceCache.Destroy(RawAllocator);
124158 GetDevice()->OnDestroyPSO(this);
125159
160 if (m_ImmutableSamplers != nullptr)
161 {
162 for (Uint32 i = 0; i < m_Desc.ResourceLayout.NumImmutableSamplers; ++i)
163 {
164 m_ImmutableSamplers[i].~SamplerPtr();
165 }
166 }
167
126168 for (Uint32 i = 0; i < GetNumShaderStages(); ++i)
127169 {
128 m_GLPrograms[i].~GLProgramObj();
129 m_ProgramResources[i].~GLProgramResources();
130 }
131 for (Uint32 i = 0; i < m_Desc.ResourceLayout.NumImmutableSamplers; ++i)
132 {
133 m_ImmutableSamplers[i].~SamplerPtr();
134 }
135
136 void* pRawMem = m_GLPrograms;
137 RawAllocator.Free(pRawMem);
170 if (m_GLPrograms != nullptr)
171 {
172 m_GLPrograms[i].~GLProgramObj();
173 }
174 if (m_ProgramResources != nullptr)
175 {
176 m_ProgramResources[i].~GLProgramResources();
177 }
178 }
179
180 if (void* pRawMem = m_GLPrograms)
181 {
182 RawAllocator.Free(pRawMem);
183 }
138184 }
139185
140186 IMPLEMENT_QUERY_INTERFACE(PipelineStateGLImpl, IID_PipelineStateGL, TPipelineStateBase)
144190 LinearAllocator& MemPool)
145191 {
146192 auto* const pDeviceGL = GetDevice();
147 const auto& DeviceCaps = pDeviceGL->GetDeviceCaps();
148 VERIFY(DeviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized");
193 const auto& deviceCaps = pDeviceGL->GetDeviceCaps();
194 VERIFY(deviceCaps.DevType != RENDER_DEVICE_TYPE_UNDEFINED, "Device caps are not initialized");
149195
150196 auto pImmediateCtx = m_pDevice->GetImmediateContext();
151197 VERIFY_EXPR(pImmediateCtx);
156202 m_TotalSamplerBindings = 0;
157203 m_TotalImageBindings = 0;
158204 m_TotalStorageBufferBindings = 0;
159 if (DeviceCaps.Features.SeparablePrograms)
205 if (deviceCaps.Features.SeparablePrograms)
160206 {
161207 // Program pipelines are not shared between GL contexts, so we cannot create
162208 // it now
163209 m_ShaderResourceLayoutHash = 0;
164 m_GLPrograms = MemPool.Allocate<GLProgramObj>(ShaderStages.size());
165 m_ProgramResources = MemPool.ConstructArray<GLProgramResources>(ShaderStages.size());
166210 for (size_t i = 0; i < ShaderStages.size(); ++i)
167211 {
168212 auto* pShaderGL = ShaderStages[i].pShader;
169213 const auto& ShaderDesc = pShaderGL->GetDesc();
170 new (m_GLPrograms + i) GLProgramObj{ShaderGLImpl::LinkProgram(&pShaderGL, 1, true)};
214 m_GLPrograms[i] = GLProgramObj{ShaderGLImpl::LinkProgram(&pShaderGL, 1, true)};
171215 // Load uniforms and assign bindings
172216 m_ProgramResources[i].LoadUniforms(ShaderDesc.ShaderType, m_GLPrograms[i], GLState,
173217 m_TotalUniformBufferBindings,
190234 ActiveStages |= Stage.Type;
191235 }
192236
193 m_GLPrograms = MemPool.Construct<GLProgramObj>(ShaderGLImpl::LinkProgram(Shaders.data(), static_cast<Uint32>(ShaderStages.size()), false));
194 m_ProgramResources = MemPool.Construct<GLProgramResources>();
237 m_GLPrograms[0] = ShaderGLImpl::LinkProgram(Shaders.data(), static_cast<Uint32>(Shaders.size()), false);
195238
196239 m_ProgramResources[0].LoadUniforms(ActiveStages, m_GLPrograms[0], GLState,
197240 m_TotalUniformBufferBindings,
203246 }
204247
205248 // Initialize master resource layout that keeps all variable types and does not reference a resource cache
206 m_ResourceLayout.Initialize(m_ProgramResources, static_cast<Uint32>(ShaderStages.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr);
207 }
208
209 m_ImmutableSamplers = MemPool.ConstructArray<SamplerPtr>(m_Desc.ResourceLayout.NumImmutableSamplers);
249 m_ResourceLayout.Initialize(m_ProgramResources, GetNumShaderStages(), m_Desc.PipelineType, m_Desc.ResourceLayout, nullptr, 0, nullptr);
250 }
251
210252 for (Uint32 s = 0; s < m_Desc.ResourceLayout.NumImmutableSamplers; ++s)
211253 {
212254 pDeviceGL->CreateSampler(m_Desc.ResourceLayout.ImmutableSamplers[s].Desc, &m_ImmutableSamplers[s]);
215257 {
216258 // Clone only static variables into static resource layout, assign and initialize static resource cache
217259 const SHADER_RESOURCE_VARIABLE_TYPE StaticVars[] = {SHADER_RESOURCE_VARIABLE_TYPE_STATIC};
218 m_StaticResourceLayout.Initialize(m_ProgramResources, static_cast<Uint32>(ShaderStages.size()), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache);
260 m_StaticResourceLayout.Initialize(m_ProgramResources, GetNumShaderStages(), m_Desc.PipelineType, m_Desc.ResourceLayout, StaticVars, _countof(StaticVars), &m_StaticResourceCache);
219261 InitImmutableSamplersInResourceCache(m_StaticResourceLayout, m_StaticResourceCache);
220262 }
221263 }
128128 using TShaderStages = ShaderResourceLayoutVk::TShaderStages;
129129
130130 template <typename PSOCreateInfoType>
131 LinearAllocator InitInternalObjects(const PSOCreateInfoType& CreateInfo,
132 std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
133 std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules);
131 void InitInternalObjects(const PSOCreateInfoType& CreateInfo,
132 std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
133 std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules);
134134
135135 void InitResourceLayouts(const PipelineStateCreateInfo& CreateInfo,
136136 TShaderStages& ShaderStages);
137
138 void Destruct();
137139
138140 const ShaderResourceLayoutVk& GetStaticShaderResLayout(Uint32 ShaderInd) const
139141 {
147149 return m_StaticResCaches[ShaderInd];
148150 }
149151
150 ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const
152 const ShaderVariableManagerVk& GetStaticVarMgr(Uint32 ShaderInd) const
151153 {
152154 VERIFY_EXPR(ShaderInd < GetNumShaderStages());
153155 return m_StaticVarsMgrs[ShaderInd];
7474 };
7575
7676 // clang-format off
77 ShaderResourceCacheVk(DbgCacheContentType dbgContentType)
77 ShaderResourceCacheVk(DbgCacheContentType dbgContentType) noexcept
7878 #ifdef DILIGENT_DEBUG
7979 : m_DbgContentType{dbgContentType}
8080 #endif
127127 };
128128 using TShaderStages = std::vector<ShaderStageInfo>;
129129
130 ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) :
130 ShaderResourceLayoutVk(const VulkanUtilities::VulkanLogicalDevice& LogicalDevice) noexcept :
131131 m_LogicalDevice{LogicalDevice}
132132 {
133133 }
7272 class ShaderVariableManagerVk
7373 {
7474 public:
75 ShaderVariableManagerVk(IObject& Owner,
76 const ShaderResourceLayoutVk& SrcLayout,
77 IMemoryAllocator& Allocator,
78 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
79 Uint32 NumAllowedTypes,
80 ShaderResourceCacheVk& ResourceCache);
75 ShaderVariableManagerVk(IObject& Owner,
76 ShaderResourceCacheVk& ResourceCache) noexcept :
77 m_Owner{Owner},
78 m_ResourceCache{ResourceCache}
79 {}
80
81 void Initialize(const ShaderResourceLayoutVk& SrcLayout,
82 IMemoryAllocator& Allocator,
83 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
84 Uint32 NumAllowedTypes);
8185
8286 ~ShaderVariableManagerVk();
8387
8488 void DestroyVariables(IMemoryAllocator& Allocator);
8589
86 ShaderVariableVkImpl* GetVariable(const Char* Name);
87 ShaderVariableVkImpl* GetVariable(Uint32 Index);
88
89 void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags);
90 ShaderVariableVkImpl* GetVariable(const Char* Name) const;
91 ShaderVariableVkImpl* GetVariable(Uint32 Index) const;
92
93 void BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) const;
9094
9195 static size_t GetRequiredMemorySize(const ShaderResourceLayoutVk& Layout,
9296 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
114118 Uint32 m_NumVariables = 0;
115119
116120 #ifdef DILIGENT_DEBUG
117 IMemoryAllocator& m_DbgAllocator;
121 IMemoryAllocator* m_pDbgAllocator = nullptr;
118122 #endif
119123 };
120124
412412 const auto ShaderType = StageInfo.Type;
413413 const auto ShaderTypeInd = GetShaderTypePipelineIndex(ShaderType, m_Desc.PipelineType);
414414
415 new (m_ShaderResourceLayouts + s) ShaderResourceLayoutVk{LogicalDevice};
416
417415 m_ResourceLayoutIndex[ShaderTypeInd] = static_cast<Int8>(s);
418416
419 auto* pStaticResLayout = new (m_ShaderResourceLayouts + ShaderStages.size() + s) ShaderResourceLayoutVk{LogicalDevice};
420 auto* pStaticResCache = new (m_StaticResCaches + s) ShaderResourceCacheVk{ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources};
421 pStaticResLayout->InitializeStaticResourceLayout(StageInfo.pShader, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]);
422
423 new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, *pStaticResLayout, GetRawAllocator(), nullptr, 0, *pStaticResCache};
417 auto& StaticResLayout = m_ShaderResourceLayouts[GetNumShaderStages() + s];
418 StaticResLayout.InitializeStaticResourceLayout(StageInfo.pShader, GetRawAllocator(), m_Desc.ResourceLayout, m_StaticResCaches[s]);
419
420 m_StaticVarsMgrs[s].Initialize(StaticResLayout, GetRawAllocator(), nullptr, 0);
424421 }
425422 ShaderResourceLayoutVk::Initialize(pDeviceVk, ShaderStages, m_ShaderResourceLayouts, GetRawAllocator(),
426423 m_Desc.ResourceLayout, m_PipelineLayout,
463460 }
464461
465462 template <typename PSOCreateInfoType>
466 LinearAllocator PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType& CreateInfo,
467 std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
468 std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules)
463 void PipelineStateVkImpl::InitInternalObjects(const PSOCreateInfoType& CreateInfo,
464 std::vector<VkPipelineShaderStageCreateInfo>& vkShaderStages,
465 std::vector<VulkanUtilities::ShaderModuleWrapper>& ShaderModules)
469466 {
470467 m_ResourceLayoutIndex.fill(-1);
471468
472469 TShaderStages ShaderStages;
473470 ExtractShaders<ShaderVkImpl>(CreateInfo, ShaderStages);
474471
475 // Memory must be released if an exception is thrown.
476472 LinearAllocator MemPool{GetRawAllocator()};
477473
478 MemPool.AddSpace<ShaderResourceLayoutVk>(GetNumShaderStages() * 2);
479 MemPool.AddSpace<ShaderResourceCacheVk>(GetNumShaderStages());
480 MemPool.AddSpace<ShaderVariableManagerVk>(GetNumShaderStages());
474 const auto NumShaderStages = GetNumShaderStages();
475 VERIFY_EXPR(NumShaderStages > 0 && NumShaderStages == ShaderStages.size());
476
477 MemPool.AddSpace<ShaderResourceCacheVk>(NumShaderStages);
478 MemPool.AddSpace<ShaderResourceLayoutVk>(NumShaderStages * 2);
479 MemPool.AddSpace<ShaderVariableManagerVk>(NumShaderStages);
481480
482481 ReserveSpaceForPipelineDesc(CreateInfo, MemPool);
483482
484483 MemPool.Reserve();
485484
486 m_ShaderResourceLayouts = MemPool.Allocate<ShaderResourceLayoutVk>(GetNumShaderStages() * 2);
487 m_StaticResCaches = MemPool.Allocate<ShaderResourceCacheVk>(GetNumShaderStages());
488 m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(GetNumShaderStages());
485 const auto& LogicalDevice = GetDevice()->GetLogicalDevice();
486
487 m_StaticResCaches = MemPool.ConstructArray<ShaderResourceCacheVk>(NumShaderStages, ShaderResourceCacheVk::DbgCacheContentType::StaticShaderResources);
488
489 // The memory is now owned by PipelineStateVkImpl and will be freed by Destruct().
490 auto* Ptr = MemPool.ReleaseOwnership();
491 VERIFY_EXPR(Ptr == m_StaticResCaches);
492 (void)Ptr;
493
494 m_ShaderResourceLayouts = MemPool.ConstructArray<ShaderResourceLayoutVk>(NumShaderStages * 2, LogicalDevice);
495
496 m_StaticVarsMgrs = MemPool.Allocate<ShaderVariableManagerVk>(NumShaderStages);
497 for (Uint32 s = 0; s < NumShaderStages; ++s)
498 new (m_StaticVarsMgrs + s) ShaderVariableManagerVk{*this, m_StaticResCaches[s]};
489499
490500 InitializePipelineDesc(CreateInfo, MemPool);
501
502 // It is important to construct all objects before initializing them because if an exception is thrown,
503 // destructors will be called for all objects
504
491505 InitResourceLayouts(CreateInfo, ShaderStages);
492506
493507 // Create shader modules and initialize shader stages
494508 InitPipelineShaderStages(GetDevice()->GetLogicalDevice(), ShaderStages, ShaderModules, vkShaderStages);
495
496 return MemPool;
497509 }
498510
499511 PipelineStateVkImpl::PipelineStateVkImpl(IReferenceCounters* pRefCounters,
502514 TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc},
503515 m_SRBMemAllocator{GetRawAllocator()}
504516 {
505 std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
506 std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
507
508 auto MemPool = InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
509
510 CreateGraphicsPipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
511
512 void* Ptr = MemPool.Release();
513 VERIFY_EXPR(Ptr == m_ShaderResourceLayouts);
517 try
518 {
519 std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
520 std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
521
522 InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
523
524 CreateGraphicsPipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, GetGraphicsPipelineDesc(), m_Pipeline, m_pRenderPass);
525 }
526 catch (...)
527 {
528 Destruct();
529 throw;
530 }
514531 }
515532
516533
520537 TPipelineStateBase{pRefCounters, pDeviceVk, CreateInfo.PSODesc},
521538 m_SRBMemAllocator{GetRawAllocator()}
522539 {
523 std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
524 std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
525
526 auto MemPool = InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
527
528 CreateComputePipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline);
529
530 void* Ptr = MemPool.Release();
531 VERIFY_EXPR(Ptr == m_ShaderResourceLayouts);
540 try
541 {
542 std::vector<VkPipelineShaderStageCreateInfo> vkShaderStages;
543 std::vector<VulkanUtilities::ShaderModuleWrapper> ShaderModules;
544
545 InitInternalObjects(CreateInfo, vkShaderStages, ShaderModules);
546
547 CreateComputePipeline(pDeviceVk, vkShaderStages, m_PipelineLayout, m_Desc, m_Pipeline);
548 }
549 catch (...)
550 {
551 Destruct();
552 throw;
553 }
532554 }
533555
534556
535557 PipelineStateVkImpl::~PipelineStateVkImpl()
558 {
559 Destruct();
560 }
561
562 void PipelineStateVkImpl::Destruct()
536563 {
537564 m_pDevice->SafeReleaseDeviceObject(std::move(m_Pipeline), m_Desc.CommandQueueMask);
538565 m_PipelineLayout.Release(m_pDevice, m_Desc.CommandQueueMask);
539566
540567 auto& RawAllocator = GetRawAllocator();
541 for (Uint32 s = 0; s < GetNumShaderStages() * 2; ++s)
542 {
543 m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk();
544 }
545
546568 for (Uint32 s = 0; s < GetNumShaderStages(); ++s)
547569 {
548 m_StaticResCaches[s].~ShaderResourceCacheVk();
549 m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator());
550 m_StaticVarsMgrs[s].~ShaderVariableManagerVk();
551 }
552 // m_ShaderResourceLayouts, m_StaticResCaches and m_StaticVarsMgrs are allocted in
553 // contiguous chunks of memory.
554 void* pRawMem = m_ShaderResourceLayouts;
555 RawAllocator.Free(pRawMem);
570 if (m_StaticVarsMgrs != nullptr)
571 {
572 m_StaticVarsMgrs[s].DestroyVariables(GetRawAllocator());
573 m_StaticVarsMgrs[s].~ShaderVariableManagerVk();
574 }
575
576 if (m_ShaderResourceLayouts != nullptr)
577 {
578 m_ShaderResourceLayouts[s].~ShaderResourceLayoutVk();
579 m_ShaderResourceLayouts[GetNumShaderStages() + s].~ShaderResourceLayoutVk();
580 }
581
582 if (m_StaticResCaches != nullptr)
583 {
584 m_StaticResCaches[s].~ShaderResourceCacheVk();
585 }
586 }
587
588 // All internal objects are allocted in contiguous chunks of memory.
589 if (void* pRawMem = m_StaticResCaches)
590 {
591 RawAllocator.Free(pRawMem);
592 }
556593 }
557594
558595 IMPLEMENT_QUERY_INTERFACE(PipelineStateVkImpl, IID_PipelineStateVk, TPipelineStateBase)
745782 if (LayoutInd < 0)
746783 return nullptr;
747784
748 auto& StaticVarMgr = GetStaticVarMgr(LayoutInd);
785 const auto& StaticVarMgr = GetStaticVarMgr(LayoutInd);
749786 return StaticVarMgr.GetVariable(Index);
750787 }
751788
7474 // Initialize vars manager to reference mutable and dynamic variables
7575 // Note that the cache has space for all variable types
7676 const SHADER_RESOURCE_VARIABLE_TYPE VarTypes[] = {SHADER_RESOURCE_VARIABLE_TYPE_MUTABLE, SHADER_RESOURCE_VARIABLE_TYPE_DYNAMIC};
77 new (m_pShaderVarMgrs + s) ShaderVariableManagerVk{*this, SrcLayout, VarDataAllocator, VarTypes, _countof(VarTypes), m_ShaderResourceCache};
77 new (m_pShaderVarMgrs + s) ShaderVariableManagerVk{*this, m_ShaderResourceCache};
78 m_pShaderVarMgrs[s].Initialize(SrcLayout, VarDataAllocator, VarTypes, _countof(VarTypes));
7879 }
7980 #ifdef DILIGENT_DEBUG
8081 m_ShaderResourceCache.DbgVerifyResourceInitialization();
6464 }
6565
6666 // Creates shader variable for every resource from SrcLayout whose type is one AllowedVarTypes
67 ShaderVariableManagerVk::ShaderVariableManagerVk(IObject& Owner,
68 const ShaderResourceLayoutVk& SrcLayout,
69 IMemoryAllocator& Allocator,
70 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
71 Uint32 NumAllowedTypes,
72 ShaderResourceCacheVk& ResourceCache) :
73 // clang-format off
74 m_Owner {Owner },
75 m_ResourceCache{ResourceCache}
67 void ShaderVariableManagerVk::Initialize(const ShaderResourceLayoutVk& SrcLayout,
68 IMemoryAllocator& Allocator,
69 const SHADER_RESOURCE_VARIABLE_TYPE* AllowedVarTypes,
70 Uint32 NumAllowedTypes)
71 {
7672 #ifdef DILIGENT_DEBUG
77 , m_DbgAllocator {Allocator}
73 m_pDbgAllocator = &Allocator;
7874 #endif
79 // clang-format on
80 {
75
8176 const Uint32 AllowedTypeBits = GetAllowedTypeBits(AllowedVarTypes, NumAllowedTypes);
8277 VERIFY_EXPR(m_NumVariables == 0);
8378 auto MemSize = GetRequiredMemorySize(SrcLayout, AllowedVarTypes, NumAllowedTypes, m_NumVariables);
118113
119114 void ShaderVariableManagerVk::DestroyVariables(IMemoryAllocator& Allocator)
120115 {
121 VERIFY(&m_DbgAllocator == &Allocator, "Incosistent alloctor");
122
123116 if (m_pVariables != nullptr)
124117 {
118 VERIFY(m_pDbgAllocator == &Allocator, "Incosistent alloctor");
119
125120 for (Uint32 v = 0; v < m_NumVariables; ++v)
126121 m_pVariables[v].~ShaderVariableVkImpl();
127122 Allocator.Free(m_pVariables);
129124 }
130125 }
131126
132 ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name)
127 ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(const Char* Name) const
133128 {
134129 ShaderVariableVkImpl* pVar = nullptr;
135130 for (Uint32 v = 0; v < m_NumVariables; ++v)
146141 }
147142
148143
149 ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(Uint32 Index)
144 ShaderVariableVkImpl* ShaderVariableManagerVk::GetVariable(Uint32 Index) const
150145 {
151146 if (Index >= m_NumVariables)
152147 {
177172 }
178173 }
179174
180 void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags)
175 void ShaderVariableManagerVk::BindResources(IResourceMapping* pResourceMapping, Uint32 Flags) const
181176 {
182177 if (!pResourceMapping)
183178 {
182182 RT0.BlendEnable = True;
183183
184184 auto pPSO = CreateTestPSO(PSOCreateInfo, true);
185 EXPECT_TRUE(pPSO);
186 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].BlendEnable, RT0.BlendEnable);
185 EXPECT_NE(pPSO, nullptr);
186 if (pPSO != nullptr)
187 {
188 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].BlendEnable, RT0.BlendEnable);
189 }
187190 }
188191
189192 {
190193 BSDesc.AlphaToCoverageEnable = !BSDesc.AlphaToCoverageEnable;
191194
192195 auto pPSO = CreateTestPSO(PSOCreateInfo, true);
193 EXPECT_TRUE(pPSO);
194 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.AlphaToCoverageEnable, BSDesc.AlphaToCoverageEnable);
196 EXPECT_NE(pPSO, nullptr);
197 if (pPSO != nullptr)
198 {
199 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.AlphaToCoverageEnable, BSDesc.AlphaToCoverageEnable);
200 }
195201 }
196202
197203 {
198204 RT0.RenderTargetWriteMask = COLOR_MASK_BLUE;
199205
200206 auto pPSO = CreateTestPSO(PSOCreateInfo, true);
201 EXPECT_TRUE(pPSO);
202 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_BLUE);
207 EXPECT_NE(pPSO, nullptr);
208 if (pPSO != nullptr)
209 {
210 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_BLUE);
211 }
203212 }
204213
205214 {
206215 RT0.RenderTargetWriteMask = COLOR_MASK_RED;
207216
208217 auto pPSO = CreateTestPSO(PSOCreateInfo, true);
209 EXPECT_TRUE(pPSO);
210 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_RED);
218 EXPECT_NE(pPSO, nullptr);
219 if (pPSO != nullptr)
220 {
221 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_RED);
222 }
211223 }
212224
213225 {
214226 RT0.RenderTargetWriteMask = COLOR_MASK_GREEN;
215227
216228 auto pPSO = CreateTestPSO(PSOCreateInfo, true);
217 EXPECT_TRUE(pPSO);
218 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_GREEN);
229 EXPECT_NE(pPSO, nullptr);
230 if (pPSO != nullptr)
231 {
232 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_GREEN);
233 }
219234 }
220235
221236 {
222237 RT0.RenderTargetWriteMask = COLOR_MASK_ALPHA;
223238
224239 auto pPSO = CreateTestPSO(PSOCreateInfo, true);
225 EXPECT_TRUE(pPSO);
226 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_ALPHA);
240 EXPECT_NE(pPSO, nullptr);
241 if (pPSO != nullptr)
242 {
243 EXPECT_EQ(pPSO->GetGraphicsPipelineDesc().BlendDesc.RenderTargets[0].RenderTargetWriteMask, COLOR_MASK_ALPHA);
244 }
227245 }
228246 }
229247