1 /*
2  * Copyright 2014 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 GrGpuResource_DEFINED
9 #define GrGpuResource_DEFINED
10 
11 #include "include/private/GrResourceKey.h"
12 #include "include/private/GrTypesPriv.h"
13 #include "include/private/SkNoncopyable.h"
14 
15 class GrContext;
16 class GrGpu;
17 class GrResourceCache;
18 class SkTraceMemoryDump;
19 
20 /**
21  * Base class for GrGpuResource. Provides the hooks for resources to interact with the cache.
22  * Separated out as a base class to isolate the ref-cnting behavior and provide friendship without
23  * exposing all of GrGpuResource.
24  *
25  * PRIOR to the last ref being removed DERIVED::notifyRefCntWillBeZero() will be called
26  * (static poly morphism using CRTP). It is legal for additional ref's to be added
27  * during this time. AFTER the ref count reaches zero DERIVED::notifyRefCntIsZero() will be
28  * called.
29  */
30 template <typename DERIVED> class GrIORef : public SkNoncopyable {
31 public:
unique()32     bool unique() const { return fRefCnt == 1; }
33 
ref()34     void ref() const {
35         // Only the cache should be able to add the first ref to a resource.
36         SkASSERT(this->getRefCnt() > 0);
37         // No barrier required.
38         (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
39     }
40 
unref()41     void unref() const {
42         SkASSERT(this->getRefCnt() > 0);
43         if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
44             // At this point we better be the only thread accessing this resource.
45             // Trick out the notifyRefCntWillBeZero() call by adding back one more ref.
46             fRefCnt.fetch_add(+1, std::memory_order_relaxed);
47             static_cast<const DERIVED*>(this)->notifyRefCntWillBeZero();
48             // notifyRefCntWillBeZero() could have done anything, including re-refing this and
49             // passing on to another thread. Take away the ref-count we re-added above and see
50             // if we're back to zero.
51             // TODO: Consider making it so that refs can't be added and merge
52             //  notifyRefCntWillBeZero()/willRemoveLastRef() with notifyRefCntIsZero().
53             if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
54                 static_cast<const DERIVED*>(this)->notifyRefCntIsZero();
55             }
56         }
57     }
58 
59 #if GR_TEST_UTILS
testingOnly_getRefCnt()60     int32_t testingOnly_getRefCnt() const { return this->getRefCnt(); }
61 #endif
62 
63 protected:
64     friend class GrResourceCache; // for internalHasRef
65 
GrIORef()66     GrIORef() : fRefCnt(1) {}
67 
internalHasRef()68     bool internalHasRef() const { return SkToBool(this->getRefCnt()); }
69 
70     // Privileged method that allows going from ref count = 0 to ref count = 1.
addInitialRef()71     void addInitialRef() const {
72         SkASSERT(fRefCnt >= 0);
73         // No barrier required.
74         (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
75     }
76 
77 private:
getRefCnt()78     int32_t getRefCnt() const { return fRefCnt.load(std::memory_order_relaxed); }
79 
80     mutable std::atomic<int32_t> fRefCnt;
81 
82     typedef SkNoncopyable INHERITED;
83 };
84 
85 /**
86  * Base class for objects that can be kept in the GrResourceCache.
87  */
88 class GrGpuResource : public GrIORef<GrGpuResource> {
89 public:
90     /**
91      * Tests whether a object has been abandoned or released. All objects will
92      * be in this state after their creating GrContext is destroyed or has
93      * contextLost called. It's up to the client to test wasDestroyed() before
94      * attempting to use an object if it holds refs on objects across
95      * ~GrContext, freeResources with the force flag, or contextLost.
96      *
97      * @return true if the object has been released or abandoned,
98      *         false otherwise.
99      */
wasDestroyed()100     bool wasDestroyed() const { return nullptr == fGpu; }
101 
102     /**
103      * Retrieves the context that owns the object. Note that it is possible for
104      * this to return NULL. When objects have been release()ed or abandon()ed
105      * they no longer have an owning context. Destroying a GrContext
106      * automatically releases all its resources.
107      */
108     const GrContext* getContext() const;
109     GrContext* getContext();
110 
111     /**
112      * Retrieves the amount of GPU memory used by this resource in bytes. It is
113      * approximate since we aren't aware of additional padding or copies made
114      * by the driver.
115      *
116      * @return the amount of GPU memory used in bytes
117      */
gpuMemorySize()118     size_t gpuMemorySize() const {
119         if (kInvalidGpuMemorySize == fGpuMemorySize) {
120             fGpuMemorySize = this->onGpuMemorySize();
121             SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
122         }
123         return fGpuMemorySize;
124     }
125 
126     class UniqueID {
127     public:
128         UniqueID() = default;
129 
UniqueID(uint32_t id)130         explicit UniqueID(uint32_t id) : fID(id) {}
131 
asUInt()132         uint32_t asUInt() const { return fID; }
133 
134         bool operator==(const UniqueID& other) const { return fID == other.fID; }
135         bool operator!=(const UniqueID& other) const { return !(*this == other); }
136 
makeInvalid()137         void makeInvalid() { fID = SK_InvalidUniqueID; }
isInvalid()138         bool isInvalid() const { return  fID == SK_InvalidUniqueID; }
139 
140     protected:
141         uint32_t fID = SK_InvalidUniqueID;
142     };
143 
144     /**
145      * Gets an id that is unique for this GrGpuResource object. It is static in that it does
146      * not change when the content of the GrGpuResource object changes. This will never return
147      * 0.
148      */
uniqueID()149     UniqueID uniqueID() const { return fUniqueID; }
150 
151     /** Returns the current unique key for the resource. It will be invalid if the resource has no
152         associated unique key. */
getUniqueKey()153     const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
154 
155     /**
156      * Internal-only helper class used for manipulations of the resource by the cache.
157      */
158     class CacheAccess;
159     inline CacheAccess cacheAccess();
160     inline const CacheAccess cacheAccess() const;
161 
162     /**
163      * Internal-only helper class used for manipulations of the resource by GrSurfaceProxy.
164      */
165     class ProxyAccess;
166     inline ProxyAccess proxyAccess();
167 
168     /**
169      * Internal-only helper class used for manipulations of the resource by internal code.
170      */
171     class ResourcePriv;
172     inline ResourcePriv resourcePriv();
173     inline const ResourcePriv resourcePriv() const;
174 
175     /**
176      * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
177      * Typically, subclasses should not need to override this, and should only
178      * need to override setMemoryBacking.
179      **/
180     virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
181 
182     /**
183      * Describes the type of gpu resource that is represented by the implementing
184      * class (e.g. texture, buffer object, stencil).  This data is used for diagnostic
185      * purposes by dumpMemoryStatistics().
186      *
187      * The value returned is expected to be long lived and will not be copied by the caller.
188      */
189     virtual const char* getResourceType() const = 0;
190 
191     static uint32_t CreateUniqueID();
192 
193 protected:
194     // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
195     // fully initialized (i.e. only from the constructors of the final class).
196     void registerWithCache(SkBudgeted);
197 
198     // This must be called by every GrGpuObject that references any wrapped backend objects. It
199     // should be called once the object is fully initialized (i.e. only from the constructors of the
200     // final class).
201     void registerWithCacheWrapped(GrWrapCacheable);
202 
203     GrGpuResource(GrGpu*);
204     virtual ~GrGpuResource();
205 
getGpu()206     GrGpu* getGpu() const { return fGpu; }
207 
208     /** Overridden to free GPU resources in the backend API. */
onRelease()209     virtual void onRelease() { }
210     /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
211         This may be called when the underlying 3D context is no longer valid and so no
212         backend API calls should be made. */
onAbandon()213     virtual void onAbandon() { }
214 
215     /**
216      * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
217      **/
setMemoryBacking(SkTraceMemoryDump *,const SkString &)218     virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
219 
220     /**
221      * Returns a string that uniquely identifies this resource.
222      */
223     SkString getResourceName() const;
224 
225     /**
226      * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
227      * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
228      * to customize various inputs.
229      */
230     void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
231                                   const char* type, size_t size) const;
232 
233 
234 private:
235     bool isPurgeable() const;
236     bool hasRef() const;
237 
238     /**
239      * Called by the registerWithCache if the resource is available to be used as scratch.
240      * Resource subclasses should override this if the instances should be recycled as scratch
241      * resources and populate the scratchKey with the key.
242      * By default resources are not recycled as scratch.
243      **/
computeScratchKey(GrScratchKey *)244     virtual void computeScratchKey(GrScratchKey*) const {}
245 
246     /**
247      * Removes references to objects in the underlying 3D API without freeing them.
248      * Called by CacheAccess.
249      */
250     void abandon();
251 
252     /**
253      * Frees the object in the underlying 3D API. Called by CacheAccess.
254      */
255     void release();
256 
257     virtual size_t onGpuMemorySize() const = 0;
258 
259     /**
260      * Called by GrIORef when a resource is about to lose its last ref
261      */
willRemoveLastRef()262     virtual void willRemoveLastRef() {}
263 
264     // See comments in CacheAccess and ResourcePriv.
265     void setUniqueKey(const GrUniqueKey&);
266     void removeUniqueKey();
267     void notifyRefCntWillBeZero() const;
268     void notifyRefCntIsZero() const;
269     void removeScratchKey();
270     void makeBudgeted();
271     void makeUnbudgeted();
272 
273 #ifdef SK_DEBUG
274     friend class GrGpu;  // for assert in GrGpu to access getGpu
275 #endif
276 
277     // An index into a heap when this resource is purgeable or an array when not. This is maintained
278     // by the cache.
279     int fCacheArrayIndex;
280     // This value reflects how recently this resource was accessed in the cache. This is maintained
281     // by the cache.
282     uint32_t fTimestamp;
283     GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
284 
285     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
286     GrScratchKey fScratchKey;
287     GrUniqueKey fUniqueKey;
288 
289     // This is not ref'ed but abandon() or release() will be called before the GrGpu object
290     // is destroyed. Those calls set will this to NULL.
291     GrGpu* fGpu;
292     mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
293 
294     GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
295     bool fRefsWrappedObjects = false;
296     const UniqueID fUniqueID;
297 
298     typedef GrIORef<GrGpuResource> INHERITED;
299     friend class GrIORef<GrGpuResource>; // to access notifyRefCntWillBeZero and notifyRefCntIsZero.
300 };
301 
302 class GrGpuResource::ProxyAccess {
303 private:
ProxyAccess(GrGpuResource * resource)304     ProxyAccess(GrGpuResource* resource) : fResource(resource) {}
305 
306     /** Proxies are allowed to take a resource from no refs to one ref. */
307     void ref(GrResourceCache* cache);
308 
309     // No taking addresses of this type.
310     const CacheAccess* operator&() const = delete;
311     CacheAccess* operator&() = delete;
312 
313     GrGpuResource* fResource;
314 
315     friend class GrGpuResource;
316     friend class GrSurfaceProxy;
317 };
318 
proxyAccess()319 inline GrGpuResource::ProxyAccess GrGpuResource::proxyAccess() { return ProxyAccess(this); }
320 
321 #endif
322