GrResourceAllocator.h 11 KB

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