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