1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "pipeline_state_object_vk.h"
17
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstdint>
21 #include <vulkan/vulkan.h>
22
23 #include <base/util/formats.h>
24 #include <render/device/pipeline_layout_desc.h>
25 #include <render/device/pipeline_state_desc.h>
26 #include <render/namespace.h>
27
28 #include "device/device.h"
29 #include "device/gpu_program.h"
30 #include "device/gpu_program_util.h"
31 #include "device/gpu_resource_handle_util.h"
32 #include "util/log.h"
33 #include "vulkan/create_functions_vk.h"
34 #include "vulkan/device_vk.h"
35 #include "vulkan/gpu_program_vk.h"
36 #include "vulkan/pipeline_create_functions_vk.h"
37 #include "vulkan/validate_vk.h"
38
39 using namespace BASE_NS;
40
41 RENDER_BEGIN_NAMESPACE()
42 namespace {
43 constexpr uint32_t MAX_DYNAMIC_STATE_COUNT { 9 };
44
GetVertexInputs(const VertexInputDeclarationView & vertexInputDeclaration,vector<VkVertexInputBindingDescription> & vertexInputBindingDescriptions,vector<VkVertexInputAttributeDescription> & vertexInputAttributeDescriptions)45 void GetVertexInputs(const VertexInputDeclarationView& vertexInputDeclaration,
46 vector<VkVertexInputBindingDescription>& vertexInputBindingDescriptions,
47 vector<VkVertexInputAttributeDescription>& vertexInputAttributeDescriptions)
48 {
49 vertexInputBindingDescriptions.resize(vertexInputDeclaration.bindingDescriptions.size());
50 vertexInputAttributeDescriptions.resize(vertexInputDeclaration.attributeDescriptions.size());
51
52 for (size_t idx = 0; idx < vertexInputBindingDescriptions.size(); ++idx) {
53 const auto& bindingRef = vertexInputDeclaration.bindingDescriptions[idx];
54
55 const VkVertexInputRate vertexInputRate = (VkVertexInputRate)bindingRef.vertexInputRate;
56 vertexInputBindingDescriptions[idx] = {
57 bindingRef.binding, // binding
58 bindingRef.stride, // stride
59 vertexInputRate, // inputRate
60 };
61 }
62
63 for (size_t idx = 0; idx < vertexInputAttributeDescriptions.size(); ++idx) {
64 const auto& attributeRef = vertexInputDeclaration.attributeDescriptions[idx];
65 const VkFormat vertexInputFormat = (VkFormat)attributeRef.format;
66 vertexInputAttributeDescriptions[idx] = {
67 attributeRef.location, // location
68 attributeRef.binding, // binding
69 vertexInputFormat, // format
70 attributeRef.offset, // offset
71 };
72 }
73 }
74
75 struct DescriptorSetFillData {
76 uint32_t descriptorSetCount { 0 };
77 uint32_t pushConstantRangeCount { 0u };
78 VkPushConstantRange pushConstantRanges[PipelineLayoutConstants::MAX_PUSH_CONSTANT_RANGE_COUNT];
79 VkDescriptorSetLayout descriptorSetLayouts[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] { VK_NULL_HANDLE,
80 VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE };
81 // the layout can be coming for special descriptor sets (with e.g. platform formats and immutable samplers)
82 bool descriptorSetLayoutOwnership[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT] { true, true, true, true };
83 };
84
GetDescriptorSetFillData(const PipelineLayout & pipelineLayout,const LowLevelPipelineLayoutData & pipelineLayoutData,const VkDevice device,const VkShaderStageFlags neededShaderStageFlags,DescriptorSetFillData & ds)85 void GetDescriptorSetFillData(const PipelineLayout& pipelineLayout,
86 const LowLevelPipelineLayoutData& pipelineLayoutData, const VkDevice device,
87 const VkShaderStageFlags neededShaderStageFlags, DescriptorSetFillData& ds)
88 {
89 // NOTE: support for only one push constant
90 ds.pushConstantRangeCount = (pipelineLayout.pushConstant.byteSize > 0) ? 1u : 0u;
91 const LowLevelPipelineLayoutDataVk& pipelineLayoutDataVk =
92 static_cast<const LowLevelPipelineLayoutDataVk&>(pipelineLayoutData);
93 // uses the same temp array for all bindings in all sets
94 VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT];
95 for (uint32_t operationIdx = 0; operationIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++operationIdx) {
96 const auto& descRef = pipelineLayout.descriptorSetLayouts[operationIdx];
97 if (descRef.set == PipelineLayoutConstants::INVALID_INDEX) {
98 continue;
99 }
100 ds.descriptorSetCount++;
101 const uint32_t setIdx = descRef.set;
102 const auto& descSetLayoutData = pipelineLayoutDataVk.descriptorSetLayouts[setIdx];
103 // NOTE: we are currently only doing handling of special (immutable sampler needing) layouts
104 // with the descriptor set layout coming from the real descriptor set
105 if (descSetLayoutData.flags & LowLevelDescriptorSetVk::DESCRIPTOR_SET_LAYOUT_IMMUTABLE_SAMPLER_BIT) {
106 PLUGIN_ASSERT(descSetLayoutData.descriptorSetLayout);
107 ds.descriptorSetLayouts[setIdx] = descSetLayoutData.descriptorSetLayout;
108 ds.descriptorSetLayoutOwnership[setIdx] = false; // not owned, cannot be destroyed
109 } else {
110 const uint32_t bindingCount = static_cast<uint32_t>(descRef.bindings.size());
111 PLUGIN_ASSERT(bindingCount <= PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
112 for (uint32_t bindingOpIdx = 0; bindingOpIdx < bindingCount; ++bindingOpIdx) {
113 const auto& bindingRef = descRef.bindings[bindingOpIdx];
114 const VkShaderStageFlags shaderStageFlags = (VkShaderStageFlags)bindingRef.shaderStageFlags;
115 const uint32_t bindingIdx = bindingRef.binding;
116 const VkDescriptorType descriptorType = (VkDescriptorType)bindingRef.descriptorType;
117 const uint32_t descriptorCount = bindingRef.descriptorCount;
118
119 PLUGIN_ASSERT((shaderStageFlags & neededShaderStageFlags) > 0);
120 descriptorSetLayoutBindings[bindingOpIdx] = {
121 bindingIdx, // binding
122 descriptorType, // descriptorType
123 descriptorCount, // descriptorCount
124 shaderStageFlags, // stageFlags
125 nullptr, // pImmutableSamplers
126 };
127 }
128
129 constexpr VkDescriptorSetLayoutCreateFlags descriptorSetLayoutCreateFlags { 0 };
130 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo {
131 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
132 nullptr, // pNext
133 descriptorSetLayoutCreateFlags, // flags
134 bindingCount, // bindingCount
135 descriptorSetLayoutBindings, // pBindings
136 };
137
138 VALIDATE_VK_RESULT(vkCreateDescriptorSetLayout(device, // device
139 &descriptorSetLayoutCreateInfo, // pCreateInfo
140 nullptr, // pAllocator
141 &ds.descriptorSetLayouts[setIdx])); // pSetLayout
142 }
143 }
144
145 if (ds.pushConstantRangeCount == 1) {
146 const VkShaderStageFlags shaderStageFlags = (VkShaderStageFlags)pipelineLayout.pushConstant.shaderStageFlags;
147 PLUGIN_ASSERT((shaderStageFlags & neededShaderStageFlags) > 0);
148 const uint32_t bytesize = pipelineLayout.pushConstant.byteSize;
149 ds.pushConstantRanges[0] = {
150 shaderStageFlags, // stageFlags
151 0, // offset
152 bytesize, // size
153 };
154 }
155 }
156 } // namespace
157
GraphicsPipelineStateObjectVk(Device & device,const GpuShaderProgram & gpuShaderProgram,const GraphicsState & graphicsState,const PipelineLayout & pipelineLayout,const VertexInputDeclarationView & vertexInputDeclaration,const ShaderSpecializationConstantDataView & specializationConstants,const DynamicStateFlags dynamicStateFlags,const RenderPassDesc & renderPassDesc,const array_view<const RenderPassSubpassDesc> & renderPassSubpassDescs,const uint32_t subpassIndex,const LowLevelRenderPassData & renderPassData,const LowLevelPipelineLayoutData & pipelineLayoutData)158 GraphicsPipelineStateObjectVk::GraphicsPipelineStateObjectVk(Device& device, const GpuShaderProgram& gpuShaderProgram,
159 const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
160 const VertexInputDeclarationView& vertexInputDeclaration,
161 const ShaderSpecializationConstantDataView& specializationConstants, const DynamicStateFlags dynamicStateFlags,
162 const RenderPassDesc& renderPassDesc, const array_view<const RenderPassSubpassDesc>& renderPassSubpassDescs,
163 const uint32_t subpassIndex, const LowLevelRenderPassData& renderPassData,
164 const LowLevelPipelineLayoutData& pipelineLayoutData)
165 : GraphicsPipelineStateObject(), device_(device)
166 {
167 PLUGIN_ASSERT(!renderPassSubpassDescs.empty());
168
169 const LowLevelRenderPassDataVk& lowLevelRenderPassDataVk = (const LowLevelRenderPassDataVk&)renderPassData;
170
171 const DeviceVk& deviceVk = (const DeviceVk&)device_;
172 const DevicePlatformDataVk& devicePlatVk = (const DevicePlatformDataVk&)deviceVk.GetPlatformData();
173 const VkDevice vkDevice = devicePlatVk.device;
174
175 const GpuShaderProgramVk& program = static_cast<const GpuShaderProgramVk&>(gpuShaderProgram);
176 const GpuShaderProgramPlatformDataVk& platData = program.GetPlatformData();
177
178 vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
179 vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
180 GetVertexInputs(vertexInputDeclaration, vertexInputBindingDescriptions, vertexInputAttributeDescriptions);
181
182 constexpr VkPipelineVertexInputStateCreateFlags pipelineVertexInputStateCreateFlags { 0 };
183 const VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo {
184 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
185 nullptr, // pNext
186 pipelineVertexInputStateCreateFlags, // flags
187 (uint32_t)vertexInputBindingDescriptions.size(), // vertexBindingDescriptionCount
188 vertexInputBindingDescriptions.data(), // pVertexBindingDescriptions
189 (uint32_t)vertexInputAttributeDescriptions.size(), // vertexAttributeDescriptionCount
190 vertexInputAttributeDescriptions.data(), // pVertexAttributeDescriptions
191 };
192
193 const GraphicsState::InputAssembly& inputAssembly = graphicsState.inputAssembly;
194
195 constexpr VkPipelineInputAssemblyStateCreateFlags pipelineInputAssemblyStateCreateFlags { 0 };
196 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo {
197 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType
198 nullptr, // pNext
199 pipelineInputAssemblyStateCreateFlags, // flags
200 (VkPrimitiveTopology)inputAssembly.primitiveTopology, // topology
201 (VkBool32)inputAssembly.enablePrimitiveRestart, // primitiveRestartEnable
202 };
203
204 const GraphicsState::RasterizationState& rasterizationState = graphicsState.rasterizationState;
205
206 constexpr VkPipelineRasterizationStateCreateFlags pipelineRasterizationStateCreateFlags { 0 };
207 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo {
208 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType
209 nullptr, // Next
210 pipelineRasterizationStateCreateFlags, // flags
211 (VkBool32)rasterizationState.enableDepthClamp, // depthClampEnable
212 (VkBool32)rasterizationState.enableRasterizerDiscard, // rasterizerDiscardEnable
213 (VkPolygonMode)rasterizationState.polygonMode, // polygonMode
214 (VkCullModeFlags)rasterizationState.cullModeFlags, // cullMode
215 (VkFrontFace)rasterizationState.frontFace, // frontFace
216 (VkBool32)rasterizationState.enableDepthBias, // depthBiasEnable
217 rasterizationState.depthBiasConstantFactor, // depthBiasConstantFactor
218 rasterizationState.depthBiasClamp, // depthBiasClamp
219 rasterizationState.depthBiasSlopeFactor, // depthBiasSlopeFactor
220 rasterizationState.lineWidth, // lineWidth
221 };
222
223 const GraphicsState::DepthStencilState& depthStencilState = graphicsState.depthStencilState;
224
225 const GraphicsState::StencilOpState& frontStencilOpState = depthStencilState.frontStencilOpState;
226 const VkStencilOpState frontStencilOpStateVk {
227 (VkStencilOp)frontStencilOpState.failOp, // failOp
228 (VkStencilOp)frontStencilOpState.passOp, // passOp
229 (VkStencilOp)frontStencilOpState.depthFailOp, // depthFailOp
230 (VkCompareOp)frontStencilOpState.compareOp, // compareOp
231 frontStencilOpState.compareMask, // compareMask
232 frontStencilOpState.writeMask, // writeMask
233 frontStencilOpState.reference, // reference
234 };
235 const GraphicsState::StencilOpState& backStencilOpState = depthStencilState.backStencilOpState;
236 const VkStencilOpState backStencilOpStateVk {
237 (VkStencilOp)backStencilOpState.failOp, // failOp
238 (VkStencilOp)backStencilOpState.passOp, // passOp
239 (VkStencilOp)backStencilOpState.depthFailOp, // depthFailOp
240 (VkCompareOp)backStencilOpState.compareOp, // compareOp
241 backStencilOpState.compareMask, // compareMask
242 backStencilOpState.writeMask, // writeMask
243 backStencilOpState.reference, // reference
244 };
245
246 constexpr VkPipelineDepthStencilStateCreateFlags pipelineDepthStencilStateCreateFlags { 0 };
247 const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo {
248 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType
249 nullptr, // pNext
250 pipelineDepthStencilStateCreateFlags, // flags
251 (VkBool32)depthStencilState.enableDepthTest, // depthTestEnable
252 (VkBool32)depthStencilState.enableDepthWrite, // depthWriteEnable
253 (VkCompareOp)depthStencilState.depthCompareOp, // depthCompareOp
254 (VkBool32)depthStencilState.enableDepthBoundsTest, // depthBoundsTestEnable
255 (VkBool32)depthStencilState.enableStencilTest, // stencilTestEnable
256 frontStencilOpStateVk, // front
257 backStencilOpStateVk, // back
258 depthStencilState.minDepthBounds, // minDepthBounds
259 depthStencilState.maxDepthBounds, // maxDepthBounds
260 };
261
262 const GraphicsState::ColorBlendState& colorBlendState = graphicsState.colorBlendState;
263
264 VkPipelineColorBlendAttachmentState
265 pipelineColorBlendAttachmentStates[PipelineStateConstants::MAX_COLOR_ATTACHMENT_COUNT];
266 const uint32_t colAttachmentCount = renderPassSubpassDescs[subpassIndex].colorAttachmentCount;
267 PLUGIN_ASSERT(colAttachmentCount <= PipelineStateConstants::MAX_COLOR_ATTACHMENT_COUNT);
268 for (size_t idx = 0; idx < colAttachmentCount; ++idx) {
269 const GraphicsState::ColorBlendState::Attachment& attachmentBlendState = colorBlendState.colorAttachments[idx];
270
271 pipelineColorBlendAttachmentStates[idx] = {
272 (VkBool32)attachmentBlendState.enableBlend, // blendEnable
273 (VkBlendFactor)attachmentBlendState.srcColorBlendFactor, // srcColorBlendFactor
274 (VkBlendFactor)attachmentBlendState.dstColorBlendFactor, // dstColorBlendFactor
275 (VkBlendOp)attachmentBlendState.colorBlendOp, // colorBlendOp
276 (VkBlendFactor)attachmentBlendState.srcAlphaBlendFactor, // srcAlphaBlendFactor
277 (VkBlendFactor)attachmentBlendState.dstAlphaBlendFactor, // dstAlphaBlendFactor
278 (VkBlendOp)attachmentBlendState.alphaBlendOp, // alphaBlendOp
279 (VkColorComponentFlags)attachmentBlendState.colorWriteMask, // colorWriteMask
280 };
281 }
282
283 constexpr VkPipelineColorBlendStateCreateFlags pipelineColorBlendStateCreateFlags { 0 };
284 const float* bc = colorBlendState.colorBlendConstants;
285 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo {
286 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType
287 nullptr, // pNext
288 pipelineColorBlendStateCreateFlags, // flags
289 (VkBool32)colorBlendState.enableLogicOp, // logicOpEnable
290 (VkLogicOp)colorBlendState.logicOp, // logicOp
291 colAttachmentCount, // attachmentCount
292 pipelineColorBlendAttachmentStates, // pAttachments
293 { bc[0u], bc[1u], bc[2u], bc[3u] }, // blendConstants[4]
294 };
295
296 VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo {};
297 pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
298
299 VkDynamicState dynamicStates[MAX_DYNAMIC_STATE_COUNT];
300 uint32_t dynamicStateCount = 0;
301 if (dynamicStateFlags != 0) {
302 for (uint32_t idx = 0; idx < MAX_DYNAMIC_STATE_COUNT; ++idx) {
303 if (((dynamicStateFlags >> idx) & 0x1) == 1) {
304 dynamicStates[dynamicStateCount++] = (VkDynamicState)idx;
305 }
306 }
307
308 constexpr VkPipelineDynamicStateCreateFlags pipelineDynamicStateCreateFlags { 0 };
309 pipelineDynamicStateCreateInfo = {
310 VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType
311 nullptr, // pNext
312 pipelineDynamicStateCreateFlags, // flags
313 dynamicStateCount, // dynamicStateCount
314 dynamicStates, // pDynamicStates
315 };
316 }
317
318 constexpr uint32_t maxViewportCount { 1 };
319 constexpr uint32_t maxScissorCount { 1 };
320 VkPipelineViewportStateCreateInfo viewportStateCreateInfo {
321 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // sType
322 nullptr, // pNext
323 0, // flags
324 maxViewportCount, // viewportCount
325 &lowLevelRenderPassDataVk.viewport, // pViewports
326 maxScissorCount, // scissorCount
327 &lowLevelRenderPassDataVk.scissor, // pScissors
328 };
329
330 // reserve max
331 vector<VkSpecializationMapEntry> vertexStageSpecializations;
332 vector<VkSpecializationMapEntry> fragmentStageSpecializations;
333 vertexStageSpecializations.reserve(specializationConstants.constants.size());
334 fragmentStageSpecializations.reserve(specializationConstants.constants.size());
335
336 uint32_t vertexDataSize = 0;
337 uint32_t fragmentDataSize = 0;
338
339 for (auto const& constant : specializationConstants.constants) {
340 const auto constantSize = GpuProgramUtil::SpecializationByteSize(constant.type);
341 const VkSpecializationMapEntry entry {
342 static_cast<uint32_t>(constant.id), // constantID
343 constant.offset, // offset
344 constantSize // entry.size
345 };
346 if (constant.shaderStage & CORE_SHADER_STAGE_VERTEX_BIT) {
347 vertexStageSpecializations.emplace_back(entry);
348 vertexDataSize = std::max(vertexDataSize, constant.offset + constantSize);
349 }
350 if (constant.shaderStage & CORE_SHADER_STAGE_FRAGMENT_BIT) {
351 fragmentStageSpecializations.emplace_back(entry);
352 fragmentDataSize = std::max(fragmentDataSize, constant.offset + constantSize);
353 }
354 }
355
356 const VkSpecializationInfo vertexSpecializationInfo {
357 static_cast<uint32_t>(vertexStageSpecializations.size()), // mapEntryCount
358 vertexStageSpecializations.data(), // pMapEntries
359 vertexDataSize, // dataSize
360 specializationConstants.data.data() // pData
361 };
362
363 const VkSpecializationInfo fragmentSpecializationInfo {
364 static_cast<uint32_t>(fragmentStageSpecializations.size()), // mapEntryCount
365 fragmentStageSpecializations.data(), // pMapEntries
366 fragmentDataSize, // dataSize
367 specializationConstants.data.data() // pData
368 };
369
370 constexpr uint32_t stageCount { 2 };
371 const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfos[stageCount] {
372 {
373 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sTypeoldHandle
374 nullptr, // pNextoldHandle
375 0, // flags
376 VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT, // stage
377 platData.vert, // module
378 "main", // pName
379 &vertexSpecializationInfo, // pSpecializationInfo
380 },
381 {
382 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
383 nullptr, // pNext
384 0, // flags
385 VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, // stage
386 platData.frag, // module
387 "main", // pName
388 &fragmentSpecializationInfo // pSpecializationInfo
389 },
390 };
391
392 // NOTE: support for only one push constant
393 DescriptorSetFillData ds;
394 GetDescriptorSetFillData(pipelineLayout, pipelineLayoutData, vkDevice,
395 VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT | VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, ds);
396
397 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo {
398 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
399 nullptr, // pNext
400 0, // flags
401 ds.descriptorSetCount, // setLayoutCount
402 ds.descriptorSetLayouts, // pSetLayouts
403 ds.pushConstantRangeCount, // pushConstantRangeCount
404 ds.pushConstantRanges, // pPushConstantRanges
405 };
406
407 VALIDATE_VK_RESULT(vkCreatePipelineLayout(vkDevice, // device
408 &pipelineLayoutCreateInfo, // pCreateInfo,
409 nullptr, // pAllocator
410 &plat_.pipelineLayout)); // pPipelineLayout
411
412 constexpr VkPipelineMultisampleStateCreateFlags pipelineMultisampleStateCreateFlags { 0 };
413
414 VkSampleCountFlagBits sampleCountFlagBits { VK_SAMPLE_COUNT_1_BIT };
415 if (renderPassSubpassDescs[subpassIndex].colorAttachmentCount > 0) {
416 const auto& ref = lowLevelRenderPassDataVk.renderPassCompatibilityDesc.attachments[0];
417 sampleCountFlagBits = (VkSampleCountFlagBits)ref.sampleCountFlags;
418 }
419
420 VkBool32 sampleShadingEnable = VK_FALSE;
421 float minSampleShading = 0.0f;
422
423 const bool msaaEnabled =
424 (VkBool32)((sampleCountFlagBits != VkSampleCountFlagBits::VK_SAMPLE_COUNT_1_BIT) &&
425 (sampleCountFlagBits != VkSampleCountFlagBits::VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM))
426 ? true
427 : false;
428 if (msaaEnabled) {
429 if (devicePlatVk.enabledPhysicalDeviceFeatures.sampleRateShading) {
430 sampleShadingEnable = VK_TRUE;
431 minSampleShading = deviceVk.GetFeatureConfigurations().minSampleShading;
432 }
433 }
434
435 // NOTE: alpha to coverage
436 constexpr VkBool32 alphaToCoverageEnable { false };
437 constexpr VkBool32 alphaToOneEnable { false };
438
439 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo {
440 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType
441 nullptr, // pNext
442 pipelineMultisampleStateCreateFlags, // flags
443 sampleCountFlagBits, // rasterizationSamples
444 sampleShadingEnable, // sampleShadingEnable
445 minSampleShading, // minSampleShading
446 nullptr, // pSampleMask
447 alphaToCoverageEnable, // alphaToCoverageEnable
448 alphaToOneEnable, // alphaToOneEnable
449 };
450
451 // needs nullptr if no dynamic states
452 VkPipelineDynamicStateCreateInfo* ptrPipelineDynamicStateCreateInfo = nullptr;
453 if (dynamicStateCount > 0) {
454 ptrPipelineDynamicStateCreateInfo = &pipelineDynamicStateCreateInfo;
455 }
456
457 constexpr VkPipelineCreateFlags pipelineCreateFlags { 0 };
458 const VkRenderPass renderPass = lowLevelRenderPassDataVk.renderPassCompatibility;
459 const VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo {
460 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType
461 nullptr, // pNext
462 pipelineCreateFlags, // flags
463 stageCount, // stageCount
464 pipelineShaderStageCreateInfos, // pStages
465 &pipelineVertexInputStateCreateInfo, // pVertexInputState
466 &pipelineInputAssemblyStateCreateInfo, // pInputAssemblyState
467 nullptr, // pTessellationState
468 &viewportStateCreateInfo, // pViewportState
469 &pipelineRasterizationStateCreateInfo, // pRasterizationState
470 &pipelineMultisampleStateCreateInfo, // pMultisampleState
471 &pipelineDepthStencilStateCreateInfo, // pDepthStencilState
472 &pipelineColorBlendStateCreateInfo, // pColorBlendState
473 ptrPipelineDynamicStateCreateInfo, // pDynamicState
474 plat_.pipelineLayout, // layout
475 renderPass, // renderPass
476 subpassIndex, // subpass
477 VK_NULL_HANDLE, // basePipelineHandle
478 0, // basePipelineIndex
479 };
480
481 VALIDATE_VK_RESULT(vkCreateGraphicsPipelines(vkDevice, // device
482 devicePlatVk.pipelineCache, // pipelineCache
483 1, // createInfoCount
484 &graphicsPipelineCreateInfo, // pCreateInfos
485 nullptr, // pAllocator
486 &plat_.pipeline)); // pPipelines
487
488 // NOTE: direct destruction here
489 for (uint32_t idx = 0; idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++idx) {
490 const auto& descRef = ds.descriptorSetLayouts[idx];
491 if (descRef && ds.descriptorSetLayoutOwnership[idx]) {
492 vkDestroyDescriptorSetLayout(vkDevice, // device
493 descRef, // descriptorSetLayout
494 nullptr); // pAllocator
495 }
496 }
497 }
498
~GraphicsPipelineStateObjectVk()499 GraphicsPipelineStateObjectVk::~GraphicsPipelineStateObjectVk()
500 {
501 const VkDevice device = ((const DevicePlatformDataVk&)device_.GetPlatformData()).device;
502 vkDestroyPipeline(device, // device
503 plat_.pipeline, // pipeline
504 nullptr); // pAllocator
505 vkDestroyPipelineLayout(device, // device
506 plat_.pipelineLayout, // pipelineLayout
507 nullptr); // pAllocator
508 }
509
GetPlatformData() const510 const PipelineStateObjectPlatformDataVk& GraphicsPipelineStateObjectVk::GetPlatformData() const
511 {
512 return plat_;
513 }
514
ComputePipelineStateObjectVk(Device & device,const GpuComputeProgram & gpuComputeProgram,const PipelineLayout & pipelineLayout,const ShaderSpecializationConstantDataView & specializationConstants,const LowLevelPipelineLayoutData & pipelineLayoutData)515 ComputePipelineStateObjectVk::ComputePipelineStateObjectVk(Device& device, const GpuComputeProgram& gpuComputeProgram,
516 const PipelineLayout& pipelineLayout, const ShaderSpecializationConstantDataView& specializationConstants,
517 const LowLevelPipelineLayoutData& pipelineLayoutData)
518 : ComputePipelineStateObject(), device_(device)
519 {
520 const DeviceVk& deviceVk = (const DeviceVk&)device_;
521 const DevicePlatformDataVk& devicePlatVk = (const DevicePlatformDataVk&)deviceVk.GetPlatformData();
522 const VkDevice vkDevice = devicePlatVk.device;
523
524 const GpuComputeProgramVk& program = static_cast<const GpuComputeProgramVk&>(gpuComputeProgram);
525 const auto& platData = program.GetPlatformData();
526 const VkShaderModule shaderModule = platData.comp;
527
528 vector<VkSpecializationMapEntry> computeStateSpecializations;
529 computeStateSpecializations.reserve(specializationConstants.constants.size());
530 uint32_t computeDataSize = 0;
531 for (auto const& constant : specializationConstants.constants) {
532 const auto constantSize = GpuProgramUtil::SpecializationByteSize(constant.type);
533 const VkSpecializationMapEntry entry {
534 static_cast<uint32_t>(constant.id), // constantID
535 constant.offset, // offset
536 constantSize // entry.size
537 };
538 if (constant.shaderStage & CORE_SHADER_STAGE_COMPUTE_BIT) {
539 computeStateSpecializations.emplace_back(entry);
540 computeDataSize = std::max(computeDataSize, constant.offset + constantSize);
541 }
542 }
543
544 const VkSpecializationInfo computeSpecializationInfo {
545 static_cast<uint32_t>(computeStateSpecializations.size()), // mapEntryCount
546 computeStateSpecializations.data(), // pMapEntries
547 computeDataSize, // dataSize
548 specializationConstants.data.data() // pData
549 };
550
551 const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo {
552 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
553 nullptr, // pNext
554 0, // flags
555 VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT, // stage
556 shaderModule, // module
557 "main", // pName
558 &computeSpecializationInfo, // pSpecializationInfo
559 };
560
561 // NOTE: support for only one push constant
562 DescriptorSetFillData ds;
563 GetDescriptorSetFillData(
564 pipelineLayout, pipelineLayoutData, vkDevice, VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT, ds);
565
566 const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo {
567 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
568 nullptr, // pNext
569 0, // flags
570 ds.descriptorSetCount, // setLayoutCount
571 ds.descriptorSetLayouts, // pSetLayouts
572 ds.pushConstantRangeCount, // pushConstantRangeCount
573 ds.pushConstantRanges, // pPushConstantRanges
574 };
575
576 VALIDATE_VK_RESULT(vkCreatePipelineLayout(vkDevice, // device
577 &pipelineLayoutCreateInfo, // pCreateInfo,
578 nullptr, // pAllocator
579 &plat_.pipelineLayout)); // pPipelineLayout
580
581 constexpr VkPipelineCreateFlags pipelineCreateFlags { 0 };
582 const VkComputePipelineCreateInfo computePipelineCreateInfo {
583 VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType
584 nullptr, // pNext
585 pipelineCreateFlags, // flags
586 pipelineShaderStageCreateInfo, // stage
587 plat_.pipelineLayout, // layout
588 VK_NULL_HANDLE, // basePipelineHandle
589 0, // basePipelineIndex
590 };
591
592 VALIDATE_VK_RESULT(vkCreateComputePipelines(vkDevice, // device
593 devicePlatVk.pipelineCache, // pipelineCache
594 1, // createInfoCount
595 &computePipelineCreateInfo, // pCreateInfos
596 nullptr, // pAllocator
597 &plat_.pipeline)); // pPipelines
598
599 // NOTE: direct destruction here
600 for (uint32_t idx = 0; idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++idx) {
601 const auto& descRef = ds.descriptorSetLayouts[idx];
602 if (descRef && ds.descriptorSetLayoutOwnership[idx]) {
603 vkDestroyDescriptorSetLayout(vkDevice, // device
604 descRef, // descriptorSetLayout
605 nullptr); // pAllocator
606 }
607 }
608 }
609
~ComputePipelineStateObjectVk()610 ComputePipelineStateObjectVk::~ComputePipelineStateObjectVk()
611 {
612 const VkDevice device = ((const DevicePlatformDataVk&)device_.GetPlatformData()).device;
613 vkDestroyPipeline(device, // device
614 plat_.pipeline, // pipeline
615 nullptr); // pAllocator
616 vkDestroyPipelineLayout(device, // device
617 plat_.pipelineLayout, // pipelineLayout
618 nullptr); // pAllocator
619 }
620
GetPlatformData() const621 const PipelineStateObjectPlatformDataVk& ComputePipelineStateObjectVk::GetPlatformData() const
622 {
623 return plat_;
624 }
625 RENDER_END_NAMESPACE()
626