Line data Source code
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 "GrResourceKey.h"
12 : #include "GrTypesPriv.h"
13 :
14 : class GrContext;
15 : class GrGpu;
16 : class GrResourceCache;
17 : class SkTraceMemoryDump;
18 :
19 : /**
20 : * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
21 : * class to isolate the ref-cnting behavior and provide friendship without exposing all of
22 : * GrGpuResource.
23 : *
24 : * Gpu resources can have three types of refs:
25 : * 1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls
26 : * that read and write the resource via GrOpList and by any object that must own a
27 : * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code.
28 : * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read
29 : * of the resource by the GPU as a result of a skia API call but hasn't executed it yet.
30 : * 3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a
31 : * write to the resource by the GPU as a result of a skia API call but hasn't executed it yet.
32 : *
33 : * The latter two ref types are private and intended only for Gr core code.
34 : *
35 : * When all the ref/io counts reach zero DERIVED::notifyAllCntsAreZero() will be called (static poly
36 : * morphism using CRTP). Similarly when the ref (but not necessarily pending read/write) count
37 : * reaches 0 DERIVED::notifyRefCountIsZero() will be called. In the case when an unref() causes both
38 : * the ref cnt to reach zero and the other counts are zero, notifyRefCountIsZero() will be called
39 : * before notifyIsPurgeable(). Moreover, if notifyRefCountIsZero() returns false then
40 : * notifyAllRefCntsAreZero() won't be called at all. notifyRefCountIsZero() must return false if the
41 : * object may be deleted after notifyRefCntIsZero() returns.
42 : *
43 : * GrIORef and GrGpuResource are separate classes for organizational reasons and to be
44 : * able to give access via friendship to only the functions related to pending IO operations.
45 : */
46 : template <typename DERIVED> class GrIORef : public SkNoncopyable {
47 : public:
48 : // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with
49 : // templated helper classes (e.g. sk_sp). However, we have different categories of
50 : // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are
51 : // not intended to cross thread boundaries.
52 0 : void ref() const {
53 0 : this->validate();
54 0 : ++fRefCnt;
55 0 : }
56 :
57 0 : void unref() const {
58 0 : this->validate();
59 :
60 0 : if (!(--fRefCnt)) {
61 0 : if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) {
62 0 : return;
63 : }
64 : }
65 :
66 0 : this->didRemoveRefOrPendingIO(kRef_CntType);
67 : }
68 :
69 0 : void validate() const {
70 : #ifdef SK_DEBUG
71 0 : SkASSERT(fRefCnt >= 0);
72 0 : SkASSERT(fPendingReads >= 0);
73 0 : SkASSERT(fPendingWrites >= 0);
74 0 : SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
75 : #endif
76 0 : }
77 :
78 : protected:
79 0 : GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
80 :
81 : enum CntType {
82 : kRef_CntType,
83 : kPendingRead_CntType,
84 : kPendingWrite_CntType,
85 : };
86 :
87 0 : bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
88 :
89 0 : bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
90 0 : bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
91 0 : bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
92 :
93 0 : bool internalHasRef() const { return SkToBool(fRefCnt); }
94 :
95 : private:
96 : friend class GrIORefProxy; // needs to forward on wrapped IO calls
97 : // This is for a unit test.
98 : template <typename T>
99 : friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt);
100 :
101 0 : void addPendingRead() const {
102 0 : this->validate();
103 0 : ++fPendingReads;
104 0 : }
105 :
106 0 : void completedRead() const {
107 0 : this->validate();
108 0 : --fPendingReads;
109 0 : this->didRemoveRefOrPendingIO(kPendingRead_CntType);
110 0 : }
111 :
112 0 : void addPendingWrite() const {
113 0 : this->validate();
114 0 : ++fPendingWrites;
115 0 : }
116 :
117 0 : void completedWrite() const {
118 0 : this->validate();
119 0 : --fPendingWrites;
120 0 : this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
121 0 : }
122 :
123 : private:
124 0 : void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const {
125 0 : if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
126 0 : static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved);
127 : }
128 0 : }
129 :
130 : mutable int32_t fRefCnt;
131 : mutable int32_t fPendingReads;
132 : mutable int32_t fPendingWrites;
133 :
134 : // This class is used to manage conversion of refs to pending reads/writes.
135 : friend class GrGpuResourceRef;
136 : friend class GrResourceCache; // to check IO ref counts.
137 :
138 : template <typename, GrIOType> friend class GrPendingIOResource;
139 : };
140 :
141 : /**
142 : * Base class for objects that can be kept in the GrResourceCache.
143 : */
144 : class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
145 : public:
146 :
147 : /**
148 : * Tests whether a object has been abandoned or released. All objects will
149 : * be in this state after their creating GrContext is destroyed or has
150 : * contextLost called. It's up to the client to test wasDestroyed() before
151 : * attempting to use an object if it holds refs on objects across
152 : * ~GrContext, freeResources with the force flag, or contextLost.
153 : *
154 : * @return true if the object has been released or abandoned,
155 : * false otherwise.
156 : */
157 0 : bool wasDestroyed() const { return NULL == fGpu; }
158 :
159 : /**
160 : * Retrieves the context that owns the object. Note that it is possible for
161 : * this to return NULL. When objects have been release()ed or abandon()ed
162 : * they no longer have an owning context. Destroying a GrContext
163 : * automatically releases all its resources.
164 : */
165 : const GrContext* getContext() const;
166 : GrContext* getContext();
167 :
168 : /**
169 : * Retrieves the amount of GPU memory used by this resource in bytes. It is
170 : * approximate since we aren't aware of additional padding or copies made
171 : * by the driver.
172 : *
173 : * @return the amount of GPU memory used in bytes
174 : */
175 0 : size_t gpuMemorySize() const {
176 0 : if (kInvalidGpuMemorySize == fGpuMemorySize) {
177 0 : fGpuMemorySize = this->onGpuMemorySize();
178 0 : SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
179 : }
180 0 : return fGpuMemorySize;
181 : }
182 :
183 : class UniqueID {
184 : public:
185 0 : static UniqueID InvalidID() {
186 0 : return UniqueID(uint32_t(SK_InvalidUniqueID));
187 : }
188 :
189 0 : UniqueID() {}
190 :
191 0 : explicit UniqueID(uint32_t id) : fID(id) {}
192 :
193 0 : uint32_t asUInt() const { return fID; }
194 :
195 0 : bool operator==(const UniqueID& other) const {
196 0 : return fID == other.fID;
197 : }
198 0 : bool operator!=(const UniqueID& other) const {
199 0 : return !(*this == other);
200 : }
201 :
202 0 : void makeInvalid() { fID = SK_InvalidUniqueID; }
203 0 : bool isInvalid() const { return SK_InvalidUniqueID == fID; }
204 :
205 : protected:
206 : uint32_t fID;
207 : };
208 :
209 : /**
210 : * Gets an id that is unique for this GrGpuResource object. It is static in that it does
211 : * not change when the content of the GrGpuResource object changes. This will never return
212 : * 0.
213 : */
214 0 : UniqueID uniqueID() const { return fUniqueID; }
215 :
216 : /** Returns the current unique key for the resource. It will be invalid if the resource has no
217 : associated unique key. */
218 0 : const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
219 :
220 : /**
221 : * Internal-only helper class used for manipulations of the resource by the cache.
222 : */
223 : class CacheAccess;
224 : inline CacheAccess cacheAccess();
225 : inline const CacheAccess cacheAccess() const;
226 :
227 : /**
228 : * Internal-only helper class used for manipulations of the resource by internal code.
229 : */
230 : class ResourcePriv;
231 : inline ResourcePriv resourcePriv();
232 : inline const ResourcePriv resourcePriv() const;
233 :
234 : /**
235 : * Removes references to objects in the underlying 3D API without freeing them.
236 : * Called by CacheAccess.
237 : * In general this method should not be called outside of skia. It was
238 : * made by public for a special case where it needs to be called in Blink
239 : * when a texture becomes unsafe to use after having been shared through
240 : * a texture mailbox.
241 : */
242 : void abandon();
243 :
244 : /**
245 : * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
246 : * Typically, subclasses should not need to override this, and should only
247 : * need to override setMemoryBacking.
248 : **/
249 : virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
250 :
251 : static uint32_t CreateUniqueID();
252 :
253 : protected:
254 : // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
255 : // fully initialized (i.e. only from the constructors of the final class).
256 : void registerWithCache(SkBudgeted);
257 :
258 : // This must be called by every GrGpuObject that references any wrapped backend objects. It
259 : // should be called once the object is fully initialized (i.e. only from the constructors of the
260 : // final class).
261 : void registerWithCacheWrapped();
262 :
263 : // This is only called by resources that are being exported from Ganesh to client code. It
264 : // ensures that the cache can no longer reach this resource, and that it no longer counts
265 : // against the budget.
266 : void detachFromCache();
267 :
268 : GrGpuResource(GrGpu*);
269 : virtual ~GrGpuResource();
270 :
271 0 : GrGpu* getGpu() const { return fGpu; }
272 :
273 : /** Overridden to free GPU resources in the backend API. */
274 0 : virtual void onRelease() { }
275 : /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
276 : This may be called when the underlying 3D context is no longer valid and so no
277 : backend API calls should be made. */
278 0 : virtual void onAbandon() { }
279 :
280 : /**
281 : * This entry point should be called whenever gpuMemorySize() should report a different size.
282 : * The cache will call gpuMemorySize() to update the current size of the resource.
283 : */
284 : void didChangeGpuMemorySize() const;
285 :
286 : /**
287 : * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by
288 : * onMemoryDump. The default implementation adds no backing information.
289 : **/
290 0 : virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
291 :
292 : private:
293 : /**
294 : * Called by the registerWithCache if the resource is available to be used as scratch.
295 : * Resource subclasses should override this if the instances should be recycled as scratch
296 : * resources and populate the scratchKey with the key.
297 : * By default resources are not recycled as scratch.
298 : **/
299 0 : virtual void computeScratchKey(GrScratchKey*) const { }
300 :
301 : /**
302 : * Frees the object in the underlying 3D API. Called by CacheAccess.
303 : */
304 : void release();
305 :
306 : virtual size_t onGpuMemorySize() const = 0;
307 :
308 : // See comments in CacheAccess and ResourcePriv.
309 : void setUniqueKey(const GrUniqueKey&);
310 : void removeUniqueKey();
311 : void notifyAllCntsAreZero(CntType) const;
312 : bool notifyRefCountIsZero() const;
313 : void removeScratchKey();
314 : void makeBudgeted();
315 : void makeUnbudgeted();
316 :
317 : #ifdef SK_DEBUG
318 : friend class GrGpu; // for assert in GrGpu to access getGpu
319 : #endif
320 :
321 : // An index into a heap when this resource is purgeable or an array when not. This is maintained
322 : // by the cache.
323 : int fCacheArrayIndex;
324 : // This value reflects how recently this resource was accessed in the cache. This is maintained
325 : // by the cache.
326 : uint32_t fTimestamp;
327 : uint32_t fExternalFlushCntWhenBecamePurgeable;
328 : GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
329 :
330 : static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
331 : GrScratchKey fScratchKey;
332 : GrUniqueKey fUniqueKey;
333 :
334 : // This is not ref'ed but abandon() or release() will be called before the GrGpu object
335 : // is destroyed. Those calls set will this to NULL.
336 : GrGpu* fGpu;
337 : mutable size_t fGpuMemorySize;
338 :
339 : SkBudgeted fBudgeted;
340 : bool fRefsWrappedObjects;
341 : const UniqueID fUniqueID;
342 :
343 : typedef GrIORef<GrGpuResource> INHERITED;
344 : friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
345 : };
346 :
347 : #endif
|