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 "GrVkRenderTarget.h"
9
10#include "GrRenderTargetPriv.h"
11#include "GrVkCommandBuffer.h"
12#include "GrVkFramebuffer.h"
13#include "GrVkGpu.h"
14#include "GrVkImageView.h"
15#include "GrVkResourceProvider.h"
16#include "GrVkUtil.h"
17
18#include "vk/GrVkTypes.h"
19
20#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
21
22// We're virtually derived from GrSurface (via GrRenderTarget) so its
23// constructor must be explicitly called.
24GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
25                                   SkBudgeted budgeted,
26                                   const GrSurfaceDesc& desc,
27                                   const GrVkImageInfo& info,
28                                   const GrVkImageInfo& msaaInfo,
29                                   const GrVkImageView* colorAttachmentView,
30                                   const GrVkImageView* resolveAttachmentView,
31                                   GrVkImage::Wrapped wrapped)
32    : GrSurface(gpu, desc)
33    , GrVkImage(info, wrapped)
34    // for the moment we only support 1:1 color to stencil
35    , GrRenderTarget(gpu, desc)
36    , fColorAttachmentView(colorAttachmentView)
37    , fMSAAImage(new GrVkImage(msaaInfo, GrVkImage::kNot_Wrapped))
38    , fResolveAttachmentView(resolveAttachmentView)
39    , fFramebuffer(nullptr)
40    , fCachedSimpleRenderPass(nullptr) {
41    SkASSERT(desc.fSampleCnt);
42    this->createFramebuffer(gpu);
43    this->registerWithCache(budgeted);
44}
45
46// We're virtually derived from GrSurface (via GrRenderTarget) so its
47// constructor must be explicitly called.
48GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
49                                   const GrSurfaceDesc& desc,
50                                   const GrVkImageInfo& info,
51                                   const GrVkImageInfo& msaaInfo,
52                                   const GrVkImageView* colorAttachmentView,
53                                   const GrVkImageView* resolveAttachmentView,
54                                   GrVkImage::Wrapped wrapped)
55    : GrSurface(gpu, desc)
56    , GrVkImage(info, wrapped)
57    // for the moment we only support 1:1 color to stencil
58    , GrRenderTarget(gpu, desc)
59    , fColorAttachmentView(colorAttachmentView)
60    , fMSAAImage(new GrVkImage(msaaInfo, GrVkImage::kNot_Wrapped))
61    , fResolveAttachmentView(resolveAttachmentView)
62    , fFramebuffer(nullptr)
63    , fCachedSimpleRenderPass(nullptr) {
64    SkASSERT(desc.fSampleCnt);
65    this->createFramebuffer(gpu);
66}
67
68// We're virtually derived from GrSurface (via GrRenderTarget) so its
69// constructor must be explicitly called.
70GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
71                                   SkBudgeted budgeted,
72                                   const GrSurfaceDesc& desc,
73                                   const GrVkImageInfo& info,
74                                   const GrVkImageView* colorAttachmentView,
75                                   GrVkImage::Wrapped wrapped)
76    : GrSurface(gpu, desc)
77    , GrVkImage(info, wrapped)
78    , GrRenderTarget(gpu, desc)
79    , fColorAttachmentView(colorAttachmentView)
80    , fMSAAImage(nullptr)
81    , fResolveAttachmentView(nullptr)
82    , fFramebuffer(nullptr)
83    , fCachedSimpleRenderPass(nullptr) {
84    SkASSERT(!desc.fSampleCnt);
85    this->createFramebuffer(gpu);
86    this->registerWithCache(budgeted);
87}
88
89// We're virtually derived from GrSurface (via GrRenderTarget) so its
90// constructor must be explicitly called.
91GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
92                                   const GrSurfaceDesc& desc,
93                                   const GrVkImageInfo& info,
94                                   const GrVkImageView* colorAttachmentView,
95                                   GrVkImage::Wrapped wrapped)
96    : GrSurface(gpu, desc)
97    , GrVkImage(info, wrapped)
98    , GrRenderTarget(gpu, desc)
99    , fColorAttachmentView(colorAttachmentView)
100    , fMSAAImage(nullptr)
101    , fResolveAttachmentView(nullptr)
102    , fFramebuffer(nullptr)
103    , fCachedSimpleRenderPass(nullptr) {
104    SkASSERT(!desc.fSampleCnt);
105    this->createFramebuffer(gpu);
106}
107
108GrVkRenderTarget*
109GrVkRenderTarget::Create(GrVkGpu* gpu,
110                         SkBudgeted budgeted,
111                         const GrSurfaceDesc& desc,
112                         const GrVkImageInfo& info,
113                         GrVkImage::Wrapped wrapped) {
114    SkASSERT(1 == info.fLevelCount);
115    VkFormat pixelFormat;
116    GrPixelConfigToVkFormat(desc.fConfig, &pixelFormat);
117
118    VkImage colorImage;
119
120    // create msaa surface if necessary
121    GrVkImageInfo msInfo;
122    const GrVkImageView* resolveAttachmentView = nullptr;
123    if (desc.fSampleCnt) {
124        GrVkImage::ImageDesc msImageDesc;
125        msImageDesc.fImageType = VK_IMAGE_TYPE_2D;
126        msImageDesc.fFormat = pixelFormat;
127        msImageDesc.fWidth = desc.fWidth;
128        msImageDesc.fHeight = desc.fHeight;
129        msImageDesc.fLevels = 1;
130        msImageDesc.fSamples = desc.fSampleCnt;
131        msImageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
132        msImageDesc.fUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
133                                  VK_IMAGE_USAGE_TRANSFER_DST_BIT |
134                                  VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
135        msImageDesc.fMemProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
136
137        if (!GrVkImage::InitImageInfo(gpu, msImageDesc, &msInfo)) {
138            return nullptr;
139        }
140
141        // Set color attachment image
142        colorImage = msInfo.fImage;
143
144        // Create Resolve attachment view
145        resolveAttachmentView = GrVkImageView::Create(gpu, info.fImage, pixelFormat,
146                                                      GrVkImageView::kColor_Type, 1);
147        if (!resolveAttachmentView) {
148            GrVkImage::DestroyImageInfo(gpu, &msInfo);
149            return nullptr;
150        }
151    } else {
152        // Set color attachment image
153        colorImage = info.fImage;
154    }
155
156    // Get color attachment view
157    const GrVkImageView* colorAttachmentView = GrVkImageView::Create(gpu, colorImage, pixelFormat,
158                                                                     GrVkImageView::kColor_Type, 1);
159    if (!colorAttachmentView) {
160        if (desc.fSampleCnt) {
161            resolveAttachmentView->unref(gpu);
162            GrVkImage::DestroyImageInfo(gpu, &msInfo);
163        }
164        return nullptr;
165    }
166
167    GrVkRenderTarget* texRT;
168    if (desc.fSampleCnt) {
169        texRT = new GrVkRenderTarget(gpu, budgeted, desc, info, msInfo,
170                                     colorAttachmentView, resolveAttachmentView, wrapped);
171    } else {
172        texRT = new GrVkRenderTarget(gpu, budgeted, desc, info, colorAttachmentView, wrapped);
173    }
174
175    return texRT;
176}
177
178GrVkRenderTarget*
179GrVkRenderTarget::CreateNewRenderTarget(GrVkGpu* gpu,
180                                        SkBudgeted budgeted,
181                                        const GrSurfaceDesc& desc,
182                                        const GrVkImage::ImageDesc& imageDesc) {
183    SkASSERT(imageDesc.fUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
184
185    GrVkImageInfo info;
186    if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) {
187        return nullptr;
188    }
189
190    GrVkRenderTarget* rt = GrVkRenderTarget::Create(gpu, budgeted, desc, info,
191                                                    GrVkImage::kNot_Wrapped);
192    if (!rt) {
193        GrVkImage::DestroyImageInfo(gpu, &info);
194    }
195    return rt;
196}
197
198sk_sp<GrVkRenderTarget>
199GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu,
200                                          const GrSurfaceDesc& desc,
201                                          const GrVkImageInfo* info) {
202    SkASSERT(info);
203    SkASSERT(VK_NULL_HANDLE != info->fImage);
204
205    return sk_sp<GrVkRenderTarget>(
206        GrVkRenderTarget::Create(gpu, SkBudgeted::kNo, desc, *info, GrVkImage::kBorrowed_Wrapped));
207}
208
209bool GrVkRenderTarget::completeStencilAttachment() {
210    this->createFramebuffer(this->getVkGpu());
211    return true;
212}
213
214void GrVkRenderTarget::createFramebuffer(GrVkGpu* gpu) {
215    if (fFramebuffer) {
216        fFramebuffer->unref(gpu);
217    }
218    if (fCachedSimpleRenderPass) {
219        fCachedSimpleRenderPass->unref(gpu);
220    }
221
222    // Vulkan requires us to create a compatible renderpass before we can create our framebuffer,
223    // so we use this to get a (cached) basic renderpass, only for creation.
224    fCachedSimpleRenderPass =
225        gpu->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle);
226
227    // Stencil attachment view is stored in the base RT stencil attachment
228    const GrVkImageView* stencilView = this->stencilAttachmentView();
229    fFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(),
230                                           fCachedSimpleRenderPass, fColorAttachmentView,
231                                           stencilView);
232    SkASSERT(fFramebuffer);
233}
234
235void GrVkRenderTarget::getAttachmentsDescriptor(
236                                           GrVkRenderPass::AttachmentsDescriptor* desc,
237                                           GrVkRenderPass::AttachmentFlags* attachmentFlags) const {
238    int colorSamples = this->numColorSamples();
239    VkFormat colorFormat;
240    GrPixelConfigToVkFormat(this->config(), &colorFormat);
241    desc->fColor.fFormat = colorFormat;
242    desc->fColor.fSamples = colorSamples ? colorSamples : 1;
243    *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
244    uint32_t attachmentCount = 1;
245
246    const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
247    if (stencil) {
248        const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
249        desc->fStencil.fFormat = vkStencil->vkFormat();
250        desc->fStencil.fSamples = vkStencil->numSamples() ? vkStencil->numSamples() : 1;
251        // Currently in vulkan stencil and color attachments must all have same number of samples
252        SkASSERT(desc->fColor.fSamples == desc->fStencil.fSamples);
253        *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
254        ++attachmentCount;
255    }
256    desc->fAttachmentCount = attachmentCount;
257}
258
259GrVkRenderTarget::~GrVkRenderTarget() {
260    // either release or abandon should have been called by the owner of this object.
261    SkASSERT(!fMSAAImage);
262    SkASSERT(!fResolveAttachmentView);
263    SkASSERT(!fColorAttachmentView);
264    SkASSERT(!fFramebuffer);
265    SkASSERT(!fCachedSimpleRenderPass);
266}
267
268void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) const {
269    commandBuffer.addResource(this->framebuffer());
270    commandBuffer.addResource(this->colorAttachmentView());
271    commandBuffer.addResource(this->msaaImageResource() ? this->msaaImageResource()
272                                                        : this->resource());
273    if (this->stencilImageResource()) {
274        commandBuffer.addResource(this->stencilImageResource());
275        commandBuffer.addResource(this->stencilAttachmentView());
276    }
277}
278
279void GrVkRenderTarget::releaseInternalObjects() {
280    GrVkGpu* gpu = this->getVkGpu();
281
282    if (fMSAAImage) {
283        fMSAAImage->releaseImage(gpu);
284        fMSAAImage.reset();
285    }
286
287    if (fResolveAttachmentView) {
288        fResolveAttachmentView->unref(gpu);
289        fResolveAttachmentView = nullptr;
290    }
291    if (fColorAttachmentView) {
292        fColorAttachmentView->unref(gpu);
293        fColorAttachmentView = nullptr;
294    }
295    if (fFramebuffer) {
296        fFramebuffer->unref(gpu);
297        fFramebuffer = nullptr;
298    }
299    if (fCachedSimpleRenderPass) {
300        fCachedSimpleRenderPass->unref(gpu);
301        fCachedSimpleRenderPass = nullptr;
302    }
303}
304
305void GrVkRenderTarget::abandonInternalObjects() {
306    if (fMSAAImage) {
307        fMSAAImage->abandonImage();
308        fMSAAImage.reset();
309    }
310
311    if (fResolveAttachmentView) {
312        fResolveAttachmentView->unrefAndAbandon();
313        fResolveAttachmentView = nullptr;
314    }
315    if (fColorAttachmentView) {
316        fColorAttachmentView->unrefAndAbandon();
317        fColorAttachmentView = nullptr;
318    }
319    if (fFramebuffer) {
320        fFramebuffer->unrefAndAbandon();
321        fFramebuffer = nullptr;
322    }
323    if (fCachedSimpleRenderPass) {
324        fCachedSimpleRenderPass->unrefAndAbandon();
325        fCachedSimpleRenderPass = nullptr;
326    }
327}
328
329void GrVkRenderTarget::onRelease() {
330    this->releaseInternalObjects();
331    this->releaseImage(this->getVkGpu());
332    GrRenderTarget::onRelease();
333}
334
335void GrVkRenderTarget::onAbandon() {
336    this->abandonInternalObjects();
337    this->abandonImage();
338    GrRenderTarget::onAbandon();
339}
340
341
342GrBackendObject GrVkRenderTarget::getRenderTargetHandle() const {
343    // If the render target is multisampled, we currently return the ImageInfo for the resolved
344    // image. If we only wrap the msaa target (currently not implemented) we should return a handle
345    // to that instead.
346    return (GrBackendObject)&fInfo;
347}
348
349const GrVkResource* GrVkRenderTarget::stencilImageResource() const {
350    const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
351    if (stencil) {
352        const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
353        return vkStencil->imageResource();
354    }
355
356    return nullptr;
357}
358
359const GrVkImageView* GrVkRenderTarget::stencilAttachmentView() const {
360    const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
361    if (stencil) {
362        const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil);
363        return vkStencil->stencilView();
364    }
365
366    return nullptr;
367}
368
369
370GrVkGpu* GrVkRenderTarget::getVkGpu() const {
371    SkASSERT(!this->wasDestroyed());
372    return static_cast<GrVkGpu*>(this->getGpu());
373}
374