1 /*
2 * Copyright 2015 Google Inc.
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/vk/GrVkRenderPass.h"
9 
10 #include "src/gpu/GrProcessor.h"
11 #include "src/gpu/vk/GrVkFramebuffer.h"
12 #include "src/gpu/vk/GrVkGpu.h"
13 #include "src/gpu/vk/GrVkRenderTarget.h"
14 #include "src/gpu/vk/GrVkUtil.h"
15 
16 typedef GrVkRenderPass::AttachmentsDescriptor::AttachmentDesc AttachmentDesc;
17 
setup_vk_attachment_description(VkAttachmentDescription * attachment,const AttachmentDesc & desc,VkImageLayout layout)18 void setup_vk_attachment_description(VkAttachmentDescription* attachment,
19                                      const AttachmentDesc& desc,
20                                      VkImageLayout layout) {
21     attachment->flags = 0;
22     attachment->format = desc.fFormat;
23     SkAssertResult(GrSampleCountToVkSampleCount(desc.fSamples, &attachment->samples));
24     switch (layout) {
25         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
26             attachment->loadOp = desc.fLoadStoreOps.fLoadOp;
27             attachment->storeOp = desc.fLoadStoreOps.fStoreOp;
28             attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
29             attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
30             break;
31         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
32             attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
33             attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
34             attachment->stencilLoadOp = desc.fLoadStoreOps.fLoadOp;
35             attachment->stencilStoreOp = desc.fLoadStoreOps.fStoreOp;
36             break;
37         default:
38             SK_ABORT("Unexpected attachment layout");
39     }
40 
41     attachment->initialLayout = layout;
42     attachment->finalLayout = layout;
43 }
44 
initSimple(const GrVkGpu * gpu,const GrVkRenderTarget & target)45 void GrVkRenderPass::initSimple(const GrVkGpu* gpu, const GrVkRenderTarget& target) {
46     static const GrVkRenderPass::LoadStoreOps kBasicLoadStoreOps(VK_ATTACHMENT_LOAD_OP_LOAD,
47                                                                  VK_ATTACHMENT_STORE_OP_STORE);
48 
49     this->init(gpu, target, kBasicLoadStoreOps, kBasicLoadStoreOps);
50 }
51 
init(const GrVkGpu * gpu,const LoadStoreOps & colorOp,const LoadStoreOps & stencilOp)52 void GrVkRenderPass::init(const GrVkGpu* gpu,
53                           const LoadStoreOps& colorOp,
54                           const LoadStoreOps& stencilOp) {
55     uint32_t numAttachments = fAttachmentsDescriptor.fAttachmentCount;
56     // Attachment descriptions to be set on the render pass
57     SkTArray<VkAttachmentDescription> attachments(numAttachments);
58     attachments.reset(numAttachments);
59     memset(attachments.begin(), 0, numAttachments * sizeof(VkAttachmentDescription));
60 
61     // Refs to attachments on the render pass (as described by teh VkAttachmentDescription above),
62     // that are used by the subpass.
63     VkAttachmentReference colorRef;
64     VkAttachmentReference stencilRef;
65     uint32_t currentAttachment = 0;
66 
67     // Go through each of the attachment types (color, stencil) and set the necessary
68     // on the various Vk structs.
69     VkSubpassDescription subpassDesc;
70     memset(&subpassDesc, 0, sizeof(VkSubpassDescription));
71     subpassDesc.flags = 0;
72     subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
73     subpassDesc.inputAttachmentCount = 0;
74     subpassDesc.pInputAttachments = nullptr;
75     subpassDesc.pResolveAttachments = nullptr;
76 
77     if (fAttachmentFlags & kColor_AttachmentFlag) {
78         // set up color attachment
79         fAttachmentsDescriptor.fColor.fLoadStoreOps = colorOp;
80         setup_vk_attachment_description(&attachments[currentAttachment],
81                                         fAttachmentsDescriptor.fColor,
82                                         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
83         // setup subpass use of attachment
84         colorRef.attachment = currentAttachment++;
85         colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
86         subpassDesc.colorAttachmentCount = 1;
87 
88         if (VK_ATTACHMENT_LOAD_OP_CLEAR == colorOp.fLoadOp) {
89             fClearValueCount = colorRef.attachment + 1;
90         }
91     } else {
92         // I don't think there should ever be a time where we don't have a color attachment
93         SkASSERT(false);
94         colorRef.attachment = VK_ATTACHMENT_UNUSED;
95         colorRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
96         subpassDesc.colorAttachmentCount = 0;
97     }
98     subpassDesc.pColorAttachments = &colorRef;
99 
100     if (fAttachmentFlags & kStencil_AttachmentFlag) {
101         // set up stencil attachment
102         fAttachmentsDescriptor.fStencil.fLoadStoreOps = stencilOp;
103         setup_vk_attachment_description(&attachments[currentAttachment],
104                                         fAttachmentsDescriptor.fStencil,
105                                         VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
106         // setup subpass use of attachment
107         stencilRef.attachment = currentAttachment++;
108         stencilRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
109         if (VK_ATTACHMENT_LOAD_OP_CLEAR == stencilOp.fLoadOp) {
110             fClearValueCount = SkTMax(fClearValueCount, stencilRef.attachment + 1);
111         }
112     } else {
113         stencilRef.attachment = VK_ATTACHMENT_UNUSED;
114         stencilRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
115     }
116     subpassDesc.pDepthStencilAttachment = &stencilRef;
117 
118     subpassDesc.preserveAttachmentCount = 0;
119     subpassDesc.pPreserveAttachments = nullptr;
120 
121     SkASSERT(numAttachments == currentAttachment);
122 
123     // Create the VkRenderPass compatible with the attachment descriptions above
124     VkRenderPassCreateInfo createInfo;
125     memset(&createInfo, 0, sizeof(VkRenderPassCreateInfo));
126     createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
127     createInfo.pNext = nullptr;
128     createInfo.flags = 0;
129     createInfo.attachmentCount = numAttachments;
130     createInfo.pAttachments = attachments.begin();
131     createInfo.subpassCount = 1;
132     createInfo.pSubpasses = &subpassDesc;
133     createInfo.dependencyCount = 0;
134     createInfo.pDependencies = nullptr;
135 
136     GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateRenderPass(gpu->device(),
137                                                              &createInfo,
138                                                              nullptr,
139                                                              &fRenderPass));
140 
141     // Get granularity for this render pass
142     GR_VK_CALL(gpu->vkInterface(), GetRenderAreaGranularity(gpu->device(),
143                                                             fRenderPass,
144                                                             &fGranularity));
145 }
146 
init(const GrVkGpu * gpu,const GrVkRenderPass & compatibleRenderPass,const LoadStoreOps & colorOp,const LoadStoreOps & stencilOp)147 void GrVkRenderPass::init(const GrVkGpu* gpu,
148                           const GrVkRenderPass& compatibleRenderPass,
149                           const LoadStoreOps& colorOp,
150                           const LoadStoreOps& stencilOp) {
151     fAttachmentFlags = compatibleRenderPass.fAttachmentFlags;
152     fAttachmentsDescriptor = compatibleRenderPass.fAttachmentsDescriptor;
153     this->init(gpu, colorOp, stencilOp);
154 }
155 
init(const GrVkGpu * gpu,const GrVkRenderTarget & target,const LoadStoreOps & colorOp,const LoadStoreOps & stencilOp)156 void GrVkRenderPass::init(const GrVkGpu* gpu,
157                           const GrVkRenderTarget& target,
158                           const LoadStoreOps& colorOp,
159                           const LoadStoreOps& stencilOp) {
160     // Get attachment information from render target. This includes which attachments the render
161     // target has (color, stencil) and the attachments format and sample count.
162     target.getAttachmentsDescriptor(&fAttachmentsDescriptor, &fAttachmentFlags);
163     this->init(gpu, colorOp, stencilOp);
164 }
165 
freeGPUData(GrVkGpu * gpu) const166 void GrVkRenderPass::freeGPUData(GrVkGpu* gpu) const {
167     if (!(fAttachmentFlags & kExternal_AttachmentFlag)) {
168         GR_VK_CALL(gpu->vkInterface(), DestroyRenderPass(gpu->device(), fRenderPass, nullptr));
169     }
170 }
171 
colorAttachmentIndex(uint32_t * index) const172 bool GrVkRenderPass::colorAttachmentIndex(uint32_t* index) const {
173     *index = fColorAttachmentIndex;
174     if ((fAttachmentFlags & kColor_AttachmentFlag) ||
175         (fAttachmentFlags & kExternal_AttachmentFlag)) {
176         return true;
177     }
178     return false;
179 }
180 
181 // Works under the assumption that stencil attachment will always be after the color and resolve
182 // attachment.
stencilAttachmentIndex(uint32_t * index) const183 bool GrVkRenderPass::stencilAttachmentIndex(uint32_t* index) const {
184     *index = 0;
185     if (fAttachmentFlags & kColor_AttachmentFlag) {
186         ++(*index);
187     }
188     if (fAttachmentFlags & kStencil_AttachmentFlag) {
189         return true;
190     }
191     return false;
192 }
193 
isCompatible(const AttachmentsDescriptor & desc,const AttachmentFlags & flags) const194 bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc,
195                                   const AttachmentFlags& flags) const {
196     SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
197     if (flags != fAttachmentFlags) {
198         return false;
199     }
200 
201     if (fAttachmentFlags & kColor_AttachmentFlag) {
202         if (!fAttachmentsDescriptor.fColor.isCompatible(desc.fColor)) {
203             return false;
204         }
205     }
206     if (fAttachmentFlags & kStencil_AttachmentFlag) {
207         if (!fAttachmentsDescriptor.fStencil.isCompatible(desc.fStencil)) {
208             return false;
209         }
210     }
211 
212     return true;
213 }
214 
isCompatible(const GrVkRenderTarget & target) const215 bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
216     SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
217     AttachmentsDescriptor desc;
218     AttachmentFlags flags;
219     target.getAttachmentsDescriptor(&desc, &flags);
220 
221     return this->isCompatible(desc, flags);
222 }
223 
isCompatible(const GrVkRenderPass & renderPass) const224 bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const {
225     SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
226     return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags);
227 }
228 
isCompatibleExternalRP(VkRenderPass renderPass) const229 bool GrVkRenderPass::isCompatibleExternalRP(VkRenderPass renderPass) const {
230     SkASSERT(fAttachmentFlags & kExternal_AttachmentFlag);
231     return fRenderPass == renderPass;
232 }
233 
equalLoadStoreOps(const LoadStoreOps & colorOps,const LoadStoreOps & stencilOps) const234 bool GrVkRenderPass::equalLoadStoreOps(const LoadStoreOps& colorOps,
235                                        const LoadStoreOps& stencilOps) const {
236     SkASSERT(!(fAttachmentFlags & kExternal_AttachmentFlag));
237     if (fAttachmentFlags & kColor_AttachmentFlag) {
238         if (fAttachmentsDescriptor.fColor.fLoadStoreOps != colorOps) {
239             return false;
240         }
241     }
242     if (fAttachmentFlags & kStencil_AttachmentFlag) {
243         if (fAttachmentsDescriptor.fStencil.fLoadStoreOps != stencilOps) {
244             return false;
245         }
246     }
247     return true;
248 }
249 
genKey(GrProcessorKeyBuilder * b) const250 void GrVkRenderPass::genKey(GrProcessorKeyBuilder* b) const {
251     b->add32(fAttachmentFlags);
252     if (fAttachmentFlags & kColor_AttachmentFlag) {
253         b->add32(fAttachmentsDescriptor.fColor.fFormat);
254         b->add32(fAttachmentsDescriptor.fColor.fSamples);
255     }
256     if (fAttachmentFlags & kStencil_AttachmentFlag) {
257         b->add32(fAttachmentsDescriptor.fStencil.fFormat);
258         b->add32(fAttachmentsDescriptor.fStencil.fSamples);
259     }
260     if (fAttachmentFlags & kExternal_AttachmentFlag) {
261         SkASSERT(!(fAttachmentFlags & ~kExternal_AttachmentFlag));
262         uint64_t handle = (uint64_t)fRenderPass;
263         b->add32((uint32_t)(handle & 0xFFFFFFFF));
264         b->add32((uint32_t)(handle>>32));
265     }
266 }
267