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: 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 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 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 */ 79 uint32_t getUniqueID() const { return fUniqueID; } 80 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: 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 */ 96 void addGpuResource(const GrGpuResourceRef* res) { 97 fGpuResources.push_back(res); 98 } 99 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 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