1 /*
2  * Copyright 2019 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/GrVkSecondaryCBDrawContext.h"
9 
10 #include "include/core/SkDeferredDisplayList.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkSurfaceCharacterization.h"
13 #include "include/gpu/GrContext.h"
14 #include "include/gpu/vk/GrVkTypes.h"
15 #include "src/core/SkSurfacePriv.h"
16 #include "src/gpu/GrContextPriv.h"
17 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
18 #include "src/gpu/GrRenderTargetContext.h"
19 #include "src/gpu/SkGpuDevice.h"
20 
Make(GrContext * ctx,const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo,const SkSurfaceProps * props)21 sk_sp<GrVkSecondaryCBDrawContext> GrVkSecondaryCBDrawContext::Make(GrContext* ctx,
22                                                                    const SkImageInfo& imageInfo,
23                                                                    const GrVkDrawableInfo& vkInfo,
24                                                                    const SkSurfaceProps* props) {
25     if (!ctx) {
26         return nullptr;
27     }
28 
29     if (ctx->backend() != GrBackendApi::kVulkan) {
30         return nullptr;
31     }
32 
33     auto rtc = GrRenderTargetContext::MakeFromVulkanSecondaryCB(ctx, imageInfo, vkInfo, props);
34     SkASSERT(rtc->asSurfaceProxy()->isInstantiated());
35 
36     sk_sp<SkGpuDevice> device(
37             SkGpuDevice::Make(ctx, std::move(rtc), SkGpuDevice::kUninit_InitContents));
38     if (!device) {
39         return nullptr;
40     }
41 
42     return sk_sp<GrVkSecondaryCBDrawContext>(new GrVkSecondaryCBDrawContext(std::move(device),
43                                                                             props));
44 }
45 
GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice> device,const SkSurfaceProps * props)46 GrVkSecondaryCBDrawContext::GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice> device,
47                                                        const SkSurfaceProps* props)
48     : fDevice(device)
49     , fProps(SkSurfacePropsCopyOrDefault(props)) {}
50 
~GrVkSecondaryCBDrawContext()51 GrVkSecondaryCBDrawContext::~GrVkSecondaryCBDrawContext() {
52     SkASSERT(!fDevice);
53     SkASSERT(!fCachedCanvas.get());
54 }
55 
getCanvas()56 SkCanvas* GrVkSecondaryCBDrawContext::getCanvas() {
57     if (!fCachedCanvas) {
58         fCachedCanvas = std::unique_ptr<SkCanvas>(new SkCanvas(fDevice));
59     }
60     return fCachedCanvas.get();
61 }
62 
flush()63 void GrVkSecondaryCBDrawContext::flush() {
64     fDevice->flush();
65 }
66 
wait(int numSemaphores,const GrBackendSemaphore waitSemaphores[])67 bool GrVkSecondaryCBDrawContext::wait(int numSemaphores,
68                                       const GrBackendSemaphore waitSemaphores[]) {
69     return fDevice->wait(numSemaphores, waitSemaphores);
70 }
71 
releaseResources()72 void GrVkSecondaryCBDrawContext::releaseResources() {
73     fCachedCanvas.reset();
74     fDevice.reset();
75 }
76 
characterize(SkSurfaceCharacterization * characterization) const77 bool GrVkSecondaryCBDrawContext::characterize(SkSurfaceCharacterization* characterization) const {
78     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
79     GrContext* ctx = fDevice->context();
80 
81     size_t maxResourceBytes = ctx->getResourceCacheLimit();
82 
83     // We current don't support textured GrVkSecondaryCBDrawContexts.
84     SkASSERT(!rtc->asTextureProxy());
85 
86     SkColorType ct = GrColorTypeToSkColorType(rtc->colorInfo().colorType());
87     if (ct == kUnknown_SkColorType) {
88         return false;
89     }
90 
91     SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
92                                        rtc->colorInfo().refColorSpace());
93 
94     GrBackendFormat format = rtc->asRenderTargetProxy()->backendFormat();
95 
96     characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, format,
97                           rtc->origin(), rtc->numSamples(),
98                           SkSurfaceCharacterization::Textureable(false),
99                           SkSurfaceCharacterization::MipMapped(false),
100                           SkSurfaceCharacterization::UsesGLFBO0(false),
101                           SkSurfaceCharacterization::VulkanSecondaryCBCompatible(true),
102                           rtc->asRenderTargetProxy()->isProtected(),
103                           this->props());
104 
105     return true;
106 }
107 
isCompatible(const SkSurfaceCharacterization & characterization) const108 bool GrVkSecondaryCBDrawContext::isCompatible(
109         const SkSurfaceCharacterization& characterization) const {
110     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
111     GrContext* ctx = fDevice->context();
112 
113     if (!characterization.isValid()) {
114         return false;
115     }
116 
117     if (!characterization.vulkanSecondaryCBCompatible()) {
118         return false;
119     }
120 
121     // As long as the current state in the context allows for greater or equal resources,
122     // we allow the DDL to be replayed.
123     // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?
124     size_t maxResourceBytes = ctx->getResourceCacheLimit();
125 
126     if (characterization.isTextureable()) {
127         // We don't support textureable DDL when rendering to a GrVkSecondaryCBDrawContext.
128         return false;
129     }
130 
131     if (characterization.usesGLFBO0()) {
132         return false;
133     }
134 
135     SkColorType rtColorType = GrColorTypeToSkColorType(rtc->colorInfo().colorType());
136     if (rtColorType == kUnknown_SkColorType) {
137         return false;
138     }
139 
140     GrBackendFormat rtcFormat = rtc->asRenderTargetProxy()->backendFormat();
141     GrProtected isProtected = rtc->asRenderTargetProxy()->isProtected();
142 
143     return characterization.contextInfo() && characterization.contextInfo()->priv().matches(ctx) &&
144            characterization.cacheMaxResourceBytes() <= maxResourceBytes &&
145            characterization.origin() == rtc->origin() &&
146            characterization.backendFormat() == rtcFormat &&
147            characterization.width() == rtc->width() &&
148            characterization.height() == rtc->height() &&
149            characterization.colorType() == rtColorType &&
150            characterization.sampleCount() == rtc->numSamples() &&
151            SkColorSpace::Equals(characterization.colorSpace(), rtc->colorInfo().colorSpace()) &&
152            characterization.isProtected() == isProtected &&
153            characterization.surfaceProps() == rtc->surfaceProps();
154 }
155 
draw(SkDeferredDisplayList * ddl)156 bool GrVkSecondaryCBDrawContext::draw(SkDeferredDisplayList* ddl) {
157     if (!ddl || !this->isCompatible(ddl->characterization())) {
158         return false;
159     }
160 
161     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
162     GrContext* ctx = fDevice->context();
163 
164     ctx->priv().copyRenderTasksFromDDL(ddl, rtc->asRenderTargetProxy());
165     return true;
166 }
167 
168 
169