blob: 76abe1855cbe681fad9b15b90179278dc8529d03 [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#include "GrResourceAllocator.h"
9
10#include "GrSurfaceProxy.h"
11#include "GrSurfaceProxyPriv.h"
12
13void GrResourceAllocator::addInterval(GrSurfaceProxy* proxy,
14 unsigned int start, unsigned int end) {
15 SkASSERT(start <= end);
16 SkASSERT(!fAssigned); // We shouldn't be adding any intervals after (or during) assignment
17
18 if (Interval* intvl = fIntvlHash.find(proxy->uniqueID().asUInt())) {
19 // Revise the interval for an existing use
20 SkASSERT(intvl->fEnd < start);
21 intvl->fEnd = end;
22 return;
23 }
24
25 // TODO: given the usage pattern an arena allocation scheme would work well here
26 Interval* newIntvl = new Interval(proxy, start, end);
27
28 fIntvlList.insertByIncreasingStart(newIntvl);
29 fIntvlHash.add(newIntvl);
30}
31
32GrResourceAllocator::Interval* GrResourceAllocator::IntervalList::popHead() {
33 Interval* temp = fHead;
34 if (temp) {
35 fHead = temp->fNext;
36 }
37 return temp;
38}
39
40// TODO: fuse this with insertByIncreasingEnd
41void GrResourceAllocator::IntervalList::insertByIncreasingStart(Interval* intvl) {
42 if (!fHead) {
43 intvl->fNext = nullptr;
44 fHead = intvl;
45 } else if (intvl->fStart <= fHead->fStart) {
46 intvl->fNext = fHead;
47 fHead = intvl;
48 } else {
49 Interval* prev = fHead;
50 Interval* next = prev->fNext;
51 for (; next && intvl->fStart > next->fStart; prev = next, next = next->fNext) {
52 }
53 intvl->fNext = next;
54 prev->fNext = intvl;
55 }
56}
57
58// TODO: fuse this with insertByIncreasingStart
59void GrResourceAllocator::IntervalList::insertByIncreasingEnd(Interval* intvl) {
60 if (!fHead) {
61 intvl->fNext = nullptr;
62 fHead = intvl;
63 } else if (intvl->fEnd <= fHead->fEnd) {
64 intvl->fNext = fHead;
65 fHead = intvl;
66 } else {
67 Interval* prev = fHead;
68 Interval* next = prev->fNext;
69 for (; next && intvl->fEnd > next->fEnd; prev = next, next = next->fNext) {
70 }
71 intvl->fNext = next;
72 prev->fNext = intvl;
73 }
74}
75
76// 'surface' can be reused. Add it back to the free pool.
77void GrResourceAllocator::freeUpSurface(GrSurface* surface) {
Robert Phillips57aa3672017-07-21 11:38:13 -040078 const GrScratchKey &key = surface->resourcePriv().getScratchKey();
79
80 if (!key.isValid()) {
81 return; // can't do it w/o a valid scratch key
82 }
83
84 // TODO: fix this insertion so we get a more LRU-ish behavior
85 fFreePool.insert(key, surface);
Robert Phillips5af44de2017-07-18 14:49:38 -040086}
87
88// First try to reuse one of the recently allocated/used GrSurfaces in the free pool.
89// If we can't find a useable one, create a new one.
90// TODO: handle being overbudget
91sk_sp<GrSurface> GrResourceAllocator::findSurfaceFor(GrSurfaceProxy* proxy) {
Robert Phillips57aa3672017-07-21 11:38:13 -040092 // First look in the free pool
93 GrScratchKey key;
Robert Phillips5af44de2017-07-18 14:49:38 -040094
Robert Phillips57aa3672017-07-21 11:38:13 -040095 proxy->priv().computeScratchKey(&key);
96
97 GrSurface* surface = fFreePool.find(key);
98 if (surface) {
99 return sk_ref_sp(surface);
100 }
101
102 // Failing that, try to grab a new one from the resource cache
Robert Phillips5af44de2017-07-18 14:49:38 -0400103 return proxy->priv().createSurface(fResourceProvider);
104}
105
106// Remove any intervals that end before the current index. Return their GrSurfaces
107// to the free pool.
108void GrResourceAllocator::expire(unsigned int curIndex) {
109 while (!fActiveIntvls.empty() && fActiveIntvls.peekHead()->fEnd < curIndex) {
110 Interval* temp = fActiveIntvls.popHead();
111 this->freeUpSurface(temp->fProxy->priv().peekSurface());
112 delete temp;
113 }
114}
115
116void GrResourceAllocator::assign() {
117 fIntvlHash.reset(); // we don't need this anymore
118 SkDEBUGCODE(fAssigned = true;)
119
120 while (Interval* cur = fIntvlList.popHead()) {
121 this->expire(cur->fStart);
Robert Phillips57aa3672017-07-21 11:38:13 -0400122
123 if (cur->fProxy->priv().isInstantiated()) {
124 fActiveIntvls.insertByIncreasingEnd(cur);
125 continue;
126 }
127
Robert Phillips5af44de2017-07-18 14:49:38 -0400128 // TODO: add over budget handling here?
129 sk_sp<GrSurface> surface = this->findSurfaceFor(cur->fProxy);
130 if (surface) {
131 cur->fProxy->priv().assign(std::move(surface));
132 }
133 // TODO: handle resouce allocation failure upstack
134 fActiveIntvls.insertByIncreasingEnd(cur);
135 }
136}