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 GrGpuResourceRef_DEFINED
9#define GrGpuResourceRef_DEFINED
10
11#include "GrGpuResource.h"
12#include "SkRefCnt.h"
13
14/**
15 * This class is intended only for internal use in core Gr code.
16 *
17 * Class that wraps a resource referenced by a GrProgramElement or GrDrawState. It manages
18 * converting refs to pending IO operations. It allows a resource ownership to be in three
19 * states:
20 *          1. Owns a single ref
21 *          2. Owns a single ref and a pending IO operation (read, write, or read-write)
22 *          3. Owns a single pending IO operation.
23 *
24 * It is legal to destroy the GrGpuResourceRef in any of these states. It starts in state
25 * 1. Calling markPendingIO() converts it from state 1 to state 2. Calling removeRef() goes from
26 * state 2 to state 3. Calling pendingIOComplete() moves from state 2 to state 1. There is no
27 * valid way of going from state 3 back to 2 or 1.
28 *
29 * Like sk_sp, its constructor and setter adopt a ref from their caller.
30 *
31 * TODO: Once GrDODrawState no longer exists and therefore GrDrawState and GrOptDrawState no
32 * longer share an instance of this class, attempt to make the resource owned by GrGpuResourceRef
33 * only settable via the constructor.
34 */
35class GrGpuResourceRef : SkNoncopyable {
36public:
37    ~GrGpuResourceRef();
38
39    GrGpuResource* getResource() const { return fResource; }
40
41    /** Does this object own a pending read or write on the resource it is wrapping. */
42    bool ownsPendingIO() const { return fPendingIO; }
43
44    /** What type of IO does this represent? This is independent of whether a normal ref or a
45        pending IO is currently held. */
46    GrIOType ioType() const { return fIOType; }
47
48    /** Shortcut for calling setResource() with NULL. It cannot be called after markingPendingIO
49        is called. */
50    void reset();
51
52protected:
53    GrGpuResourceRef();
54
55    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
56        pending on the resource when markPendingIO is called. */
57    GrGpuResourceRef(GrGpuResource*, GrIOType);
58
59    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
60        pending on the resource when markPendingIO is called. */
61    void setResource(GrGpuResource*, GrIOType);
62
63private:
64    /** Called by owning GrProgramElement when the program element is first scheduled for
65        execution. It can only be called once. */
66    void markPendingIO() const;
67
68    /** Called when the program element/draw state is no longer owned by GrOpList-client code.
69        This lets the cache know that the drawing code will no longer schedule additional reads or
70        writes to the resource using the program element or draw state. It can only be called once.
71      */
72    void removeRef() const;
73
74    /** Called to indicate that the previous pending IO is complete. Useful when the owning object
75        still has refs, so it is not about to destroy this GrGpuResourceRef, but its previously
76        pending executions have been complete. Can only be called if removeRef() was not previously
77        called. */
78    void pendingIOComplete() const;
79
80    friend class GrResourceIOProcessor;
81
82    GrGpuResource*  fResource;
83    mutable bool    fOwnRef;
84    mutable bool    fPendingIO;
85    GrIOType        fIOType;
86
87    typedef SkNoncopyable INHERITED;
88};
89
90/**
91 * Templated version of GrGpuResourceRef to enforce type safety.
92 */
93template <typename T> class GrTGpuResourceRef : public GrGpuResourceRef {
94public:
95    GrTGpuResourceRef() {}
96
97    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
98        pending on the resource when markPendingIO is called. */
99    GrTGpuResourceRef(T* resource, GrIOType ioType) : INHERITED(resource, ioType) {}
100    GrTGpuResourceRef(sk_sp<T> resource, GrIOType ioType) : INHERITED(resource, ioType) {}
101
102    T* get() const { return static_cast<T*>(this->getResource()); }
103
104    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
105        pending on the resource when markPendingIO is called. */
106    void set(T* resource, GrIOType ioType) { this->setResource(resource, ioType); }
107
108private:
109    typedef GrGpuResourceRef INHERITED;
110};
111
112/**
113 * This is similar to GrTGpuResourceRef but can only be in the pending IO state. It never owns a
114 * ref.
115 */
116template <typename T, GrIOType IO_TYPE> class GrPendingIOResource : SkNoncopyable {
117public:
118    GrPendingIOResource(T* resource = nullptr) : fResource(nullptr) {
119        this->reset(resource);
120    }
121
122    GrPendingIOResource(const GrPendingIOResource& that)
123        : GrPendingIOResource(that.get()) {
124    }
125
126    void reset(T* resource = nullptr) {
127        if (resource) {
128            switch (IO_TYPE) {
129                case kRead_GrIOType:
130                    resource->addPendingRead();
131                    break;
132                case kWrite_GrIOType:
133                    resource->addPendingWrite();
134                    break;
135                case kRW_GrIOType:
136                    resource->addPendingRead();
137                    resource->addPendingWrite();
138                    break;
139            }
140        }
141        this->release();
142        fResource = resource;
143    }
144
145    ~GrPendingIOResource() {
146        this->release();
147    }
148
149    explicit operator bool() const { return SkToBool(fResource); }
150
151    bool operator==(const GrPendingIOResource& other) const {
152        return fResource == other.fResource;
153    }
154
155    T* get() const { return fResource; }
156
157private:
158    void release() {
159        if (fResource) {
160            switch (IO_TYPE) {
161                case kRead_GrIOType:
162                    fResource->completedRead();
163                    break;
164                case kWrite_GrIOType:
165                    fResource->completedWrite();
166                    break;
167                case kRW_GrIOType:
168                    fResource->completedRead();
169                    fResource->completedWrite();
170                    break;
171            }
172        }
173    }
174
175    T* fResource;
176};
177
178#endif
179