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