1 /* 2 * Copyright 2017 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 GrResourceAllocator_DEFINED 9 #define GrResourceAllocator_DEFINED 10 11 #include "GrGpuResourcePriv.h" 12 #include "GrSurface.h" 13 #include "GrSurfaceProxy.h" 14 15 #include "SkArenaAlloc.h" 16 #include "SkTDynamicHash.h" 17 #include "SkTMultiMap.h" 18 19 class GrDeinstantiateProxyTracker; 20 class GrResourceProvider; 21 22 // Print out explicit allocation information 23 #define GR_ALLOCATION_SPEW 0 24 25 // Print out information about interval creation 26 #define GR_TRACK_INTERVAL_CREATION 0 27 28 /* 29 * The ResourceAllocator explicitly distributes GPU resources at flush time. It operates by 30 * being given the usage intervals of the various proxies. It keeps these intervals in a singly 31 * linked list sorted by increasing start index. (It also maintains a hash table from proxyID 32 * to interval to find proxy reuse). When it comes time to allocate the resources it 33 * traverses the sorted list and: 34 * removes intervals from the active list that have completed (returning their GrSurfaces 35 * to the free pool) 36 37 * allocates a new resource (preferably from the free pool) for the new interval 38 * adds the new interval to the active list (that is sorted by increasing end index) 39 * 40 * Note: the op indices (used in the usage intervals) come from the order of the ops in 41 * their opLists after the opList DAG has been linearized. 42 */ 43 class GrResourceAllocator { 44 public: GrResourceAllocator(GrResourceProvider * resourceProvider,GrDeinstantiateProxyTracker * tracker)45 GrResourceAllocator(GrResourceProvider* resourceProvider, GrDeinstantiateProxyTracker* tracker) 46 : fResourceProvider(resourceProvider), fDeinstantiateTracker(tracker) {} 47 48 ~GrResourceAllocator(); 49 curOp()50 unsigned int curOp() const { return fNumOps; } incOps()51 void incOps() { fNumOps++; } numOps()52 unsigned int numOps() const { return fNumOps; } 53 54 // Add a usage interval from 'start' to 'end' inclusive. This is usually used for renderTargets. 55 // If an existing interval already exists it will be expanded to include the new range. 56 void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end 57 SkDEBUGCODE(, bool isDirectDstRead = false)); 58 59 // Add an interval that spans just the current op. Usually this is for texture uses. 60 // If an existing interval already exists it will be expanded to include the new operation. 61 void addInterval(GrSurfaceProxy* proxy 62 SkDEBUGCODE(, bool isDirectDstRead = false)) { 63 this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead)); 64 } 65 66 enum class AssignError { 67 kNoError, 68 kFailedProxyInstantiation 69 }; 70 71 // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed; 72 // false when nothing remains to be executed. 73 // If any proxy fails to instantiate, the AssignError will be set to kFailedProxyInstantiation. 74 // If this happens, the caller should remove all ops which reference an uninstantiated proxy. 75 // This is used to execute a portion of the queued opLists in order to reduce the total 76 // amount of GPU resources required. 77 bool assign(int* startIndex, int* stopIndex, AssignError* outError); 78 79 void markEndOfOpList(int opListIndex); 80 81 #if GR_ALLOCATION_SPEW 82 void dumpIntervals(); 83 #endif 84 85 private: 86 class Interval; 87 88 // Remove dead intervals from the active list 89 void expire(unsigned int curIndex); 90 91 // These two methods wrap the interactions with the free pool 92 void recycleSurface(sk_sp<GrSurface> surface); 93 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil); 94 95 struct FreePoolTraits { GetKeyFreePoolTraits96 static const GrScratchKey& GetKey(const GrSurface& s) { 97 return s.resourcePriv().getScratchKey(); 98 } 99 HashFreePoolTraits100 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); } OnFreeFreePoolTraits101 static void OnFree(GrSurface* s) { s->unref(); } 102 }; 103 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap; 104 105 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash; 106 107 class Interval { 108 public: Interval(GrSurfaceProxy * proxy,unsigned int start,unsigned int end)109 Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) 110 : fProxy(proxy) 111 , fProxyID(proxy->uniqueID().asUInt()) 112 , fStart(start) 113 , fEnd(end) 114 , fNext(nullptr) { 115 SkASSERT(proxy); 116 #if GR_TRACK_INTERVAL_CREATION 117 fUniqueID = CreateUniqueID(); 118 SkDebugf("New intvl %d: proxyID: %d [ %d, %d ]\n", 119 fUniqueID, proxy->uniqueID().asUInt(), start, end); 120 #endif 121 } 122 resetTo(GrSurfaceProxy * proxy,unsigned int start,unsigned int end)123 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) { 124 SkASSERT(proxy); 125 SkASSERT(!fNext); 126 127 fProxy = proxy; 128 fProxyID = proxy->uniqueID().asUInt(); 129 fStart = start; 130 fEnd = end; 131 fNext = nullptr; 132 #if GR_TRACK_INTERVAL_CREATION 133 fUniqueID = CreateUniqueID(); 134 SkDebugf("New intvl %d: proxyID: %d [ %d, %d ]\n", 135 fUniqueID, proxy->uniqueID().asUInt(), start, end); 136 #endif 137 } 138 ~Interval()139 ~Interval() { 140 SkASSERT(!fAssignedSurface); 141 } 142 proxy()143 const GrSurfaceProxy* proxy() const { return fProxy; } proxy()144 GrSurfaceProxy* proxy() { return fProxy; } start()145 unsigned int start() const { return fStart; } end()146 unsigned int end() const { return fEnd; } next()147 const Interval* next() const { return fNext; } next()148 Interval* next() { return fNext; } 149 setNext(Interval * next)150 void setNext(Interval* next) { fNext = next; } 151 extendEnd(unsigned int newEnd)152 void extendEnd(unsigned int newEnd) { 153 if (newEnd > fEnd) { 154 fEnd = newEnd; 155 #if GR_TRACK_INTERVAL_CREATION 156 SkDebugf("intvl %d: extending from %d to %d\n", fUniqueID, fEnd, newEnd); 157 #endif 158 } 159 } 160 161 void assign(sk_sp<GrSurface>); wasAssignedSurface()162 bool wasAssignedSurface() const { return fAssignedSurface != nullptr; } detachSurface()163 sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); } 164 165 // for SkTDynamicHash GetKey(const Interval & intvl)166 static const uint32_t& GetKey(const Interval& intvl) { 167 return intvl.fProxyID; 168 } Hash(const uint32_t & key)169 static uint32_t Hash(const uint32_t& key) { return key; } 170 171 private: 172 sk_sp<GrSurface> fAssignedSurface; 173 GrSurfaceProxy* fProxy; 174 uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key 175 unsigned int fStart; 176 unsigned int fEnd; 177 Interval* fNext; 178 179 #if GR_TRACK_INTERVAL_CREATION 180 uint32_t fUniqueID; 181 182 uint32_t CreateUniqueID(); 183 #endif 184 }; 185 186 class IntervalList { 187 public: 188 IntervalList() = default; ~IntervalList()189 ~IntervalList() { 190 // The only time we delete an IntervalList is in the GrResourceAllocator dtor. 191 // Since the arena allocator will clean up for us we don't bother here. 192 } 193 empty()194 bool empty() const { 195 SkASSERT(SkToBool(fHead) == SkToBool(fTail)); 196 return !SkToBool(fHead); 197 } peekHead()198 const Interval* peekHead() const { return fHead; } 199 Interval* popHead(); 200 void insertByIncreasingStart(Interval*); 201 void insertByIncreasingEnd(Interval*); 202 Interval* detachAll(); 203 204 private: 205 SkDEBUGCODE(void validate() const;) 206 207 Interval* fHead = nullptr; 208 Interval* fTail = nullptr; 209 }; 210 211 // Compositing use cases can create > 80 intervals. 212 static const int kInitialArenaSize = 128 * sizeof(Interval); 213 214 GrResourceProvider* fResourceProvider; 215 GrDeinstantiateProxyTracker* fDeinstantiateTracker; 216 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces 217 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID 218 219 IntervalList fIntvlList; // All the intervals sorted by increasing start 220 IntervalList fActiveIntvls; // List of live intervals during assignment 221 // (sorted by increasing end) 222 unsigned int fNumOps = 1; // op # 0 is reserved for uploads at the start 223 // of a flush 224 SkTArray<unsigned int> fEndOfOpListOpIndices; 225 int fCurOpListIndex = 0; 226 227 SkDEBUGCODE(bool fAssigned = false;) 228 229 char fStorage[kInitialArenaSize]; 230 SkArenaAlloc fIntervalAllocator{fStorage, kInitialArenaSize, kInitialArenaSize}; 231 Interval* fFreeIntervalList = nullptr; 232 }; 233 234 #endif // GrResourceAllocator_DEFINED 235