• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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