blob: 0030ed22313ce64909cb5864b4221de3e7ac7ba0 [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
Robert Phillipseafd48a2017-11-16 07:52:08 -050060 // Returns true when the opLists from 'startIndex' to 'stopIndex' should be executed;
61 // false when nothing remains to be executed.
62 // This is used to execute a portion of the queued opLists in order to reduce the total
63 // amount of GPU resources required.
64 bool assign(int* startIndex, int* stopIndex);
65
66 void markEndOfOpList(int opListIndex);
Robert Phillips5af44de2017-07-18 14:49:38 -040067
68private:
69 class Interval;
70
71 // Remove dead intervals from the active list
72 void expire(unsigned int curIndex);
73
74 // These two methods wrap the interactions with the free pool
Robert Phillips5b65a842017-11-13 15:48:12 -050075 void freeUpSurface(sk_sp<GrSurface> surface);
Robert Phillipseafd48a2017-11-16 07:52:08 -050076 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy, bool needsStencil);
Robert Phillips5af44de2017-07-18 14:49:38 -040077
Robert Phillips57aa3672017-07-21 11:38:13 -040078 struct FreePoolTraits {
79 static const GrScratchKey& GetKey(const GrSurface& s) {
80 return s.resourcePriv().getScratchKey();
81 }
Robert Phillips5af44de2017-07-18 14:49:38 -040082
Robert Phillips57aa3672017-07-21 11:38:13 -040083 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
Robert Phillipsf8e25022017-11-08 15:24:31 -050084 static void OnFree(GrSurface* s) { s->unref(); }
Robert Phillips5af44de2017-07-18 14:49:38 -040085 };
Robert Phillips57aa3672017-07-21 11:38:13 -040086 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
87
Robert Phillips5af44de2017-07-18 14:49:38 -040088 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
89
90 class Interval {
91 public:
92 Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end)
93 : fProxy(proxy)
94 , fProxyID(proxy->uniqueID().asUInt())
95 , fStart(start)
96 , fEnd(end)
97 , fNext(nullptr) {
98 SkASSERT(proxy);
99 }
100
Robert Phillips8186cbe2017-11-01 17:32:39 -0400101 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
102 SkASSERT(proxy);
103
104 fProxy = proxy;
105 fProxyID = proxy->uniqueID().asUInt();
106 fStart = start;
107 fEnd = end;
108 fNext = nullptr;
109 }
110
Robert Phillips5b65a842017-11-13 15:48:12 -0500111 ~Interval() {
112 SkASSERT(!fAssignedSurface);
113 }
114
Robert Phillipsf8e25022017-11-08 15:24:31 -0500115 const GrSurfaceProxy* proxy() const { return fProxy; }
116 GrSurfaceProxy* proxy() { return fProxy; }
117 unsigned int start() const { return fStart; }
118 unsigned int end() const { return fEnd; }
119 const Interval* next() const { return fNext; }
120 Interval* next() { return fNext; }
121
122 void setNext(Interval* next) { fNext = next; }
123
124 void extendEnd(unsigned int newEnd) {
Chris Dalton8816b932017-11-29 16:48:25 -0700125 if (newEnd > fEnd) {
126 fEnd = newEnd;
127 }
Robert Phillipsf8e25022017-11-08 15:24:31 -0500128 }
129
Robert Phillips5b65a842017-11-13 15:48:12 -0500130 void assign(sk_sp<GrSurface>);
131 bool wasAssignedSurface() const { return fAssignedSurface; }
132 sk_sp<GrSurface> detachSurface() { return std::move(fAssignedSurface); }
133
Robert Phillips5af44de2017-07-18 14:49:38 -0400134 // for SkTDynamicHash
135 static const uint32_t& GetKey(const Interval& intvl) {
136 return intvl.fProxyID;
137 }
138 static uint32_t Hash(const uint32_t& key) { return key; }
139
Robert Phillipsf8e25022017-11-08 15:24:31 -0500140 private:
Robert Phillips5b65a842017-11-13 15:48:12 -0500141 sk_sp<GrSurface> fAssignedSurface;
142 GrSurfaceProxy* fProxy;
143 uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key
144 unsigned int fStart;
145 unsigned int fEnd;
146 Interval* fNext;
Robert Phillips5af44de2017-07-18 14:49:38 -0400147 };
148
149 class IntervalList {
150 public:
151 IntervalList() = default;
152 ~IntervalList() {
Robert Phillips8186cbe2017-11-01 17:32:39 -0400153 // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
154 // Since the arena allocator will clean up for us we don't bother here.
Robert Phillips5af44de2017-07-18 14:49:38 -0400155 }
156
157 bool empty() const { return !SkToBool(fHead); }
158 const Interval* peekHead() const { return fHead; }
159 Interval* popHead();
160 void insertByIncreasingStart(Interval*);
161 void insertByIncreasingEnd(Interval*);
162
163 private:
164 Interval* fHead = nullptr;
165 };
166
Robert Phillips8186cbe2017-11-01 17:32:39 -0400167 // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
168 static const int kInitialArenaSize = 12 * sizeof(Interval);
169
Robert Phillipseafd48a2017-11-16 07:52:08 -0500170 GrResourceProvider* fResourceProvider;
171 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces
172 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID
Robert Phillips5af44de2017-07-18 14:49:38 -0400173
Robert Phillipseafd48a2017-11-16 07:52:08 -0500174 IntervalList fIntvlList; // All the intervals sorted by increasing start
175 IntervalList fActiveIntvls; // List of live intervals during assignment
176 // (sorted by increasing end)
177 unsigned int fNumOps = 0;
178 SkTArray<unsigned int> fEndOfOpListOpIndices;
179 int fCurOpListIndex = 0;
Robert Phillips8186cbe2017-11-01 17:32:39 -0400180
Robert Phillipseafd48a2017-11-16 07:52:08 -0500181 SkDEBUGCODE(bool fAssigned = false;)
182
183 char fStorage[kInitialArenaSize];
184 SkArenaAlloc fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
185 Interval* fFreeIntervalList = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400186};
187
188#endif // GrResourceAllocator_DEFINED