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 "GrVkRenderPass.h"
9
10 #include "GrProcessor.h"
11 #include "GrVkFramebuffer.h"
12 #include "GrVkGpu.h"
13 #include "GrVkRenderTarget.h"
14 #include "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);
264 b->add32((uint32_t)(handle>>32));
265 }
266 }
267