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
16SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {}
17
18SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {}
19
20bool SkDeferredDisplayListRecorder::init() { return false; }
21
22SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; }
23
24sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; }
25
26sk_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
43sk_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
74SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c)
75 : fCharacterization(c) {
76 if (fCharacterization.isValid()) {
77 fContext = GrRecordingContextPriv::MakeDDL(fCharacterization.refContextInfo());
78 }
79}
80
81SkDeferredDisplayListRecorder::~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
99bool 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
199SkCanvas* 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
211sk_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
234sk_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
268sk_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