blob: 427ff327cb12c632c66a7cec24bc3463908ec129 [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
22/*
23 * The ResourceAllocator explicitly distributes GPU resources at flush time. It operates by
24 * being given the usage intervals of the various proxies. It keeps these intervals in a singly
25 * linked list sorted by increasing start index. (It also maintains a hash table from proxyID
26 * to interval to find proxy reuse). When it comes time to allocate the resources it
27 * traverses the sorted list and:
28 * removes intervals from the active list that have completed (returning their GrSurfaces
29 * to the free pool)
30
31 * allocates a new resource (preferably from the free pool) for the new interval
32 * adds the new interval to the active list (that is sorted by increasing end index)
33 *
34 * Note: the op indices (used in the usage intervals) come from the order of the ops in
35 * their opLists after the opList DAG has been linearized.
36 */
37class GrResourceAllocator {
38public:
39 GrResourceAllocator(GrResourceProvider* resourceProvider)
40 : fResourceProvider(resourceProvider) {
41 }
42
Robert Phillips5b65a842017-11-13 15:48:12 -050043 ~GrResourceAllocator();
44
Robert Phillips5af44de2017-07-18 14:49:38 -040045 unsigned int curOp() const { return fNumOps; }
46 void incOps() { fNumOps++; }
47 unsigned int numOps() const { return fNumOps; }
48
Robert Phillipseafd48a2017-11-16 07:52:08 -050049 // Add a usage interval from 'start' to 'end' inclusive. This is usually used for renderTargets.
Robert Phillips5af44de2017-07-18 14:49:38 -040050 // If an existing interval already exists it will be expanded to include the new range.
Chris Dalton8816b932017-11-29 16:48:25 -070051 void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end
52 SkDEBUGCODE(, bool isDirectDstRead = false));
Robert Phillips5af44de2017-07-18 14:49:38 -040053
54 // Add an interval that spans just the current op. Usually this is for texture uses.
55 // If an existing interval already exists it will be expanded to include the new operation.
Chris Dalton8816b932017-11-29 16:48:25 -070056 void addInterval(GrSurfaceProxy* proxy
57 SkDEBUGCODE(, bool isDirectDstRead = false)) {
58 this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead));
Robert Phillips5af44de2017-07-18 14:49:38 -040059 }
60
Greg Danielaa3dfbe2018-01-29 10:34:25 -050061 enum class AssignError {
62 kNoError,
63 kFailedProxyInstantiation
64 };
65
Robert Phillipseafd48a2017-11-16 07:52:08 -050066 // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
67 // false when nothing remains to be executed.
Greg Danielaa3dfbe2018-01-29 10:34:25 -050068 // If any proxy fails to instantiate, the AssignError will be set to kFailedProxyInstantiation.
69 // If this happens, the caller should remove all ops which reference an uninstantiated proxy.
Robert Phillipseafd48a2017-11-16 07:52:08 -050070 // This is used to execute a portion of the queued opLists in order to reduce the total
71 // amount of GPU resources required.
Greg Daniel4684f822018-03-08 15:27:36 -050072 bool assign(int* startIndex, int* stopIndex, GrUninstantiateProxyTracker*,
73 AssignError* outError);
Robert Phillipseafd48a2017-11-16 07:52:08 -050074
75 void markEndOfOpList(int opListIndex);
Robert Phillips5af44de2017-07-18 14:49:38 -040076
77private:
78 class Interval;
79
80 // Remove dead intervals from the active list
81 void expire(unsigned int curIndex);
82
83 // These two methods wrap the interactions with the free pool
Robert Phillips5b65a842017-11-13 15:48:12 -050084 void freeUpSurface(sk_sp<GrSurface> surface);
Robert Phillipseafd48a2017-11-16 07:52:08 -050085 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil);
Robert Phillips5af44de2017-07-18 14:49:38 -040086
Robert Phillips57aa3672017-07-21 11:38:13 -040087 struct FreePoolTraits {
88 static const GrScratchKey& GetKey(const GrSurface& s) {
89 return s.resourcePriv().getScratchKey();
90 }
Robert Phillips5af44de2017-07-18 14:49:38 -040091
Robert Phillips57aa3672017-07-21 11:38:13 -040092 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
Robert Phillipsf8e25022017-11-08 15:24:31 -050093 static void OnFree(GrSurface* s) { s->unref(); }
Robert Phillips5af44de2017-07-18 14:49:38 -040094 };
Robert Phillips57aa3672017-07-21 11:38:13 -040095 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
96
Robert Phillips5af44de2017-07-18 14:49:38 -040097 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
98
99 class Interval {
100 public:
101 Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end)
102 : fProxy(proxy)
103 , fProxyID(proxy->uniqueID().asUInt())
104 , fStart(start)
105 , fEnd(end)
106 , fNext(nullptr) {
107 SkASSERT(proxy);
108 }
109
Robert Phillips8186cbe2017-11-01 17:32:39 -0400110 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
111 SkASSERT(proxy);
112
113 fProxy = proxy;
114 fProxyID = proxy->uniqueID().asUInt();
115 fStart = start;
116 fEnd = end;
117 fNext = nullptr;
118 }
119
Robert Phillips5b65a842017-11-13 15:48:12 -0500120 ~Interval() {
121 SkASSERT(!fAssignedSurface);
122 }
123
Robert Phillipsf8e25022017-11-08 15:24:31 -0500124 const GrSurfaceProxy* proxy() const { return fProxy; }
125 GrSurfaceProxy* proxy() { return fProxy; }
126 unsigned int start() const { return fStart; }
127 unsigned int end() const { return fEnd; }
128 const Interval* next() const { return fNext; }
129 Interval* next() { return fNext; }
130
131 void setNext(Interval* next) { fNext = next; }
132
133 void extendEnd(unsigned int newEnd) {
Chris Dalton8816b932017-11-29 16:48:25 -0700134 if (newEnd > fEnd) {
135 fEnd = newEnd;
136 }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500137 }
138
Robert Phillips5b65a842017-11-13 15:48:12 -0500139 void assign(sk_sp<GrSurface>);
140 bool wasAssignedSurface() const { return fAssignedSurface; }
141 sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); }
142
Robert Phillips5af44de2017-07-18 14:49:38 -0400143 // for SkTDynamicHash
144 static const uint32_t& GetKey(const Interval& intvl) {
145 return intvl.fProxyID;
146 }
147 static uint32_t Hash(const uint32_t& key) { return key; }
148
Robert Phillipsf8e25022017-11-08 15:24:31 -0500149 private:
Robert Phillips5b65a842017-11-13 15:48:12 -0500150 sk_sp<GrSurface> fAssignedSurface;
151 GrSurfaceProxy* fProxy;
152 uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key
153 unsigned int fStart;
154 unsigned int fEnd;
155 Interval* fNext;
Robert Phillips5af44de2017-07-18 14:49:38 -0400156 };
157
158 class IntervalList {
159 public:
160 IntervalList() = default;
161 ~IntervalList() {
Robert Phillips8186cbe2017-11-01 17:32:39 -0400162 // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
163 // Since the arena allocator will clean up for us we don't bother here.
Robert Phillips5af44de2017-07-18 14:49:38 -0400164 }
165
166 bool empty() const { return !SkToBool(fHead); }
167 const Interval* peekHead() const { return fHead; }
168 Interval* popHead();
169 void insertByIncreasingStart(Interval*);
170 void insertByIncreasingEnd(Interval*);
Robert Phillips4150eea2018-02-07 17:08:21 -0500171 Interval* detachAll();
Robert Phillips5af44de2017-07-18 14:49:38 -0400172
173 private:
174 Interval* fHead = nullptr;
175 };
176
Robert Phillips8186cbe2017-11-01 17:32:39 -0400177 // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
178 static const int kInitialArenaSize = 12 * sizeof(Interval);
179
Robert Phillipseafd48a2017-11-16 07:52:08 -0500180 GrResourceProvider* fResourceProvider;
181 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces
182 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID
Robert Phillips5af44de2017-07-18 14:49:38 -0400183
Robert Phillipseafd48a2017-11-16 07:52:08 -0500184 IntervalList fIntvlList; // All the intervals sorted by increasing start
185 IntervalList fActiveIntvls; // List of live intervals during assignment
186 // (sorted by increasing end)
Robert Phillips51b20f22017-12-01 15:32:35 -0500187 unsigned int fNumOps = 1; // op # 0 is reserved for uploads at the start
188 // of a flush
Robert Phillipseafd48a2017-11-16 07:52:08 -0500189 SkTArray<unsigned int> fEndOfOpListOpIndices;
190 int fCurOpListIndex = 0;
Robert Phillips8186cbe2017-11-01 17:32:39 -0400191
Robert Phillipseafd48a2017-11-16 07:52:08 -0500192 SkDEBUGCODE(bool fAssigned = false;)
193
194 char fStorage[kInitialArenaSize];
195 SkArenaAlloc fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
196 Interval* fFreeIntervalList = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400197};
198
199#endif // GrResourceAllocator_DEFINED