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 SkFAIL("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++;
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++;
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(const GrVkGpu * gpu) const166 void GrVkRenderPass::freeGPUData(const GrVkGpu* gpu) const {
167 GR_VK_CALL(gpu->vkInterface(), DestroyRenderPass(gpu->device(), fRenderPass, nullptr));
168 }
169
170 // Works under the assumption that color attachment will always be the first attachment in our
171 // attachment array if it exists.
colorAttachmentIndex(uint32_t * index) const172 bool GrVkRenderPass::colorAttachmentIndex(uint32_t* index) const {
173 *index = 0;
174 if (fAttachmentFlags & kColor_AttachmentFlag) {
175 return true;
176 }
177 return false;
178 }
179
180 // Works under the assumption that stencil attachment will always be after the color and resolve
181 // attachment.
stencilAttachmentIndex(uint32_t * index) const182 bool GrVkRenderPass::stencilAttachmentIndex(uint32_t* index) const {
183 *index = 0;
184 if (fAttachmentFlags & kColor_AttachmentFlag) {
185 ++(*index);
186 }
187 if (fAttachmentFlags & kStencil_AttachmentFlag) {
188 return true;
189 }
190 return false;
191 }
192
isCompatible(const AttachmentsDescriptor & desc,const AttachmentFlags & flags) const193 bool GrVkRenderPass::isCompatible(const AttachmentsDescriptor& desc,
194 const AttachmentFlags& flags) const {
195 if (flags != fAttachmentFlags) {
196 return false;
197 }
198
199 if (fAttachmentFlags & kColor_AttachmentFlag) {
200 if (!fAttachmentsDescriptor.fColor.isCompatible(desc.fColor)) {
201 return false;
202 }
203 }
204 if (fAttachmentFlags & kStencil_AttachmentFlag) {
205 if (!fAttachmentsDescriptor.fStencil.isCompatible(desc.fStencil)) {
206 return false;
207 }
208 }
209
210 return true;
211 }
212
isCompatible(const GrVkRenderTarget & target) const213 bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const {
214 AttachmentsDescriptor desc;
215 AttachmentFlags flags;
216 target.getAttachmentsDescriptor(&desc, &flags);
217
218 return this->isCompatible(desc, flags);
219 }
220
isCompatible(const GrVkRenderPass & renderPass) const221 bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const {
222 return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags);
223 }
224
equalLoadStoreOps(const LoadStoreOps & colorOps,const LoadStoreOps & stencilOps) const225 bool GrVkRenderPass::equalLoadStoreOps(const LoadStoreOps& colorOps,
226 const LoadStoreOps& stencilOps) const {
227 if (fAttachmentFlags & kColor_AttachmentFlag) {
228 if (fAttachmentsDescriptor.fColor.fLoadStoreOps != colorOps) {
229 return false;
230 }
231 }
232 if (fAttachmentFlags & kStencil_AttachmentFlag) {
233 if (fAttachmentsDescriptor.fStencil.fLoadStoreOps != stencilOps) {
234 return false;
235 }
236 }
237 return true;
238 }
239
genKey(GrProcessorKeyBuilder * b) const240 void GrVkRenderPass::genKey(GrProcessorKeyBuilder* b) const {
241 b->add32(fAttachmentFlags);
242 if (fAttachmentFlags & kColor_AttachmentFlag) {
243 b->add32(fAttachmentsDescriptor.fColor.fFormat);
244 b->add32(fAttachmentsDescriptor.fColor.fSamples);
245 }
246 if (fAttachmentFlags & kStencil_AttachmentFlag) {
247 b->add32(fAttachmentsDescriptor.fStencil.fFormat);
248 b->add32(fAttachmentsDescriptor.fStencil.fSamples);
249 }
250 }
251