blob: f25bef309e135e906aa71e37d0fd65a705713a3b [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;
20
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
30 * allocates a new resource (preferably from the free pool) for the new interval
31 * adds the new interval to the active list (that is sorted by increasing end index)
32 *
33 * Note: the op indices (used in the usage intervals) come from the order of the ops in
34 * their opLists after the opList DAG has been linearized.
35 */
36class GrResourceAllocator {
37public:
38 GrResourceAllocator(GrResourceProvider* resourceProvider)
39 : fResourceProvider(resourceProvider) {
40 }
41
Robert Phillips5b65a842017-11-13 15:48:12 -050042 ~GrResourceAllocator();
43
Robert Phillips5af44de2017-07-18 14:49:38 -040044 unsigned int curOp() const { return fNumOps; }
45 void incOps() { fNumOps++; }
46 unsigned int numOps() const { return fNumOps; }
47
Robert Phillipseafd48a2017-11-16 07:52:08 -050048 // Add a usage interval from 'start' to 'end' inclusive. This is usually used for renderTargets.
Robert Phillips5af44de2017-07-18 14:49:38 -040049 // If an existing interval already exists it will be expanded to include the new range.
Chris Dalton8816b932017-11-29 16:48:25 -070050 void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end
51 SkDEBUGCODE(, bool isDirectDstRead = false));
Robert Phillips5af44de2017-07-18 14:49:38 -040052
53 // Add an interval that spans just the current op. Usually this is for texture uses.
54 // If an existing interval already exists it will be expanded to include the new operation.
Chris Dalton8816b932017-11-29 16:48:25 -070055 void addInterval(GrSurfaceProxy* proxy
56 SkDEBUGCODE(, bool isDirectDstRead = false)) {
57 this->addInterval(proxy, fNumOps, fNumOps SkDEBUGCODE(, isDirectDstRead));
Robert Phillips5af44de2017-07-18 14:49:38 -040058 }
59
Greg Danielaa3dfbe2018-01-29 10:34:25 -050060 enum class AssignError {
61 kNoError,
62 kFailedProxyInstantiation
63 };
64
Robert Phillipseafd48a2017-11-16 07:52:08 -050065 // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
66 // false when nothing remains to be executed.
Greg Danielaa3dfbe2018-01-29 10:34:25 -050067 // If any proxy fails to instantiate, the AssignError will be set to kFailedProxyInstantiation.
68 // If this happens, the caller should remove all ops which reference an uninstantiated proxy.
Robert Phillipseafd48a2017-11-16 07:52:08 -050069 // This is used to execute a portion of the queued opLists in order to reduce the total
70 // amount of GPU resources required.
Greg Danielaa3dfbe2018-01-29 10:34:25 -050071 bool assign(int* startIndex, int* stopIndex, AssignError* outError);
Robert Phillipseafd48a2017-11-16 07:52:08 -050072
73 void markEndOfOpList(int opListIndex);
Robert Phillips5af44de2017-07-18 14:49:38 -040074
75private:
76 class Interval;
77
78 // Remove dead intervals from the active list
79 void expire(unsigned int curIndex);
80
81 // These two methods wrap the interactions with the free pool
Robert Phillips5b65a842017-11-13 15:48:12 -050082 void freeUpSurface(sk_sp<GrSurface> surface);
Robert Phillipseafd48a2017-11-16 07:52:08 -050083 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil);
Robert Phillips5af44de2017-07-18 14:49:38 -040084
Robert Phillips57aa3672017-07-21 11:38:13 -040085 struct FreePoolTraits {
86 static const GrScratchKey& GetKey(const GrSurface& s) {
87 return s.resourcePriv().getScratchKey();
88 }
Robert Phillips5af44de2017-07-18 14:49:38 -040089
Robert Phillips57aa3672017-07-21 11:38:13 -040090 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
Robert Phillipsf8e25022017-11-08 15:24:31 -050091 static void OnFree(GrSurface* s) { s->unref(); }
Robert Phillips5af44de2017-07-18 14:49:38 -040092 };
Robert Phillips57aa3672017-07-21 11:38:13 -040093 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
94
Robert Phillips5af44de2017-07-18 14:49:38 -040095 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
96
97 class Interval {
98 public:
99 Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end)
100 : fProxy(proxy)
101 , fProxyID(proxy->uniqueID().asUInt())
102 , fStart(start)
103 , fEnd(end)
104 , fNext(nullptr) {
105 SkASSERT(proxy);
106 }
107
Robert Phillips8186cbe2017-11-01 17:32:39 -0400108 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
109 SkASSERT(proxy);
110
111 fProxy = proxy;
112 fProxyID = proxy->uniqueID().asUInt();
113 fStart = start;
114 fEnd = end;
115 fNext = nullptr;
116 }
117
Robert Phillips5b65a842017-11-13 15:48:12 -0500118 ~Interval() {
119 SkASSERT(!fAssignedSurface);
120 }
121
Robert Phillipsf8e25022017-11-08 15:24:31 -0500122 const GrSurfaceProxy* proxy() const { return fProxy; }
123 GrSurfaceProxy* proxy() { return fProxy; }
124 unsigned int start() const { return fStart; }
125 unsigned int end() const { return fEnd; }
126 const Interval* next() const { return fNext; }
127 Interval* next() { return fNext; }
128
129 void setNext(Interval* next) { fNext = next; }
130
131 void extendEnd(unsigned int newEnd) {
Chris Dalton8816b932017-11-29 16:48:25 -0700132 if (newEnd > fEnd) {
133 fEnd = newEnd;
134 }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500135 }
136
Robert Phillips5b65a842017-11-13 15:48:12 -0500137 void assign(sk_sp<GrSurface>);
138 bool wasAssignedSurface() const { return fAssignedSurface; }
139 sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); }
140
Robert Phillips5af44de2017-07-18 14:49:38 -0400141 // for SkTDynamicHash
142 static const uint32_t& GetKey(const Interval& intvl) {
143 return intvl.fProxyID;
144 }
145 static uint32_t Hash(const uint32_t& key) { return key; }
146
Robert Phillipsf8e25022017-11-08 15:24:31 -0500147 private:
Robert Phillips5b65a842017-11-13 15:48:12 -0500148 sk_sp<GrSurface> fAssignedSurface;
149 GrSurfaceProxy* fProxy;
150 uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key
151 unsigned int fStart;
152 unsigned int fEnd;
153 Interval* fNext;
Robert Phillips5af44de2017-07-18 14:49:38 -0400154 };
155
156 class IntervalList {
157 public:
158 IntervalList() = default;
159 ~IntervalList() {
Robert Phillips8186cbe2017-11-01 17:32:39 -0400160 // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
161 // Since the arena allocator will clean up for us we don't bother here.
Robert Phillips5af44de2017-07-18 14:49:38 -0400162 }
163
164 bool empty() const { return !SkToBool(fHead); }
165 const Interval* peekHead() const { return fHead; }
166 Interval* popHead();
167 void insertByIncreasingStart(Interval*);
168 void insertByIncreasingEnd(Interval*);
Robert Phillips4150eea2018-02-07 17:08:21 -0500169 Interval* detachAll();
Robert Phillips5af44de2017-07-18 14:49:38 -0400170
171 private:
172 Interval* fHead = nullptr;
173 };
174
Robert Phillips8186cbe2017-11-01 17:32:39 -0400175 // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
176 static const int kInitialArenaSize = 12 * sizeof(Interval);
177
Robert Phillipseafd48a2017-11-16 07:52:08 -0500178 GrResourceProvider* fResourceProvider;
179 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces
180 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID
Robert Phillips5af44de2017-07-18 14:49:38 -0400181
Robert Phillipseafd48a2017-11-16 07:52:08 -0500182 IntervalList fIntvlList; // All the intervals sorted by increasing start
183 IntervalList fActiveIntvls; // List of live intervals during assignment
184 // (sorted by increasing end)
Robert Phillips51b20f22017-12-01 15:32:35 -0500185 unsigned int fNumOps = 1; // op # 0 is reserved for uploads at the start
186 // of a flush
Robert Phillipseafd48a2017-11-16 07:52:08 -0500187 SkTArray<unsigned int> fEndOfOpListOpIndices;
188 int fCurOpListIndex = 0;
Robert Phillips8186cbe2017-11-01 17:32:39 -0400189
Robert Phillipseafd48a2017-11-16 07:52:08 -0500190 SkDEBUGCODE(bool fAssigned = false;)
191
192 char fStorage[kInitialArenaSize];
193 SkArenaAlloc fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
194 Interval* fFreeIntervalList = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400195};
196
197#endif // GrResourceAllocator_DEFINED