• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_core.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/gpu_program.h"
29 #include "device/gpu_program_util.h"
30 #include "device/gpu_resource_handle_util.h"
31 #include "render/shaders/common/render_compatibility_common.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 { 10u };
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 auto 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 auto 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 DeviceVk & deviceVk,const PipelineLayout & pipelineLayout,const LowLevelPipelineLayoutData & pipelineLayoutData,const VkDevice device,const VkShaderStageFlags neededShaderStageFlags,DescriptorSetFillData & ds)85 void GetDescriptorSetFillData(const DeviceVk& deviceVk, 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 auto& pipelineLayoutDataVk = static_cast<const LowLevelPipelineLayoutDataVk&>(pipelineLayoutData);
92     // uses the same temp array for all bindings in all sets
93     VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT];
94     for (uint32_t operationIdx = 0; operationIdx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++operationIdx) {
95         const uint32_t setIdx = operationIdx;
96         const auto& descRef = pipelineLayout.descriptorSetLayouts[setIdx];
97         if (descRef.set == PipelineLayoutConstants::INVALID_INDEX) {
98             ds.descriptorSetLayouts[setIdx] = deviceVk.GetDefaultVulkanObjects().emptyDescriptorSetLayout;
99             ds.descriptorSetLayoutOwnership[setIdx] = false; // not owned, cannot be destroyed
100             continue;
101         }
102         ds.descriptorSetCount = setIdx + 1U; // store the final valid set
103         const auto& descSetLayoutData = pipelineLayoutDataVk.descriptorSetLayouts[setIdx];
104         // NOTE: we are currently only doing handling of special (immutable sampler needing) layouts
105         // with the descriptor set layout coming from the real descriptor set
106         if (descSetLayoutData.flags & LowLevelDescriptorSetVk::DESCRIPTOR_SET_LAYOUT_IMMUTABLE_SAMPLER_BIT) {
107             PLUGIN_ASSERT(descSetLayoutData.descriptorSetLayout);
108             ds.descriptorSetLayouts[setIdx] = descSetLayoutData.descriptorSetLayout;
109             ds.descriptorSetLayoutOwnership[setIdx] = false; // not owned, cannot be destroyed
110         } else {
111             constexpr VkDescriptorSetLayoutCreateFlags descriptorSetLayoutCreateFlags { 0 };
112             const auto bindingCount = static_cast<uint32_t>(descRef.bindings.size());
113             PLUGIN_ASSERT(bindingCount <= PipelineLayoutConstants::MAX_DESCRIPTOR_SET_BINDING_COUNT);
114             for (uint32_t bindingOpIdx = 0; bindingOpIdx < bindingCount; ++bindingOpIdx) {
115                 const auto& bindingRef = descRef.bindings[bindingOpIdx];
116                 const auto shaderStageFlags = (VkShaderStageFlags)bindingRef.shaderStageFlags;
117                 const uint32_t bindingIdx = bindingRef.binding;
118                 const auto descriptorType = (VkDescriptorType)bindingRef.descriptorType;
119                 const uint32_t descriptorCount = bindingRef.descriptorCount;
120 
121                 PLUGIN_ASSERT((shaderStageFlags & neededShaderStageFlags) > 0);
122                 descriptorSetLayoutBindings[bindingOpIdx] = {
123                     bindingIdx,       // binding
124                     descriptorType,   // descriptorType
125                     descriptorCount,  // descriptorCount
126                     shaderStageFlags, // stageFlags
127                     nullptr,          // pImmutableSamplers
128                 };
129             }
130 
131             const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo {
132                 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // sType
133                 nullptr,                                             // pNext
134                 descriptorSetLayoutCreateFlags,                      // flags
135                 bindingCount,                                        // bindingCount
136                 descriptorSetLayoutBindings,                         // pBindings
137             };
138 
139             VALIDATE_VK_RESULT(vkCreateDescriptorSetLayout(device, // device
140                 &descriptorSetLayoutCreateInfo,                    // pCreateInfo
141                 nullptr,                                           // pAllocator
142                 &ds.descriptorSetLayouts[setIdx]));                // pSetLayout
143         }
144     }
145 
146     if (ds.pushConstantRangeCount == 1) {
147         const auto shaderStageFlags = (VkShaderStageFlags)pipelineLayout.pushConstant.shaderStageFlags;
148         PLUGIN_ASSERT((shaderStageFlags & neededShaderStageFlags) > 0);
149         const uint32_t bytesize = pipelineLayout.pushConstant.byteSize;
150         ds.pushConstantRanges[0] = {
151             shaderStageFlags, // stageFlags
152             0,                // offset
153             bytesize,         // size
154         };
155     }
156 }
157 
GetSpecializationFillData(const ShaderSpecializationConstantDataView & inputSpecConstants,GraphicsPipelineStateObjectVk::SpecializationData & outputSpecData)158 void GetSpecializationFillData(const ShaderSpecializationConstantDataView& inputSpecConstants,
159     GraphicsPipelineStateObjectVk::SpecializationData& outputSpecData)
160 {
161     outputSpecData.constantData.constants.resize(inputSpecConstants.constants.size());
162     for (size_t idx = 0; idx < inputSpecConstants.constants.size(); ++idx) {
163         outputSpecData.constantData.constants[idx] = inputSpecConstants.constants[idx];
164     }
165     outputSpecData.constantData.data.resize(inputSpecConstants.data.size());
166     for (size_t idx = 0; idx < inputSpecConstants.data.size(); ++idx) {
167         outputSpecData.constantData.data[idx] = inputSpecConstants.data[idx];
168     }
169     // handle possible surface transform specialization additions
170     // expects that they are not pre-filled by users
171     if (outputSpecData.surfaceTransformFlags != 0U) {
172         auto FillConstantData = [&](const ShaderStageFlags shaderStageFlags) {
173             const auto offset = static_cast<uint32_t>(outputSpecData.constantData.data.size_in_bytes());
174             outputSpecData.constantData.constants.push_back(ShaderSpecialization::Constant {
175                 shaderStageFlags, CORE_BACKEND_TYPE_SPEC_ID, ShaderSpecialization::Constant::Type::UINT32, offset });
176             outputSpecData.constantData.data.push_back(
177                 outputSpecData.surfaceTransformFlags << CORE_BACKEND_TRANSFORM_OFFSET);
178         };
179         FillConstantData(
180             ShaderStageFlagBits::CORE_SHADER_STAGE_VERTEX_BIT | ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT);
181     }
182 
183     // reserve max
184     outputSpecData.vs.reserve(inputSpecConstants.constants.size());
185     outputSpecData.fs.reserve(inputSpecConstants.constants.size());
186 }
187 } // namespace
188 
GraphicsPipelineStateObjectVk(Device & device,const GpuShaderProgram & gpuShaderProgram,const GraphicsState & graphicsState,const PipelineLayout & pipelineLayout,const VertexInputDeclarationView & vertexInputDeclaration,const ShaderSpecializationConstantDataView & inputSpecConstants,const array_view<const DynamicStateEnum> dynamicStates,const array_view<const RenderPassSubpassDesc> & renderPassSubpassDescs,const uint32_t subpassIndex,const LowLevelRenderPassData & renderPassData,const LowLevelPipelineLayoutData & pipelineLayoutData)189 GraphicsPipelineStateObjectVk::GraphicsPipelineStateObjectVk(Device& device, const GpuShaderProgram& gpuShaderProgram,
190     const GraphicsState& graphicsState, const PipelineLayout& pipelineLayout,
191     const VertexInputDeclarationView& vertexInputDeclaration,
192     const ShaderSpecializationConstantDataView& inputSpecConstants,
193     const array_view<const DynamicStateEnum> dynamicStates,
194     const array_view<const RenderPassSubpassDesc>& renderPassSubpassDescs, const uint32_t subpassIndex,
195     const LowLevelRenderPassData& renderPassData, const LowLevelPipelineLayoutData& pipelineLayoutData)
196     : GraphicsPipelineStateObject(), device_(device)
197 {
198     PLUGIN_ASSERT(!renderPassSubpassDescs.empty());
199 
200     specializationData_.Clear();
201     const auto& lowLevelRenderPassDataVk = (const LowLevelRenderPassDataVk&)renderPassData;
202 
203     const auto& deviceVk = (const DeviceVk&)device_;
204     const auto& devicePlatVk = (const DevicePlatformDataVk&)deviceVk.GetPlatformData();
205     const VkDevice vkDevice = devicePlatVk.device;
206 
207     const auto& program = static_cast<const GpuShaderProgramVk&>(gpuShaderProgram);
208     const GpuShaderProgramPlatformDataVk& platData = program.GetPlatformData();
209     if (!platData.vert || !platData.frag) {
210         return;
211     }
212 
213     vector<VkVertexInputBindingDescription> vertexInputBindingDescriptions;
214     vector<VkVertexInputAttributeDescription> vertexInputAttributeDescriptions;
215     GetVertexInputs(vertexInputDeclaration, vertexInputBindingDescriptions, vertexInputAttributeDescriptions);
216 
217     constexpr VkPipelineVertexInputStateCreateFlags pipelineVertexInputStateCreateFlags { 0 };
218     const VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo {
219         VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
220         nullptr,                                                   // pNext
221         pipelineVertexInputStateCreateFlags,                       // flags
222         (uint32_t)vertexInputBindingDescriptions.size(),           // vertexBindingDescriptionCount
223         vertexInputBindingDescriptions.data(),                     // pVertexBindingDescriptions
224         (uint32_t)vertexInputAttributeDescriptions.size(),         // vertexAttributeDescriptionCount
225         vertexInputAttributeDescriptions.data(),                   // pVertexAttributeDescriptions
226     };
227 
228     const GraphicsState::InputAssembly& inputAssembly = graphicsState.inputAssembly;
229 
230     constexpr VkPipelineInputAssemblyStateCreateFlags pipelineInputAssemblyStateCreateFlags { 0 };
231     const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo {
232         VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType
233         nullptr,                                                     // pNext
234         pipelineInputAssemblyStateCreateFlags,                       // flags
235         (VkPrimitiveTopology)inputAssembly.primitiveTopology,        // topology
236         (VkBool32)inputAssembly.enablePrimitiveRestart,              // primitiveRestartEnable
237     };
238 
239     const GraphicsState::RasterizationState& rasterizationState = graphicsState.rasterizationState;
240 
241     constexpr VkPipelineRasterizationStateCreateFlags pipelineRasterizationStateCreateFlags { 0 };
242     const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo {
243         VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType
244         nullptr,                                                    // Next
245         pipelineRasterizationStateCreateFlags,                      // flags
246         (VkBool32)rasterizationState.enableDepthClamp,              // depthClampEnable
247         (VkBool32)rasterizationState.enableRasterizerDiscard,       // rasterizerDiscardEnable
248         (VkPolygonMode)rasterizationState.polygonMode,              // polygonMode
249         (VkCullModeFlags)rasterizationState.cullModeFlags,          // cullMode
250         (VkFrontFace)rasterizationState.frontFace,                  // frontFace
251         (VkBool32)rasterizationState.enableDepthBias,               // depthBiasEnable
252         rasterizationState.depthBiasConstantFactor,                 // depthBiasConstantFactor
253         rasterizationState.depthBiasClamp,                          // depthBiasClamp
254         rasterizationState.depthBiasSlopeFactor,                    // depthBiasSlopeFactor
255         rasterizationState.lineWidth,                               // lineWidth
256     };
257 
258     const GraphicsState::DepthStencilState& depthStencilState = graphicsState.depthStencilState;
259 
260     const GraphicsState::StencilOpState& frontStencilOpState = depthStencilState.frontStencilOpState;
261     const VkStencilOpState frontStencilOpStateVk {
262         (VkStencilOp)frontStencilOpState.failOp,      // failOp
263         (VkStencilOp)frontStencilOpState.passOp,      // passOp
264         (VkStencilOp)frontStencilOpState.depthFailOp, // depthFailOp
265         (VkCompareOp)frontStencilOpState.compareOp,   // compareOp
266         frontStencilOpState.compareMask,              // compareMask
267         frontStencilOpState.writeMask,                // writeMask
268         frontStencilOpState.reference,                // reference
269     };
270     const GraphicsState::StencilOpState& backStencilOpState = depthStencilState.backStencilOpState;
271     const VkStencilOpState backStencilOpStateVk {
272         (VkStencilOp)backStencilOpState.failOp,      // failOp
273         (VkStencilOp)backStencilOpState.passOp,      // passOp
274         (VkStencilOp)backStencilOpState.depthFailOp, // depthFailOp
275         (VkCompareOp)backStencilOpState.compareOp,   // compareOp
276         backStencilOpState.compareMask,              // compareMask
277         backStencilOpState.writeMask,                // writeMask
278         backStencilOpState.reference,                // reference
279     };
280 
281     constexpr VkPipelineDepthStencilStateCreateFlags pipelineDepthStencilStateCreateFlags { 0 };
282     const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo {
283         VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType
284         nullptr,                                                    // pNext
285         pipelineDepthStencilStateCreateFlags,                       // flags
286         (VkBool32)depthStencilState.enableDepthTest,                // depthTestEnable
287         (VkBool32)depthStencilState.enableDepthWrite,               // depthWriteEnable
288         (VkCompareOp)depthStencilState.depthCompareOp,              // depthCompareOp
289         (VkBool32)depthStencilState.enableDepthBoundsTest,          // depthBoundsTestEnable
290         (VkBool32)depthStencilState.enableStencilTest,              // stencilTestEnable
291         frontStencilOpStateVk,                                      // front
292         backStencilOpStateVk,                                       // back
293         depthStencilState.minDepthBounds,                           // minDepthBounds
294         depthStencilState.maxDepthBounds,                           // maxDepthBounds
295     };
296 
297     const GraphicsState::ColorBlendState& colorBlendState = graphicsState.colorBlendState;
298 
299     VkPipelineColorBlendAttachmentState
300         pipelineColorBlendAttachmentStates[PipelineStateConstants::MAX_COLOR_ATTACHMENT_COUNT];
301     const uint32_t colAttachmentCount = renderPassSubpassDescs[subpassIndex].colorAttachmentCount;
302     PLUGIN_ASSERT(colAttachmentCount <= PipelineStateConstants::MAX_COLOR_ATTACHMENT_COUNT);
303     for (size_t idx = 0; idx < colAttachmentCount; ++idx) {
304         const GraphicsState::ColorBlendState::Attachment& attachmentBlendState = colorBlendState.colorAttachments[idx];
305 
306         pipelineColorBlendAttachmentStates[idx] = {
307             (VkBool32)attachmentBlendState.enableBlend,                 // blendEnable
308             (VkBlendFactor)attachmentBlendState.srcColorBlendFactor,    // srcColorBlendFactor
309             (VkBlendFactor)attachmentBlendState.dstColorBlendFactor,    // dstColorBlendFactor
310             (VkBlendOp)attachmentBlendState.colorBlendOp,               // colorBlendOp
311             (VkBlendFactor)attachmentBlendState.srcAlphaBlendFactor,    // srcAlphaBlendFactor
312             (VkBlendFactor)attachmentBlendState.dstAlphaBlendFactor,    // dstAlphaBlendFactor
313             (VkBlendOp)attachmentBlendState.alphaBlendOp,               // alphaBlendOp
314             (VkColorComponentFlags)attachmentBlendState.colorWriteMask, // colorWriteMask
315         };
316     }
317 
318     constexpr VkPipelineColorBlendStateCreateFlags pipelineColorBlendStateCreateFlags { 0 };
319     const float* bc = colorBlendState.colorBlendConstants;
320     const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo {
321         VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType
322         nullptr,                                                  // pNext
323         pipelineColorBlendStateCreateFlags,                       // flags
324         (VkBool32)colorBlendState.enableLogicOp,                  // logicOpEnable
325         (VkLogicOp)colorBlendState.logicOp,                       // logicOp
326         colAttachmentCount,                                       // attachmentCount
327         pipelineColorBlendAttachmentStates,                       // pAttachments
328         { bc[0u], bc[1u], bc[2u], bc[3u] },                       // blendConstants[4]
329     };
330 
331     VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo {};
332     pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
333 
334     VkDynamicState vkDynamicStates[MAX_DYNAMIC_STATE_COUNT];
335     uint32_t dynamicStateCount = Math::min(MAX_DYNAMIC_STATE_COUNT, static_cast<uint32_t>(dynamicStates.size()));
336     if (dynamicStateCount > 0) {
337         for (uint32_t idx = 0; idx < dynamicStateCount; ++idx) {
338             vkDynamicStates[idx] = (VkDynamicState)dynamicStates[idx];
339         }
340 
341         constexpr VkPipelineDynamicStateCreateFlags pipelineDynamicStateCreateFlags { 0 };
342         pipelineDynamicStateCreateInfo = {
343             VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // sType
344             nullptr,                                              // pNext
345             pipelineDynamicStateCreateFlags,                      // flags
346             dynamicStateCount,                                    // dynamicStateCount
347             vkDynamicStates,                                      // pDynamicStates
348         };
349     }
350 
351     constexpr uint32_t maxViewportCount { 1 };
352     constexpr uint32_t maxScissorCount { 1 };
353     VkPipelineViewportStateCreateInfo viewportStateCreateInfo {
354         VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // sType
355         nullptr,                                               // pNext
356         0,                                                     // flags
357         maxViewportCount,                                      // viewportCount
358         &lowLevelRenderPassDataVk.viewport,                    // pViewports
359         maxScissorCount,                                       // scissorCount
360         &lowLevelRenderPassDataVk.scissor,                     // pScissors
361     };
362 
363     PLUGIN_ASSERT(specializationData_.surfaceTransformFlags == 0U);
364     if (lowLevelRenderPassDataVk.isSwapchain && (lowLevelRenderPassDataVk.surfaceTransformFlags != 0U)) {
365         specializationData_.surfaceTransformFlags = lowLevelRenderPassDataVk.surfaceTransformFlags;
366     }
367     // fill the data to members
368     GetSpecializationFillData(inputSpecConstants, specializationData_);
369 
370     uint32_t vertexDataSize = 0;
371     uint32_t fragmentDataSize = 0;
372 
373     for (auto const& constant : specializationData_.constantData.constants) {
374         const auto constantSize = GpuProgramUtil::SpecializationByteSize(constant.type);
375         const VkSpecializationMapEntry entry {
376             static_cast<uint32_t>(constant.id), // constantID
377             constant.offset,                    // offset
378             constantSize                        // entry.size
379         };
380         if (constant.shaderStage & CORE_SHADER_STAGE_VERTEX_BIT) {
381             specializationData_.vs.push_back(entry);
382             vertexDataSize = Math::max(vertexDataSize, constant.offset + constantSize);
383         }
384         if (constant.shaderStage & CORE_SHADER_STAGE_FRAGMENT_BIT) {
385             specializationData_.fs.push_back(entry);
386             fragmentDataSize = Math::max(fragmentDataSize, constant.offset + constantSize);
387         }
388     }
389 
390     const VkSpecializationInfo vertexSpecializationInfo {
391         static_cast<uint32_t>(specializationData_.vs.size()), // mapEntryCount
392         specializationData_.vs.data(),                        // pMapEntries
393         vertexDataSize,                                       // dataSize
394         specializationData_.constantData.data.data(),         // pData
395     };
396 
397     const VkSpecializationInfo fragmentSpecializationInfo {
398         static_cast<uint32_t>(specializationData_.fs.size()), // mapEntryCount
399         specializationData_.fs.data(),                        // pMapEntries
400         fragmentDataSize,                                     // dataSize
401         specializationData_.constantData.data.data(),         // pData
402     };
403 
404     constexpr uint32_t stageCount { 2 };
405     const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfos[stageCount] {
406         {
407             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sTypeoldHandle
408             nullptr,                                             // pNextoldHandle
409             0,                                                   // flags
410             VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT,   // stage
411             platData.vert,                                       // module
412             "main",                                              // pName
413             &vertexSpecializationInfo,                           // pSpecializationInfo
414         },
415         {
416             VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
417             nullptr,                                             // pNext
418             0,                                                   // flags
419             VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, // stage
420             platData.frag,                                       // module
421             "main",                                              // pName
422             &fragmentSpecializationInfo                          // pSpecializationInfo
423         },
424     };
425 
426     // NOTE: support for only one push constant
427     DescriptorSetFillData ds;
428     GetDescriptorSetFillData(deviceVk, pipelineLayout, pipelineLayoutData, vkDevice,
429         VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT | VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, ds);
430 
431     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo {
432         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
433         nullptr,                                       // pNext
434         0,                                             // flags
435         ds.descriptorSetCount,                         // setLayoutCount
436         ds.descriptorSetLayouts,                       // pSetLayouts
437         ds.pushConstantRangeCount,                     // pushConstantRangeCount
438         ds.pushConstantRanges,                         // pPushConstantRanges
439     };
440 
441     VALIDATE_VK_RESULT(vkCreatePipelineLayout(vkDevice, // device
442         &pipelineLayoutCreateInfo,                      // pCreateInfo,
443         nullptr,                                        // pAllocator
444         &plat_.pipelineLayout));                        // pPipelineLayout
445 
446     constexpr VkPipelineMultisampleStateCreateFlags pipelineMultisampleStateCreateFlags { 0 };
447 
448     VkSampleCountFlagBits sampleCountFlagBits { VK_SAMPLE_COUNT_1_BIT };
449     if (renderPassSubpassDescs[subpassIndex].colorAttachmentCount > 0) {
450         const auto& ref = lowLevelRenderPassDataVk.renderPassCompatibilityDesc.attachments[0];
451         sampleCountFlagBits = (ref.sampleCountFlags == 0) ? VkSampleCountFlagBits::VK_SAMPLE_COUNT_1_BIT
452                                                           : (VkSampleCountFlagBits)ref.sampleCountFlags;
453     }
454 
455     VkBool32 sampleShadingEnable = VK_FALSE;
456     float minSampleShading = 0.0f;
457 
458     const bool msaaEnabled =
459         (VkBool32)((sampleCountFlagBits != VkSampleCountFlagBits::VK_SAMPLE_COUNT_1_BIT) &&
460                    (sampleCountFlagBits != VkSampleCountFlagBits::VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM)) != 0;
461     if (msaaEnabled) {
462         if (devicePlatVk.enabledPhysicalDeviceFeatures.sampleRateShading) {
463             sampleShadingEnable = VK_TRUE;
464             minSampleShading = deviceVk.GetFeatureConfigurations().minSampleShading;
465         }
466     }
467 
468     // NOTE: alpha to coverage
469     constexpr VkBool32 alphaToCoverageEnable { false };
470     constexpr VkBool32 alphaToOneEnable { false };
471 
472     const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo {
473         VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType
474         nullptr,                                                  // pNext
475         pipelineMultisampleStateCreateFlags,                      // flags
476         sampleCountFlagBits,                                      // rasterizationSamples
477         sampleShadingEnable,                                      // sampleShadingEnable
478         minSampleShading,                                         // minSampleShading
479         nullptr,                                                  // pSampleMask
480         alphaToCoverageEnable,                                    // alphaToCoverageEnable
481         alphaToOneEnable,                                         // alphaToOneEnable
482     };
483 
484     // needs nullptr if no dynamic states
485     VkPipelineDynamicStateCreateInfo* ptrPipelineDynamicStateCreateInfo = nullptr;
486     if (dynamicStateCount > 0) {
487         ptrPipelineDynamicStateCreateInfo = &pipelineDynamicStateCreateInfo;
488     }
489 
490     constexpr VkPipelineCreateFlags pipelineCreateFlags { 0 };
491     const VkRenderPass renderPass = lowLevelRenderPassDataVk.renderPassCompatibility;
492     const VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo {
493         VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType
494         nullptr,                                         // pNext
495         pipelineCreateFlags,                             // flags
496         stageCount,                                      // stageCount
497         pipelineShaderStageCreateInfos,                  // pStages
498         &pipelineVertexInputStateCreateInfo,             // pVertexInputState
499         &pipelineInputAssemblyStateCreateInfo,           // pInputAssemblyState
500         nullptr,                                         // pTessellationState
501         &viewportStateCreateInfo,                        // pViewportState
502         &pipelineRasterizationStateCreateInfo,           // pRasterizationState
503         &pipelineMultisampleStateCreateInfo,             // pMultisampleState
504         &pipelineDepthStencilStateCreateInfo,            // pDepthStencilState
505         &pipelineColorBlendStateCreateInfo,              // pColorBlendState
506         ptrPipelineDynamicStateCreateInfo,               // pDynamicState
507         plat_.pipelineLayout,                            // layout
508         renderPass,                                      // renderPass
509         subpassIndex,                                    // subpass
510         VK_NULL_HANDLE,                                  // basePipelineHandle
511         0,                                               // basePipelineIndex
512     };
513 
514     VALIDATE_VK_RESULT(vkCreateGraphicsPipelines(vkDevice, // device
515         devicePlatVk.pipelineCache,                        // pipelineCache
516         1,                                                 // createInfoCount
517         &graphicsPipelineCreateInfo,                       // pCreateInfos
518         nullptr,                                           // pAllocator
519         &plat_.pipeline));                                 // pPipelines
520 
521     // NOTE: direct destruction here
522     for (uint32_t idx = 0; idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++idx) {
523         const auto& descRef = ds.descriptorSetLayouts[idx];
524         if (descRef && ds.descriptorSetLayoutOwnership[idx]) {
525             vkDestroyDescriptorSetLayout(vkDevice, // device
526                 descRef,                           // descriptorSetLayout
527                 nullptr);                          // pAllocator
528         }
529     }
530 }
531 
~GraphicsPipelineStateObjectVk()532 GraphicsPipelineStateObjectVk::~GraphicsPipelineStateObjectVk()
533 {
534     const VkDevice device = ((const DevicePlatformDataVk&)device_.GetPlatformData()).device;
535     if (plat_.pipeline) {
536         vkDestroyPipeline(device, // device
537             plat_.pipeline,       // pipeline
538             nullptr);             // pAllocator
539     }
540     if (plat_.pipelineLayout) {
541         vkDestroyPipelineLayout(device, // device
542             plat_.pipelineLayout,       // pipelineLayout
543             nullptr);                   // pAllocator
544     }
545 }
546 
GetPlatformData() const547 const PipelineStateObjectPlatformDataVk& GraphicsPipelineStateObjectVk::GetPlatformData() const
548 {
549     return plat_;
550 }
551 
ComputePipelineStateObjectVk(Device & device,const GpuComputeProgram & gpuComputeProgram,const PipelineLayout & pipelineLayout,const ShaderSpecializationConstantDataView & specializationConstants,const LowLevelPipelineLayoutData & pipelineLayoutData)552 ComputePipelineStateObjectVk::ComputePipelineStateObjectVk(Device& device, const GpuComputeProgram& gpuComputeProgram,
553     const PipelineLayout& pipelineLayout, const ShaderSpecializationConstantDataView& specializationConstants,
554     const LowLevelPipelineLayoutData& pipelineLayoutData)
555     : ComputePipelineStateObject(), device_(device)
556 {
557     const auto& deviceVk = (const DeviceVk&)device_;
558     const auto& devicePlatVk = (const DevicePlatformDataVk&)deviceVk.GetPlatformData();
559     const VkDevice vkDevice = devicePlatVk.device;
560 
561     const auto& program = static_cast<const GpuComputeProgramVk&>(gpuComputeProgram);
562     const auto& platData = program.GetPlatformData();
563     if (!platData.comp) {
564         return;
565     }
566 
567     vector<VkSpecializationMapEntry> computeStateSpecializations;
568     computeStateSpecializations.reserve(specializationConstants.constants.size());
569     uint32_t computeDataSize = 0;
570     for (auto const& constant : specializationConstants.constants) {
571         const auto constantSize = GpuProgramUtil::SpecializationByteSize(constant.type);
572         const VkSpecializationMapEntry entry {
573             static_cast<uint32_t>(constant.id), // constantID
574             constant.offset,                    // offset
575             constantSize                        // entry.size
576         };
577         if (constant.shaderStage & CORE_SHADER_STAGE_COMPUTE_BIT) {
578             computeStateSpecializations.push_back(entry);
579             computeDataSize = std::max(computeDataSize, constant.offset + constantSize);
580         }
581     }
582 
583     const VkSpecializationInfo computeSpecializationInfo {
584         static_cast<uint32_t>(computeStateSpecializations.size()), // mapEntryCount
585         computeStateSpecializations.data(),                        // pMapEntries
586         computeDataSize,                                           // dataSize
587         specializationConstants.data.data()                        // pData
588     };
589 
590     const VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo {
591         VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType
592         nullptr,                                             // pNext
593         0,                                                   // flags
594         VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT,  // stage
595         platData.comp,                                       // module
596         "main",                                              // pName
597         &computeSpecializationInfo,                          // pSpecializationInfo
598     };
599 
600     // NOTE: support for only one push constant
601     DescriptorSetFillData ds;
602     GetDescriptorSetFillData(
603         deviceVk, pipelineLayout, pipelineLayoutData, vkDevice, VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT, ds);
604 
605     const VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo {
606         VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
607         nullptr,                                       // pNext
608         0,                                             // flags
609         ds.descriptorSetCount,                         // setLayoutCount
610         ds.descriptorSetLayouts,                       // pSetLayouts
611         ds.pushConstantRangeCount,                     // pushConstantRangeCount
612         ds.pushConstantRanges,                         // pPushConstantRanges
613     };
614 
615     VALIDATE_VK_RESULT(vkCreatePipelineLayout(vkDevice, // device
616         &pipelineLayoutCreateInfo,                      // pCreateInfo,
617         nullptr,                                        // pAllocator
618         &plat_.pipelineLayout));                        // pPipelineLayout
619 
620     constexpr VkPipelineCreateFlags pipelineCreateFlags { 0 };
621     const VkComputePipelineCreateInfo computePipelineCreateInfo {
622         VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, // sType
623         nullptr,                                        // pNext
624         pipelineCreateFlags,                            // flags
625         pipelineShaderStageCreateInfo,                  // stage
626         plat_.pipelineLayout,                           // layout
627         VK_NULL_HANDLE,                                 // basePipelineHandle
628         0,                                              // basePipelineIndex
629     };
630 
631     VALIDATE_VK_RESULT(vkCreateComputePipelines(vkDevice, // device
632         devicePlatVk.pipelineCache,                       // pipelineCache
633         1,                                                // createInfoCount
634         &computePipelineCreateInfo,                       // pCreateInfos
635         nullptr,                                          // pAllocator
636         &plat_.pipeline));                                // pPipelines
637 
638     // NOTE: direct destruction here
639     for (uint32_t idx = 0; idx < PipelineLayoutConstants::MAX_DESCRIPTOR_SET_COUNT; ++idx) {
640         const auto& descRef = ds.descriptorSetLayouts[idx];
641         if (descRef && ds.descriptorSetLayoutOwnership[idx]) {
642             vkDestroyDescriptorSetLayout(vkDevice, // device
643                 descRef,                           // descriptorSetLayout
644                 nullptr);                          // pAllocator
645         }
646     }
647 }
648 
~ComputePipelineStateObjectVk()649 ComputePipelineStateObjectVk::~ComputePipelineStateObjectVk()
650 {
651     const VkDevice device = ((const DevicePlatformDataVk&)device_.GetPlatformData()).device;
652     vkDestroyPipeline(device,       // device
653         plat_.pipeline,             // pipeline
654         nullptr);                   // pAllocator
655     vkDestroyPipelineLayout(device, // device
656         plat_.pipelineLayout,       // pipelineLayout
657         nullptr);                   // pAllocator
658 }
659 
GetPlatformData() const660 const PipelineStateObjectPlatformDataVk& ComputePipelineStateObjectVk::GetPlatformData() const
661 {
662     return plat_;
663 }
664 RENDER_END_NAMESPACE()
665