blob: d7aed0591e872621f9d253db6dac9088319563f0 [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
42 unsigned int curOp() const { return fNumOps; }
43 void incOps() { fNumOps++; }
44 unsigned int numOps() const { return fNumOps; }
45
46 // Add a usage interval from start to end inclusive. This is usually used for renderTargets.
47 // If an existing interval already exists it will be expanded to include the new range.
48 void addInterval(GrSurfaceProxy*, unsigned int start, unsigned int end);
49
50 // Add an interval that spans just the current op. Usually this is for texture uses.
51 // If an existing interval already exists it will be expanded to include the new operation.
52 void addInterval(GrSurfaceProxy* proxy) {
53 this->addInterval(proxy, fNumOps, fNumOps);
54 }
55
56 void assign();
57
58private:
59 class Interval;
60
61 // Remove dead intervals from the active list
62 void expire(unsigned int curIndex);
63
64 // These two methods wrap the interactions with the free pool
65 void freeUpSurface(GrSurface* surface);
Robert Phillipsd375dbf2017-09-14 12:45:25 -040066 sk_sp<GrSurface> findSurfaceFor(const GrSurfaceProxy* proxy);
Robert Phillips5af44de2017-07-18 14:49:38 -040067
Robert Phillips57aa3672017-07-21 11:38:13 -040068 struct FreePoolTraits {
69 static const GrScratchKey& GetKey(const GrSurface& s) {
70 return s.resourcePriv().getScratchKey();
71 }
Robert Phillips5af44de2017-07-18 14:49:38 -040072
Robert Phillips57aa3672017-07-21 11:38:13 -040073 static uint32_t Hash(const GrScratchKey& key) { return key.hash(); }
Robert Phillipsf8e25022017-11-08 15:24:31 -050074 static void OnFree(GrSurface* s) { s->unref(); }
Robert Phillips5af44de2017-07-18 14:49:38 -040075 };
Robert Phillips57aa3672017-07-21 11:38:13 -040076 typedef SkTMultiMap<GrSurface, GrScratchKey, FreePoolTraits> FreePoolMultiMap;
77
Robert Phillips5af44de2017-07-18 14:49:38 -040078 typedef SkTDynamicHash<Interval, unsigned int> IntvlHash;
79
80 class Interval {
81 public:
82 Interval(GrSurfaceProxy* proxy, unsigned int start, unsigned int end)
83 : fProxy(proxy)
84 , fProxyID(proxy->uniqueID().asUInt())
85 , fStart(start)
86 , fEnd(end)
87 , fNext(nullptr) {
88 SkASSERT(proxy);
89 }
90
Robert Phillips8186cbe2017-11-01 17:32:39 -040091 void resetTo(GrSurfaceProxy* proxy, unsigned int start, unsigned int end) {
92 SkASSERT(proxy);
93
94 fProxy = proxy;
95 fProxyID = proxy->uniqueID().asUInt();
96 fStart = start;
97 fEnd = end;
98 fNext = nullptr;
99 }
100
Robert Phillipsf8e25022017-11-08 15:24:31 -0500101 const GrSurfaceProxy* proxy() const { return fProxy; }
102 GrSurfaceProxy* proxy() { return fProxy; }
103 unsigned int start() const { return fStart; }
104 unsigned int end() const { return fEnd; }
105 const Interval* next() const { return fNext; }
106 Interval* next() { return fNext; }
107
108 void setNext(Interval* next) { fNext = next; }
109
110 void extendEnd(unsigned int newEnd) {
111 SkASSERT(newEnd >= fEnd);
112 fEnd = newEnd;
113 }
114
Robert Phillips5af44de2017-07-18 14:49:38 -0400115 // for SkTDynamicHash
116 static const uint32_t& GetKey(const Interval& intvl) {
117 return intvl.fProxyID;
118 }
119 static uint32_t Hash(const uint32_t& key) { return key; }
120
Robert Phillipsf8e25022017-11-08 15:24:31 -0500121 private:
Robert Phillips5af44de2017-07-18 14:49:38 -0400122 GrSurfaceProxy* fProxy;
Robert Phillips09dfc472017-09-13 15:25:47 -0400123 uint32_t fProxyID; // This is here b.c. DynamicHash requires a ref to the key
Robert Phillips5af44de2017-07-18 14:49:38 -0400124 unsigned int fStart;
125 unsigned int fEnd;
126 Interval* fNext;
127 };
128
129 class IntervalList {
130 public:
131 IntervalList() = default;
132 ~IntervalList() {
Robert Phillips8186cbe2017-11-01 17:32:39 -0400133 // The only time we delete an IntervalList is in the GrResourceAllocator dtor.
134 // Since the arena allocator will clean up for us we don't bother here.
Robert Phillips5af44de2017-07-18 14:49:38 -0400135 }
136
137 bool empty() const { return !SkToBool(fHead); }
138 const Interval* peekHead() const { return fHead; }
139 Interval* popHead();
140 void insertByIncreasingStart(Interval*);
141 void insertByIncreasingEnd(Interval*);
142
143 private:
144 Interval* fHead = nullptr;
145 };
146
Robert Phillips8186cbe2017-11-01 17:32:39 -0400147 // Gathered statistics indicate that 99% of flushes will be covered by <= 12 Intervals
148 static const int kInitialArenaSize = 12 * sizeof(Interval);
149
Robert Phillips5af44de2017-07-18 14:49:38 -0400150 GrResourceProvider* fResourceProvider;
Robert Phillips57aa3672017-07-21 11:38:13 -0400151 FreePoolMultiMap fFreePool; // Recently created/used GrSurfaces
Robert Phillips5af44de2017-07-18 14:49:38 -0400152 IntvlHash fIntvlHash; // All the intervals, hashed by proxyID
153
154 IntervalList fIntvlList; // All the intervals sorted by increasing start
155 IntervalList fActiveIntvls; // List of live intervals during assignment
156 // (sorted by increasing end)
157 unsigned int fNumOps = 0;
158 SkDEBUGCODE(bool fAssigned = false;)
Robert Phillips8186cbe2017-11-01 17:32:39 -0400159
160 char fStorage[kInitialArenaSize];
161 SkArenaAlloc fIntervalAllocator { fStorage, kInitialArenaSize, 0 };
162 Interval* fFreeIntervalList = nullptr;
Robert Phillips5af44de2017-07-18 14:49:38 -0400163};
164
165#endif // GrResourceAllocator_DEFINED