GrGpuResource.h revision f320e04c50a1c8a861bc1d8f50bf732044ff9843
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#include "SkData.h"
14#include "SkInstCnt.h"
15
16class GrContext;
17class GrGpu;
18class GrResourceCache;
19
20/**
21 * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
22 * class to isolate the ref-cnting behavior and provide friendship without exposing all of
23 * GrGpuResource.
24 *
25 * Gpu resources can have three types of refs:
26 *   1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls
27 *      that read and write the resource via GrDrawTarget and by any object that must own a
28 *      GrGpuResource and is itself owned (directly or indirectly) by Skia-client code.
29 *   2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read
30 *      of the resource by the GPU as a result of a skia API call but hasn't executed it yet.
31 *   3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a
32 *      write to the resource by the GPU as a result of a skia API call but hasn't executed it yet.
33 *
34 * The latter two ref types are private and intended only for Gr core code.
35 *
36 * When an item is purgeable DERIVED:notifyIsPurgeable() will be called (static poly morphism using
37 * CRTP). GrIORef and GrGpuResource are separate classes for organizational reasons and to be
38 * able to give access via friendship to only the functions related to pending IO operations.
39 */
40template <typename DERIVED> class GrIORef : public SkNoncopyable {
41public:
42    SK_DECLARE_INST_COUNT(GrIORef)
43
44    // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with
45    // templated helper classes (e.g. SkAutoTUnref). However, we have different categories of
46    // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are
47    // not intended to cross thread boundaries.
48    void ref() const {
49        this->validate();
50        ++fRefCnt;
51    }
52
53    void unref() const {
54        this->validate();
55        --fRefCnt;
56        this->didUnref();
57    }
58
59    void validate() const {
60#ifdef SK_DEBUG
61        SkASSERT(fRefCnt >= 0);
62        SkASSERT(fPendingReads >= 0);
63        SkASSERT(fPendingWrites >= 0);
64        SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
65#endif
66    }
67
68protected:
69    GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
70
71    bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
72
73    bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
74    bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
75    bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
76
77    bool internalHasRef() const { return SkToBool(fRefCnt); }
78
79private:
80    void addPendingRead() const {
81        this->validate();
82        ++fPendingReads;
83    }
84
85    void completedRead() const {
86        this->validate();
87        --fPendingReads;
88        this->didUnref();
89    }
90
91    void addPendingWrite() const {
92        this->validate();
93        ++fPendingWrites;
94    }
95
96    void completedWrite() const {
97        this->validate();
98        --fPendingWrites;
99        this->didUnref();
100    }
101
102private:
103    void didUnref() const {
104        if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
105            static_cast<const DERIVED*>(this)->notifyIsPurgeable();
106        }
107    }
108
109    mutable int32_t fRefCnt;
110    mutable int32_t fPendingReads;
111    mutable int32_t fPendingWrites;
112
113    // This class is used to manage conversion of refs to pending reads/writes.
114    friend class GrGpuResourceRef;
115    friend class GrResourceCache; // to check IO ref counts.
116
117    template <typename, GrIOType> friend class GrPendingIOResource;
118};
119
120/**
121 * Base class for objects that can be kept in the GrResourceCache.
122 */
123class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
124public:
125    SK_DECLARE_INST_COUNT(GrGpuResource)
126
127    enum LifeCycle {
128        /**
129         * The resource is cached and owned by Skia. Resources with this status may be kept alive
130         * by the cache as either scratch or content resources even when there are no refs to them.
131         * The cache may release them whenever there are no refs.
132         */
133        kCached_LifeCycle,
134        /**
135         * The resource is uncached. As soon as there are no more refs to it, it is released. Under
136         * the hood the cache may opaquely recycle it as a cached resource.
137         */
138        kUncached_LifeCycle,
139        /**
140         * Similar to uncached, but Skia does not manage the lifetime of the underlying backend
141         * 3D API object(s). The client is responsible for freeing those. Used to inject client-
142         * created GPU resources into Skia (e.g. to render to a client-created texture).
143         */
144        kWrapped_LifeCycle,
145    };
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    /**
184     * Gets an id that is unique for this GrGpuResource object. It is static in that it does
185     * not change when the content of the GrGpuResource object changes. This will never return
186     * 0.
187     */
188    uint32_t getUniqueID() const { return fUniqueID; }
189
190    /** Returns the current content key for the resource. It will be invalid if the resource has not
191        been cached by its contents. */
192    const GrContentKey& getContentKey() const { return fContentKey; }
193
194    /**
195     * Attach a custom data object to this resource. The data will remain attached
196     * for the lifetime of this resource (until it is abandoned or released).
197     * Takes a ref on data. Previously attached data, if any, is unrefed.
198     * Returns the data argument, for convenience.
199     */
200    const SkData* setCustomData(const SkData* data);
201
202    /**
203     * Returns the custom data object that was attached to this resource by
204     * calling setCustomData.
205     */
206    const SkData* getCustomData() const { return fData.get(); }
207
208    /**
209     * Internal-only helper class used for manipulations of the resource by the cache.
210     */
211    class CacheAccess;
212    inline CacheAccess cacheAccess();
213    inline const CacheAccess cacheAccess() const;
214
215    /**
216     * Internal-only helper class used for manipulations of the resource by internal code.
217     */
218    class ResourcePriv;
219    inline ResourcePriv resourcePriv();
220    inline const ResourcePriv resourcePriv() const;
221
222    /**
223     * Removes references to objects in the underlying 3D API without freeing them.
224     * Called by CacheAccess.
225     * In general this method should not be called outside of skia. It was
226     * made by public for a special case where it needs to be called in Blink
227     * when a texture becomes unsafe to use after having been shared through
228     * a texture mailbox.
229     */
230    void abandon();
231
232protected:
233    // This must be called by every GrGpuObject. It should be called once the object is fully
234    // initialized (i.e. not in a base class constructor).
235    void registerWithCache();
236
237    GrGpuResource(GrGpu*, LifeCycle);
238    virtual ~GrGpuResource();
239
240    GrGpu* getGpu() const { return fGpu; }
241
242    /** Overridden to free GPU resources in the backend API. */
243    virtual void onRelease() { }
244    /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
245        This may be called when the underlying 3D context is no longer valid and so no
246        backend API calls should be made. */
247    virtual void onAbandon() { }
248
249    bool isWrapped() const { return kWrapped_LifeCycle == fLifeCycle; }
250
251    /**
252     * This entry point should be called whenever gpuMemorySize() should report a different size.
253     * The cache will call gpuMemorySize() to update the current size of the resource.
254     */
255    void didChangeGpuMemorySize() const;
256
257    /**
258     * Optionally called by the GrGpuResource subclass if the resource can be used as scratch.
259     * By default resources are not usable as scratch. This should only be called once.
260     **/
261    void setScratchKey(const GrScratchKey& scratchKey);
262
263private:
264    /**
265     * Frees the object in the underlying 3D API. Called by CacheAccess.
266     */
267    void release();
268
269    virtual size_t onGpuMemorySize() const = 0;
270
271    // See comments in CacheAccess and ResourcePriv.
272    bool setContentKey(const GrContentKey& contentKey);
273    void removeContentKey();
274    void notifyIsPurgeable() const;
275    void removeScratchKey();
276    void makeBudgeted();
277    void makeUnbudgeted();
278
279#ifdef SK_DEBUG
280    friend class GrGpu; // for assert in GrGpu to access getGpu
281#endif
282
283    static uint32_t CreateUniqueID();
284
285    // An index into a heap when this resource is purgeable or an array when not. This is maintained
286    // by the cache.
287    int                         fCacheArrayIndex;
288    // This value reflects how recently this resource was accessed in the cache. This is maintained
289    // by the cache.
290    uint32_t                    fTimestamp;
291
292    static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
293    GrScratchKey                fScratchKey;
294    GrContentKey                fContentKey;
295
296    // This is not ref'ed but abandon() or release() will be called before the GrGpu object
297    // is destroyed. Those calls set will this to NULL.
298    GrGpu*                      fGpu;
299    mutable size_t              fGpuMemorySize;
300
301    LifeCycle                   fLifeCycle;
302    const uint32_t              fUniqueID;
303
304    SkAutoTUnref<const SkData>  fData;
305
306    typedef GrIORef<GrGpuResource> INHERITED;
307    friend class GrIORef<GrGpuResource>; // to access notifyIsPurgeable.
308};
309
310#endif
311