blob: fc3d031165dad3544663a011a98ea0c812c37009 [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
19class GrResourceProvider;
Greg Daniel4684f822018-03-08 15:27:36 -050020class GrUninstantiateProxyTracker;
Robert Phillips5af44de2017-07-18 14:49:38 -040021
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:
45 GrResourceAllocator(GrResourceProvider* resourceProvider)
46 : fResourceProvider(resourceProvider) {
47 }
48
Robert Phillips5b65a842017-11-13 15:48:12 -050049 ~GrResourceAllocator();
50
Robert Phillips5af44de2017-07-18 14:49:38 -040051 unsigned int curOp() const { return fNumOps; }
52 void incOps() { fNumOps++; }
53 unsigned int numOps() const { return fNumOps; }
54
Robert Phillipseafd48a2017-11-16 07:52:08 -050055 // Add a usage interval from 'start' to 'end' inclusive. This is usually used for renderTargets.
Robert Phillips5af44de2017-07-18 14:49:38 -040056 // If an existing interval already exists it will be expanded to include the new range.
Chris Dalton8816b932017-11-29 16:48:25 -070057 void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end
58 SkDEBUGCODE(, bool isDirectDstRead = false));
Robert Phillips5af44de2017-07-18 14:49:38 -040059
60 // Add an interval that spans just the current op. Usually this is for texture uses.
61 // If an existing interval already exists it will be expanded to include the new operation.
Chris Dalton8816b932017-11-29 16:48:25 -070062 void addInterval(GrSurfaceProxy* proxy
63 SkDEBUGCODE(, bool isDirectDstRead = false)) {
64 this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead));
Robert Phillips5af44de2017-07-18 14:49:38 -040065 }
66
Greg Danielaa3dfbe2018-01-29 10:34:25 -050067 enum class AssignError {
68 kNoError,
69 kFailedProxyInstantiation
70 };
71
Robert Phillipseafd48a2017-11-16 07:52:08 -050072 // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
73 // false when nothing remains to be executed.
Greg Danielaa3dfbe2018-01-29 10:34:25 -050074 // If any proxy fails to instantiate, the AssignError will be set to kFailedProxyInstantiation.
75 // If this happens, the caller should remove all ops which reference an uninstantiated proxy.
Robert Phillipseafd48a2017-11-16 07:52:08 -050076 // This is used to execute a portion of the queued opLists in order to reduce the total
77 // amount of GPU resources required.
Greg Daniel4684f822018-03-08 15:27:36 -050078 bool assign(int* startIndex, int* stopIndex, GrUninstantiateProxyTracker*,
79 AssignError* outError);
Robert Phillipseafd48a2017-11-16 07:52:08 -050080
81 void markEndOfOpList(int opListIndex);
Robert Phillips5af44de2017-07-18 14:49:38 -040082
Robert Phillips715d08c2018-07-18 13:56:48 -040083#if GR_ALLOCATION_SPEW
84 void dumpIntervals();
85#endif
86
Robert Phillips5af44de2017-07-18 14:49:38 -040087private:
88 class Interval;
89
90 // Remove dead intervals from the active list
91 void expire(unsigned int curIndex);
92
93 // These two methods wrap the interactions with the free pool
Robert Phillips715d08c2018-07-18 13:56:48 -040094 void recycleSurface(sk_sp<GrSurface> surface);
Robert Phillipseafd48a2017-11-16 07:52:08 -050095 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil);
Robert Phillips5af44de2017-07-18 14:49:38 -040096
Robert Phillips57aa3672017-07-21 11:38:13 -040097 struct FreePoolTraits {
98 static const GrScratchKey& GetKey(const GrSurface& s) {
99 return s.resourcePriv().getScratchKey();
100 }
Robert Phillips5af44de2017-07-18 14:49:38 -0400101
Robert Phillips57aa3672017-07-21 11:38:13 -0400102 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500103 static void OnFree(GrSurface* s) { s->unref(); }
Robert Phillips5af44de2017-07-18 14:49:38 -0400104 };
Robert Phillips57aa3672017-07-21 11:38:13 -0400105 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
106
Robert Phillips5af44de2017-07-18 14:49:38 -0400107 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
108
109 class Interval {
110 public:
111 Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end)
112 : fProxy(proxy)
113 , fProxyID(proxy->uniqueID().asUInt())
114 , fStart(start)
115 , fEnd(end)
116 , fNext(nullptr) {
117 SkASSERT(proxy);
Robert Phillipsda1be462018-07-27 07:18:06 -0400118#if GR_TRACK_INTERVAL_CREATION
119 fUniqueID = CreateUniqueID();
120 SkDebugf("New intvl %d: proxyID: %d [ %d, %d ]\n",
121 fUniqueID, proxy->uniqueID().asUInt(), start, end);
122#endif
Robert Phillips5af44de2017-07-18 14:49:38 -0400123 }
124
Robert Phillips8186cbe2017-11-01 17:32:39 -0400125 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
126 SkASSERT(proxy);
127
128 fProxy = proxy;
129 fProxyID = proxy->uniqueID().asUInt();
130 fStart = start;
131 fEnd = end;
132 fNext = nullptr;
Robert Phillipsda1be462018-07-27 07:18:06 -0400133#if GR_TRACK_INTERVAL_CREATION
134 fUniqueID = CreateUniqueID();
135 SkDebugf("New intvl %d: proxyID: %d [ %d, %d ]\n",
136 fUniqueID, proxy->uniqueID().asUInt(), start, end);
137#endif
Robert Phillips8186cbe2017-11-01 17:32:39 -0400138 }
139
Robert Phillips5b65a842017-11-13 15:48:12 -0500140 ~Interval() {
141 SkASSERT(!fAssignedSurface);
142 }
143
Robert Phillipsf8e25022017-11-08 15:24:31 -0500144 const GrSurfaceProxy* proxy() const { return fProxy; }
145 GrSurfaceProxy* proxy() { return fProxy; }
146 unsigned int start() const { return fStart; }
147 unsigned int end() const { return fEnd; }
148 const Interval* next() const { return fNext; }
149 Interval* next() { return fNext; }
150
151 void setNext(Interval* next) { fNext = next; }
152
153 void extendEnd(unsigned int newEnd) {
Chris Dalton8816b932017-11-29 16:48:25 -0700154 if (newEnd > fEnd) {
155 fEnd = newEnd;
Robert Phillipsda1be462018-07-27 07:18:06 -0400156#if GR_TRACK_INTERVAL_CREATION
157 SkDebugf("intvl %d: extending from %d to %d\n", fUniqueID, fEnd, newEnd);
158#endif
Chris Dalton8816b932017-11-29 16:48:25 -0700159 }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500160 }
161
Robert Phillips5b65a842017-11-13 15:48:12 -0500162 void assign(sk_sp<GrSurface>);
Ben Wagner5d1adbf2018-05-28 13:35:39 -0400163 bool wasAssignedSurface() const { return fAssignedSurface != nullptr; }
Robert Phillips5b65a842017-11-13 15:48:12 -0500164 sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); }
165
Robert Phillips5af44de2017-07-18 14:49:38 -0400166 // for SkTDynamicHash
167 static const uint32_t& GetKey(const Interval& intvl) {
168 return intvl.fProxyID;
169 }
170 static uint32_t Hash(const uint32_t& key) { return key; }
171
Robert Phillipsf8e25022017-11-08 15:24:31 -0500172 private:
Robert Phillips5b65a842017-11-13 15:48:12 -0500173 sk_sp<GrSurface> fAssignedSurface;
174 GrSurfaceProxy* fProxy;
175 uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key
176 unsigned int fStart;
177 unsigned int fEnd;
178 Interval* fNext;
Robert Phillipsda1be462018-07-27 07:18:06 -0400179
180#if GR_TRACK_INTERVAL_CREATION
181 uint32_t fUniqueID;
182
183 uint32_t CreateUniqueID();
184#endif
Robert Phillips5af44de2017-07-18 14:49:38 -0400185 };
186
187 class IntervalList {
188 public:
189 IntervalList() = default;
190 ~IntervalList() {
Robert Phillips8186cbe2017-11-01 17:32:39 -0400191 // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
192 // Since the arena allocator will clean up for us we don't bother here.
Robert Phillips5af44de2017-07-18 14:49:38 -0400193 }
194
195 bool empty() const { return !SkToBool(fHead); }
196 const Interval* peekHead() const { return fHead; }
197 Interval* popHead();
198 void insertByIncreasingStart(Interval*);
199 void insertByIncreasingEnd(Interval*);
Robert Phillips4150eea2018-02-07 17:08:21 -0500200 Interval* detachAll();
Robert Phillips5af44de2017-07-18 14:49:38 -0400201
202 private:
203 Interval* fHead = nullptr;
204 };
205
Robert Phillips8186cbe2017-11-01 17:32:39 -0400206 // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
207 static const int kInitialArenaSize = 12 * sizeof(Interval);
208
Robert Phillipseafd48a2017-11-16 07:52:08 -0500209 GrResourceProvider* fResourceProvider;
210 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces
211 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID
Robert Phillips5af44de2017-07-18 14:49:38 -0400212
Robert Phillipseafd48a2017-11-16 07:52:08 -0500213 IntervalList fIntvlList; // All the intervals sorted by increasing start
214 IntervalList fActiveIntvls; // List of live intervals during assignment
215 // (sorted by increasing end)
Robert Phillips51b20f22017-12-01 15:32:35 -0500216 unsigned int fNumOps = 1; // op # 0 is reserved for uploads at the start
217 // of a flush
Robert Phillipseafd48a2017-11-16 07:52:08 -0500218 SkTArray<unsigned int> fEndOfOpListOpIndices;
219 int fCurOpListIndex = 0;
Robert Phillips8186cbe2017-11-01 17:32:39 -0400220
Robert Phillipseafd48a2017-11-16 07:52:08 -0500221 SkDEBUGCODE(bool fAssigned = false;)
222
223 char fStorage[kInitialArenaSize];
224 SkArenaAlloc fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
225 Interval* fFreeIntervalList = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400226};
227
228#endif // GrResourceAllocator_DEFINED