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