• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/gpu/graphite/vk/VulkanRenderPass.h"
9 
10 #include "src/gpu/graphite/RenderPassDesc.h"
11 #include "src/gpu/graphite/Texture.h"
12 #include "src/gpu/graphite/vk/VulkanCommandBuffer.h"
13 #include "src/gpu/graphite/vk/VulkanGraphiteUtilsPriv.h"
14 #include "src/gpu/graphite/vk/VulkanSharedContext.h"
15 #include "src/gpu/graphite/vk/VulkanTexture.h"
16 
17 #include <limits>
18 
19 namespace skgpu::graphite {
20 
21 namespace { // anonymous namespace
22 
determine_uint32_count(int rpAttachmentCount,int subpassCount,int subpassDependencyCount)23 int 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 
add_attachment_description_info_to_key(ResourceKey::Builder & builder,const TextureInfo & textureInfo,int & builderIdx,LoadOp loadOp,StoreOp storeOp)48 void 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 
add_subpass_info_to_key(ResourceKey::Builder & builder,int & builderIdx,bool hasColorAttachment,bool hasColorResolveAttachment,bool hasDepthStencilAttachment,bool loadMSAAFromResolve,int subpassCount,int subpassDependencyCount)68 void 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.
108                     (VulkanRenderPass::kColorResolveAttachmentIdx << 24);
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
121                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
122         builder[builderIdx++] = VK_DEPENDENCY_BY_REGION_BIT;                   // dependencyFlags
123     }
124 }
125 
populate_key(VulkanRenderPass::VulkanRenderPassMetaData & rpMetaData,ResourceKey::Builder & builder,int & builderIdx,bool compatibleOnly)126 void 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 
VulkanRenderPassMetaData(const RenderPassDesc & renderPassDesc)158 VulkanRenderPass::VulkanRenderPassMetaData::VulkanRenderPassMetaData(
159         const RenderPassDesc& renderPassDesc) {
160     fLoadMSAAFromResolve = renderPassDesc.fColorResolveAttachment.fTextureInfo.isValid() &&
161                            renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
162     fHasColorAttachment        = renderPassDesc.fColorAttachment.fTextureInfo.isValid();
163     fHasColorResolveAttachment =
164             renderPassDesc.fColorResolveAttachment.fTextureInfo.isValid();
165     fHasDepthStencilAttachment =
166             renderPassDesc.fDepthStencilAttachment.fTextureInfo.isValid();
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.
171     fNumColorAttachments        = fHasColorAttachment ? 1 : 0;
172     fNumResolveAttachments      = fHasColorResolveAttachment ? 1 : 0;
173     fNumDepthStencilAttachments = fHasDepthStencilAttachment ? 1 : 0;
174 
175     // Accumulate attachments into a container to mimic future structure in RenderPassDesc
176     fAttachments = skia_private::TArray<const AttachmentDesc*>(fNumColorAttachments   +
177                                                                fNumResolveAttachments +
178                                                                fNumDepthStencilAttachments);
179     if (fHasColorAttachment) {
180         fAttachments.push_back(&renderPassDesc.fColorAttachment);
181     }
182     if (fHasColorResolveAttachment) {
183         fAttachments.push_back(&renderPassDesc.fColorResolveAttachment);
184     }
185     if (fHasDepthStencilAttachment) {
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).
191     fSubpassCount = fLoadMSAAFromResolve ? 2 : 1;
192     fSubpassDependencyCount = fLoadMSAAFromResolve ? 1 : 0;
193     fUint32DataCnt = determine_uint32_count(
194             fAttachments.size(), fSubpassCount,  fSubpassDependencyCount);
195 }
196 
MakeRenderPassKey(const RenderPassDesc & renderPassDesc,bool compatibleOnly)197 GraphiteResourceKey VulkanRenderPass::MakeRenderPassKey(
198         const RenderPassDesc& renderPassDesc, bool compatibleOnly) {
199 
200     VulkanRenderPassMetaData rpMetaData = VulkanRenderPassMetaData(renderPassDesc);
201 
202     static const ResourceType kType = GraphiteResourceKey::GenerateResourceType();
203     GraphiteResourceKey key;
204     GraphiteResourceKey::Builder builder(&key, kType, rpMetaData.fUint32DataCnt, Shareable::kYes);
205 
206     int startingIdx = 0;
207     populate_key(rpMetaData, builder, startingIdx, compatibleOnly);
208 
209     builder.finish();
210     return key;
211 }
212 
AddRenderPassInfoToKey(VulkanRenderPassMetaData & rpMetaData,ResourceKey::Builder & builder,int & builderIdx,bool compatibleOnly)213 void VulkanRenderPass::AddRenderPassInfoToKey(VulkanRenderPassMetaData& rpMetaData,
214                                               ResourceKey::Builder& builder,
215                                               int& builderIdx,
216                                               bool compatibleOnly) {
217     populate_key(rpMetaData, builder, builderIdx, /*compatibleOnly=*/true);
218 }
219 
220 namespace { // anonymous namespace
setup_vk_attachment_description(VkAttachmentDescription * outAttachment,const VulkanTextureInfo & textureInfo,const AttachmentDesc & desc,const LoadOp loadOp,const StoreOp storeOp,const VkImageLayout initialLayout,const VkImageLayout finalLayout)221 void setup_vk_attachment_description(VkAttachmentDescription* outAttachment,
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;
239     SkAssertResult(
240             skgpu::SampleCountToVkSampleCount(textureInfo.fSampleCount, &sampleCount));
241     outAttachment->samples = sampleCount;
242     switch (initialLayout) {
243         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
244         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
245         case VK_IMAGE_LAYOUT_GENERAL:
246             outAttachment->loadOp = vkLoadOp[static_cast<int>(loadOp)];
247             outAttachment->storeOp = vkStoreOp[static_cast<int>(storeOp)];
248             outAttachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
249             outAttachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
250             break;
251         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
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 
MakeRenderPass(const VulkanSharedContext * context,const RenderPassDesc & renderPassDesc,bool compatibleOnly)268 sk_sp<VulkanRenderPass> VulkanRenderPass::MakeRenderPass(const VulkanSharedContext* context,
269                                                          const RenderPassDesc& renderPassDesc,
270                                                          bool compatibleOnly) {
271     VkRenderPass renderPass;
272     renderPass = VK_NULL_HANDLE;
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 
280     skia_private::TArray<VkAttachmentDescription> attachmentDescs;
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));
296         setup_vk_attachment_description(
297                 &vkColorAttachDesc,
298                 colorAttachTexInfo,
299                 colorAttachDesc,
300                 compatibleOnly ? LoadOp::kDiscard  : colorAttachDesc.fLoadOp,
301                 compatibleOnly ? StoreOp::kDiscard : colorAttachDesc.fStoreOp,
302                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
303                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
304         colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
305 
306         if (hasColorResolveAttachment) {
307             loadMSAAFromResolve = renderPassDesc.fColorResolveAttachment.fLoadOp == LoadOp::kLoad;
308             SkASSERT(renderPassDesc.fColorResolveAttachment.fStoreOp == StoreOp::kStore);
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));
316             setup_vk_attachment_description(
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
323                                         : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
324                     VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
325             resolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
326         } else {
327             resolveRef.attachment = VK_ATTACHMENT_UNUSED;
328             resolveRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
329         }
330     } else {
331         SkASSERT(false);
332         colorRef.attachment = VK_ATTACHMENT_UNUSED;
333         colorRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
334         resolveRef.attachment = VK_ATTACHMENT_UNUSED;
335         resolveRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
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();
345         setup_vk_attachment_description(
346                 &vkDepthStencilAttachDesc,
347                 depthStencilTexInfo,
348                 depthStencilAttachDesc,
349                 compatibleOnly ? LoadOp::kDiscard   : depthStencilAttachDesc.fLoadOp,
350                 compatibleOnly ? StoreOp::kDiscard  : depthStencilAttachDesc.fStoreOp,
351                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
352                 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
353         depthStencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
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));
362     renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
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.
371     VkSubpassDependency dependency;
372     if (loadMSAAFromResolve) {
373         resolveLoadInputRef.attachment = resolveRef.attachment;
374         resolveLoadInputRef.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
375 
376         VkSubpassDescription& loadSubpassDesc = subpassDescs.push_back();
377         memset(&loadSubpassDesc, 0, sizeof(VkSubpassDescription));
378         loadSubpassDesc.flags = 0;
379         loadSubpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
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;
394         dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
395         dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
396         dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
397         dependency.dstAccessMask =
398                 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
399     }
400 
401     VkSubpassDescription& mainSubpassDesc = subpassDescs.push_back();
402     memset(&mainSubpassDesc, 0, sizeof(VkSubpassDescription));
403     mainSubpassDesc.flags = 0;
404     mainSubpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
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 
420     VkResult result;
421     VULKAN_CALL_RESULT(context,
422                        result,
423                        CreateRenderPass(context->device(), &renderPassInfo, nullptr, &renderPass));
424     if (result != VK_SUCCESS) {
425         return nullptr;
426     }
427     VkExtent2D granularity;
428     VULKAN_CALL(context->interface(), GetRenderAreaGranularity(context->device(),
429                                                                renderPass,
430                                                                &granularity));
431     return sk_sp<VulkanRenderPass>(new VulkanRenderPass(context, renderPass, granularity));
432 }
433 
VulkanRenderPass(const VulkanSharedContext * context,VkRenderPass renderPass,VkExtent2D granularity)434 VulkanRenderPass::VulkanRenderPass(const VulkanSharedContext* context,
435                                    VkRenderPass renderPass,
436                                    VkExtent2D granularity)
437         : Resource(context,
438                    Ownership::kOwned,
439                    skgpu::Budgeted::kYes,
440                    /*gpuMemorySize=*/0)
441         , fSharedContext(context)
442         , fRenderPass(renderPass)
443         , fGranularity(granularity) {}
444 
freeGpuData()445 void VulkanRenderPass::freeGpuData() {
446     VULKAN_CALL(fSharedContext->interface(),
447                 DestroyRenderPass(fSharedContext->device(), fRenderPass, nullptr));
448 }
449 
450 } // namespace skgpu::graphite
451