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