1 | /* |
2 | * Copyright 2016 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 | #ifndef GrSurfaceProxy_DEFINED |
9 | #define GrSurfaceProxy_DEFINED |
10 | |
11 | #include "include/core/SkRect.h" |
12 | #include "include/gpu/GrBackendSurface.h" |
13 | #include "include/private/SkNoncopyable.h" |
14 | #include "src/gpu/GrGpuResource.h" |
15 | #include "src/gpu/GrNonAtomicRef.h" |
16 | #include "src/gpu/GrSurface.h" |
17 | #include "src/gpu/GrTexture.h" |
18 | |
19 | class GrCaps; |
20 | class GrContext_Base; |
21 | class GrOpsTask; |
22 | class GrRecordingContext; |
23 | class GrRenderTargetProxy; |
24 | class GrRenderTask; |
25 | class GrResourceProvider; |
26 | class GrSurfaceContext; |
27 | class GrSurfaceProxyPriv; |
28 | class GrSurfaceProxyView; |
29 | class GrTextureProxy; |
30 | |
31 | class GrSurfaceProxy : public SkNVRefCnt<GrSurfaceProxy> { |
32 | public: |
33 | virtual ~GrSurfaceProxy(); |
34 | |
35 | /** |
36 | * Indicates "resolutions" that need to be done on a surface before its pixels can be accessed. |
37 | * If both types of resolve are requested, the MSAA resolve will happen first. |
38 | */ |
39 | enum class ResolveFlags { |
40 | kNone = 0, |
41 | kMSAA = 1 << 0, // Blit and resolve an internal MSAA render buffer into the texture. |
42 | kMipMaps = 1 << 1, // Regenerate all mipmap levels. |
43 | }; |
44 | |
45 | /** |
46 | * Some lazy proxy callbacks want to set their own (or no key) on the GrSurfaces they return. |
47 | * Others want the GrSurface's key to be kept in sync with the proxy's key. This enum controls |
48 | * the key relationship between proxies and their targets. |
49 | */ |
50 | enum class LazyInstantiationKeyMode { |
51 | /** |
52 | * Don't key the GrSurface with the proxy's key. The lazy instantiation callback is free to |
53 | * return a GrSurface that already has a unique key unrelated to the proxy's key. |
54 | */ |
55 | kUnsynced, |
56 | /** |
57 | * Keep the GrSurface's unique key in sync with the proxy's unique key. The GrSurface |
58 | * returned from the lazy instantiation callback must not have a unique key or have the same |
59 | * same unique key as the proxy. If the proxy is later assigned a key it is in turn assigned |
60 | * to the GrSurface. |
61 | */ |
62 | kSynced |
63 | }; |
64 | |
65 | /** |
66 | * Specifies the expected properties of the GrSurface returned by a lazy instantiation |
67 | * callback. The dimensions will be negative in the case of a fully lazy proxy. |
68 | */ |
69 | struct LazySurfaceDesc { |
70 | SkISize fDimensions; |
71 | SkBackingFit fFit; |
72 | GrRenderable fRenderable; |
73 | GrMipmapped fMipmapped; |
74 | int fSampleCnt; |
75 | const GrBackendFormat& fFormat; |
76 | GrProtected fProtected; |
77 | SkBudgeted fBudgeted; |
78 | }; |
79 | |
80 | struct LazyCallbackResult { |
81 | LazyCallbackResult() = default; |
82 | LazyCallbackResult(const LazyCallbackResult&) = default; |
83 | LazyCallbackResult(LazyCallbackResult&& that) = default; |
84 | LazyCallbackResult(sk_sp<GrSurface> surf, |
85 | bool releaseCallback = true, |
86 | LazyInstantiationKeyMode mode = LazyInstantiationKeyMode::kSynced) |
87 | : fSurface(std::move(surf)), fKeyMode(mode), fReleaseCallback(releaseCallback) {} |
88 | LazyCallbackResult(sk_sp<GrTexture> tex) |
89 | : LazyCallbackResult(sk_sp<GrSurface>(std::move(tex))) {} |
90 | |
91 | LazyCallbackResult& operator=(const LazyCallbackResult&) = default; |
92 | LazyCallbackResult& operator=(LazyCallbackResult&&) = default; |
93 | |
94 | sk_sp<GrSurface> fSurface; |
95 | LazyInstantiationKeyMode fKeyMode = LazyInstantiationKeyMode::kSynced; |
96 | /** |
97 | * Should the callback be disposed of after it has returned or preserved until the proxy |
98 | * is freed. Only honored if fSurface is not-null. If it is null the callback is preserved. |
99 | */ |
100 | bool fReleaseCallback = true; |
101 | }; |
102 | |
103 | using LazyInstantiateCallback = |
104 | std::function<LazyCallbackResult(GrResourceProvider*, const LazySurfaceDesc&)>; |
105 | |
106 | enum class UseAllocator { |
107 | /** |
108 | * This proxy will be instantiated outside the allocator (e.g. for proxies that are |
109 | * instantiated in on-flush callbacks). |
110 | */ |
111 | kNo = false, |
112 | /** |
113 | * GrResourceAllocator should instantiate this proxy. |
114 | */ |
115 | kYes = true, |
116 | }; |
117 | |
118 | bool isLazy() const { return !this->isInstantiated() && SkToBool(fLazyInstantiateCallback); } |
119 | |
120 | bool isFullyLazy() const { |
121 | bool result = fDimensions.width() < 0; |
122 | SkASSERT(result == (fDimensions.height() < 0)); |
123 | SkASSERT(!result || this->isLazy()); |
124 | return result; |
125 | } |
126 | |
127 | SkISize dimensions() const { |
128 | SkASSERT(!this->isFullyLazy()); |
129 | return fDimensions; |
130 | } |
131 | int width() const { return this->dimensions().width(); } |
132 | int height() const { return this->dimensions().height(); } |
133 | |
134 | SkISize backingStoreDimensions() const; |
135 | |
136 | /** |
137 | * Helper that gets the width and height of the proxy as a bounding rectangle. |
138 | */ |
139 | SkRect getBoundsRect() const { return SkRect::Make(this->dimensions()); } |
140 | |
141 | /* A perhaps faster check for this->dimensions() == this->backingStoreDimensions(). */ |
142 | bool isFunctionallyExact() const; |
143 | |
144 | /** |
145 | * Helper that gets the dimensions the backing GrSurface will have as a bounding rectangle. |
146 | */ |
147 | SkRect backingStoreBoundsRect() const { |
148 | return SkRect::Make(this->backingStoreDimensions()); |
149 | } |
150 | |
151 | const GrBackendFormat& backendFormat() const { return fFormat; } |
152 | |
153 | bool isFormatCompressed(const GrCaps*) const; |
154 | |
155 | class UniqueID { |
156 | public: |
157 | static UniqueID InvalidID() { |
158 | return UniqueID(uint32_t(SK_InvalidUniqueID)); |
159 | } |
160 | |
161 | // wrapped |
162 | explicit UniqueID(const GrGpuResource::UniqueID& id) : fID(id.asUInt()) { } |
163 | // deferred and lazy-callback |
164 | UniqueID() : fID(GrGpuResource::CreateUniqueID()) { } |
165 | |
166 | uint32_t asUInt() const { return fID; } |
167 | |
168 | bool operator==(const UniqueID& other) const { |
169 | return fID == other.fID; |
170 | } |
171 | bool operator!=(const UniqueID& other) const { |
172 | return !(*this == other); |
173 | } |
174 | |
175 | void makeInvalid() { fID = SK_InvalidUniqueID; } |
176 | bool isInvalid() const { return SK_InvalidUniqueID == fID; } |
177 | |
178 | private: |
179 | explicit UniqueID(uint32_t id) : fID(id) {} |
180 | |
181 | uint32_t fID; |
182 | }; |
183 | |
184 | /* |
185 | * The contract for the uniqueID is: |
186 | * for wrapped resources: |
187 | * the uniqueID will match that of the wrapped resource |
188 | * |
189 | * for deferred resources: |
190 | * the uniqueID will be different from the real resource, when it is allocated |
191 | * the proxy's uniqueID will not change across the instantiate call |
192 | * |
193 | * the uniqueIDs of the proxies and the resources draw from the same pool |
194 | * |
195 | * What this boils down to is that the uniqueID of a proxy can be used to consistently |
196 | * track/identify a proxy but should never be used to distinguish between |
197 | * resources and proxies - beware! |
198 | */ |
199 | UniqueID uniqueID() const { return fUniqueID; } |
200 | |
201 | UniqueID underlyingUniqueID() const { |
202 | if (fTarget) { |
203 | return UniqueID(fTarget->uniqueID()); |
204 | } |
205 | |
206 | return fUniqueID; |
207 | } |
208 | |
209 | virtual bool instantiate(GrResourceProvider*) = 0; |
210 | |
211 | void deinstantiate(); |
212 | |
213 | /** |
214 | * Proxies that are already instantiated and whose backing surface cannot be recycled to |
215 | * instantiate other proxies do not need to be considered by GrResourceAllocator. |
216 | */ |
217 | bool canSkipResourceAllocator() const; |
218 | |
219 | /** |
220 | * @return the texture proxy associated with the surface proxy, may be NULL. |
221 | */ |
222 | virtual GrTextureProxy* asTextureProxy() { return nullptr; } |
223 | virtual const GrTextureProxy* asTextureProxy() const { return nullptr; } |
224 | |
225 | /** |
226 | * @return the render target proxy associated with the surface proxy, may be NULL. |
227 | */ |
228 | virtual GrRenderTargetProxy* asRenderTargetProxy() { return nullptr; } |
229 | virtual const GrRenderTargetProxy* asRenderTargetProxy() const { return nullptr; } |
230 | |
231 | bool isInstantiated() const { return SkToBool(fTarget); } |
232 | |
233 | // If the proxy is already instantiated, return its backing GrTexture; if not, return null. |
234 | GrSurface* peekSurface() const { return fTarget.get(); } |
235 | |
236 | // If this is a texture proxy and the proxy is already instantiated, return its backing |
237 | // GrTexture; if not, return null. |
238 | GrTexture* peekTexture() const { return fTarget ? fTarget->asTexture() : nullptr; } |
239 | |
240 | // If this is a render target proxy and the proxy is already instantiated, return its backing |
241 | // GrRenderTarget; if not, return null. |
242 | GrRenderTarget* peekRenderTarget() const { |
243 | return fTarget ? fTarget->asRenderTarget() : nullptr; |
244 | } |
245 | |
246 | /** |
247 | * Does the resource count against the resource budget? |
248 | */ |
249 | SkBudgeted isBudgeted() const { return fBudgeted; } |
250 | |
251 | /** |
252 | * The pixel values of this proxy's surface cannot be modified (e.g. doesn't support write |
253 | * pixels or MIP map level regen). Read-only proxies also bypass interval tracking and |
254 | * assignment in GrResourceAllocator. |
255 | */ |
256 | bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; } |
257 | bool framebufferOnly() const { |
258 | return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly; |
259 | } |
260 | |
261 | /** |
262 | * This means surface is a multisampled render target, and internally holds a non-msaa texture |
263 | * for resolving into. The render target resolves itself by blitting into this internal texture. |
264 | * (asTexture() might or might not return the internal texture, but if it does, we always |
265 | * resolve the render target before accessing this texture's data.) |
266 | */ |
267 | bool requiresManualMSAAResolve() const { |
268 | return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve; |
269 | } |
270 | |
271 | /** |
272 | * Retrieves the amount of GPU memory that will be or currently is used by this resource |
273 | * in bytes. It is approximate since we aren't aware of additional padding or copies made |
274 | * by the driver. |
275 | * |
276 | * @return the amount of GPU memory used in bytes |
277 | */ |
278 | size_t gpuMemorySize(const GrCaps& caps) const { |
279 | SkASSERT(!this->isFullyLazy()); |
280 | if (fTarget) { |
281 | return fTarget->gpuMemorySize(); |
282 | } |
283 | if (kInvalidGpuMemorySize == fGpuMemorySize) { |
284 | fGpuMemorySize = this->onUninstantiatedGpuMemorySize(caps); |
285 | SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); |
286 | } |
287 | return fGpuMemorySize; |
288 | } |
289 | |
290 | enum class RectsMustMatch : bool { |
291 | kNo = false, |
292 | kYes = true |
293 | }; |
294 | |
295 | // Helper function that creates a temporary SurfaceContext to perform the copy |
296 | // The copy is is not a render target and not multisampled. |
297 | // |
298 | // The intended use of this copy call is simply to copy exact pixel values from one proxy to a |
299 | // new one. Thus, there isn't a need for a swizzle when doing the copy. The format of the copy |
300 | // will be the same as the src. Therefore, the copy can be used in a view with the same swizzle |
301 | // as the original for use with a given color type. |
302 | static sk_sp<GrSurfaceProxy> Copy(GrRecordingContext*, |
303 | GrSurfaceProxy* src, |
304 | GrSurfaceOrigin, |
305 | GrMipmapped, |
306 | SkIRect srcRect, |
307 | SkBackingFit, |
308 | SkBudgeted, |
309 | RectsMustMatch = RectsMustMatch::kNo); |
310 | |
311 | // Same as above Copy but copies the entire 'src' |
312 | static sk_sp<GrSurfaceProxy> Copy(GrRecordingContext*, |
313 | GrSurfaceProxy* src, |
314 | GrSurfaceOrigin, |
315 | GrMipmapped, |
316 | SkBackingFit, |
317 | SkBudgeted); |
318 | |
319 | #if GR_TEST_UTILS |
320 | int32_t testingOnly_getBackingRefCnt() const; |
321 | GrInternalSurfaceFlags testingOnly_getFlags() const; |
322 | #endif |
323 | |
324 | SkDEBUGCODE(void validate(GrContext_Base*) const;) |
325 | |
326 | // Provides access to functions that aren't part of the public API. |
327 | inline GrSurfaceProxyPriv priv(); |
328 | inline const GrSurfaceProxyPriv priv() const; // NOLINT(readability-const-return-type) |
329 | |
330 | GrProtected isProtected() const { return fIsProtected; } |
331 | |
332 | protected: |
333 | // Deferred version - takes a new UniqueID from the shared resource/proxy pool. |
334 | GrSurfaceProxy(const GrBackendFormat&, |
335 | SkISize, |
336 | SkBackingFit, |
337 | SkBudgeted, |
338 | GrProtected, |
339 | GrInternalSurfaceFlags, |
340 | UseAllocator); |
341 | // Lazy-callback version - takes a new UniqueID from the shared resource/proxy pool. |
342 | GrSurfaceProxy(LazyInstantiateCallback&&, |
343 | const GrBackendFormat&, |
344 | SkISize, |
345 | SkBackingFit, |
346 | SkBudgeted, |
347 | GrProtected, |
348 | GrInternalSurfaceFlags, |
349 | UseAllocator); |
350 | |
351 | // Wrapped version - shares the UniqueID of the passed surface. |
352 | // Takes UseAllocator because even though this is already instantiated it still can participate |
353 | // in allocation by having its backing resource recycled to other uninstantiated proxies or |
354 | // not depending on UseAllocator. |
355 | GrSurfaceProxy(sk_sp<GrSurface>, |
356 | SkBackingFit, |
357 | UseAllocator); |
358 | |
359 | friend class GrSurfaceProxyPriv; |
360 | |
361 | // Methods made available via GrSurfaceProxyPriv |
362 | bool ignoredByResourceAllocator() const { return fIgnoredByResourceAllocator; } |
363 | void setIgnoredByResourceAllocator() { fIgnoredByResourceAllocator = true; } |
364 | |
365 | void computeScratchKey(const GrCaps&, GrScratchKey*) const; |
366 | |
367 | virtual sk_sp<GrSurface> createSurface(GrResourceProvider*) const = 0; |
368 | void assign(sk_sp<GrSurface> surface); |
369 | |
370 | sk_sp<GrSurface> createSurfaceImpl(GrResourceProvider*, int sampleCnt, GrRenderable, |
371 | GrMipmapped) const; |
372 | |
373 | // Once the dimensions of a fully-lazy proxy are decided, and before it gets instantiated, the |
374 | // client can use this optional method to specify the proxy's dimensions. (A proxy's dimensions |
375 | // can be less than the GPU surface that backs it. e.g., SkBackingFit::kApprox.) Otherwise, |
376 | // the proxy's dimensions will be set to match the underlying GPU surface upon instantiation. |
377 | void setLazyDimensions(SkISize dimensions) { |
378 | SkASSERT(this->isFullyLazy()); |
379 | SkASSERT(!dimensions.isEmpty()); |
380 | fDimensions = dimensions; |
381 | } |
382 | |
383 | bool instantiateImpl(GrResourceProvider* resourceProvider, int sampleCnt, GrRenderable, |
384 | GrMipmapped, const GrUniqueKey*); |
385 | |
386 | // For deferred proxies this will be null until the proxy is instantiated. |
387 | // For wrapped proxies it will point to the wrapped resource. |
388 | sk_sp<GrSurface> fTarget; |
389 | |
390 | // In many cases these flags aren't actually known until the proxy has been instantiated. |
391 | // However, Ganesh frequently needs to change its behavior based on these settings. For |
392 | // internally create proxies we will know these properties ahead of time. For wrapped |
393 | // proxies we will copy the properties off of the GrSurface. For lazy proxies we force the |
394 | // call sites to provide the required information ahead of time. At instantiation time |
395 | // we verify that the assumed properties match the actual properties. |
396 | GrInternalSurfaceFlags fSurfaceFlags; |
397 | |
398 | private: |
399 | // For wrapped resources, 'fFormat', 'fWidth', and 'fHeight'; will always be filled in from the |
400 | // wrapped resource. |
401 | const GrBackendFormat fFormat; |
402 | SkISize fDimensions; |
403 | |
404 | SkBackingFit fFit; // always kApprox for lazy-callback resources |
405 | // always kExact for wrapped resources |
406 | mutable SkBudgeted fBudgeted; // always kYes for lazy-callback resources |
407 | // set from the backing resource for wrapped resources |
408 | // mutable bc of SkSurface/SkImage wishy-washiness |
409 | // Only meaningful if fLazyInstantiateCallback is non-null. |
410 | UseAllocator fUseAllocator; |
411 | |
412 | const UniqueID fUniqueID; // set from the backing resource for wrapped resources |
413 | |
414 | LazyInstantiateCallback fLazyInstantiateCallback; |
415 | |
416 | SkDEBUGCODE(void validateSurface(const GrSurface*);) |
417 | SkDEBUGCODE(virtual void onValidateSurface(const GrSurface*) = 0;) |
418 | |
419 | static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); |
420 | SkDEBUGCODE(size_t getRawGpuMemorySize_debugOnly() const { return fGpuMemorySize; }) |
421 | |
422 | virtual size_t onUninstantiatedGpuMemorySize(const GrCaps&) const = 0; |
423 | |
424 | virtual LazySurfaceDesc callbackDesc() const = 0; |
425 | |
426 | bool fIgnoredByResourceAllocator = false; |
427 | GrProtected fIsProtected; |
428 | |
429 | // This entry is lazily evaluated so, when the proxy wraps a resource, the resource |
430 | // will be called but, when the proxy is deferred, it will compute the answer itself. |
431 | // If the proxy computes its own answer that answer is checked (in debug mode) in |
432 | // the instantiation method. |
433 | mutable size_t fGpuMemorySize; |
434 | }; |
435 | |
436 | GR_MAKE_BITFIELD_CLASS_OPS(GrSurfaceProxy::ResolveFlags) |
437 | |
438 | #endif |
439 | |