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 |
16 | SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {} |
17 | |
18 | SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {} |
19 | |
20 | bool SkDeferredDisplayListRecorder::init() { return false; } |
21 | |
22 | SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; } |
23 | |
24 | sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; } |
25 | |
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 | |
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 "include/gpu/GrRecordingContext.h" |
65 | #include "src/gpu/GrProxyProvider.h" |
66 | #include "src/gpu/GrRecordingContextPriv.h" |
67 | #include "src/gpu/GrRenderTargetContext.h" |
68 | #include "src/gpu/GrTexture.h" |
69 | #include "src/gpu/SkGr.h" |
70 | #include "src/image/SkImage_Gpu.h" |
71 | #include "src/image/SkImage_GpuYUVA.h" |
72 | #include "src/image/SkSurface_Gpu.h" |
73 | |
74 | SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c) |
75 | : fCharacterization(c) { |
76 | if (fCharacterization.isValid()) { |
77 | fContext = GrRecordingContextPriv::MakeDDL(fCharacterization.refContextInfo()); |
78 | } |
79 | } |
80 | |
81 | SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() { |
82 | if (fContext) { |
83 | auto proxyProvider = fContext->priv().proxyProvider(); |
84 | |
85 | // This allows the uniquely keyed proxies to keep their keys but removes their back |
86 | // pointer to the about-to-be-deleted proxy provider. The proxies will use their |
87 | // unique key to reattach to cached versions of themselves or to appropriately tag new |
88 | // resources (if a cached version was not found). This system operates independent of |
89 | // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not |
90 | // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine |
91 | // since no one else should be trying to reconnect to the orphaned proxies and orphaned |
92 | // proxies from different DDLs that share the same key should simply reconnect to the |
93 | // same cached resource. |
94 | proxyProvider->orphanAllUniqueKeys(); |
95 | } |
96 | } |
97 | |
98 | |
99 | bool SkDeferredDisplayListRecorder::init() { |
100 | SkASSERT(fContext); |
101 | SkASSERT(!fTargetProxy); |
102 | SkASSERT(!fLazyProxyData); |
103 | SkASSERT(!fSurface); |
104 | |
105 | if (!fCharacterization.isValid()) { |
106 | return false; |
107 | } |
108 | |
109 | fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>( |
110 | new SkDeferredDisplayList::LazyProxyData); |
111 | |
112 | auto proxyProvider = fContext->priv().proxyProvider(); |
113 | const GrCaps* caps = fContext->priv().caps(); |
114 | |
115 | bool usesGLFBO0 = fCharacterization.usesGLFBO0(); |
116 | if (usesGLFBO0) { |
117 | if (GrBackendApi::kOpenGL != fContext->backend() || |
118 | fCharacterization.isTextureable()) { |
119 | return false; |
120 | } |
121 | } |
122 | |
123 | if (fCharacterization.vulkanSecondaryCBCompatible()) { |
124 | // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead |
125 | // of time that we don't be able to support certain parameter combinations. Specifially we |
126 | // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object. |
127 | // And finally the GrVkSecondaryCBDrawContext always assumes a top left origin. |
128 | if (usesGLFBO0 || |
129 | fCharacterization.isTextureable() || |
130 | fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) { |
131 | return false; |
132 | } |
133 | } |
134 | |
135 | GrColorType grColorType = SkColorTypeToGrColorType(fCharacterization.colorType()); |
136 | |
137 | sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData; |
138 | |
139 | // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy |
140 | // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the |
141 | // DDL is being replayed into. |
142 | |
143 | GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone; |
144 | if (usesGLFBO0) { |
145 | surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; |
146 | } else if (fCharacterization.sampleCount() > 1 && !caps->msaaResolvesAutomatically() && |
147 | fCharacterization.isTextureable()) { |
148 | surfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve; |
149 | } |
150 | // FIXME: Why do we use GrMipmapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped? |
151 | static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipmapped::kNo, |
152 | GrTextureType::k2D}; |
153 | const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr; |
154 | if (fCharacterization.isTextureable()) { |
155 | optionalTextureInfo = &kTextureInfo; |
156 | } |
157 | |
158 | GrSwizzle readSwizzle = caps->getReadSwizzle(fCharacterization.backendFormat(), grColorType); |
159 | |
160 | fTargetProxy = proxyProvider->createLazyRenderTargetProxy( |
161 | [lazyProxyData](GrResourceProvider* resourceProvider, |
162 | const GrSurfaceProxy::LazySurfaceDesc&) { |
163 | // The proxy backing the destination surface had better have been instantiated |
164 | // prior to the this one (i.e., the proxy backing the DLL's surface). |
165 | // Fulfill this lazy proxy with the destination surface's GrRenderTarget. |
166 | SkASSERT(lazyProxyData->fReplayDest->peekSurface()); |
167 | auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface()); |
168 | return GrSurfaceProxy::LazyCallbackResult(std::move(surface)); |
169 | }, |
170 | fCharacterization.backendFormat(), |
171 | fCharacterization.dimensions(), |
172 | fCharacterization.sampleCount(), |
173 | surfaceFlags, |
174 | optionalTextureInfo, |
175 | GrMipmapStatus::kNotAllocated, |
176 | SkBackingFit::kExact, |
177 | SkBudgeted::kYes, |
178 | fCharacterization.isProtected(), |
179 | fCharacterization.vulkanSecondaryCBCompatible(), |
180 | GrSurfaceProxy::UseAllocator::kYes); |
181 | |
182 | if (!fTargetProxy) { |
183 | return false; |
184 | } |
185 | |
186 | GrSwizzle writeSwizzle = caps->getWriteSwizzle(fCharacterization.backendFormat(), grColorType); |
187 | |
188 | GrSurfaceProxyView readView(fTargetProxy, fCharacterization.origin(), readSwizzle); |
189 | GrSurfaceProxyView writeView(fTargetProxy, fCharacterization.origin(), writeSwizzle); |
190 | |
191 | auto rtc = std::make_unique<GrRenderTargetContext>(fContext.get(), std::move(readView), |
192 | std::move(writeView), grColorType, |
193 | fCharacterization.refColorSpace(), |
194 | &fCharacterization.surfaceProps()); |
195 | fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), std::move(rtc)); |
196 | return SkToBool(fSurface.get()); |
197 | } |
198 | |
199 | SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { |
200 | if (!fContext) { |
201 | return nullptr; |
202 | } |
203 | |
204 | if (!fSurface && !this->init()) { |
205 | return nullptr; |
206 | } |
207 | |
208 | return fSurface->getCanvas(); |
209 | } |
210 | |
211 | sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { |
212 | if (!fContext || !fTargetProxy) { |
213 | return nullptr; |
214 | } |
215 | |
216 | if (fSurface) { |
217 | SkCanvas* canvas = fSurface->getCanvas(); |
218 | |
219 | canvas->restoreToCount(0); |
220 | } |
221 | |
222 | auto ddl = sk_sp<SkDeferredDisplayList>(new SkDeferredDisplayList(fCharacterization, |
223 | std::move(fTargetProxy), |
224 | 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 | |
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 | |
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 | |