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