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 "SkDeferredDisplayListRecorder.h"
9 #include "SkMessageBus.h"
10 #include "SkDeferredDisplayList.h"
11 #include "SkSurface.h"
12 #include "SkSurfaceCharacterization.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,DelayReleaseCallback delayReleaseCallback)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 DelayReleaseCallback delayReleaseCallback) {
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[],DelayReleaseCallback delayReleaseCallback)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 DelayReleaseCallback delayReleaseCallback) {
56 return nullptr;
57 }
58
59 #else
60
61 #include "GrContextPriv.h"
62 #include "GrProxyProvider.h"
63 #include "GrRenderTargetContext.h"
64 #include "GrTexture.h"
65 #include "SkGr.h"
66 #include "SkImage_Gpu.h"
67 #include "SkImage_GpuYUVA.h"
68 #include "SkMakeUnique.h"
69 #include "SkPromiseImageTexture.h"
70 #include "SkSurface_Gpu.h"
71 #include "SkYUVASizeInfo.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->contextPriv().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->contextPriv().proxyProvider();
111
112 bool usesGLFBO0 = fCharacterization.usesGLFBO0();
113 if (usesGLFBO0) {
114 if (GrBackendApi::kOpenGL != fContext->backend() ||
115 fCharacterization.isTextureable()) {
116 return false;
117 }
118 }
119
120 GrSurfaceDesc desc;
121 desc.fFlags = kRenderTarget_GrSurfaceFlag;
122 desc.fWidth = fCharacterization.width();
123 desc.fHeight = fCharacterization.height();
124 desc.fConfig = fCharacterization.config();
125 desc.fSampleCnt = fCharacterization.stencilCount();
126
127 sk_sp<SkDeferredDisplayList::LazyProxyData> lazyProxyData = fLazyProxyData;
128
129 // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy
130 // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the
131 // DDL is being replayed into.
132
133 GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
134 if (fContext->contextPriv().caps()->usesMixedSamples() && desc.fSampleCnt > 1 && !usesGLFBO0) {
135 // In GL, FBO 0 never supports mixed samples
136 surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;
137 }
138 if (usesGLFBO0) {
139 surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
140 }
141 static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo,
142 GrTextureType::k2D};
143 const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr;
144 if (fCharacterization.isTextureable()) {
145 optionalTextureInfo = &kTextureInfo;
146 }
147
148 const GrBackendFormat format = fContext->contextPriv().caps()->getBackendFormatFromColorType(
149 fCharacterization.colorType());
150
151 sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
152 [lazyProxyData](GrResourceProvider* resourceProvider) {
153 if (!resourceProvider) {
154 return sk_sp<GrSurface>();
155 }
156
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 return sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
161 },
162 format,
163 desc,
164 fCharacterization.origin(),
165 surfaceFlags,
166 optionalTextureInfo,
167 SkBackingFit::kExact,
168 SkBudgeted::kYes);
169
170 sk_sp<GrSurfaceContext> c = fContext->contextPriv().makeWrappedSurfaceContext(
171 std::move(proxy),
172 fCharacterization.refColorSpace(),
173 &fCharacterization.surfaceProps());
174 fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(),
175 sk_ref_sp(c->asRenderTargetContext()));
176 return SkToBool(fSurface.get());
177 }
178
getCanvas()179 SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
180 if (!fContext) {
181 return nullptr;
182 }
183
184 if (!fSurface && !this->init()) {
185 return nullptr;
186 }
187
188 return fSurface->getCanvas();
189 }
190
detach()191 std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
192 if (!fContext) {
193 return nullptr;
194 }
195
196 if (fSurface) {
197 SkCanvas* canvas = fSurface->getCanvas();
198
199 canvas->restoreToCount(0);
200 }
201
202 auto ddl = std::unique_ptr<SkDeferredDisplayList>(
203 new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData)));
204
205 fContext->contextPriv().moveOpListsToDDL(ddl.get());
206
207 // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed)
208 // SkSurface to be regenerated for each DDL.
209 fSurface = nullptr;
210 return ddl;
211 }
212
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,DelayReleaseCallback delayReleaseCallback)213 sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
214 const GrBackendFormat& backendFormat,
215 int width,
216 int height,
217 GrMipMapped mipMapped,
218 GrSurfaceOrigin origin,
219 SkColorType colorType,
220 SkAlphaType alphaType,
221 sk_sp<SkColorSpace> colorSpace,
222 PromiseImageTextureFulfillProc textureFulfillProc,
223 PromiseImageTextureReleaseProc textureReleaseProc,
224 PromiseImageTextureDoneProc textureDoneProc,
225 PromiseImageTextureContext textureContext,
226 DelayReleaseCallback delayReleaseCallback) {
227 if (!fContext) {
228 return nullptr;
229 }
230
231 return SkImage_Gpu::MakePromiseTexture(fContext.get(),
232 backendFormat,
233 width,
234 height,
235 mipMapped,
236 origin,
237 colorType,
238 alphaType,
239 std::move(colorSpace),
240 textureFulfillProc,
241 textureReleaseProc,
242 textureDoneProc,
243 textureContext,
244 delayReleaseCallback);
245 }
246
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[],DelayReleaseCallback delayReleaseCallback)247 sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
248 SkYUVColorSpace yuvColorSpace,
249 const GrBackendFormat yuvaFormats[],
250 const SkISize yuvaSizes[],
251 const SkYUVAIndex yuvaIndices[4],
252 int imageWidth,
253 int imageHeight,
254 GrSurfaceOrigin imageOrigin,
255 sk_sp<SkColorSpace> imageColorSpace,
256 PromiseImageTextureFulfillProc textureFulfillProc,
257 PromiseImageTextureReleaseProc textureReleaseProc,
258 PromiseImageTextureDoneProc textureDoneProc,
259 PromiseImageTextureContext textureContexts[],
260 DelayReleaseCallback delayReleaseCallback) {
261 if (!fContext) {
262 return nullptr;
263 }
264
265 return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext.get(),
266 yuvColorSpace,
267 yuvaFormats,
268 yuvaSizes,
269 yuvaIndices,
270 imageWidth,
271 imageHeight,
272 imageOrigin,
273 std::move(imageColorSpace),
274 textureFulfillProc,
275 textureReleaseProc,
276 textureDoneProc,
277 textureContexts,
278 delayReleaseCallback);
279 }
280
281 #endif
282