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