blob: ea1250f537dfce7307f0ba7ec11fbf7b10500a3b [file] [log] [blame]
Robert Phillips5af44de2017-07-18 14:49:38 -04001/*
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
Robert Phillips57aa3672017-07-21 11:38:13 -040011#include "GrGpuResourcePriv.h"
12#include "GrSurface.h"
Robert Phillips5af44de2017-07-18 14:49:38 -040013#include "GrSurfaceProxy.h"
Robert Phillips8186cbe2017-11-01 17:32:39 -040014
15#include "SkArenaAlloc.h"
Robert Phillips5af44de2017-07-18 14:49:38 -040016#include "SkTDynamicHash.h"
Robert Phillips57aa3672017-07-21 11:38:13 -040017#include "SkTMultiMap.h"
Robert Phillips5af44de2017-07-18 14:49:38 -040018
Brian Salomon967df202018-12-07 11:15:53 -050019class GrDeinstantiateProxyTracker;
Robert Phillips5af44de2017-07-18 14:49:38 -040020class GrResourceProvider;
21
Robert Phillips715d08c2018-07-18 13:56:48 -040022// Print out explicit allocation information
23#define GR_ALLOCATION_SPEW 0
24
Robert Phillipsda1be462018-07-27 07:18:06 -040025// Print out information about interval creation
26#define GR_TRACK_INTERVAL_CREATION 0
27
Robert Phillips5af44de2017-07-18 14:49:38 -040028/*
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 */
43class GrResourceAllocator {
44public:
Brian Salomon967df202018-12-07 11:15:53 -050045 GrResourceAllocator(GrResourceProvider* resourceProvider, GrDeinstantiateProxyTracker* tracker)
46 : fResourceProvider(resourceProvider), fDeinstantiateTracker(tracker) {}
Robert Phillips5af44de2017-07-18 14:49:38 -040047
Robert Phillips5b65a842017-11-13 15:48:12 -050048 ~GrResourceAllocator();
49
Robert Phillips5af44de2017-07-18 14:49:38 -040050 unsigned int curOp() const { return fNumOps; }
51 void incOps() { fNumOps++; }
52 unsigned int numOps() const { return fNumOps; }
53
Robert Phillipseafd48a2017-11-16 07:52:08 -050054 // Add a usage interval from 'start' to 'end' inclusive. This is usually used for renderTargets.
Robert Phillips5af44de2017-07-18 14:49:38 -040055 // If an existing interval already exists it will be expanded to include the new range.
Chris Dalton8816b932017-11-29 16:48:25 -070056 void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end
57 SkDEBUGCODE(, bool isDirectDstRead = false));
Robert Phillips5af44de2017-07-18 14:49:38 -040058
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.
Chris Dalton8816b932017-11-29 16:48:25 -070061 void addInterval(GrSurfaceProxy* proxy
62 SkDEBUGCODE(, bool isDirectDstRead = false)) {
63 this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead));
Robert Phillips5af44de2017-07-18 14:49:38 -040064 }
65
Greg Danielaa3dfbe2018-01-29 10:34:25 -050066 enum class AssignError {
67 kNoError,
68 kFailedProxyInstantiation
69 };
70
Robert Phillipseafd48a2017-11-16 07:52:08 -050071 // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
72 // false when nothing remains to be executed.
Greg Danielaa3dfbe2018-01-29 10:34:25 -050073 // 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.
Robert Phillipseafd48a2017-11-16 07:52:08 -050075 // This is used to execute a portion of the queued opLists in order to reduce the total
76 // amount of GPU resources required.
Brian Salomon577aa0f2018-11-30 13:32:23 -050077 bool assign(int* startIndex, int* stopIndex, AssignError* outError);
Robert Phillipseafd48a2017-11-16 07:52:08 -050078
79 void markEndOfOpList(int opListIndex);
Robert Phillips5af44de2017-07-18 14:49:38 -040080
Robert Phillips715d08c2018-07-18 13:56:48 -040081#if GR_ALLOCATION_SPEW
82 void dumpIntervals();
83#endif
84
Robert Phillips5af44de2017-07-18 14:49:38 -040085private:
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
Robert Phillips715d08c2018-07-18 13:56:48 -040092 void recycleSurface(sk_sp<GrSurface> surface);
Robert Phillipseafd48a2017-11-16 07:52:08 -050093 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil);
Robert Phillips5af44de2017-07-18 14:49:38 -040094
Robert Phillips57aa3672017-07-21 11:38:13 -040095 struct FreePoolTraits {
96 static const GrScratchKey& GetKey(const GrSurface& s) {
97 return s.resourcePriv().getScratchKey();
98 }
Robert Phillips5af44de2017-07-18 14:49:38 -040099
Robert Phillips57aa3672017-07-21 11:38:13 -0400100 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500101 static void OnFree(GrSurface* s) { s->unref(); }
Robert Phillips5af44de2017-07-18 14:49:38 -0400102 };
Robert Phillips57aa3672017-07-21 11:38:13 -0400103 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
104
Robert Phillips5af44de2017-07-18 14:49:38 -0400105 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
106
107 class Interval {
108 public:
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);
Robert Phillipsda1be462018-07-27 07:18:06 -0400116#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
Robert Phillips5af44de2017-07-18 14:49:38 -0400121 }
122
Robert Phillips8186cbe2017-11-01 17:32:39 -0400123 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
124 SkASSERT(proxy);
Robert Phillipsdf25e3a2018-08-08 12:48:40 -0400125 SkASSERT(!fNext);
Robert Phillips8186cbe2017-11-01 17:32:39 -0400126
127 fProxy = proxy;
128 fProxyID = proxy->uniqueID().asUInt();
129 fStart = start;
130 fEnd = end;
131 fNext = nullptr;
Robert Phillipsda1be462018-07-27 07:18:06 -0400132#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
Robert Phillips8186cbe2017-11-01 17:32:39 -0400137 }
138
Robert Phillips5b65a842017-11-13 15:48:12 -0500139 ~Interval() {
140 SkASSERT(!fAssignedSurface);
141 }
142
Robert Phillipsf8e25022017-11-08 15:24:31 -0500143 const GrSurfaceProxy* proxy() const { return fProxy; }
144 GrSurfaceProxy* proxy() { return fProxy; }
145 unsigned int start() const { return fStart; }
146 unsigned int end() const { return fEnd; }
147 const Interval* next() const { return fNext; }
148 Interval* next() { return fNext; }
149
150 void setNext(Interval* next) { fNext = next; }
151
152 void extendEnd(unsigned int newEnd) {
Chris Dalton8816b932017-11-29 16:48:25 -0700153 if (newEnd > fEnd) {
154 fEnd = newEnd;
Robert Phillipsda1be462018-07-27 07:18:06 -0400155#if GR_TRACK_INTERVAL_CREATION
156 SkDebugf("intvl %d: extending from %d to %d\n", fUniqueID, fEnd, newEnd);
157#endif
Chris Dalton8816b932017-11-29 16:48:25 -0700158 }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500159 }
160
Robert Phillips5b65a842017-11-13 15:48:12 -0500161 void assign(sk_sp<GrSurface>);
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400162 bool wasAssignedSurface() const { return fAssignedSurface != nullptr; }
Robert Phillips5b65a842017-11-13 15:48:12 -0500163 sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); }
164
Robert Phillips5af44de2017-07-18 14:49:38 -0400165 // for SkTDynamicHash
166 static const uint32_t& GetKey(const Interval& intvl) {
167 return intvl.fProxyID;
168 }
169 static uint32_t Hash(const uint32_t& key) { return key; }
170
Robert Phillipsf8e25022017-11-08 15:24:31 -0500171 private:
Robert Phillips5b65a842017-11-13 15:48:12 -0500172 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;
Robert Phillipsda1be462018-07-27 07:18:06 -0400178
179#if GR_TRACK_INTERVAL_CREATION
180 uint32_t fUniqueID;
181
182 uint32_t CreateUniqueID();
183#endif
Robert Phillips5af44de2017-07-18 14:49:38 -0400184 };
185
186 class IntervalList {
187 public:
188 IntervalList() = default;
189 ~IntervalList() {
Robert Phillips8186cbe2017-11-01 17:32:39 -0400190 // 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.
Robert Phillips5af44de2017-07-18 14:49:38 -0400192 }
193
Robert Phillipsdf25e3a2018-08-08 12:48:40 -0400194 bool empty() const {
195 SkASSERT(SkToBool(fHead) == SkToBool(fTail));
196 return !SkToBool(fHead);
197 }
Robert Phillips5af44de2017-07-18 14:49:38 -0400198 const Interval* peekHead() const { return fHead; }
199 Interval* popHead();
200 void insertByIncreasingStart(Interval*);
201 void insertByIncreasingEnd(Interval*);
Robert Phillips4150eea2018-02-07 17:08:21 -0500202 Interval* detachAll();
Robert Phillips5af44de2017-07-18 14:49:38 -0400203
204 private:
Robert Phillipsdf25e3a2018-08-08 12:48:40 -0400205 SkDEBUGCODE(void validate() const;)
206
Robert Phillips5af44de2017-07-18 14:49:38 -0400207 Interval* fHead = nullptr;
Robert Phillipsdf25e3a2018-08-08 12:48:40 -0400208 Interval* fTail = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400209 };
210
Brian Salomon309b0532018-10-10 17:22:00 -0400211 // Compositing use cases can create > 80 intervals.
212 static const int kInitialArenaSize = 128 * sizeof(Interval);
Robert Phillips8186cbe2017-11-01 17:32:39 -0400213
Brian Salomon577aa0f2018-11-30 13:32:23 -0500214 GrResourceProvider* fResourceProvider;
Brian Salomon967df202018-12-07 11:15:53 -0500215 GrDeinstantiateProxyTracker* fDeinstantiateTracker;
Brian Salomon577aa0f2018-11-30 13:32:23 -0500216 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces
217 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID
Robert Phillips5af44de2017-07-18 14:49:38 -0400218
Brian Salomon577aa0f2018-11-30 13:32:23 -0500219 IntervalList fIntvlList; // All the intervals sorted by increasing start
220 IntervalList fActiveIntvls; // List of live intervals during assignment
Robert Phillipseafd48a2017-11-16 07:52:08 -0500221 // (sorted by increasing end)
Brian Salomon577aa0f2018-11-30 13:32:23 -0500222 unsigned int fNumOps = 1; // op # 0 is reserved for uploads at the start
Robert Phillips51b20f22017-12-01 15:32:35 -0500223 // of a flush
Brian Salomon577aa0f2018-11-30 13:32:23 -0500224 SkTArray<unsigned int> fEndOfOpListOpIndices;
225 int fCurOpListIndex = 0;
Robert Phillips8186cbe2017-11-01 17:32:39 -0400226
Brian Salomon577aa0f2018-11-30 13:32:23 -0500227 SkDEBUGCODE(bool fAssigned = false;)
Robert Phillipseafd48a2017-11-16 07:52:08 -0500228
Brian Salomon577aa0f2018-11-30 13:32:23 -0500229 char fStorage[kInitialArenaSize];
230 SkArenaAlloc fIntervalAllocator{fStorage, kInitialArenaSize, kInitialArenaSize};
231 Interval* fFreeIntervalList = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400232};
233
234#endif // GrResourceAllocator_DEFINED