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