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 
10 #include "include/core/SkDeferredDisplayList.h"
11 #include "include/core/SkSurface.h"
12 #include "include/core/SkSurfaceCharacterization.h"
13 #include "src/core/SkMessageBus.h"
14 
15 #if !SK_SUPPORT_GPU
SkDeferredDisplayListRecorder(const SkSurfaceCharacterization &)16 SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {}
17 
~SkDeferredDisplayListRecorder()18 SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {}
19 
init()20 bool SkDeferredDisplayListRecorder::init() { return false; }
21 
getCanvas()22 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; }
23 
detach()24 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; }
25 
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)26 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
27         const GrBackendFormat& backendFormat,
28         int width,
29         int height,
30         GrMipMapped mipMapped,
31         GrSurfaceOrigin origin,
32         SkColorType colorType,
33         SkAlphaType alphaType,
34         sk_sp<SkColorSpace> colorSpace,
35         PromiseImageTextureFulfillProc textureFulfillProc,
36         PromiseImageTextureReleaseProc textureReleaseProc,
37         PromiseImageTextureDoneProc textureDoneProc,
38         PromiseImageTextureContext textureContext,
39         PromiseImageApiVersion) {
40     return nullptr;
41 }
42 
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)43 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
44         SkYUVColorSpace yuvColorSpace,
45         const GrBackendFormat yuvaFormats[],
46         const SkISize yuvaSizes[],
47         const SkYUVAIndex yuvaIndices[4],
48         int imageWidth,
49         int imageHeight,
50         GrSurfaceOrigin imageOrigin,
51         sk_sp<SkColorSpace> imageColorSpace,
52         PromiseImageTextureFulfillProc textureFulfillProc,
53         PromiseImageTextureReleaseProc textureReleaseProc,
54         PromiseImageTextureDoneProc textureDoneProc,
55         PromiseImageTextureContext textureContexts[],
56         PromiseImageApiVersion) {
57     return nullptr;
58 }
59 
60 #else
61 
62 #include "include/core/SkPromiseImageTexture.h"
63 #include "include/core/SkYUVASizeInfo.h"
64 #include "src/gpu/GrContextPriv.h"
65 #include "src/gpu/GrProxyProvider.h"
66 #include "src/gpu/GrRenderTargetContext.h"
67 #include "src/gpu/GrTexture.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     sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData;
136 
137     // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
138     // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
139     // DDL is being replayed into.
140 
141     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
142     if (usesGLFBO0) {
143         surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
144     }
145     // FIXME: Why do we use GrMipMapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped?
146     static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo,
147                                                                GrTextureType::k2D};
148     const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr;
149     if (fCharacterization.isTextureable()) {
150         optionalTextureInfo = &kTextureInfo;
151     }
152 
153     GrSwizzle readSwizzle = caps->getReadSwizzle(fCharacterization.backendFormat(), grColorType);
154 
155     sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
156             [lazyProxyData](GrResourceProvider* resourceProvider) {
157                 // The proxy backing the destination surface had better have been instantiated
158                 // prior to the proxy backing the DLL's surface. Steal its GrRenderTarget.
159                 SkASSERT(lazyProxyData->fReplayDest->peekSurface());
160                 auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
161                 return GrSurfaceProxy::LazyCallbackResult(std::move(surface));
162             },
163             fCharacterization.backendFormat(),
164             fCharacterization.dimensions(),
165             fCharacterization.sampleCount(),
166             surfaceFlags,
167             optionalTextureInfo,
168             GrMipMapsStatus::kNotAllocated,
169             SkBackingFit::kExact,
170             SkBudgeted::kYes,
171             fCharacterization.isProtected(),
172             fCharacterization.vulkanSecondaryCBCompatible(),
173             GrSurfaceProxy::UseAllocator::kYes);
174 
175     if (!proxy) {
176         return false;
177     }
178 
179     GrSwizzle writeSwizzle = caps->getWriteSwizzle(fCharacterization.backendFormat(), grColorType);
180 
181     GrSurfaceProxyView readView(proxy, fCharacterization.origin(), readSwizzle);
182     GrSurfaceProxyView outputView(std::move(proxy), fCharacterization.origin(), writeSwizzle);
183 
184     auto rtc = std::make_unique<GrRenderTargetContext>(fContext.get(), std::move(readView),
185                                                        std::move(outputView), grColorType,
186                                                        fCharacterization.refColorSpace(),
187                                                        &fCharacterization.surfaceProps());
188     fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), std::move(rtc));
189     return SkToBool(fSurface.get());
190 }
191 
getCanvas()192 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
193     if (!fContext) {
194         return nullptr;
195     }
196 
197     if (!fSurface && !this->init()) {
198         return nullptr;
199     }
200 
201     return fSurface->getCanvas();
202 }
203 
detach()204 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
205     if (!fContext) {
206         return nullptr;
207     }
208 
209     if (fSurface) {
210         SkCanvas* canvas = fSurface->getCanvas();
211 
212         canvas->restoreToCount(0);
213     }
214 
215     auto ddl = std::unique_ptr<SkDeferredDisplayList>(
216                            new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData)));
217 
218     fContext->priv().moveRenderTasksToDDL(ddl.get());
219 
220     // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed)
221     // SkSurface to be regenerated for each DDL.
222     fSurface = nullptr;
223     return ddl;
224 }
225 
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)226 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
227         const GrBackendFormat& backendFormat,
228         int width,
229         int height,
230         GrMipMapped mipMapped,
231         GrSurfaceOrigin origin,
232         SkColorType colorType,
233         SkAlphaType alphaType,
234         sk_sp<SkColorSpace> colorSpace,
235         PromiseImageTextureFulfillProc textureFulfillProc,
236         PromiseImageTextureReleaseProc textureReleaseProc,
237         PromiseImageTextureDoneProc textureDoneProc,
238         PromiseImageTextureContext textureContext,
239         PromiseImageApiVersion version) {
240     if (!fContext) {
241         return nullptr;
242     }
243 
244     return SkImage_Gpu::MakePromiseTexture(fContext.get(),
245                                            backendFormat,
246                                            width,
247                                            height,
248                                            mipMapped,
249                                            origin,
250                                            colorType,
251                                            alphaType,
252                                            std::move(colorSpace),
253                                            textureFulfillProc,
254                                            textureReleaseProc,
255                                            textureDoneProc,
256                                            textureContext,
257                                            version);
258 }
259 
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)260 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
261         SkYUVColorSpace yuvColorSpace,
262         const GrBackendFormat yuvaFormats[],
263         const SkISize yuvaSizes[],
264         const SkYUVAIndex yuvaIndices[4],
265         int imageWidth,
266         int imageHeight,
267         GrSurfaceOrigin imageOrigin,
268         sk_sp<SkColorSpace> imageColorSpace,
269         PromiseImageTextureFulfillProc textureFulfillProc,
270         PromiseImageTextureReleaseProc textureReleaseProc,
271         PromiseImageTextureDoneProc textureDoneProc,
272         PromiseImageTextureContext textureContexts[],
273         PromiseImageApiVersion version) {
274     if (!fContext) {
275         return nullptr;
276     }
277 
278     return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext.get(),
279                                                    yuvColorSpace,
280                                                    yuvaFormats,
281                                                    yuvaSizes,
282                                                    yuvaIndices,
283                                                    imageWidth,
284                                                    imageHeight,
285                                                    imageOrigin,
286                                                    std::move(imageColorSpace),
287                                                    textureFulfillProc,
288                                                    textureReleaseProc,
289                                                    textureDoneProc,
290                                                    textureContexts,
291                                                    version);
292 }
293 
294 #endif
295