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 SkAutoTUnref, 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    SK_DECLARE_INST_COUNT_ROOT(GrGpuResourceRef);
38
39    ~GrGpuResourceRef();
40
41    GrGpuResource* getResource() const { return fResource; }
42
43    /** Does this object own a pending read or write on the resource it is wrapping. */
44    bool ownsPendingIO() const { return fPendingIO; }
45
46    /** Shortcut for calling setResource() with NULL. It cannot be called after markingPendingIO
47        is called. */
48    void reset();
49
50protected:
51    GrGpuResourceRef();
52
53    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
54        pending on the resource when markPendingIO is called. */
55    GrGpuResourceRef(GrGpuResource*, GrIORef::IOType);
56
57    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
58        pending on the resource when markPendingIO is called. */
59    void setResource(GrGpuResource*, GrIORef::IOType);
60
61private:
62    /** Called by owning GrProgramElement when the program element is first scheduled for
63        execution. It can only be called once. */
64    void markPendingIO() const;
65
66    /** Called when the program element/draw state is no longer owned by GrDrawTarget-client code.
67        This lets the cache know that the drawing code will no longer schedule additional reads or
68        writes to the resource using the program element or draw state. It can only be called once.
69      */
70    void removeRef() const;
71
72    /** Called to indicate that the previous pending IO is complete. Useful when the owning object
73        still has refs, so it is not about to destroy this GrGpuResourceRef, but its previously
74        pending executions have been complete. Can only be called if removeRef() was not previously
75        called. */
76    void pendingIOComplete() const;
77
78    friend class GrRODrawState;
79    friend class GrProgramElement;
80
81    GrGpuResource*      fResource;
82    mutable bool        fOwnRef;
83    mutable bool        fPendingIO;
84    GrIORef::IOType     fIOType;
85
86    typedef SkNoncopyable INHERITED;
87};
88
89/**
90 * Templated version of GrGpuResourceRef to enforce type safety.
91 */
92template <typename T> class GrTGpuResourceRef : public GrGpuResourceRef {
93public:
94    GrTGpuResourceRef() {}
95
96    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
97        pending on the resource when markPendingIO is called. */
98    GrTGpuResourceRef(T* resource, GrIORef::IOType ioType) : INHERITED(resource, ioType) {}
99
100    T* get() const { return static_cast<T*>(this->getResource()); }
101
102    /** Adopts a ref from the caller. ioType expresses what type of IO operations will be marked as
103        pending on the resource when markPendingIO is called. */
104    void set(T* resource, GrIORef::IOType ioType) { this->setResource(resource, ioType); }
105
106private:
107    typedef GrGpuResourceRef INHERITED;
108};
109
110/**
111 * This is similar to GrTGpuResourceRef but can only be in the pending IO state. It never owns a
112 * ref.
113 */
114template <typename T, GrIORef::IOType IO_TYPE> class GrPendingIOResource : SkNoncopyable {
115public:
116    GrPendingIOResource(T* resource) : fResource(resource) {
117        if (NULL != fResource) {
118            switch (IO_TYPE) {
119                case GrIORef::kRead_IOType:
120                    fResource->addPendingRead();
121                    break;
122                case GrIORef::kWrite_IOType:
123                    fResource->addPendingWrite();
124                    break;
125                case GrIORef::kRW_IOType:
126                    fResource->addPendingRead();
127                    fResource->addPendingWrite();
128                    break;
129            }
130        }
131    }
132
133    ~GrPendingIOResource() {
134        if (NULL != fResource) {
135            switch (IO_TYPE) {
136                case GrIORef::kRead_IOType:
137                    fResource->completedRead();
138                    break;
139                case GrIORef::kWrite_IOType:
140                    fResource->completedWrite();
141                    break;
142                case GrIORef::kRW_IOType:
143                    fResource->completedRead();
144                    fResource->completedWrite();
145                    break;
146            }
147        }
148    }
149
150    T* get() const { return fResource; }
151
152private:
153    T*      fResource;
154};
155#endif
156