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