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 "../private/GrTypesPriv.h"
12#include "GrResourceKey.h"
13
14class GrContext;
15class GrGpu;
16class GrResourceCache;
17class 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 */
46template <typename DERIVED> class GrIORef : public SkNoncopyable {
47public:
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    void ref() const {
53        this->validate();
54        ++fRefCnt;
55    }
56
57    void unref() const {
58        this->validate();
59
60        if (!(--fRefCnt)) {
61            if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) {
62                return;
63            }
64        }
65
66        this->didRemoveRefOrPendingIO(kRef_CntType);
67    }
68
69    void validate() const {
70#ifdef SK_DEBUG
71        SkASSERT(fRefCnt >= 0);
72        SkASSERT(fPendingReads >= 0);
73        SkASSERT(fPendingWrites >= 0);
74        SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
75#endif
76    }
77
78protected:
79    GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
80
81    enum CntType {
82        kRef_CntType,
83        kPendingRead_CntType,
84        kPendingWrite_CntType,
85    };
86
87    bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
88
89    bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
90    bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
91    bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
92
93    bool internalHasRef() const { return SkToBool(fRefCnt); }
94
95private:
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    void addPendingRead() const {
102        this->validate();
103        ++fPendingReads;
104    }
105
106    void completedRead() const {
107        this->validate();
108        --fPendingReads;
109        this->didRemoveRefOrPendingIO(kPendingRead_CntType);
110    }
111
112    void addPendingWrite() const {
113        this->validate();
114        ++fPendingWrites;
115    }
116
117    void completedWrite() const {
118        this->validate();
119        --fPendingWrites;
120        this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
121    }
122
123private:
124    void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const {
125        if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
126            static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved);
127        }
128    }
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 */
144class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
145public:
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    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    size_t gpuMemorySize() const {
176        if (kInvalidGpuMemorySize == fGpuMemorySize) {
177            fGpuMemorySize = this->onGpuMemorySize();
178            SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
179        }
180        return fGpuMemorySize;
181    }
182
183    class UniqueID {
184    public:
185        static UniqueID InvalidID() {
186            return UniqueID(uint32_t(SK_InvalidUniqueID));
187        }
188
189        UniqueID() {}
190
191        explicit UniqueID(uint32_t id) : fID(id) {}
192
193        uint32_t asUInt() const { return fID; }
194
195        bool operator==(const UniqueID& other) const {
196            return fID == other.fID;
197        }
198        bool operator!=(const UniqueID& other) const {
199            return !(*this == other);
200        }
201
202        void makeInvalid() { fID = SK_InvalidUniqueID; }
203        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    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    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
253protected:
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    GrGpuResource(GrGpu*);
264    virtual ~GrGpuResource();
265
266    GrGpu* getGpu() const { return fGpu; }
267
268    /** Overridden to free GPU resources in the backend API. */
269    virtual void onRelease() { }
270    /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
271        This may be called when the underlying 3D context is no longer valid and so no
272        backend API calls should be made. */
273    virtual void onAbandon() { }
274
275    /**
276     * This entry point should be called whenever gpuMemorySize() should report a different size.
277     * The cache will call gpuMemorySize() to update the current size of the resource.
278     */
279    void didChangeGpuMemorySize() const;
280
281    /**
282     * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by
283     * onMemoryDump. The default implementation adds no backing information.
284     **/
285    virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
286
287private:
288    /**
289     * Called by the registerWithCache if the resource is available to be used as scratch.
290     * Resource subclasses should override this if the instances should be recycled as scratch
291     * resources and populate the scratchKey with the key.
292     * By default resources are not recycled as scratch.
293     **/
294    virtual void computeScratchKey(GrScratchKey*) const { }
295
296    /**
297     * Frees the object in the underlying 3D API. Called by CacheAccess.
298     */
299    void release();
300
301    virtual size_t onGpuMemorySize() const = 0;
302
303    // See comments in CacheAccess and ResourcePriv.
304    void setUniqueKey(const GrUniqueKey&);
305    void removeUniqueKey();
306    void notifyAllCntsAreZero(CntType) const;
307    bool notifyRefCountIsZero() const;
308    void removeScratchKey();
309    void makeBudgeted();
310    void makeUnbudgeted();
311
312#ifdef SK_DEBUG
313    friend class GrGpu;  // for assert in GrGpu to access getGpu
314#endif
315
316    // An index into a heap when this resource is purgeable or an array when not. This is maintained
317    // by the cache.
318    int fCacheArrayIndex;
319    // This value reflects how recently this resource was accessed in the cache. This is maintained
320    // by the cache.
321    uint32_t fTimestamp;
322    uint32_t fExternalFlushCntWhenBecamePurgeable;
323    GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
324
325    static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
326    GrScratchKey fScratchKey;
327    GrUniqueKey fUniqueKey;
328
329    // This is not ref'ed but abandon() or release() will be called before the GrGpu object
330    // is destroyed. Those calls set will this to NULL.
331    GrGpu* fGpu;
332    mutable size_t fGpuMemorySize;
333
334    SkBudgeted fBudgeted;
335    bool fRefsWrappedObjects;
336    const UniqueID fUniqueID;
337
338    typedef GrIORef<GrGpuResource> INHERITED;
339    friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
340};
341
342#endif
343