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/GrVkRenderTarget.h"
9
10#include "include/gpu/GrBackendSurface.h"
11#include "include/gpu/GrDirectContext.h"
12#include "src/gpu/GrBackendSurfaceMutableStateImpl.h"
13#include "src/gpu/GrDirectContextPriv.h"
14#include "src/gpu/GrResourceProvider.h"
15#include "src/gpu/vk/GrVkCommandBuffer.h"
16#include "src/gpu/vk/GrVkDescriptorSet.h"
17#include "src/gpu/vk/GrVkFramebuffer.h"
18#include "src/gpu/vk/GrVkGpu.h"
19#include "src/gpu/vk/GrVkImageView.h"
20#include "src/gpu/vk/GrVkResourceProvider.h"
21#include "src/gpu/vk/GrVkUtil.h"
22
23#include "include/gpu/vk/GrVkTypes.h"
24
25#define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
26
27static int renderpass_features_to_index(bool hasResolve, bool hasStencil,
28                                        GrVkRenderPass::SelfDependencyFlags selfDepFlags,
29                                        GrVkRenderPass::LoadFromResolve loadFromReslove) {
30    int index = 0;
31    if (hasResolve) {
32        index += 1;
33    }
34    if (hasStencil) {
35        index += 2;
36    }
37    if (selfDepFlags & GrVkRenderPass::SelfDependencyFlags::kForInputAttachment) {
38        index += 4;
39    }
40    if (selfDepFlags & GrVkRenderPass::SelfDependencyFlags::kForNonCoherentAdvBlend) {
41        index += 8;
42    }
43    if (loadFromReslove == GrVkRenderPass::LoadFromResolve::kLoad) {
44        index += 16;
45    }
46    return index;
47}
48
49// We're virtually derived from GrSurface (via GrRenderTarget) so its
50// constructor must be explicitly called.
51GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
52                                   SkISize dimensions,
53                                   sk_sp<GrVkImage> colorAttachment,
54                                   sk_sp<GrVkImage> resolveAttachment,
55                                   CreateType createType)
56        : GrSurface(gpu, dimensions,
57                    colorAttachment->isProtected() ? GrProtected::kYes : GrProtected::kNo)
58        // for the moment we only support 1:1 color to stencil
59        , GrRenderTarget(gpu, dimensions, colorAttachment->numSamples(),
60                         colorAttachment->isProtected() ? GrProtected::kYes : GrProtected::kNo)
61        , fColorAttachment(std::move(colorAttachment))
62        , fResolveAttachment(std::move(resolveAttachment))
63        , fCachedFramebuffers() {
64    SkASSERT(fColorAttachment);
65
66    if (fColorAttachment->numSamples() == 1 && fColorAttachment->supportsInputAttachmentUsage()) {
67        SkASSERT(!resolveAttachment);
68        // When we have a single sampled color attachment, we set both the color and resolve
69        // to the same attachment. This way if we use DMAA on this render target we will resolve
70        // to the single target attachment.
71        fResolveAttachment = fColorAttachment;
72    }
73
74    SkASSERT(!resolveAttachment ||
75             (fResolveAttachment->isProtected() == fColorAttachment->isProtected()));
76    SkASSERT(SkToBool(fColorAttachment->vkUsageFlags() & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
77    this->setFlags();
78    if (createType == CreateType::kDirectlyWrapped) {
79        this->registerWithCacheWrapped(GrWrapCacheable::kNo);
80    }
81}
82
83GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu,
84                                   SkISize dimensions,
85                                   sk_sp<GrVkFramebuffer> externalFramebuffer)
86        : GrSurface(gpu, dimensions,
87                    externalFramebuffer->colorAttachment()->isProtected() ? GrProtected::kYes
88                                                                          : GrProtected::kNo)
89        , GrRenderTarget(gpu, dimensions, 1,
90                         externalFramebuffer->colorAttachment()->isProtected() ? GrProtected::kYes
91                                                                               : GrProtected::kNo)
92        , fCachedFramebuffers()
93        , fExternalFramebuffer(externalFramebuffer) {
94    SkASSERT(fExternalFramebuffer);
95    SkASSERT(!fColorAttachment);
96    SkDEBUGCODE(auto colorAttachment = fExternalFramebuffer->colorAttachment());
97    SkASSERT(colorAttachment);
98    SkASSERT(colorAttachment->numSamples() == 1);
99    SkASSERT(SkToBool(colorAttachment->vkUsageFlags() & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT));
100    SkASSERT(!SkToBool(colorAttachment->vkUsageFlags() & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
101    this->setFlags();
102    this->registerWithCacheWrapped(GrWrapCacheable::kNo);
103}
104
105void GrVkRenderTarget::setFlags() {
106    if (this->wrapsSecondaryCommandBuffer()) {
107        return;
108    }
109    GrVkImage* nonMSAAAttachment = this->nonMSAAAttachment();
110    if (nonMSAAAttachment && nonMSAAAttachment->supportsInputAttachmentUsage()) {
111        this->setVkRTSupportsInputAttachment();
112    }
113}
114
115sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(
116        GrVkGpu* gpu,
117        SkISize dimensions,
118        int sampleCnt,
119        const GrVkImageInfo& info,
120        sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) {
121    SkASSERT(VK_NULL_HANDLE != info.fImage);
122    SkASSERT(1 == info.fLevelCount);
123    SkASSERT(sampleCnt >= 1 && info.fSampleCount >= 1);
124
125    int wrappedImageSampleCnt = static_cast<int>(info.fSampleCount);
126    if (sampleCnt != wrappedImageSampleCnt && wrappedImageSampleCnt != 1) {
127        return nullptr;
128    }
129
130    sk_sp<GrVkImage> wrappedAttachment =
131            GrVkImage::MakeWrapped(gpu,
132                                   dimensions,
133                                   info,
134                                   std::move(mutableState),
135                                   GrAttachment::UsageFlags::kColorAttachment,
136                                   kBorrow_GrWrapOwnership,
137                                   GrWrapCacheable::kNo);
138    if (!wrappedAttachment) {
139        return nullptr;
140    }
141
142    sk_sp<GrVkImage> colorAttachment;
143    colorAttachment = std::move(wrappedAttachment);
144
145    if (!colorAttachment) {
146        return nullptr;
147    }
148
149    GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu,dimensions, std::move(colorAttachment),
150                                                  nullptr, CreateType::kDirectlyWrapped);
151    return sk_sp<GrVkRenderTarget>(vkRT);
152}
153
154sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget(
155        GrVkGpu* gpu, SkISize dimensions, const GrVkDrawableInfo& vkInfo) {
156    const GrVkRenderPass* rp = gpu->resourceProvider().findCompatibleExternalRenderPass(
157            vkInfo.fCompatibleRenderPass, vkInfo.fColorAttachmentIndex);
158    if (!rp) {
159        return nullptr;
160    }
161
162    if (vkInfo.fSecondaryCommandBuffer == VK_NULL_HANDLE) {
163        return nullptr;
164    }
165
166    // We only set the few properties of the GrVkImageInfo that we know like layout and format. The
167    // others we keep at the default "null" values.
168    GrVkImageInfo info;
169    info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
170    info.fFormat = vkInfo.fFormat;
171    info.fImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
172                            VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
173
174    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(new GrBackendSurfaceMutableStateImpl(
175            VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_QUEUE_FAMILY_IGNORED));
176
177    sk_sp<GrVkImage> colorAttachment =
178            GrVkImage::MakeWrapped(gpu,
179                                   dimensions,
180                                   info,
181                                   std::move(mutableState),
182                                   GrAttachment::UsageFlags::kColorAttachment,
183                                   kBorrow_GrWrapOwnership,
184                                   GrWrapCacheable::kNo,
185                                   true);
186
187    std::unique_ptr<GrVkSecondaryCommandBuffer> scb(
188            GrVkSecondaryCommandBuffer::Create(vkInfo.fSecondaryCommandBuffer, rp));
189    if (!scb) {
190        return nullptr;
191    }
192
193    sk_sp<GrVkFramebuffer> framebuffer(new GrVkFramebuffer(
194            gpu, std::move(colorAttachment), sk_sp<const GrVkRenderPass>(rp),
195            std::move(scb)));
196
197    GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, std::move(framebuffer));
198
199    return sk_sp<GrVkRenderTarget>(vkRT);
200}
201
202GrBackendFormat GrVkRenderTarget::backendFormat() const {
203    if (this->wrapsSecondaryCommandBuffer()) {
204        return fExternalFramebuffer->colorAttachment()->backendFormat();
205    }
206    return fColorAttachment->backendFormat();
207}
208
209GrVkImage* GrVkRenderTarget::nonMSAAAttachment() const {
210    if (fColorAttachment->numSamples() == 1) {
211        return fColorAttachment.get();
212    } else {
213        return fResolveAttachment.get();
214    }
215}
216
217GrVkImage* GrVkRenderTarget::dynamicMSAAAttachment() {
218    if (fDynamicMSAAAttachment) {
219        return fDynamicMSAAAttachment.get();
220    }
221    const GrVkImage* nonMSAAColorAttachment = this->colorAttachment();
222    SkASSERT(nonMSAAColorAttachment->numSamples() == 1);
223
224    GrVkGpu* gpu = this->getVkGpu();
225    auto rp = gpu->getContext()->priv().resourceProvider();
226
227    const GrBackendFormat& format = nonMSAAColorAttachment->backendFormat();
228
229    GrMemoryless memoryless =
230            gpu->vkCaps().supportsMemorylessAttachments() ? GrMemoryless::kYes : GrMemoryless::kNo;
231
232    sk_sp<GrAttachment> msaaAttachment =
233            rp->getDiscardableMSAAAttachment(nonMSAAColorAttachment->dimensions(),
234                                             format,
235                                             gpu->caps()->internalMultisampleCount(format),
236                                             GrProtected(nonMSAAColorAttachment->isProtected()),
237                                             memoryless);
238    if (!msaaAttachment) {
239        return nullptr;
240    }
241    fDynamicMSAAAttachment = sk_sp<GrVkImage>(static_cast<GrVkImage*>(msaaAttachment.release()));
242    return fDynamicMSAAAttachment.get();
243}
244
245GrVkImage* GrVkRenderTarget::msaaAttachment() {
246    return this->colorAttachment()->numSamples() == 1 ? this->dynamicMSAAAttachment()
247                                                      : this->colorAttachment();
248}
249
250bool GrVkRenderTarget::canAttemptStencilAttachment(bool useMSAASurface) const {
251    SkASSERT(!useMSAASurface || this->numSamples() > 1 ||
252             this->getVkGpu()->vkCaps().supportsDiscardableMSAAForDMSAA());
253    if (!useMSAASurface && this->numSamples() > 1) {
254        return false;
255    }
256    bool validMSAA = true;
257    if (useMSAASurface) {
258        validMSAA = this->numSamples() > 1 ||
259                    (this->getVkGpu()->vkCaps().supportsDiscardableMSAAForDMSAA() &&
260                     this->colorAttachment()->supportsInputAttachmentUsage());
261    }
262    // We don't know the status of the stencil attachment for wrapped external secondary command
263    // buffers so we just assume we don't have one.
264    return validMSAA && !this->wrapsSecondaryCommandBuffer();
265}
266
267bool GrVkRenderTarget::completeStencilAttachment(GrAttachment* stencil, bool useMSAASurface) {
268    SkASSERT(!this->wrapsSecondaryCommandBuffer());
269    SkASSERT(!useMSAASurface ||
270             this->numSamples() > 1 ||
271             this->getVkGpu()->vkCaps().supportsDiscardableMSAAForDMSAA());
272    return true;
273}
274
275sk_sp<GrVkFramebuffer> GrVkRenderTarget::externalFramebuffer() const {
276    return fExternalFramebuffer;
277}
278
279GrVkResourceProvider::CompatibleRPHandle GrVkRenderTarget::compatibleRenderPassHandle(
280        bool withResolve,
281        bool withStencil,
282        SelfDependencyFlags selfDepFlags,
283        LoadFromResolve loadFromResolve) {
284    SkASSERT(!this->wrapsSecondaryCommandBuffer());
285
286    const GrVkFramebuffer* fb =
287            this->getFramebuffer(withResolve, withStencil, selfDepFlags, loadFromResolve);
288    if (!fb) {
289        return {};
290    }
291
292    return fb->compatibleRenderPassHandle();
293}
294
295const GrVkRenderPass* GrVkRenderTarget::getSimpleRenderPass(bool withResolve,
296                                                            bool withStencil,
297                                                            SelfDependencyFlags selfDepFlags,
298                                                            LoadFromResolve loadFromResolve) {
299    if (this->wrapsSecondaryCommandBuffer()) {
300         return fExternalFramebuffer->externalRenderPass();
301    }
302
303    const GrVkFramebuffer* fb =
304            this->getFramebuffer(withResolve, withStencil, selfDepFlags, loadFromResolve);
305    if (!fb) {
306        return nullptr;
307    }
308
309    return fb->compatibleRenderPass();
310}
311
312std::pair<const GrVkRenderPass*, GrVkResourceProvider::CompatibleRPHandle>
313GrVkRenderTarget::createSimpleRenderPass(bool withResolve,
314                                         bool withStencil,
315                                         SelfDependencyFlags selfDepFlags,
316                                         LoadFromResolve loadFromResolve) {
317    SkASSERT(!this->wrapsSecondaryCommandBuffer());
318
319    GrVkResourceProvider& rp = this->getVkGpu()->resourceProvider();
320
321    GrVkResourceProvider::CompatibleRPHandle handle;
322    const GrVkRenderPass* renderPass = rp.findCompatibleRenderPass(
323            this, &handle, withResolve, withStencil, selfDepFlags,
324            loadFromResolve);
325    SkASSERT(!renderPass || handle.isValid());
326    return {renderPass, handle};
327}
328
329const GrVkFramebuffer* GrVkRenderTarget::getFramebuffer(bool withResolve,
330                                                        bool withStencil,
331                                                        SelfDependencyFlags selfDepFlags,
332                                                        LoadFromResolve loadFromResolve) {
333    int cacheIndex =
334            renderpass_features_to_index(withResolve, withStencil, selfDepFlags, loadFromResolve);
335    SkASSERT(cacheIndex < GrVkRenderTarget::kNumCachedFramebuffers);
336    if (auto fb = fCachedFramebuffers[cacheIndex]) {
337        return fb.get();
338    }
339
340    this->createFramebuffer(withResolve, withStencil, selfDepFlags, loadFromResolve);
341    return fCachedFramebuffers[cacheIndex].get();
342}
343
344void GrVkRenderTarget::createFramebuffer(bool withResolve,
345                                         bool withStencil,
346                                         SelfDependencyFlags selfDepFlags,
347                                         LoadFromResolve loadFromResolve) {
348    SkASSERT(!this->wrapsSecondaryCommandBuffer());
349    GrVkGpu* gpu = this->getVkGpu();
350
351    auto[renderPass, compatibleHandle] =
352            this->createSimpleRenderPass(withResolve, withStencil, selfDepFlags, loadFromResolve);
353    if (!renderPass) {
354        return;
355    }
356    SkASSERT(compatibleHandle.isValid());
357
358    int cacheIndex =
359            renderpass_features_to_index(withResolve, withStencil, selfDepFlags, loadFromResolve);
360    SkASSERT(cacheIndex < GrVkRenderTarget::kNumCachedFramebuffers);
361
362    GrVkImage* resolve = withResolve ? this->resolveAttachment() : nullptr;
363    GrVkImage* colorAttachment = withResolve ? this->msaaAttachment() : this->colorAttachment();
364
365    // Stencil attachment view is stored in the base RT stencil attachment
366    bool useMSAA = this->numSamples() > 1 || withResolve;
367    GrVkImage* stencil =  withStencil ? static_cast<GrVkImage*>(this->getStencilAttachment(useMSAA))
368                                      : nullptr;
369    fCachedFramebuffers[cacheIndex] =
370            GrVkFramebuffer::Make(gpu, this->dimensions(),
371                                  sk_sp<const GrVkRenderPass>(renderPass),
372                                  colorAttachment, resolve, stencil, compatibleHandle);
373}
374
375void GrVkRenderTarget::getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc,
376                                                GrVkRenderPass::AttachmentFlags* attachmentFlags,
377                                                bool withResolve,
378                                                bool withStencil) {
379    SkASSERT(!this->wrapsSecondaryCommandBuffer());
380    const GrVkImage* colorAttachment =
381            withResolve ? this->msaaAttachment() : this->colorAttachment();
382
383    desc->fColor.fFormat = colorAttachment->imageFormat();
384    desc->fColor.fSamples = colorAttachment->numSamples();
385    *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag;
386    uint32_t attachmentCount = 1;
387
388    if (withResolve) {
389        desc->fResolve.fFormat = desc->fColor.fFormat;
390        desc->fResolve.fSamples = 1;
391        *attachmentFlags |= GrVkRenderPass::kResolve_AttachmentFlag;
392        ++attachmentCount;
393    }
394
395    if (withStencil) {
396        bool useMSAA = this->numSamples() > 1 || withResolve;
397        const GrAttachment* stencil = this->getStencilAttachment(useMSAA);
398        SkASSERT(stencil);
399        const GrVkImage* vkStencil = static_cast<const GrVkImage*>(stencil);
400        desc->fStencil.fFormat = vkStencil->imageFormat();
401        desc->fStencil.fSamples = vkStencil->numSamples();
402        SkASSERT(desc->fStencil.fSamples == desc->fColor.fSamples);
403        *attachmentFlags |= GrVkRenderPass::kStencil_AttachmentFlag;
404        ++attachmentCount;
405    }
406    desc->fAttachmentCount = attachmentCount;
407}
408
409void GrVkRenderTarget::ReconstructAttachmentsDescriptor(const GrVkCaps& vkCaps,
410                                                        const GrProgramInfo& programInfo,
411                                                        GrVkRenderPass::AttachmentsDescriptor* desc,
412                                                        GrVkRenderPass::AttachmentFlags* flags) {
413    VkFormat format;
414    SkAssertResult(programInfo.backendFormat().asVkFormat(&format));
415
416    desc->fColor.fFormat = format;
417    desc->fColor.fSamples = programInfo.numSamples();
418    *flags = GrVkRenderPass::kColor_AttachmentFlag;
419    uint32_t attachmentCount = 1;
420
421    if (vkCaps.programInfoWillUseDiscardableMSAA(programInfo)) {
422        desc->fResolve.fFormat = desc->fColor.fFormat;
423        desc->fResolve.fSamples = 1;
424        *flags |= GrVkRenderPass::kResolve_AttachmentFlag;
425        ++attachmentCount;
426    }
427
428    SkASSERT(!programInfo.isStencilEnabled() || programInfo.needsStencil());
429    if (programInfo.needsStencil()) {
430        VkFormat stencilFormat = vkCaps.preferredStencilFormat();
431        desc->fStencil.fFormat = stencilFormat;
432        desc->fStencil.fSamples = programInfo.numSamples();
433        SkASSERT(desc->fStencil.fSamples == desc->fColor.fSamples);
434        *flags |= GrVkRenderPass::kStencil_AttachmentFlag;
435        ++attachmentCount;
436    }
437    desc->fAttachmentCount = attachmentCount;
438}
439
440GrVkRenderTarget::~GrVkRenderTarget() {
441    // either release or abandon should have been called by the owner of this object.
442    SkASSERT(!fColorAttachment);
443    SkASSERT(!fResolveAttachment);
444    SkASSERT(!fDynamicMSAAAttachment);
445
446    for (int i = 0; i < kNumCachedFramebuffers; ++i) {
447        SkASSERT(!fCachedFramebuffers[i]);
448    }
449
450    SkASSERT(!fCachedInputDescriptorSet);
451}
452
453void GrVkRenderTarget::releaseInternalObjects() {
454    fColorAttachment.reset();
455    fResolveAttachment.reset();
456    fDynamicMSAAAttachment.reset();
457
458    for (int i = 0; i < kNumCachedFramebuffers; ++i) {
459        if (fCachedFramebuffers[i]) {
460            fCachedFramebuffers[i].reset();
461        }
462    }
463
464    if (fCachedInputDescriptorSet) {
465        fCachedInputDescriptorSet->recycle();
466        fCachedInputDescriptorSet = nullptr;
467    }
468
469    fExternalFramebuffer.reset();
470}
471
472void GrVkRenderTarget::onRelease() {
473    this->releaseInternalObjects();
474    GrRenderTarget::onRelease();
475}
476
477void GrVkRenderTarget::onAbandon() {
478    this->releaseInternalObjects();
479    GrRenderTarget::onAbandon();
480}
481
482GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const {
483    SkASSERT(!this->wrapsSecondaryCommandBuffer());
484    // This should only get called with a non-released GrVkRenderTargets.
485    SkASSERT(!this->wasDestroyed());
486    // If we have a resolve attachment that is what we return for the backend render target
487    const GrVkImage* beAttachment = this->externalAttachment();
488    return GrBackendRenderTarget(beAttachment->width(), beAttachment->height(),
489                                 beAttachment->vkImageInfo(), beAttachment->getMutableState());
490}
491
492GrVkGpu* GrVkRenderTarget::getVkGpu() const {
493    SkASSERT(!this->wasDestroyed());
494    return static_cast<GrVkGpu*>(this->getGpu());
495}
496