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