• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 GrProgramElement_DEFINED
9 #define GrProgramElement_DEFINED
10 
11 #include "../private/SkTArray.h"
12 #include "SkRefCnt.h"
13 
14 class GrGpuResourceRef;
15 
16 /**
17  * Base class for GrProcessor. This exists to manage transitioning a GrProcessor from being owned by
18  * a client to being scheduled for execution. While a GrProcessor is ref'ed by drawing code its
19  * GrGpu resources must also be ref'ed to prevent incorrectly recycling them through the cache.
20  * However, once the GrProcessor is baked into a GrPipeline and the drawing code has stopped ref'ing
21  * it, it's internal resources can be recycled in some cases.
22  *
23  * We track this using two types of refs on GrProgramElement. A regular ref is owned by any client
24  * that may continue to issue draws that use the GrProgramElement. The GrPipeline owns "pending
25  * executions" instead of refs. A pending execution is cleared by ~GrPipeline().
26  *
27  * While a GrProgramElement is ref'ed any resources it owns are also ref'ed. However, once it gets
28  * into the state where it has pending executions AND no refs then it converts its ownership of
29  * its GrGpuResources from refs to pending IOs. The pending IOs allow the cache to track when it is
30  * safe to recycle a resource even though we still have buffered GrBatches that read or write to the
31  * the resource.
32  *
33  * To make this work all GrGpuResource objects owned by a GrProgramElement or derived classes
34  * (either directly or indirectly) must be wrapped in a GrGpuResourceRef and registered with the
35  * GrProgramElement using addGpuResource(). This allows the regular refs to be converted to pending
36  * IO events when the program element is scheduled for deferred execution.
37  *
38  * Moreover, a GrProgramElement that in turn owns other GrProgramElements must convert its ownership
39  * of its children to pending executions when its ref count reaches zero so that the GrGpuResources
40  * owned by the children GrProgramElements are correctly converted from ownership by ref to
41  * ownership by pending IO. Any GrProgramElement hierarchy is managed by subclasses which must
42  * implement notifyRefCntIsZero() in order to convert refs of children to pending executions.
43  */
44 class GrProgramElement : public SkNoncopyable {
45 public:
~GrProgramElement()46     virtual ~GrProgramElement() {
47         // fRefCnt can be one when an effect is created statically using GR_CREATE_STATIC_EFFECT
48         SkASSERT((0 == fRefCnt || 1 == fRefCnt) && 0 == fPendingExecutions);
49         // Set to invalid values.
50         SkDEBUGCODE(fRefCnt = fPendingExecutions = -10;)
51     }
52 
ref()53     void ref() const {
54         this->validate();
55         // Once the ref cnt reaches zero it should never be ref'ed again.
56         SkASSERT(fRefCnt > 0);
57         ++fRefCnt;
58         this->validate();
59     }
60 
unref()61     void unref() const {
62         this->validate();
63         --fRefCnt;
64         if (0 == fRefCnt) {
65             this->notifyRefCntIsZero();
66             if (0 == fPendingExecutions) {
67                 delete this;
68                 return;
69             } else {
70                 this->removeRefs();
71             }
72         }
73         this->validate();
74     }
75 
76     /**
77      * Gets an id that is unique for this GrProgramElement object. This will never return 0.
78      */
getUniqueID()79     uint32_t getUniqueID() const { return fUniqueID; }
80 
validate()81     void validate() const {
82 #ifdef SK_DEBUG
83         SkASSERT(fRefCnt >= 0);
84         SkASSERT(fPendingExecutions >= 0);
85         SkASSERT(fRefCnt + fPendingExecutions > 0);
86 #endif
87     }
88 
89 protected:
GrProgramElement()90     GrProgramElement() : fRefCnt(1), fPendingExecutions(0), fUniqueID(CreateUniqueID()) {}
91 
92     /** Subclasses registers their resources using this function. It is assumed the GrProgramResouce
93         is and will remain owned by the subclass and this function will retain a raw ptr. Once a
94         GrGpuResourceRef is registered its setResource must not be called.
95      */
addGpuResource(const GrGpuResourceRef * res)96     void addGpuResource(const GrGpuResourceRef* res) {
97         fGpuResources.push_back(res);
98     }
99 
addPendingExecution()100     void addPendingExecution() const {
101         this->validate();
102         SkASSERT(fRefCnt > 0);
103         if (0 == fPendingExecutions) {
104             this->addPendingIOs();
105         }
106         ++fPendingExecutions;
107         this->validate();
108     }
109 
completedExecution()110     void completedExecution() const {
111         this->validate();
112         --fPendingExecutions;
113         if (0 == fPendingExecutions) {
114             if (0 == fRefCnt) {
115                 delete this;
116                 return;
117             } else {
118                 this->pendingIOComplete();
119             }
120         }
121         this->validate();
122     }
123 
124 private:
125     /** This will be called when the ref cnt is zero. The object may or may not have pending
126         executions. */
127     virtual void notifyRefCntIsZero() const = 0;
128 
129     static uint32_t CreateUniqueID();
130 
131     void removeRefs() const;
132     void addPendingIOs() const;
133     void pendingIOComplete() const;
134 
135     mutable int32_t fRefCnt;
136     // Count of deferred executions not yet issued to the 3D API.
137     mutable int32_t fPendingExecutions;
138     uint32_t        fUniqueID;
139 
140     SkSTArray<4, const GrGpuResourceRef*, true> fGpuResources;
141 
142     // Only this class can access addPendingExecution() and completedExecution().
143     template <typename T> friend class GrPendingProgramElement;
144 
145     typedef SkNoncopyable INHERITED;
146 };
147 
148 #endif
149