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
16typedef GrVkRenderPass::AttachmentsDescriptor::AttachmentDesc AttachmentDesc;
17
18void 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
45void 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
52void 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
147void 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
156void 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
166void 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.
172bool 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.
182bool 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
193bool 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
213bool 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
221bool GrVkRenderPass::isCompatible(const GrVkRenderPass& renderPass) const {
222    return this->isCompatible(renderPass.fAttachmentsDescriptor, renderPass.fAttachmentFlags);
223}
224
225bool 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
240void 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