1 /*
2 * Copyright (c) 2024 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_create_functions_vk.h"
17
18 #include <algorithm>
19 #include <vulkan/vulkan_core.h>
20
21 #include <base/containers/array_view.h>
22 #include <base/containers/vector.h>
23 #include <base/math/mathf.h>
24 #include <render/device/pipeline_state_desc.h>
25 #include <render/namespace.h>
26
27 #include "nodecontext/render_command_list.h"
28 #include "util/log.h"
29 #include "vulkan/device_vk.h"
30 #include "vulkan/validate_vk.h"
31
32 using namespace BASE_NS;
33
34 RENDER_BEGIN_NAMESPACE()
35 namespace {
LocalClamp(const Size2D val,const Size2D minVal,const Size2D maxVal)36 inline constexpr Size2D LocalClamp(const Size2D val, const Size2D minVal, const Size2D maxVal)
37 {
38 return Size2D { Math::max(minVal.width, Math::min(val.width, maxVal.width)),
39 Math::max(minVal.height, Math::min(val.height, maxVal.height)) };
40 }
41
ClampShadingRateAttachmentTexelSize(const DeviceVk & deviceVk,const Size2D val)42 inline Size2D ClampShadingRateAttachmentTexelSize(const DeviceVk& deviceVk, const Size2D val)
43 {
44 const FragmentShadingRateProperties& fsrp = deviceVk.GetCommonDeviceProperties().fragmentShadingRateProperties;
45 return LocalClamp(
46 val, fsrp.minFragmentShadingRateAttachmentTexelSize, fsrp.maxFragmentShadingRateAttachmentTexelSize);
47 }
48
CreateAttachmentDescriptions(const array_view<const RenderPassDesc::AttachmentDesc> attachments,const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,const array_view<const ImageLayout> initialImageLayouts,const array_view<const ImageLayout> finalImageLayouts,array_view<VkAttachmentDescription> newAttachments)49 void CreateAttachmentDescriptions(const array_view<const RenderPassDesc::AttachmentDesc> attachments,
50 const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,
51 const array_view<const ImageLayout> initialImageLayouts, const array_view<const ImageLayout> finalImageLayouts,
52 array_view<VkAttachmentDescription> newAttachments)
53 {
54 PLUGIN_ASSERT(attachments.size() == compatibilityAttachmentDescs.size());
55 PLUGIN_ASSERT(attachments.size() <= newAttachments.size());
56 PLUGIN_ASSERT(attachments.size() <= initialImageLayouts.size());
57 PLUGIN_ASSERT(attachments.size() <= finalImageLayouts.size());
58 auto itNewAttachments = newAttachments.begin();
59 auto itInitialImageLayouts = initialImageLayouts.begin();
60 auto itFinalImageLayouts = finalImageLayouts.begin();
61 for (size_t idx = 0; idx < attachments.size(); ++idx) {
62 const auto& attachmentRef = attachments[idx];
63 const auto& compatibilityAttachmentRef = compatibilityAttachmentDescs[idx];
64 const ImageLayout initialLayout = *itInitialImageLayouts++;
65 const ImageLayout finalLayout = *itFinalImageLayouts++;
66 PLUGIN_ASSERT(compatibilityAttachmentRef.format != VkFormat::VK_FORMAT_UNDEFINED);
67
68 constexpr VkAttachmentDescriptionFlags attachmentDescriptionFlags { 0 };
69 *itNewAttachments++ = {
70 attachmentDescriptionFlags, // flags
71 compatibilityAttachmentRef.format, // format
72 compatibilityAttachmentRef.sampleCountFlags, // samples
73 (VkAttachmentLoadOp)attachmentRef.loadOp, // loadOp
74 (VkAttachmentStoreOp)attachmentRef.storeOp, // storeOp
75 (VkAttachmentLoadOp)attachmentRef.stencilLoadOp, // stencilLoadOp
76 (VkAttachmentStoreOp)attachmentRef.stencilStoreOp, // stencilStoreOp
77 (VkImageLayout)initialLayout, // initialLayout
78 (VkImageLayout)finalLayout, // finalLayout
79 };
80 }
81 }
82
CreateAttachmentDescriptions2(const array_view<const RenderPassDesc::AttachmentDesc> attachments,const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,const array_view<const ImageLayout> initialImageLayouts,const array_view<const ImageLayout> finalImageLayouts,array_view<VkAttachmentDescription2KHR> newAttachments)83 void CreateAttachmentDescriptions2(const array_view<const RenderPassDesc::AttachmentDesc> attachments,
84 const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,
85 const array_view<const ImageLayout> initialImageLayouts, const array_view<const ImageLayout> finalImageLayouts,
86 array_view<VkAttachmentDescription2KHR> newAttachments)
87 {
88 PLUGIN_ASSERT(attachments.size() == compatibilityAttachmentDescs.size());
89 PLUGIN_ASSERT(attachments.size() <= newAttachments.size());
90 PLUGIN_ASSERT(attachments.size() <= initialImageLayouts.size());
91 PLUGIN_ASSERT(attachments.size() <= finalImageLayouts.size());
92 auto itNewAttachments = newAttachments.begin();
93 auto itInitialImageLayouts = initialImageLayouts.begin();
94 auto itFinalImageLayouts = finalImageLayouts.begin();
95 for (size_t idx = 0; idx < attachments.size(); ++idx) {
96 const auto& attachmentRef = attachments[idx];
97 const auto& compatibilityAttachmentRef = compatibilityAttachmentDescs[idx];
98 const ImageLayout initialLayout = *itInitialImageLayouts++;
99 const ImageLayout finalLayout = *itFinalImageLayouts++;
100 #if (RENDER_VALIDATION_ENABLED == 1)
101 if (compatibilityAttachmentRef.format == VkFormat::VK_FORMAT_UNDEFINED) {
102 PLUGIN_LOG_E("RENDER_VALIDATION: VK_FORMAT_UNDEFINED with PSO attachment descriptions");
103 }
104 #endif
105
106 constexpr VkAttachmentDescriptionFlags attachmentDescriptionFlags { 0 };
107 *itNewAttachments++ = {
108 VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR, // sType
109 nullptr, // pNext
110 attachmentDescriptionFlags, // flags
111 compatibilityAttachmentRef.format, // format
112 compatibilityAttachmentRef.sampleCountFlags, // samples
113 (VkAttachmentLoadOp)attachmentRef.loadOp, // loadOp
114 (VkAttachmentStoreOp)attachmentRef.storeOp, // storeOp
115 (VkAttachmentLoadOp)attachmentRef.stencilLoadOp, // stencilLoadOp
116 (VkAttachmentStoreOp)attachmentRef.stencilStoreOp, // stencilStoreOp
117 (VkImageLayout)initialLayout, // initialLayout
118 (VkImageLayout)finalLayout, // finalLayout
119 };
120 }
121 }
122
CreateAttachmentDescriptionsCompatibility(const array_view<const RenderPassDesc::AttachmentDesc> attachments,const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,array_view<VkAttachmentDescription> newAttachments)123 void CreateAttachmentDescriptionsCompatibility(const array_view<const RenderPassDesc::AttachmentDesc> attachments,
124 const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,
125 array_view<VkAttachmentDescription> newAttachments)
126 {
127 PLUGIN_ASSERT(attachments.size() == compatibilityAttachmentDescs.size());
128 PLUGIN_ASSERT(attachments.size() <= newAttachments.size());
129 auto itNewAttachments = newAttachments.begin();
130 for (size_t idx = 0; idx < attachments.size(); ++idx) {
131 const auto& compatibilityAttachmentRef = compatibilityAttachmentDescs[idx];
132 PLUGIN_ASSERT(compatibilityAttachmentRef.format != VkFormat::VK_FORMAT_UNDEFINED);
133
134 constexpr VkAttachmentDescriptionFlags attachmentDescriptionFlags { 0 };
135 *itNewAttachments++ = {
136 attachmentDescriptionFlags, // flags
137 compatibilityAttachmentRef.format, // format
138 compatibilityAttachmentRef.sampleCountFlags, // samples
139 VkAttachmentLoadOp::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // loadOp
140 VkAttachmentStoreOp::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
141 VkAttachmentLoadOp::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
142 VkAttachmentStoreOp::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
143 VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
144 VkImageLayout::VK_IMAGE_LAYOUT_GENERAL, // finalLayout
145 };
146 }
147 }
148
CreateAttachmentDescriptionsCompatibility2(const array_view<const RenderPassDesc::AttachmentDesc> attachments,const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,array_view<VkAttachmentDescription2KHR> newAttachments)149 void CreateAttachmentDescriptionsCompatibility2(const array_view<const RenderPassDesc::AttachmentDesc> attachments,
150 const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,
151 array_view<VkAttachmentDescription2KHR> newAttachments)
152 {
153 PLUGIN_ASSERT(attachments.size() == compatibilityAttachmentDescs.size());
154 PLUGIN_ASSERT(attachments.size() <= newAttachments.size());
155 auto itNewAttachments = newAttachments.begin();
156 for (size_t idx = 0; idx < attachments.size(); ++idx) {
157 const auto& compatibilityAttachmentRef = compatibilityAttachmentDescs[idx];
158 #if (RENDER_VALIDATION_ENABLED == 1)
159 if (compatibilityAttachmentRef.format == VkFormat::VK_FORMAT_UNDEFINED) {
160 PLUGIN_LOG_E("RENDER_VALIDATION: VK_FORMAT_UNDEFINED with PSO attachment descriptions");
161 }
162 #endif
163 constexpr VkAttachmentDescriptionFlags attachmentDescriptionFlags { 0 };
164 *itNewAttachments++ = {
165 VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR, // sType
166 nullptr, // pNext
167 attachmentDescriptionFlags, // flags
168 compatibilityAttachmentRef.format, // format
169 compatibilityAttachmentRef.sampleCountFlags, // samples
170 VkAttachmentLoadOp::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // loadOp
171 VkAttachmentStoreOp::VK_ATTACHMENT_STORE_OP_DONT_CARE, // storeOp
172 VkAttachmentLoadOp::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
173 VkAttachmentStoreOp::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
174 VkImageLayout::VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
175 VkImageLayout::VK_IMAGE_LAYOUT_GENERAL, // finalLayout
176 };
177 }
178 }
179
CreateAttachmentReferences(const uint32_t * attachmentIndices,const ImageLayout * layouts,const uint32_t attachmentCount,const uint32_t attachmentStartIndex,const bool createCompatibility,VkAttachmentReference * newAttachments)180 void CreateAttachmentReferences(const uint32_t* attachmentIndices,
181 const ImageLayout* layouts, // can be null if compatibility
182 const uint32_t attachmentCount, const uint32_t attachmentStartIndex, const bool createCompatibility,
183 VkAttachmentReference* newAttachments)
184 {
185 PLUGIN_ASSERT(newAttachments);
186 #if (RENDER_VALIDATION_ENABLED == 1)
187 if (createCompatibility) {
188 PLUGIN_ASSERT(layouts == nullptr);
189 }
190 #endif
191 VkImageLayout imageLayout = VkImageLayout::VK_IMAGE_LAYOUT_GENERAL;
192 for (uint32_t idx = 0; idx < attachmentCount; ++idx) {
193 const uint32_t attachmentIndex = attachmentIndices[idx];
194 if (!createCompatibility) {
195 imageLayout = (VkImageLayout)layouts[attachmentIndex];
196 }
197 newAttachments[attachmentStartIndex + idx] = {
198 attachmentIndex, // attachment
199 imageLayout, // layout
200 };
201 }
202 }
203
CreateAttachmentReferences2(const uint32_t * attachmentIndices,const ImageLayout * layouts,const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,const uint32_t attachmentCount,const uint32_t attachmentStartIndex,const bool createCompatibility,VkAttachmentReference2KHR * newAttachments)204 void CreateAttachmentReferences2(const uint32_t* attachmentIndices,
205 const ImageLayout* layouts, // null if compatibility
206 const array_view<const LowLevelRenderPassCompatibilityDescVk::Attachment> compatibilityAttachmentDescs,
207 const uint32_t attachmentCount, const uint32_t attachmentStartIndex, const bool createCompatibility,
208 VkAttachmentReference2KHR* newAttachments)
209 {
210 PLUGIN_ASSERT(newAttachments);
211 #if (RENDER_VALIDATION_ENABLED == 1)
212 if (createCompatibility) {
213 PLUGIN_ASSERT(layouts == nullptr);
214 }
215 #endif
216 VkImageLayout imageLayout = VkImageLayout::VK_IMAGE_LAYOUT_GENERAL;
217 VkImageAspectFlags imageAspectFlags = 0;
218 for (uint32_t idx = 0; idx < attachmentCount; ++idx) {
219 const uint32_t attachmentIndex = attachmentIndices[idx];
220 imageAspectFlags = compatibilityAttachmentDescs[attachmentIndex].aspectFlags;
221 if (!createCompatibility) {
222 imageLayout = (VkImageLayout)layouts[attachmentIndex];
223 }
224 newAttachments[attachmentStartIndex + idx] = {
225 VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR, // sType
226 nullptr, // pNext
227 attachmentIndex, // attachment
228 imageLayout, // layout
229 imageAspectFlags, // aspectMask
230 };
231 }
232 }
233
CreateRenderPassCombined(const DeviceVk & deviceVk,const RenderPassDesc & renderPassDesc,const LowLevelRenderPassDataVk & lowLevelRenderPassData,const array_view<const RenderPassSubpassDesc> subpassDescs,const RenderPassAttachmentResourceStates * subpassResourceStates,const RenderPassAttachmentResourceStates * inputResourceStates,const RenderPassImageLayouts * imageLayouts,const uint32_t maxAttachmentReferenceCountPerSubpass,const bool createRenderPassCompatibility,RenderPassCreatorVk::RenderPassStorage1 & rps1)234 VkRenderPass CreateRenderPassCombined(const DeviceVk& deviceVk, const RenderPassDesc& renderPassDesc,
235 const LowLevelRenderPassDataVk& lowLevelRenderPassData, const array_view<const RenderPassSubpassDesc> subpassDescs,
236 const RenderPassAttachmentResourceStates* subpassResourceStates,
237 const RenderPassAttachmentResourceStates* inputResourceStates,
238 const RenderPassImageLayouts* imageLayouts, // null when using compatibility
239 const uint32_t maxAttachmentReferenceCountPerSubpass, const bool createRenderPassCompatibility,
240 RenderPassCreatorVk::RenderPassStorage1& rps1)
241 {
242 const VkDevice device = (deviceVk.GetPlatformDataVk()).device;
243 const uint32_t attachmentCount = renderPassDesc.attachmentCount;
244 PLUGIN_ASSERT(attachmentCount <= PipelineStateConstants::MAX_RENDER_PASS_ATTACHMENT_COUNT);
245
246 VkAttachmentDescription attachmentDescriptions[PipelineStateConstants::MAX_RENDER_PASS_ATTACHMENT_COUNT];
247 {
248 // add all attachments to attachmentDescriptions array
249 const auto attachments = array_view(renderPassDesc.attachments, renderPassDesc.attachmentCount);
250 const auto compatibilityAttachments =
251 array_view(lowLevelRenderPassData.renderPassCompatibilityDesc.attachments, renderPassDesc.attachmentCount);
252 const auto descriptions = array_view(attachmentDescriptions, countof(attachmentDescriptions));
253 if (createRenderPassCompatibility) {
254 CreateAttachmentDescriptionsCompatibility(attachments, compatibilityAttachments, descriptions);
255 } else {
256 PLUGIN_ASSERT(imageLayouts);
257 const auto initialLayouts =
258 array_view(imageLayouts->attachmentInitialLayouts, renderPassDesc.attachmentCount);
259 const auto finalLayouts = array_view(imageLayouts->attachmentFinalLayouts, renderPassDesc.attachmentCount);
260 CreateAttachmentDescriptions(
261 attachments, compatibilityAttachments, initialLayouts, finalLayouts, descriptions);
262 }
263 }
264
265 // resize vector for all subpass references
266 const uint32_t subpassCount = renderPassDesc.subpassCount;
267 auto& subpassDescriptions = rps1.subpassDescriptions;
268 auto& subpassDependencies = rps1.subpassDependencies;
269 auto& attachmentReferences = rps1.attachmentReferences;
270 auto& multiViewMasks = rps1.multiViewMasks;
271 subpassDescriptions.resize(subpassCount);
272 subpassDependencies.resize(subpassCount);
273 attachmentReferences.resize(subpassCount * maxAttachmentReferenceCountPerSubpass);
274 multiViewMasks.clear();
275 multiViewMasks.resize(subpassCount);
276
277 bool hasMultiView = false;
278 uint32_t srcSubpass = VK_SUBPASS_EXTERNAL;
279 const RenderPassAttachmentResourceStates* srcResourceStates = inputResourceStates;
280 for (uint32_t subpassIdx = 0; subpassIdx < subpassCount; ++subpassIdx) {
281 const RenderPassSubpassDesc& subpassDesc = subpassDescs[subpassIdx];
282
283 const uint32_t startReferenceIndex = subpassIdx * maxAttachmentReferenceCountPerSubpass;
284 uint32_t referenceIndex = startReferenceIndex;
285
286 VkAttachmentReference* inputAttachments = nullptr;
287 const ImageLayout* layouts =
288 (createRenderPassCompatibility) ? nullptr : subpassResourceStates[subpassIdx].layouts;
289 if (subpassDesc.inputAttachmentCount > 0) {
290 inputAttachments = &attachmentReferences[referenceIndex];
291 CreateAttachmentReferences(subpassDesc.inputAttachmentIndices, layouts, subpassDesc.inputAttachmentCount,
292 referenceIndex, createRenderPassCompatibility, attachmentReferences.data());
293 referenceIndex += subpassDesc.inputAttachmentCount;
294 }
295
296 VkAttachmentReference* colorAttachments = nullptr;
297 if (subpassDesc.colorAttachmentCount > 0) {
298 colorAttachments = &attachmentReferences[referenceIndex];
299 CreateAttachmentReferences(subpassDesc.colorAttachmentIndices, layouts, subpassDesc.colorAttachmentCount,
300 referenceIndex, createRenderPassCompatibility, attachmentReferences.data());
301 referenceIndex += subpassDesc.colorAttachmentCount;
302 }
303
304 VkAttachmentReference* resolveAttachments = nullptr;
305 if (subpassDesc.resolveAttachmentCount > 0) {
306 resolveAttachments = &attachmentReferences[referenceIndex];
307 CreateAttachmentReferences(subpassDesc.resolveAttachmentIndices, layouts,
308 subpassDesc.resolveAttachmentCount, referenceIndex, createRenderPassCompatibility,
309 attachmentReferences.data());
310 referenceIndex += subpassDesc.resolveAttachmentCount;
311 }
312
313 // NOTE: preserve attachments
314 VkAttachmentReference* depthAttachment = nullptr;
315 if (subpassDesc.depthAttachmentCount > 0) {
316 depthAttachment = &attachmentReferences[referenceIndex];
317 CreateAttachmentReferences(&subpassDesc.depthAttachmentIndex, layouts, subpassDesc.depthAttachmentCount,
318 referenceIndex, createRenderPassCompatibility, attachmentReferences.data());
319 referenceIndex += subpassDesc.depthAttachmentCount;
320 }
321
322 multiViewMasks[subpassIdx] = subpassDesc.viewMask;
323 if (subpassDesc.viewMask > 0u) {
324 hasMultiView = true;
325 }
326
327 constexpr VkSubpassDescriptionFlags subpassDescriptionFlags { 0 };
328 subpassDescriptions[subpassIdx] = {
329 subpassDescriptionFlags, // flags
330 VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
331 subpassDesc.inputAttachmentCount, // inputAttachmentCount
332 inputAttachments, // pInputAttachments
333 subpassDesc.colorAttachmentCount, // colorAttachmentCount
334 colorAttachments, // pColorAttachments
335 resolveAttachments, // pResolveAttachments
336 depthAttachment, // pDepthStencilAttachment
337 0, // preserveAttachmentCount
338 nullptr, // pPreserveAttachments
339 };
340
341 VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
342 VkPipelineStageFlags dstStageMask = 0;
343 VkAccessFlags srcAccessMask = 0;
344 VkAccessFlags dstAccessMask = 0;
345 {
346 PLUGIN_ASSERT(srcResourceStates);
347 const RenderPassAttachmentResourceStates& dstResourceStates = subpassResourceStates[subpassIdx];
348 for (uint32_t attachmentIdx = 0; attachmentIdx < attachmentCount; ++attachmentIdx) {
349 srcStageMask |= (VkPipelineStageFlagBits)srcResourceStates->states[attachmentIdx].pipelineStageFlags;
350 srcAccessMask |= srcResourceStates->states[attachmentIdx].accessFlags;
351
352 dstStageMask |= (VkPipelineStageFlagBits)dstResourceStates.states[attachmentIdx].pipelineStageFlags;
353 dstAccessMask |= dstResourceStates.states[attachmentIdx].accessFlags;
354 }
355
356 // store for next subpass
357 srcResourceStates = &dstResourceStates;
358 }
359
360 constexpr VkDependencyFlags dependencyFlags { VkDependencyFlagBits::VK_DEPENDENCY_BY_REGION_BIT };
361 const uint32_t dstSubpass = subpassIdx;
362 subpassDependencies[subpassIdx] = {
363 srcSubpass, // srcSubpass
364 subpassIdx, // dstSubpass
365 srcStageMask, // srcStageMask
366 dstStageMask, // dstStageMask
367 srcAccessMask, // srcAccessMask
368 dstAccessMask, // dstAccessMask
369 dependencyFlags, // dependencyFlags
370 };
371 srcSubpass = dstSubpass;
372 }
373
374 VkRenderPassMultiviewCreateInfo* pMultiviewCreateInfo = nullptr;
375 VkRenderPassMultiviewCreateInfo multiViewCreateInfo;
376 if (hasMultiView && deviceVk.GetCommonDeviceExtensions().multiView) {
377 PLUGIN_ASSERT(renderPassDesc.subpassCount == static_cast<uint32_t>(multiViewMasks.size()));
378 multiViewCreateInfo = {
379 VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO, // sType
380 nullptr, // pNext
381 renderPassDesc.subpassCount, // subpassCount
382 multiViewMasks.data(), // pViewMasks
383 0u, // dependencyCount
384 nullptr, // pViewOffsets
385 0u, // correlationMaskCount
386 nullptr, // pCorrelationMasks
387 };
388 pMultiviewCreateInfo = &multiViewCreateInfo;
389 }
390
391 constexpr VkRenderPassCreateFlags renderPassCreateFlags { 0 };
392 const VkRenderPassCreateInfo renderPassCreateInfo {
393 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType
394 pMultiviewCreateInfo, // pNext
395 renderPassCreateFlags, // flags
396 attachmentCount, // attachmentCount
397 attachmentDescriptions, // pAttachments
398 static_cast<uint32_t>(subpassDescriptions.size()), // subpassCount
399 subpassDescriptions.data(), // pSubpasses
400 static_cast<uint32_t>(subpassDependencies.size()), // dependencyCount
401 subpassDependencies.data(), // pDependencies
402 };
403
404 VkRenderPass renderPass { VK_NULL_HANDLE };
405 VALIDATE_VK_RESULT(vkCreateRenderPass(device, // device
406 &renderPassCreateInfo, // pCreateInfo
407 nullptr, // pAllocator
408 &renderPass)); // pRenderPass
409
410 return renderPass;
411 }
412
CreateRenderPassCombined2(const DeviceVk & deviceVk,const RenderPassDesc & renderPassDesc,const LowLevelRenderPassDataVk & lowLevelRenderPassData,const array_view<const RenderPassSubpassDesc> subpassDescs,const RenderPassAttachmentResourceStates * subpassResourceStates,const RenderPassAttachmentResourceStates * inputResourceStates,const RenderPassImageLayouts * imageLayouts,const uint32_t maxAttachmentReferenceCountPerSubpass,const bool createRenderPassCompatibility,RenderPassCreatorVk::RenderPassStorage2 & rps2)413 VkRenderPass CreateRenderPassCombined2(const DeviceVk& deviceVk, const RenderPassDesc& renderPassDesc,
414 const LowLevelRenderPassDataVk& lowLevelRenderPassData, const array_view<const RenderPassSubpassDesc> subpassDescs,
415 const RenderPassAttachmentResourceStates* subpassResourceStates,
416 const RenderPassAttachmentResourceStates* inputResourceStates,
417 const RenderPassImageLayouts* imageLayouts, // null when using compatibility
418 const uint32_t maxAttachmentReferenceCountPerSubpass, const bool createRenderPassCompatibility,
419 RenderPassCreatorVk::RenderPassStorage2& rps2)
420 {
421 const VkDevice device = (deviceVk.GetPlatformDataVk()).device;
422 const uint32_t attachmentCount = renderPassDesc.attachmentCount;
423 PLUGIN_ASSERT(attachmentCount <= PipelineStateConstants::MAX_RENDER_PASS_ATTACHMENT_COUNT);
424
425 VkAttachmentDescription2KHR attachmentDescriptions[PipelineStateConstants::MAX_RENDER_PASS_ATTACHMENT_COUNT];
426 const auto compatibilityAttachments =
427 array_view(lowLevelRenderPassData.renderPassCompatibilityDesc.attachments, renderPassDesc.attachmentCount);
428 {
429 // add all attachments to attachmentDescriptions array
430 const auto attachments = array_view(renderPassDesc.attachments, renderPassDesc.attachmentCount);
431 const auto descriptions = array_view(attachmentDescriptions, countof(attachmentDescriptions));
432 if (createRenderPassCompatibility) {
433 CreateAttachmentDescriptionsCompatibility2(attachments, compatibilityAttachments, descriptions);
434 } else {
435 PLUGIN_ASSERT(imageLayouts);
436 const auto initialLayouts =
437 array_view(imageLayouts->attachmentInitialLayouts, renderPassDesc.attachmentCount);
438 const auto finalLayouts = array_view(imageLayouts->attachmentFinalLayouts, renderPassDesc.attachmentCount);
439 CreateAttachmentDescriptions2(
440 attachments, compatibilityAttachments, initialLayouts, finalLayouts, descriptions);
441 }
442 }
443
444 // resize vector for all subpass references
445 const uint32_t subpassCount = renderPassDesc.subpassCount;
446 auto& subpassDescriptions = rps2.subpassDescriptions;
447 auto& subpassDependencies = rps2.subpassDependencies;
448 auto& subpassDescriptionsDepthStencilResolve = rps2.subpassDescriptionsDepthStencilResolve;
449 auto& attachmentReferences = rps2.attachmentReferences;
450 subpassDescriptions.resize(subpassCount);
451 subpassDependencies.resize(subpassCount);
452 subpassDescriptionsDepthStencilResolve.resize(subpassCount);
453 #if (RENDER_VULKAN_FSR_ENABLED == 1)
454 auto& fragmentShadingRateAttachmentInfos = rps2.fragmentShadingRateAttachmentInfos;
455 fragmentShadingRateAttachmentInfos.resize(subpassCount);
456 #endif
457 attachmentReferences.resize(subpassCount * maxAttachmentReferenceCountPerSubpass);
458
459 uint32_t srcSubpass = VK_SUBPASS_EXTERNAL;
460 const RenderPassAttachmentResourceStates* srcResourceStates = inputResourceStates;
461 const bool supportsMultiView = deviceVk.GetCommonDeviceExtensions().multiView;
462 for (uint32_t subpassIdx = 0; subpassIdx < subpassCount; ++subpassIdx) {
463 const RenderPassSubpassDesc& subpassDesc = subpassDescs[subpassIdx];
464
465 const uint32_t startReferenceIndex = subpassIdx * maxAttachmentReferenceCountPerSubpass;
466 uint32_t referenceIndex = startReferenceIndex;
467
468 VkAttachmentReference2KHR* inputAttachments = nullptr;
469 const ImageLayout* layouts =
470 (createRenderPassCompatibility) ? nullptr : subpassResourceStates[subpassIdx].layouts;
471 if (subpassDesc.inputAttachmentCount > 0) {
472 inputAttachments = &attachmentReferences[referenceIndex];
473 CreateAttachmentReferences2(subpassDesc.inputAttachmentIndices, layouts, compatibilityAttachments,
474 subpassDesc.inputAttachmentCount, referenceIndex, createRenderPassCompatibility,
475 attachmentReferences.data());
476 referenceIndex += subpassDesc.inputAttachmentCount;
477 }
478
479 VkAttachmentReference2KHR* colorAttachments = nullptr;
480 if (subpassDesc.colorAttachmentCount > 0) {
481 colorAttachments = &attachmentReferences[referenceIndex];
482 CreateAttachmentReferences2(subpassDesc.colorAttachmentIndices, layouts, compatibilityAttachments,
483 subpassDesc.colorAttachmentCount, referenceIndex, createRenderPassCompatibility,
484 attachmentReferences.data());
485 referenceIndex += subpassDesc.colorAttachmentCount;
486 }
487
488 VkAttachmentReference2KHR* resolveAttachments = nullptr;
489 if (subpassDesc.resolveAttachmentCount > 0) {
490 resolveAttachments = &attachmentReferences[referenceIndex];
491 CreateAttachmentReferences2(subpassDesc.resolveAttachmentIndices, layouts, compatibilityAttachments,
492 subpassDesc.resolveAttachmentCount, referenceIndex, createRenderPassCompatibility,
493 attachmentReferences.data());
494 referenceIndex += subpassDesc.resolveAttachmentCount;
495 }
496
497 // for extensions
498 void* pFirstExt = nullptr;
499 const void** ppNext = nullptr;
500 #if (RENDER_VULKAN_FSR_ENABLED == 1)
501 if (subpassDesc.fragmentShadingRateAttachmentCount > 0) {
502 VkAttachmentReference2KHR* fragmentShadingRateAttachments = &attachmentReferences[referenceIndex];
503 CreateAttachmentReferences2(&subpassDesc.fragmentShadingRateAttachmentIndex, layouts,
504 compatibilityAttachments, subpassDesc.fragmentShadingRateAttachmentCount, referenceIndex,
505 createRenderPassCompatibility, attachmentReferences.data());
506 referenceIndex += subpassDesc.fragmentShadingRateAttachmentCount;
507
508 VkFragmentShadingRateAttachmentInfoKHR& fragmentShadingRateAttachmentInfo =
509 fragmentShadingRateAttachmentInfos[subpassIdx];
510 fragmentShadingRateAttachmentInfo.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
511 fragmentShadingRateAttachmentInfo.pNext = nullptr;
512 const Size2D srats = ClampShadingRateAttachmentTexelSize(deviceVk, subpassDesc.shadingRateTexelSize);
513 fragmentShadingRateAttachmentInfo.shadingRateAttachmentTexelSize = { srats.width, srats.height };
514 fragmentShadingRateAttachmentInfo.pFragmentShadingRateAttachment = fragmentShadingRateAttachments;
515 if (!pFirstExt) {
516 pFirstExt = &fragmentShadingRateAttachmentInfo;
517 ppNext = &(fragmentShadingRateAttachmentInfo.pNext);
518 } else {
519 *ppNext = &fragmentShadingRateAttachmentInfo;
520 ppNext = &(fragmentShadingRateAttachmentInfo.pNext);
521 }
522 }
523 #endif
524
525 // NOTE: preserve attachments
526 VkAttachmentReference2KHR* depthAttachment = nullptr;
527 if (subpassDesc.depthAttachmentCount > 0) {
528 depthAttachment = &attachmentReferences[referenceIndex];
529 CreateAttachmentReferences2(&subpassDesc.depthAttachmentIndex, layouts, compatibilityAttachments,
530 subpassDesc.depthAttachmentCount, referenceIndex, createRenderPassCompatibility,
531 attachmentReferences.data());
532 referenceIndex += subpassDesc.depthAttachmentCount;
533 // cannot resolve mode NONE
534 if ((subpassDesc.depthResolveAttachmentCount > 0) &&
535 (subpassDesc.depthResolveModeFlagBit || subpassDesc.stencilResolveModeFlagBit)) {
536 VkAttachmentReference2KHR* depthResolveAttachment = nullptr;
537 depthResolveAttachment = &attachmentReferences[referenceIndex];
538 CreateAttachmentReferences2(&subpassDesc.depthResolveAttachmentIndex, layouts, compatibilityAttachments,
539 subpassDesc.depthResolveAttachmentCount, referenceIndex, createRenderPassCompatibility,
540 attachmentReferences.data());
541 referenceIndex += subpassDesc.depthResolveAttachmentCount;
542 VkSubpassDescriptionDepthStencilResolveKHR& subpassDescriptionDepthStencilResolve =
543 subpassDescriptionsDepthStencilResolve[subpassIdx];
544 subpassDescriptionDepthStencilResolve.sType =
545 VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
546 subpassDescriptionDepthStencilResolve.pNext = nullptr;
547 // NOTE: acceptable values needs to be evaluated from the device
548 // independent resolve not yet supported
549 const VkResolveModeFlagBitsKHR depthStencilResolveMode =
550 (VkResolveModeFlagBitsKHR)subpassDesc.depthResolveModeFlagBit;
551 subpassDescriptionDepthStencilResolve.depthResolveMode = depthStencilResolveMode;
552 subpassDescriptionDepthStencilResolve.stencilResolveMode = depthStencilResolveMode;
553 subpassDescriptionDepthStencilResolve.pDepthStencilResolveAttachment = depthResolveAttachment;
554
555 if (!pFirstExt) {
556 pFirstExt = &subpassDescriptionDepthStencilResolve;
557 ppNext = &(subpassDescriptionDepthStencilResolve.pNext);
558 } else {
559 *ppNext = &subpassDescriptionDepthStencilResolve;
560 ppNext = &(subpassDescriptionDepthStencilResolve.pNext);
561 }
562 }
563 }
564
565 constexpr VkSubpassDescriptionFlags subpassDescriptionFlags { 0 };
566 subpassDescriptions[subpassIdx] = {
567 VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR, // sType
568 pFirstExt, // pNext
569 subpassDescriptionFlags, // flags
570 VkPipelineBindPoint::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
571 supportsMultiView ? subpassDesc.viewMask : 0, // viewMask
572 subpassDesc.inputAttachmentCount, // inputAttachmentCount
573 inputAttachments, // pInputAttachments
574 subpassDesc.colorAttachmentCount, // colorAttachmentCount
575 colorAttachments, // pColorAttachments
576 resolveAttachments, // pResolveAttachments
577 depthAttachment, // pDepthStencilAttachment
578 0, // preserveAttachmentCount
579 nullptr, // pPreserveAttachments
580 };
581
582 VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
583 VkPipelineStageFlags dstStageMask = 0;
584 VkAccessFlags srcAccessMask = 0;
585 VkAccessFlags dstAccessMask = 0;
586 {
587 PLUGIN_ASSERT(srcResourceStates);
588 const RenderPassAttachmentResourceStates& dstResourceStates = subpassResourceStates[subpassIdx];
589 for (uint32_t attachmentIdx = 0; attachmentIdx < attachmentCount; ++attachmentIdx) {
590 srcStageMask |= srcResourceStates->states[attachmentIdx].pipelineStageFlags;
591 srcAccessMask |= srcResourceStates->states[attachmentIdx].accessFlags;
592
593 dstStageMask |= dstResourceStates.states[attachmentIdx].pipelineStageFlags;
594 dstAccessMask |= dstResourceStates.states[attachmentIdx].accessFlags;
595 }
596
597 // store for next subpass
598 srcResourceStates = &dstResourceStates;
599 }
600
601 constexpr VkDependencyFlags dependencyFlags { VkDependencyFlagBits::VK_DEPENDENCY_BY_REGION_BIT };
602 const uint32_t dstSubpass = subpassIdx;
603 subpassDependencies[subpassIdx] = {
604 VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR, // sType
605 nullptr, // pNext
606 srcSubpass, // srcSubpass
607 subpassIdx, // dstSubpass
608 srcStageMask, // srcStageMask
609 dstStageMask, // dstStageMask
610 srcAccessMask, // srcAccessMask
611 dstAccessMask, // dstAccessMask
612 dependencyFlags, // dependencyFlags
613 0, // viewOffset
614 };
615 srcSubpass = dstSubpass;
616 }
617
618 constexpr VkRenderPassCreateFlags renderPassCreateFlags { 0 };
619 const VkRenderPassCreateInfo2KHR renderPassCreateInfo {
620 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR, // sType
621 nullptr, // pNext
622 renderPassCreateFlags, // flags
623 attachmentCount, // attachmentCount
624 attachmentDescriptions, // pAttachments
625 static_cast<uint32_t>(subpassDescriptions.size()), // subpassCount
626 subpassDescriptions.data(), // pSubpasses
627 static_cast<uint32_t>(subpassDependencies.size()), // dependencyCount
628 subpassDependencies.data(), // pDependencies
629 0u, // correlatedViewMaskCount
630 nullptr, // pCorrelatedViewMasks
631 };
632
633 VkRenderPass renderPass { VK_NULL_HANDLE };
634 const DeviceVk::ExtFunctions& extFunctions = deviceVk.GetExtFunctions();
635 PLUGIN_ASSERT(extFunctions.vkCreateRenderPass2KHR); // required here
636 VALIDATE_VK_RESULT(extFunctions.vkCreateRenderPass2KHR(device, // device
637 &renderPassCreateInfo, // pCreateInfo
638 nullptr, // pAllocator
639 &renderPass)); // pRenderPass
640
641 return renderPass;
642 }
643 } // namespace
644
CreateRenderPass(const DeviceVk & deviceVk,const RenderCommandBeginRenderPass & beginRenderPass,const LowLevelRenderPassDataVk & lowLevelRenderPassData)645 VkRenderPass RenderPassCreatorVk::CreateRenderPass(const DeviceVk& deviceVk,
646 const RenderCommandBeginRenderPass& beginRenderPass, const LowLevelRenderPassDataVk& lowLevelRenderPassData)
647 {
648 const uint32_t subpassCount = beginRenderPass.renderPassDesc.subpassCount;
649 uint32_t maxAttachmentReferenceCountPerSubpass = 0;
650 for (uint32_t subpassIdx = 0; subpassIdx < subpassCount; ++subpassIdx) {
651 const auto& subpassDesc = beginRenderPass.subpasses[subpassIdx];
652 maxAttachmentReferenceCountPerSubpass = Math::max(maxAttachmentReferenceCountPerSubpass,
653 subpassDesc.inputAttachmentCount + subpassDesc.colorAttachmentCount + subpassDesc.resolveAttachmentCount +
654 subpassDesc.depthAttachmentCount + subpassDesc.depthResolveAttachmentCount +
655 subpassDesc.fragmentShadingRateAttachmentCount);
656 }
657
658 const DeviceVk::CommonDeviceExtensions& deviceExtensions = deviceVk.GetCommonDeviceExtensions();
659 // use renderPass2 when ever the extension is present (to make extensions work)
660 if (deviceExtensions.renderPass2) {
661 return CreateRenderPassCombined2(deviceVk, beginRenderPass.renderPassDesc, lowLevelRenderPassData,
662 beginRenderPass.subpasses, beginRenderPass.subpassResourceStates.data(),
663 &beginRenderPass.inputResourceStates, &beginRenderPass.imageLayouts, maxAttachmentReferenceCountPerSubpass,
664 false, rps2_);
665 } else {
666 return CreateRenderPassCombined(deviceVk, beginRenderPass.renderPassDesc, lowLevelRenderPassData,
667 beginRenderPass.subpasses, beginRenderPass.subpassResourceStates.data(),
668 &beginRenderPass.inputResourceStates, &beginRenderPass.imageLayouts, maxAttachmentReferenceCountPerSubpass,
669 false, rps1_);
670 }
671 }
672
CreateRenderPassCompatibility(const DeviceVk & deviceVk,const RenderCommandBeginRenderPass & beginRenderPass,const LowLevelRenderPassDataVk & lowLevelRenderPassData)673 VkRenderPass RenderPassCreatorVk::CreateRenderPassCompatibility(const DeviceVk& deviceVk,
674 const RenderCommandBeginRenderPass& beginRenderPass, const LowLevelRenderPassDataVk& lowLevelRenderPassData)
675 {
676 const uint32_t subpassCount = beginRenderPass.renderPassDesc.subpassCount;
677 uint32_t maxAttachmentReferenceCountPerSubpass = 0;
678 for (uint32_t subpassIdx = 0; subpassIdx < subpassCount; ++subpassIdx) {
679 const auto& subpassDesc = beginRenderPass.subpasses[subpassIdx];
680 maxAttachmentReferenceCountPerSubpass = Math::max(maxAttachmentReferenceCountPerSubpass,
681 subpassDesc.inputAttachmentCount + subpassDesc.colorAttachmentCount + subpassDesc.resolveAttachmentCount +
682 subpassDesc.depthAttachmentCount + subpassDesc.depthResolveAttachmentCount +
683 subpassDesc.fragmentShadingRateAttachmentCount);
684 }
685
686 const DeviceVk::CommonDeviceExtensions& deviceExtensions = deviceVk.GetCommonDeviceExtensions();
687 // use renderPass2 when ever the extension is present (to make extensions work)
688 if (deviceExtensions.renderPass2) {
689 return CreateRenderPassCombined2(deviceVk, beginRenderPass.renderPassDesc, lowLevelRenderPassData,
690 beginRenderPass.subpasses, beginRenderPass.subpassResourceStates.data(),
691 &beginRenderPass.inputResourceStates, nullptr, maxAttachmentReferenceCountPerSubpass, true, rps2_);
692 } else {
693 return CreateRenderPassCombined(deviceVk, beginRenderPass.renderPassDesc, lowLevelRenderPassData,
694 beginRenderPass.subpasses, beginRenderPass.subpassResourceStates.data(),
695 &beginRenderPass.inputResourceStates, nullptr, maxAttachmentReferenceCountPerSubpass, true, rps1_);
696 }
697 }
698
DestroyRenderPass(VkDevice device,VkRenderPass renderPass)699 void RenderPassCreatorVk::DestroyRenderPass(VkDevice device, VkRenderPass renderPass)
700 {
701 PLUGIN_ASSERT(device);
702 PLUGIN_ASSERT(renderPass);
703
704 vkDestroyRenderPass(device, // device
705 renderPass, // renderPass
706 nullptr); // pAllocator
707 }
708
709 RENDER_END_NAMESPACE()
710