/src/skia/src/core/SkDeferredDisplayListRecorder.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | PromiseImageTextureContext textureContext) { |
38 | | return nullptr; |
39 | | } |
40 | | |
41 | | sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture( |
42 | | const GrYUVABackendTextureInfo& yuvaBackendTextureInfo, |
43 | | sk_sp<SkColorSpace> imageColorSpace, |
44 | | PromiseImageTextureFulfillProc textureFulfillProc, |
45 | | PromiseImageTextureReleaseProc textureReleaseProc, |
46 | | PromiseImageTextureContext textureContexts[]) { |
47 | | return nullptr; |
48 | | } |
49 | | |
50 | | #else |
51 | | |
52 | | #include "include/core/SkPromiseImageTexture.h" |
53 | | #include "include/gpu/GrRecordingContext.h" |
54 | | #include "include/gpu/GrYUVABackendTextures.h" |
55 | | #include "src/gpu/GrProxyProvider.h" |
56 | | #include "src/gpu/GrRecordingContextPriv.h" |
57 | | #include "src/gpu/GrTexture.h" |
58 | | #include "src/gpu/SkGr.h" |
59 | | #include "src/image/SkImage_Gpu.h" |
60 | | #include "src/image/SkImage_GpuYUVA.h" |
61 | | #include "src/image/SkSurface_Gpu.h" |
62 | | |
63 | | SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c) |
64 | 0 | : fCharacterization(c) { |
65 | 0 | if (fCharacterization.isValid()) { |
66 | 0 | fContext = GrRecordingContextPriv::MakeDDL(fCharacterization.refContextInfo()); |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | 0 | SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() { |
71 | 0 | if (fContext) { |
72 | 0 | auto proxyProvider = fContext->priv().proxyProvider(); |
73 | | |
74 | | // This allows the uniquely keyed proxies to keep their keys but removes their back |
75 | | // pointer to the about-to-be-deleted proxy provider. The proxies will use their |
76 | | // unique key to reattach to cached versions of themselves or to appropriately tag new |
77 | | // resources (if a cached version was not found). This system operates independent of |
78 | | // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not |
79 | | // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine |
80 | | // since no one else should be trying to reconnect to the orphaned proxies and orphaned |
81 | | // proxies from different DDLs that share the same key should simply reconnect to the |
82 | | // same cached resource. |
83 | 0 | proxyProvider->orphanAllUniqueKeys(); |
84 | 0 | } |
85 | 0 | } |
86 | | |
87 | 0 | bool SkDeferredDisplayListRecorder::init() { |
88 | 0 | SkASSERT(fContext); |
89 | 0 | SkASSERT(!fTargetProxy); |
90 | 0 | SkASSERT(!fLazyProxyData); |
91 | 0 | SkASSERT(!fSurface); |
92 | |
|
93 | 0 | if (!fCharacterization.isValid()) { |
94 | 0 | return false; |
95 | 0 | } |
96 | | |
97 | 0 | fLazyProxyData = sk_sp<SkDeferredDisplayList::LazyProxyData>( |
98 | 0 | new SkDeferredDisplayList::LazyProxyData); |
99 | |
|
100 | 0 | auto proxyProvider = fContext->priv().proxyProvider(); |
101 | 0 | const GrCaps* caps = fContext->priv().caps(); |
102 | |
|
103 | 0 | bool usesGLFBO0 = fCharacterization.usesGLFBO0(); |
104 | 0 | if (usesGLFBO0) { |
105 | 0 | if (GrBackendApi::kOpenGL != fContext->backend() || |
106 | 0 | fCharacterization.isTextureable()) { |
107 | 0 | return false; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | 0 | bool vkRTSupportsInputAttachment = fCharacterization.vkRTSupportsInputAttachment(); |
112 | 0 | if (vkRTSupportsInputAttachment && GrBackendApi::kVulkan != fContext->backend()) { |
113 | 0 | return false; |
114 | 0 | } |
115 | | |
116 | 0 | if (fCharacterization.vulkanSecondaryCBCompatible()) { |
117 | | // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead |
118 | | // of time that we don't be able to support certain parameter combinations. Specifically we |
119 | | // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object. |
120 | | // We can't use it as in input attachment since we don't control the render pass this will |
121 | | // be played into and thus can't force it to have an input attachment and the correct |
122 | | // dependencies. And finally the GrVkSecondaryCBDrawContext always assumes a top left |
123 | | // origin. |
124 | 0 | if (usesGLFBO0 || |
125 | 0 | vkRTSupportsInputAttachment || |
126 | 0 | fCharacterization.isTextureable() || |
127 | 0 | fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) { |
128 | 0 | return false; |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | 0 | GrColorType grColorType = SkColorTypeToGrColorType(fCharacterization.colorType()); |
133 | | |
134 | | // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy |
135 | | // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the |
136 | | // DDL is being replayed into. |
137 | |
|
138 | 0 | GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone; |
139 | 0 | if (usesGLFBO0) { |
140 | 0 | surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; |
141 | 0 | } else if (fCharacterization.sampleCount() > 1 && !caps->msaaResolvesAutomatically() && |
142 | 0 | fCharacterization.isTextureable()) { |
143 | 0 | surfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve; |
144 | 0 | } |
145 | |
|
146 | 0 | if (vkRTSupportsInputAttachment) { |
147 | 0 | surfaceFlags |= GrInternalSurfaceFlags::kVkRTSupportsInputAttachment; |
148 | 0 | } |
149 | | |
150 | | // FIXME: Why do we use GrMipmapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped? |
151 | 0 | static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipmapped::kNo, |
152 | 0 | GrTextureType::k2D}; |
153 | 0 | const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr; |
154 | 0 | if (fCharacterization.isTextureable()) { |
155 | 0 | optionalTextureInfo = &kTextureInfo; |
156 | 0 | } |
157 | |
|
158 | 0 | fTargetProxy = proxyProvider->createLazyRenderTargetProxy( |
159 | 0 | [lazyProxyData = fLazyProxyData](GrResourceProvider* resourceProvider, |
160 | 0 | const GrSurfaceProxy::LazySurfaceDesc&) { |
161 | | // The proxy backing the destination surface had better have been instantiated |
162 | | // prior to this one (i.e., the proxy backing the DDL's surface). |
163 | | // Fulfill this lazy proxy with the destination surface's GrRenderTarget. |
164 | 0 | SkASSERT(lazyProxyData->fReplayDest->peekSurface()); |
165 | 0 | auto surface = sk_ref_sp<GrSurface>(lazyProxyData->fReplayDest->peekSurface()); |
166 | 0 | return GrSurfaceProxy::LazyCallbackResult(std::move(surface)); |
167 | 0 | }, |
168 | 0 | fCharacterization.backendFormat(), |
169 | 0 | fCharacterization.dimensions(), |
170 | 0 | fCharacterization.sampleCount(), |
171 | 0 | surfaceFlags, |
172 | 0 | optionalTextureInfo, |
173 | 0 | GrMipmapStatus::kNotAllocated, |
174 | 0 | SkBackingFit::kExact, |
175 | 0 | SkBudgeted::kYes, |
176 | 0 | fCharacterization.isProtected(), |
177 | 0 | fCharacterization.vulkanSecondaryCBCompatible(), |
178 | 0 | GrSurfaceProxy::UseAllocator::kYes); |
179 | |
|
180 | 0 | if (!fTargetProxy) { |
181 | 0 | return false; |
182 | 0 | } |
183 | 0 | fTargetProxy->priv().setIsDDLTarget(); |
184 | |
|
185 | 0 | auto device = fContext->priv().createDevice(grColorType, |
186 | 0 | fTargetProxy, |
187 | 0 | fCharacterization.refColorSpace(), |
188 | 0 | fCharacterization.origin(), |
189 | 0 | fCharacterization.surfaceProps(), |
190 | 0 | skgpu::BaseDevice::kUninit_InitContents); |
191 | 0 | if (!device) { |
192 | 0 | return false; |
193 | 0 | } |
194 | | |
195 | 0 | fSurface = sk_make_sp<SkSurface_Gpu>(std::move(device)); |
196 | 0 | return SkToBool(fSurface.get()); |
197 | 0 | } |
198 | | |
199 | 0 | SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { |
200 | 0 | if (!fContext) { |
201 | 0 | return nullptr; |
202 | 0 | } |
203 | | |
204 | 0 | if (!fSurface && !this->init()) { |
205 | 0 | return nullptr; |
206 | 0 | } |
207 | | |
208 | 0 | return fSurface->getCanvas(); |
209 | 0 | } |
210 | | |
211 | 0 | sk_sp<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { |
212 | 0 | if (!fContext || !fTargetProxy) { |
213 | 0 | return nullptr; |
214 | 0 | } |
215 | | |
216 | 0 | if (fSurface) { |
217 | 0 | SkCanvas* canvas = fSurface->getCanvas(); |
218 | |
|
219 | 0 | canvas->restoreToCount(0); |
220 | 0 | } |
221 | |
|
222 | 0 | auto ddl = sk_sp<SkDeferredDisplayList>(new SkDeferredDisplayList(fCharacterization, |
223 | 0 | std::move(fTargetProxy), |
224 | 0 | std::move(fLazyProxyData))); |
225 | |
|
226 | 0 | 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 | 0 | fSurface = nullptr; |
231 | 0 | return ddl; |
232 | 0 | } |
233 | | |
234 | | #ifndef SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API |
235 | | sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture( |
236 | | const GrBackendFormat& backendFormat, |
237 | | int width, |
238 | | int height, |
239 | | GrMipmapped mipMapped, |
240 | | GrSurfaceOrigin origin, |
241 | | SkColorType colorType, |
242 | | SkAlphaType alphaType, |
243 | | sk_sp<SkColorSpace> colorSpace, |
244 | | PromiseImageTextureFulfillProc textureFulfillProc, |
245 | | PromiseImageTextureReleaseProc textureReleaseProc, |
246 | 0 | PromiseImageTextureContext textureContext) { |
247 | 0 | if (!fContext) { |
248 | 0 | return nullptr; |
249 | 0 | } |
250 | 0 | return SkImage::MakePromiseTexture(fContext->threadSafeProxy(), |
251 | 0 | backendFormat, |
252 | 0 | {width, height}, |
253 | 0 | mipMapped, |
254 | 0 | origin, |
255 | 0 | colorType, |
256 | 0 | alphaType, |
257 | 0 | std::move(colorSpace), |
258 | 0 | textureFulfillProc, |
259 | 0 | textureReleaseProc, |
260 | 0 | textureContext); |
261 | 0 | } |
262 | | |
263 | | sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture( |
264 | | const GrYUVABackendTextureInfo& backendTextureInfo, |
265 | | sk_sp<SkColorSpace> imageColorSpace, |
266 | | PromiseImageTextureFulfillProc textureFulfillProc, |
267 | | PromiseImageTextureReleaseProc textureReleaseProc, |
268 | 0 | PromiseImageTextureContext textureContexts[]) { |
269 | 0 | if (!fContext) { |
270 | 0 | return nullptr; |
271 | 0 | } |
272 | 0 | return SkImage::MakePromiseYUVATexture(fContext->threadSafeProxy(), |
273 | 0 | backendTextureInfo, |
274 | 0 | std::move(imageColorSpace), |
275 | 0 | textureFulfillProc, |
276 | 0 | textureReleaseProc, |
277 | 0 | textureContexts); |
278 | 0 | } |
279 | | #endif // !SK_MAKE_PROMISE_TEXTURE_DISABLE_LEGACY_API |
280 | | |
281 | | #endif |