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 | std::unique_ptr<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 "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 | |
73 | SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c) |
74 | : fCharacterization(c) { |
75 | if (fCharacterization.isValid()) { |
76 | fContext = GrContextPriv::MakeDDL(fCharacterization.refContextInfo()); |
77 | } |
78 | } |
79 | |
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 | |
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 writeView(std::move(proxy), fCharacterization.origin(), writeSwizzle); |
183 | |
184 | auto rtc = std::make_unique<GrRenderTargetContext>(fContext.get(), std::move(readView), |
185 | std::move(writeView), grColorType, |
186 | fCharacterization.refColorSpace(), |
187 | &fCharacterization.surfaceProps()); |
188 | fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), std::move(rtc)); |
189 | return SkToBool(fSurface.get()); |
190 | } |
191 | |
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 | |
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 | |
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 | |
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 | |