Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
VulkanRenderPass.cpp
Go to the documentation of this file.
1/*
2* Copyright 2023 Google LLC
3*
4* Use of this source code is governed by a BSD-style license that can be
5* found in the LICENSE file.
6*/
7
9
16
17#include <limits>
18
19namespace skgpu::graphite {
20
21namespace { // anonymous namespace
22
23int determine_uint32_count(int rpAttachmentCount, int subpassCount, int subpassDependencyCount ) {
24 // The key will be formed such that bigger-picture items (such as the total attachment count)
25 // will be near the front of the key to more quickly eliminate incompatible keys. Each
26 // renderpass key will start with the total number of attachments associated with it
27 // followed by how many subpasses and subpass dependencies the renderpass has.Packed together,
28 // these will use one uint32.
29 int num32DataCnt = 1;
30 SkASSERT(static_cast<uint32_t>(rpAttachmentCount) <= (1u << 8));
31 SkASSERT(static_cast<uint32_t>(subpassCount) <= (1u << 8));
32 SkASSERT(static_cast<uint32_t>(subpassDependencyCount) <= (1u << 8));
33
34 // The key will then contain key information for each attachment. This includes format, sample
35 // count, and load/store operation information.
36 num32DataCnt += 3 * rpAttachmentCount;
37 // Then, subpass information will be added in the form of attachment reference indices. Reserve
38 // one int32 for each possible attachment reference type, of which there are 4.
39 // There are 4 possible attachment reference types. Pack all 4 attachment reference indices into
40 // one uint32.
41 num32DataCnt += subpassCount;
42 // Each subpass dependency will be allotted 6 int32s to store all its pertinent information.
43 num32DataCnt += 6 * subpassDependencyCount;
44
45 return num32DataCnt;
46}
47
48void add_attachment_description_info_to_key(ResourceKey::Builder& builder,
49 const TextureInfo& textureInfo,
50 int& builderIdx,
51 LoadOp loadOp,
52 StoreOp storeOp) {
53 VulkanTextureInfo vkTexInfo;
54 if (textureInfo.isValid() && textureInfo.getVulkanTextureInfo(&vkTexInfo)) {
55 builder[builderIdx++] = vkTexInfo.fFormat;
56 builder[builderIdx++] = vkTexInfo.fSampleCount;
57 SkASSERT(sizeof(loadOp) < (1u << 8));
58 SkASSERT(sizeof(storeOp) < (1u << 8));
59 builder[builderIdx++] = static_cast<uint8_t>(loadOp) << 8 | static_cast<uint8_t>(storeOp);
60 }
61 // We only count attachments that are valid textures when calculating the total number of
62 // render pass attachments, so if a texture is invalid, simply skip it rather than using
63 // VK_ATTACHMENT_UNUSED and incrementing the builderIdx. Attachments can be differentiated from
64 // one another by their sample count and format (i.e. depth/stencil attachments will have a
65 // depth/stencil format).
66}
67
68void add_subpass_info_to_key(ResourceKey::Builder& builder,
69 int& builderIdx,
70 bool hasColorAttachment,
71 bool hasColorResolveAttachment,
72 bool hasDepthStencilAttachment,
73 bool loadMSAAFromResolve,
74 int subpassCount,
75 int subpassDependencyCount) {
76 // TODO: Fetch actual attachment reference and index information for each
77 // subpass from RenderPassDesc. For now, determine subpass data based upon whether we are
78 // loading from MSAA or not.
79 const int mainSubpassIdx = loadMSAAFromResolve ? 1 : 0;
80 // Assign a smaller value to represent VK_ATTACHMENT_UNUSED.
81 static constexpr int kAttachmentUnused = std::numeric_limits<uint8_t>::max();
82
83 // The following key structure assumes that we only have up to one reference of each type per
84 // subpass and that attachments are indexed in order of color, resolve, depth/stencil, then
85 // input attachments. These indices are statically defined in the VulkanRenderPass header file.
86 for (int j = 0; j < subpassCount; j++) {
87 if (j == mainSubpassIdx) {
88 uint32_t attachmentIdxKeyInfo;
89 attachmentIdxKeyInfo = hasColorAttachment ? VulkanRenderPass::kColorAttachmentIdx
90 : kAttachmentUnused;
91 attachmentIdxKeyInfo |=
92 (hasColorResolveAttachment ? VulkanRenderPass::kColorResolveAttachmentIdx
93 : kAttachmentUnused) << 8;
94 attachmentIdxKeyInfo |=
95 (hasDepthStencilAttachment ? VulkanRenderPass::kDepthStencilAttachmentIdx
96 : kAttachmentUnused) << 16;
97 // TODO: Add input attachment info to key once supported for use in main subpass
98 attachmentIdxKeyInfo |= kAttachmentUnused << 24;
99
100 builder[builderIdx++] = attachmentIdxKeyInfo;
101 } else { // Loading MSAA from resolve subpass
102 SkASSERT(hasColorAttachment);
103 builder[builderIdx++] =
104 VulkanRenderPass::kColorAttachmentIdx | // color attachment
105 (kAttachmentUnused << 8) | // No color resolve attachment
106 (kAttachmentUnused << 16) | // No depth/stencil attachment
107 // The input attachment for the load subpass is the color resolve texture.
109 }
110 }
111
112 // TODO: Query RenderPassDesc for subpass dependency information & populate the key accordingly.
113 // For now, we know that the only subpass dependency will be that expected for loading MSAA from
114 // resolve.
115 for (int i = 0; i < subpassDependencyCount; i++) {
116 builder[builderIdx++] = 0 | (mainSubpassIdx << 8); // srcSubpass, dstSubpass
117 builder[builderIdx++] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // srcStageMask
118 builder[builderIdx++] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; // dstStageMask
119 builder[builderIdx++] = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; // srcAccessMask
120 builder[builderIdx++] = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | // dstAccessMask
122 builder[builderIdx++] = VK_DEPENDENCY_BY_REGION_BIT; // dependencyFlags
123 }
124}
125
126void populate_key(VulkanRenderPass::VulkanRenderPassMetaData& rpMetaData,
127 ResourceKey::Builder& builder,
128 int& builderIdx,
129 bool compatibleOnly) {
130 builder[builderIdx++] = rpMetaData.fAttachments.size() |
131 (rpMetaData.fSubpassCount << 8) |
132 (rpMetaData.fSubpassDependencyCount << 16);
133
134 // Iterate through each renderpass attachment to add its information
135 for (int i = 0; i < rpMetaData.fAttachments.size(); i++) {
136 add_attachment_description_info_to_key(
137 builder,
138 rpMetaData.fAttachments[i]->fTextureInfo,
139 builderIdx,
140 // Assign LoadOp::kLoad and StoreOp::kStore as default load/store operations for
141 // compatible render passes where load/store ops don't need to match.
142 compatibleOnly ? LoadOp::kLoad : rpMetaData.fAttachments[i]->fLoadOp,
143 compatibleOnly ? StoreOp::kStore : rpMetaData.fAttachments[i]->fStoreOp);
144 }
145
146 add_subpass_info_to_key(builder,
147 builderIdx,
148 rpMetaData.fHasColorAttachment,
149 rpMetaData.fHasColorResolveAttachment,
150 rpMetaData.fHasDepthStencilAttachment,
151 rpMetaData.fLoadMSAAFromResolve,
152 rpMetaData.fSubpassCount,
153 rpMetaData.fSubpassDependencyCount);
154}
155
156} // anonymous namespace
157
159 const RenderPassDesc& renderPassDesc) {
167
168 // TODO: Query for more attachments once the RenderPassDesc struct contains that information.
169 // For now, we only ever expect to see 0 or 1 of each attachment type (color, resolve, and
170 // depth/stencil), so the count of each of those can simply be determined with a bool.
174
175 // Accumulate attachments into a container to mimic future structure in RenderPassDesc
180 fAttachments.push_back(&renderPassDesc.fColorAttachment);
181 }
183 fAttachments.push_back(&renderPassDesc.fColorResolveAttachment);
184 }
186 fAttachments.push_back(&renderPassDesc.fDepthStencilAttachment);
187 }
188
189 // TODO: Reference RenderPassDesc to determine number and makeup of subpasses and their
190 // dependencies. For now, we only ever expect 1 (in most cases) or 2 (when loading MSAA).
193 fUint32DataCnt = determine_uint32_count(
195}
196
198 const RenderPassDesc& renderPassDesc, bool compatibleOnly) {
199
200 VulkanRenderPassMetaData rpMetaData = VulkanRenderPassMetaData(renderPassDesc);
201
205
206 int startingIdx = 0;
207 populate_key(rpMetaData, builder, startingIdx, compatibleOnly);
208
209 builder.finish();
210 return key;
211}
212
214 ResourceKey::Builder& builder,
215 int& builderIdx,
216 bool compatibleOnly) {
217 populate_key(rpMetaData, builder, builderIdx, /*compatibleOnly=*/true);
218}
219
220namespace { // anonymous namespace
222 const VulkanTextureInfo& textureInfo,
223 const AttachmentDesc& desc,
224 const LoadOp loadOp,
225 const StoreOp storeOp,
226 const VkImageLayout initialLayout,
227 const VkImageLayout finalLayout) {
228 static_assert((int)LoadOp::kLoad == 0);
229 static_assert((int)LoadOp::kClear == 1);
230 static_assert((int)LoadOp::kDiscard == 2);
231 static_assert(std::size(vkLoadOp) == kLoadOpCount);
232 static_assert((int)StoreOp::kStore == 0);
233 static_assert((int)StoreOp::kDiscard == 1);
234 static_assert(std::size(vkStoreOp) == kStoreOpCount);
235
236 outAttachment->flags = 0;
237 outAttachment->format = textureInfo.fFormat;
238 VkSampleCountFlagBits sampleCount;
240 skgpu::SampleCountToVkSampleCount(textureInfo.fSampleCount, &sampleCount));
241 outAttachment->samples = sampleCount;
242 switch (initialLayout) {
246 outAttachment->loadOp = vkLoadOp[static_cast<int>(loadOp)];
247 outAttachment->storeOp = vkStoreOp[static_cast<int>(storeOp)];
250 break;
252 // The loadOp and storeOp refer to the depth part of the attachment and the stencil*Ops
253 // refer to the stencil bits in the attachment.
254 outAttachment->loadOp = vkLoadOp[static_cast<int>(loadOp)];
255 outAttachment->storeOp = vkStoreOp[static_cast<int>(storeOp)];
256 outAttachment->stencilLoadOp = vkLoadOp[static_cast<int>(loadOp)];
257 outAttachment->stencilStoreOp = vkStoreOp[static_cast<int>(storeOp)];
258 break;
259 default:
260 SK_ABORT("Unexpected attachment layout");
261 }
262 outAttachment->initialLayout = initialLayout;
263 outAttachment->finalLayout = finalLayout == VK_IMAGE_LAYOUT_UNDEFINED ? initialLayout
264 : finalLayout;
265}
266} // anonymous namespace
267
269 const RenderPassDesc& renderPassDesc,
270 bool compatibleOnly) {
271 VkRenderPass renderPass;
273 auto& colorAttachmentTextureInfo = renderPassDesc.fColorAttachment.fTextureInfo;
274 auto& colorResolveAttachmentTextureInfo = renderPassDesc.fColorResolveAttachment.fTextureInfo;
275 auto& depthStencilAttachmentTextureInfo = renderPassDesc.fDepthStencilAttachment.fTextureInfo;
276 bool hasColorAttachment = colorAttachmentTextureInfo.isValid();
277 bool hasColorResolveAttachment = colorResolveAttachmentTextureInfo.isValid();
278 bool hasDepthStencilAttachment = depthStencilAttachmentTextureInfo.isValid();
279
281 // Create and track attachment references for the subpass.
282 VkAttachmentReference colorRef;
283 VkAttachmentReference resolveRef;
284 VkAttachmentReference resolveLoadInputRef;
285 VkAttachmentReference depthStencilRef;
286
287 bool loadMSAAFromResolve = false;
288 if (hasColorAttachment) {
289 VulkanTextureInfo colorAttachTexInfo;
290 colorAttachmentTextureInfo.getVulkanTextureInfo(&colorAttachTexInfo);
291 auto& colorAttachDesc = renderPassDesc.fColorAttachment;
292
293 colorRef.attachment = attachmentDescs.size();
294 VkAttachmentDescription& vkColorAttachDesc = attachmentDescs.push_back();
295 memset(&vkColorAttachDesc, 0, sizeof(VkAttachmentDescription));
297 &vkColorAttachDesc,
298 colorAttachTexInfo,
299 colorAttachDesc,
300 compatibleOnly ? LoadOp::kDiscard : colorAttachDesc.fLoadOp,
301 compatibleOnly ? StoreOp::kDiscard : colorAttachDesc.fStoreOp,
305
306 if (hasColorResolveAttachment) {
307 loadMSAAFromResolve = renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
309 VulkanTextureInfo resolveAttachTexInfo;
310 colorResolveAttachmentTextureInfo.getVulkanTextureInfo(&resolveAttachTexInfo);
311 auto& resolveAttachDesc = renderPassDesc.fColorResolveAttachment;
312
313 resolveRef.attachment = attachmentDescs.size();
314 VkAttachmentDescription& vkResolveAttachDesc = attachmentDescs.push_back();
315 memset(&vkResolveAttachDesc, 0, sizeof(VkAttachmentDescription));
317 &vkResolveAttachDesc,
318 resolveAttachTexInfo,
319 resolveAttachDesc,
320 compatibleOnly ? LoadOp::kDiscard : resolveAttachDesc.fLoadOp,
321 compatibleOnly ? StoreOp::kDiscard : resolveAttachDesc.fStoreOp,
322 loadMSAAFromResolve ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
326 } else {
327 resolveRef.attachment = VK_ATTACHMENT_UNUSED;
329 }
330 } else {
331 SkASSERT(false);
334 resolveRef.attachment = VK_ATTACHMENT_UNUSED;
336 }
337
338 if (hasDepthStencilAttachment) {
339 VulkanTextureInfo depthStencilTexInfo;
340 depthStencilAttachmentTextureInfo.getVulkanTextureInfo(&depthStencilTexInfo);
341 auto& depthStencilAttachDesc = renderPassDesc.fDepthStencilAttachment;
342
343 depthStencilRef.attachment = attachmentDescs.size();
344 VkAttachmentDescription& vkDepthStencilAttachDesc = attachmentDescs.push_back();
346 &vkDepthStencilAttachDesc,
347 depthStencilTexInfo,
348 depthStencilAttachDesc,
349 compatibleOnly ? LoadOp::kDiscard : depthStencilAttachDesc.fLoadOp,
350 compatibleOnly ? StoreOp::kDiscard : depthStencilAttachDesc.fStoreOp,
354 } else {
355 depthStencilRef.attachment = VK_ATTACHMENT_UNUSED;
356 depthStencilRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
357 }
358
359 // Create VkRenderPass
360 VkRenderPassCreateInfo renderPassInfo;
361 memset(&renderPassInfo, 0, sizeof(VkRenderPassCreateInfo));
363 renderPassInfo.pNext = nullptr;
364 renderPassInfo.flags = 0;
365 renderPassInfo.subpassCount = loadMSAAFromResolve ? 2 : 1;
366
367 skia_private::TArray<VkSubpassDescription> subpassDescs(renderPassInfo.subpassCount);
368 memset(subpassDescs.begin(), 0, renderPassInfo.subpassCount * sizeof(VkSubpassDescription));
369
370 // If we are loading MSAA from resolve, that subpass must always be first.
372 if (loadMSAAFromResolve) {
373 resolveLoadInputRef.attachment = resolveRef.attachment;
375
376 VkSubpassDescription& loadSubpassDesc = subpassDescs.push_back();
377 memset(&loadSubpassDesc, 0, sizeof(VkSubpassDescription));
378 loadSubpassDesc.flags = 0;
380 loadSubpassDesc.inputAttachmentCount = 1;
381 loadSubpassDesc.pInputAttachments = &resolveLoadInputRef;
382 loadSubpassDesc.colorAttachmentCount = 1;
383 loadSubpassDesc.pColorAttachments = &colorRef;
384 loadSubpassDesc.pResolveAttachments = nullptr;
385 loadSubpassDesc.pDepthStencilAttachment = nullptr;
386 loadSubpassDesc.preserveAttachmentCount = 0;
387 loadSubpassDesc.pPreserveAttachments = nullptr;
388
389 // Set up the subpass dependency
390 const int mainSubpassIdx = loadMSAAFromResolve ? 1 : 0;
391 dependency.srcSubpass = 0;
392 dependency.dstSubpass = mainSubpassIdx;
393 dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
397 dependency.dstAccessMask =
399 }
400
401 VkSubpassDescription& mainSubpassDesc = subpassDescs.push_back();
402 memset(&mainSubpassDesc, 0, sizeof(VkSubpassDescription));
403 mainSubpassDesc.flags = 0;
405 mainSubpassDesc.inputAttachmentCount = 0; // TODO: Add input attachment support in main subpass
406 mainSubpassDesc.pInputAttachments = nullptr;
407 mainSubpassDesc.colorAttachmentCount = 1;
408 mainSubpassDesc.pColorAttachments = &colorRef;
409 mainSubpassDesc.pResolveAttachments = &resolveRef;
410 mainSubpassDesc.pDepthStencilAttachment = &depthStencilRef;
411 mainSubpassDesc.preserveAttachmentCount = 0;
412 mainSubpassDesc.pPreserveAttachments = nullptr;
413
414 renderPassInfo.pSubpasses = subpassDescs.begin();
415 renderPassInfo.dependencyCount = loadMSAAFromResolve ? 1 : 0;
416 renderPassInfo.pDependencies = loadMSAAFromResolve ? &dependency : VK_NULL_HANDLE;
417 renderPassInfo.attachmentCount = attachmentDescs.size();
418 renderPassInfo.pAttachments = attachmentDescs.begin();
419
421 VULKAN_CALL_RESULT(context,
422 result,
423 CreateRenderPass(context->device(), &renderPassInfo, nullptr, &renderPass));
424 if (result != VK_SUCCESS) {
425 return nullptr;
426 }
428 VULKAN_CALL(context->interface(), GetRenderAreaGranularity(context->device(),
430 &granularity));
432}
433
434VulkanRenderPass::VulkanRenderPass(const VulkanSharedContext* context,
435 VkRenderPass renderPass,
437 : Resource(context,
440 /*gpuMemorySize=*/0,
441 /*label=*/"VulkanRenderPass")
442 , fSharedContext(context)
443 , fRenderPass (renderPass)
444 , fGranularity (granularity) {
445}
446
448 VULKAN_CALL(fSharedContext->interface(),
449 DestroyRenderPass(fSharedContext->device(), fRenderPass, nullptr));
450}
451
452} // namespace skgpu::graphite
void setup_vk_attachment_description(VkAttachmentDescription *attachment, const AttachmentDesc &desc, VkImageLayout startLayout, VkImageLayout endLayout)
#define SkAssertResult(cond)
Definition SkAssert.h:123
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kYes
Do pre-clip the geometry before applying the (perspective) matrix.
#define VULKAN_CALL(IFACE, X)
#define VULKAN_CALL_RESULT(SHARED_CONTEXT, RESULT, X)
Type::kYUV Type::kRGBA() int(0.7 *637)
const GraphiteResourceKey & key() const
Definition Resource.h:153
static constexpr int kColorAttachmentIdx
static void AddRenderPassInfoToKey(VulkanRenderPassMetaData &rpMetaData, ResourceKey::Builder &builder, int &builderIdx, bool compatibleOnly)
static sk_sp< VulkanRenderPass > MakeRenderPass(const VulkanSharedContext *, const RenderPassDesc &, bool compatibleOnly)
static constexpr int kColorResolveAttachmentIdx
static constexpr int kDepthStencilAttachmentIdx
static GraphiteResourceKey MakeRenderPassKey(const RenderPassDesc &, bool compatibleOnly)
const skgpu::VulkanInterface * interface() const
int size() const
Definition SkTArray.h:416
GAsyncResult * result
uint32_t ResourceType
static constexpr int kLoadOpCount
static const VkAttachmentLoadOp vkLoadOp[]
static constexpr int kStoreOpCount
static const VkAttachmentStoreOp vkStoreOp[]
Budgeted
Definition GpuTypes.h:35
static constexpr bool SampleCountToVkSampleCount(uint32_t samples, VkSampleCountFlagBits *vkSamples)
VkAttachmentLoadOp loadOp
VkAttachmentStoreOp stencilStoreOp
VkSampleCountFlagBits samples
VkAttachmentDescriptionFlags flags
VkAttachmentStoreOp storeOp
VkImageLayout initialLayout
VkImageLayout finalLayout
VkAttachmentLoadOp stencilLoadOp
VkStructureType sType
const VkSubpassDescription * pSubpasses
const VkSubpassDependency * pDependencies
const VkAttachmentDescription * pAttachments
VkRenderPassCreateFlags flags
const VkAttachmentReference * pDepthStencilAttachment
VkSubpassDescriptionFlags flags
uint32_t inputAttachmentCount
const VkAttachmentReference * pResolveAttachments
const uint32_t * pPreserveAttachments
const VkAttachmentReference * pInputAttachments
uint32_t colorAttachmentCount
const VkAttachmentReference * pColorAttachments
VkPipelineBindPoint pipelineBindPoint
uint32_t preserveAttachmentCount
skia_private::TArray< const AttachmentDesc * > fAttachments
VulkanRenderPassMetaData(const RenderPassDesc &renderPassDesc)
VkImageLayout
@ VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
@ VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
@ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
@ VK_IMAGE_LAYOUT_UNDEFINED
@ VK_IMAGE_LAYOUT_GENERAL
@ VK_DEPENDENCY_BY_REGION_BIT
@ VK_PIPELINE_BIND_POINT_GRAPHICS
#define VK_ATTACHMENT_UNUSED
VkSampleCountFlagBits
VkResult
@ VK_SUCCESS
@ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
@ VK_ACCESS_COLOR_ATTACHMENT_READ_BIT
#define VK_NULL_HANDLE
Definition vulkan_core.h:46
@ VK_ATTACHMENT_LOAD_OP_DONT_CARE
@ VK_ATTACHMENT_STORE_OP_DONT_CARE
@ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT
@ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO