1 /*
2  * Copyright 2017 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 "include/core/SkDeferredDisplayListRecorder.h"
9 #include "include/core/SkSurface.h"
10 #include "include/core/SkSurfaceCharacterization.h"
11 #include "include/private/SkDeferredDisplayList.h"
12 #include "src/core/SkMessageBus.h"
13 
14 #if !SK_SUPPORT_GPU
SkDeferredDisplayListRecorder(const SkSurfaceCharacterization &)15 SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {}
16 
~SkDeferredDisplayListRecorder()17 SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {}
18 
init()19 bool SkDeferredDisplayListRecorder::init() { return false; }
20 
getCanvas()21 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; }
22 
detach()23 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; }
24 
makePromiseTexture(const GrBackendFormat & backendFormat,int width,int height,GrMipMapped mipMapped,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureDoneProc textureDoneProc,PromiseImageTextureContext textureContext,PromiseImageApiVersion)25 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
26         const GrBackendFormat& backendFormat,
27         int width,
28         int height,
29         GrMipMapped mipMapped,
30         GrSurfaceOrigin origin,
31         SkColorType colorType,
32         SkAlphaType alphaType,
33         sk_sp<SkColorSpace> colorSpace,
34         PromiseImageTextureFulfillProc textureFulfillProc,
35         PromiseImageTextureReleaseProc textureReleaseProc,
36         PromiseImageTextureDoneProc textureDoneProc,
37         PromiseImageTextureContext textureContext,
38         PromiseImageApiVersion) {
39     return nullptr;
40 }
41 
makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace,const GrBackendFormat yuvaFormats[],const SkISize yuvaSizes[],const SkYUVAIndex yuvaIndices[4],int imageWidth,int imageHeight,GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureDoneProc textureDoneProc,PromiseImageTextureContext textureContexts[],PromiseImageApiVersion)42 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
43         SkYUVColorSpace yuvColorSpace,
44         const GrBackendFormat yuvaFormats[],
45         const SkISize yuvaSizes[],
46         const SkYUVAIndex yuvaIndices[4],
47         int imageWidth,
48         int imageHeight,
49         GrSurfaceOrigin imageOrigin,
50         sk_sp<SkColorSpace> imageColorSpace,
51         PromiseImageTextureFulfillProc textureFulfillProc,
52         PromiseImageTextureReleaseProc textureReleaseProc,
53         PromiseImageTextureDoneProc textureDoneProc,
54         PromiseImageTextureContext textureContexts[],
55         PromiseImageApiVersion) {
56     return nullptr;
57 }
58 
59 #else
60 
61 #include "include/core/SkPromiseImageTexture.h"
62 #include "include/core/SkYUVASizeInfo.h"
63 #include "include/gpu/GrTexture.h"
64 #include "src/core/SkMakeUnique.h"
65 #include "src/gpu/GrContextPriv.h"
66 #include "src/gpu/GrProxyProvider.h"
67 #include "src/gpu/GrRenderTargetContext.h"
68 #include "src/gpu/SkGr.h"
69 #include "src/image/SkImage_Gpu.h"
70 #include "src/image/SkImage_GpuYUVA.h"
71 #include "src/image/SkSurface_Gpu.h"
72 
SkDeferredDisplayListRecorder(const SkSurfaceCharacterization & c)73 SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c)
74         : fCharacterization(c) {
75     if (fCharacterization.isValid()) {
76         fContext = GrContextPriv::MakeDDL(fCharacterization.refContextInfo());
77     }
78 }
79 
~SkDeferredDisplayListRecorder()80 SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {
81     if (fContext) {
82         auto proxyProvider = fContext->priv().proxyProvider();
83 
84         // This allows the uniquely keyed proxies to keep their keys but removes their back
85         // pointer to the about-to-be-deleted proxy provider. The proxies will use their
86         // unique key to reattach to cached versions of themselves or to appropriately tag new
87         // resources (if a cached version was not found). This system operates independent of
88         // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not
89         // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine
90         // since no one else should be trying to reconnect to the orphaned proxies and orphaned
91         // proxies from different DDLs that share the same key should simply reconnect to the
92         // same cached resource.
93         proxyProvider->orphanAllUniqueKeys();
94     }
95 }
96 
97 
init()98 bool SkDeferredDisplayListRecorder::init() {
99     SkASSERT(fContext);
100     SkASSERT(!fLazyProxyData);
101     SkASSERT(!fSurface);
102 
103     if (!fCharacterization.isValid()) {
104         return false;
105     }
106 
107     fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>(
108                                                     new SkDeferredDisplayList::LazyProxyData);
109 
110     auto proxyProvider = fContext->priv().proxyProvider();
111     const GrCaps* caps = fContext->priv().caps();
112 
113     bool usesGLFBO0 = fCharacterization.usesGLFBO0();
114     if (usesGLFBO0) {
115         if (GrBackendApi::kOpenGL != fContext->backend() ||
116             fCharacterization.isTextureable()) {
117             return false;
118         }
119     }
120 
121     if (fCharacterization.vulkanSecondaryCBCompatible()) {
122         // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead
123         // of time that we don't be able to support certain parameter combinations. Specifially we
124         // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object.
125         // And finally the GrVkSecondaryCBDrawContext always assumes a top left origin.
126         if (usesGLFBO0 ||
127             fCharacterization.isTextureable() ||
128             fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) {
129             return false;
130         }
131     }
132 
133     GrColorType grColorType = SkColorTypeToGrColorType(fCharacterization.colorType());
134 
135     GrPixelConfig config = caps->getConfigFromBackendFormat(fCharacterization.backendFormat(),
136                                                             grColorType);
137     if (config == kUnknown_GrPixelConfig) {
138         return false;
139     }
140 
141     GrSurfaceDesc desc;
142     desc.fWidth = fCharacterization.width();
143     desc.fHeight = fCharacterization.height();
144     desc.fConfig = config;
145 
146     sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData;
147 
148     // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
149     // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
150     // DDL is being replayed into.
151 
152     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
153     if (usesGLFBO0) {
154         surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
155     }
156     // FIXME: Why do we use GrMipMapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped?
157     static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo,
158                                                                GrTextureType::k2D};
159     const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr;
160     if (fCharacterization.isTextureable()) {
161         optionalTextureInfo = &kTextureInfo;
162     }
163 
164     sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
165             [lazyProxyData](GrResourceProvider* resourceProvider) {
166                 // The proxy backing the destination surface had better have been instantiated
167                 // prior to the proxy backing the DLL's surface. Steal its GrRenderTarget.
168                 SkASSERT(lazyProxyData->fReplayDest->peekSurface());
169                 auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
170                 return GrSurfaceProxy::LazyCallbackResult(std::move(surface));
171             },
172             fCharacterization.backendFormat(),
173             desc,
174             fCharacterization.sampleCount(),
175             fCharacterization.origin(),
176             surfaceFlags,
177             optionalTextureInfo,
178             GrMipMapsStatus::kNotAllocated,
179             SkBackingFit::kExact,
180             SkBudgeted::kYes,
181             fCharacterization.isProtected(),
182             fCharacterization.vulkanSecondaryCBCompatible(),
183             GrSurfaceProxy::UseAllocator::kYes);
184 
185     if (!proxy) {
186         return false;
187     }
188 
189     auto c = fContext->priv().makeWrappedSurfaceContext(std::move(proxy),
190                                                         grColorType,
191                                                         kPremul_SkAlphaType,
192                                                         fCharacterization.refColorSpace(),
193                                                         &fCharacterization.surfaceProps());
194     SkASSERT(c->asRenderTargetContext());
195     std::unique_ptr<GrRenderTargetContext> rtc(c.release()->asRenderTargetContext());
196     fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), std::move(rtc));
197     return SkToBool(fSurface.get());
198 }
199 
getCanvas()200 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
201     if (!fContext) {
202         return nullptr;
203     }
204 
205     if (!fSurface && !this->init()) {
206         return nullptr;
207     }
208 
209     return fSurface->getCanvas();
210 }
211 
detach()212 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
213     if (!fContext) {
214         return nullptr;
215     }
216 
217     if (fSurface) {
218         SkCanvas* canvas = fSurface->getCanvas();
219 
220         canvas->restoreToCount(0);
221     }
222 
223     auto ddl = std::unique_ptr<SkDeferredDisplayList>(
224                            new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData)));
225 
226     fContext->priv().moveRenderTasksToDDL(ddl.get());
227 
228     // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed)
229     // SkSurface to be regenerated for each DDL.
230     fSurface = nullptr;
231     return ddl;
232 }
233 
makePromiseTexture(const GrBackendFormat & backendFormat,int width,int height,GrMipMapped mipMapped,GrSurfaceOrigin origin,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureDoneProc textureDoneProc,PromiseImageTextureContext textureContext,PromiseImageApiVersion version)234 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
235         const GrBackendFormat& backendFormat,
236         int width,
237         int height,
238         GrMipMapped mipMapped,
239         GrSurfaceOrigin origin,
240         SkColorType colorType,
241         SkAlphaType alphaType,
242         sk_sp<SkColorSpace> colorSpace,
243         PromiseImageTextureFulfillProc textureFulfillProc,
244         PromiseImageTextureReleaseProc textureReleaseProc,
245         PromiseImageTextureDoneProc textureDoneProc,
246         PromiseImageTextureContext textureContext,
247         PromiseImageApiVersion version) {
248     if (!fContext) {
249         return nullptr;
250     }
251 
252     return SkImage_Gpu::MakePromiseTexture(fContext.get(),
253                                            backendFormat,
254                                            width,
255                                            height,
256                                            mipMapped,
257                                            origin,
258                                            colorType,
259                                            alphaType,
260                                            std::move(colorSpace),
261                                            textureFulfillProc,
262                                            textureReleaseProc,
263                                            textureDoneProc,
264                                            textureContext,
265                                            version);
266 }
267 
makeYUVAPromiseTexture(SkYUVColorSpace yuvColorSpace,const GrBackendFormat yuvaFormats[],const SkISize yuvaSizes[],const SkYUVAIndex yuvaIndices[4],int imageWidth,int imageHeight,GrSurfaceOrigin imageOrigin,sk_sp<SkColorSpace> imageColorSpace,PromiseImageTextureFulfillProc textureFulfillProc,PromiseImageTextureReleaseProc textureReleaseProc,PromiseImageTextureDoneProc textureDoneProc,PromiseImageTextureContext textureContexts[],PromiseImageApiVersion version)268 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
269         SkYUVColorSpace yuvColorSpace,
270         const GrBackendFormat yuvaFormats[],
271         const SkISize yuvaSizes[],
272         const SkYUVAIndex yuvaIndices[4],
273         int imageWidth,
274         int imageHeight,
275         GrSurfaceOrigin imageOrigin,
276         sk_sp<SkColorSpace> imageColorSpace,
277         PromiseImageTextureFulfillProc textureFulfillProc,
278         PromiseImageTextureReleaseProc textureReleaseProc,
279         PromiseImageTextureDoneProc textureDoneProc,
280         PromiseImageTextureContext textureContexts[],
281         PromiseImageApiVersion version) {
282     if (!fContext) {
283         return nullptr;
284     }
285 
286     return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext.get(),
287                                                    yuvColorSpace,
288                                                    yuvaFormats,
289                                                    yuvaSizes,
290                                                    yuvaIndices,
291                                                    imageWidth,
292                                                    imageHeight,
293                                                    imageOrigin,
294                                                    std::move(imageColorSpace),
295                                                    textureFulfillProc,
296                                                    textureReleaseProc,
297                                                    textureDoneProc,
298                                                    textureContexts,
299                                                    version);
300 }
301 
302 #endif
303