OLD | NEW |
---|---|
(Empty) | |
1 | |
2 /* | |
3 * Copyright 2014 Google Inc. | |
4 * | |
5 * Use of this source code is governed by a BSD-style license that can be | |
6 * found in the LICENSE file. | |
bsalomon
2014/05/30 18:09:11
This file could really use some documentation.
| |
7 */ | |
8 | |
9 #include "GrGLNameAllocator.h" | |
10 | |
11 class GrGLNameAllocator::SparseNameRange { | |
12 public: | |
13 virtual ~SparseNameRange() {} | |
14 | |
15 GrGLuint first() const { return fFirst; } | |
16 GrGLuint end() const { return fEnd; } | |
17 GrGLuint height() const { return fHeight; } | |
18 | |
19 virtual SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* ou tName) = 0; | |
20 virtual SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange (GrGLuint* removedCount) = 0; | |
21 virtual GrGLuint appendNames(GrGLuint count) = 0; | |
22 | |
23 virtual SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) = 0; | |
24 | |
25 // Implement ref/unref without atomics. | |
26 SparseNameRange* ref() { | |
bsalomon
2014/05/30 18:09:11
Are these really frequently ref'ed and unref'ed?
Chris Dalton
2014/05/30 21:39:41
In theory it could. In practice it might not. I ca
bsalomon
2014/06/02 15:14:43
I'd prefer that. If we're going to tackle non-atom
| |
27 ++fRefCnt; | |
28 return this; | |
29 } | |
30 int unref() { | |
31 if (0 == --fRefCnt) { | |
32 SkDELETE(this); | |
33 return 0; | |
34 } | |
35 return fRefCnt; | |
36 } | |
37 | |
38 protected: | |
39 SparseNameRange() : fRefCnt(1) {} | |
40 | |
41 GrGLuint fFirst; | |
42 GrGLuint fEnd; | |
43 GrGLuint fHeight; | |
44 | |
45 private: | |
46 int fRefCnt; | |
47 }; | |
48 | |
49 class GrGLNameAllocator::SparseNameTree : public SparseNameRange { | |
50 public: | |
51 SparseNameTree(SparseNameRange* left, SparseNameRange* right) | |
52 : fLeft(left), | |
53 fRight(right) { | |
54 SkASSERT(fLeft.get()); | |
55 SkASSERT(fRight.get()); | |
56 this->updateStats(); | |
57 } | |
58 | |
59 virtual SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* ou tName) SK_OVERRIDE { | |
60 // Try allocating the range inside fLeft's internal gaps. | |
61 fLeft.reset(fLeft->internalAllocate(outName)); | |
62 if (0 != *outName) { | |
63 this->updateStats(); | |
64 return this->rebalance(); | |
65 } | |
66 | |
67 if (fLeft->end() + 1 == fRight->first()) { | |
68 // It closed the gap between fLeft and fRight; merge. | |
69 GrGLuint removedCount; | |
70 fRight.reset(fRight->removeLeftmostContiguousRange(&removedCount)); | |
71 *outName = fLeft->appendNames(1 + removedCount); | |
72 if (NULL == fRight.get()) { | |
73 return fLeft.detach(); | |
74 } | |
75 this->updateStats(); | |
76 return this->rebalance(); | |
77 } | |
78 | |
79 *outName = fLeft->appendNames(1); | |
80 return this->ref(); | |
81 } | |
82 | |
83 virtual SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange (GrGLuint* removedCount) SK_OVERRIDE { | |
84 fLeft.reset(fLeft->removeLeftmostContiguousRange(removedCount)); | |
85 if (NULL == fLeft) { | |
86 return fRight.detach(); | |
87 } | |
88 this->updateStats(); | |
89 return this->rebalance(); | |
90 } | |
91 | |
92 virtual GrGLuint SK_WARN_UNUSED_RESULT appendNames(GrGLuint count) SK_OVERRI DE { | |
93 SkASSERT(fEnd + count > fEnd); // Check for integer wrap. | |
94 GrGLuint name = fRight->appendNames(count); | |
95 SkASSERT(fRight->end() == fEnd + count); | |
96 this->updateStats(); | |
97 return name; | |
98 } | |
99 | |
100 virtual SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) SK_OVERRI DE { | |
101 if (name < fLeft->end()) { | |
102 fLeft.reset(fLeft->free(name)); | |
103 if (NULL == fLeft) { | |
104 // fLeft became empty after the free. | |
105 return fRight.detach(); | |
106 } | |
107 this->updateStats(); | |
108 return this->rebalance(); | |
109 } else { | |
110 SkASSERT(name >= fRight->first()); | |
111 fRight.reset(fRight->free(name)); | |
112 if (NULL == fRight) { | |
113 // fRight became empty after the free. | |
114 return fLeft.detach(); | |
115 } | |
116 this->updateStats(); | |
117 return this->rebalance(); | |
118 } | |
119 } | |
120 | |
121 protected: | |
122 typedef SkAutoTUnref<SparseNameRange> SparseNameTree::* ChildRange; | |
123 | |
124 SparseNameRange* SK_WARN_UNUSED_RESULT rebalance() { | |
125 if (fLeft->height() > fRight->height() + 1) { | |
126 return this->rebalanceImpl<&SparseNameTree::fLeft, &SparseNameTree:: fRight>(); | |
127 } | |
128 if (fRight->height() > fLeft->height() + 1) { | |
129 return this->rebalanceImpl<&SparseNameTree::fRight, &SparseNameTree: :fLeft>(); | |
130 } | |
131 return this->ref(); | |
132 } | |
133 | |
134 template<ChildRange Tall, ChildRange Short> | |
135 SparseNameRange* SK_WARN_UNUSED_RESULT rebalanceImpl() { | |
136 // We should be calling rebalance() enough that the tree never gets more | |
137 // than one rotation off balance. | |
138 SkASSERT(2 == (this->*Tall)->height() - (this->*Short)->height()); | |
139 SparseNameTree* tallChild = static_cast<SparseNameTree*>((this->*Tall).g et()); | |
140 if ((tallChild->*Tall)->height() < (tallChild->*Short)->height()) { | |
141 (this->*Tall).reset(tallChild->rotate<Short, Tall>()); | |
142 } | |
143 return this->rotate<Tall, Short>(); | |
144 } | |
145 | |
146 template<ChildRange Tall, ChildRange Short> | |
147 SparseNameRange* SK_WARN_UNUSED_RESULT rotate() { | |
148 SparseNameTree* newRoot = static_cast<SparseNameTree*>((this->*Tall).det ach()); | |
149 | |
150 (this->*Tall).reset((newRoot->*Short).detach()); | |
151 this->updateStats(); | |
152 | |
153 (newRoot->*Short).reset(this->ref()); | |
154 newRoot->updateStats(); | |
155 | |
156 return newRoot; | |
157 } | |
158 | |
159 void updateStats() { | |
160 SkASSERT(fLeft->end() < fRight->first()); // There must be a gap between left and right. | |
161 fFirst = fLeft->first(); | |
162 fEnd = fRight->end(); | |
163 fHeight = 1 + SkMax32(fLeft->height(), fRight->height()); | |
164 } | |
165 | |
166 private: | |
167 SkAutoTUnref<SparseNameRange> fLeft; | |
168 SkAutoTUnref<SparseNameRange> fRight; | |
169 }; | |
170 | |
171 class GrGLNameAllocator::ContiguousNameRange : public SparseNameRange { | |
172 public: | |
173 ContiguousNameRange(GrGLuint first, GrGLuint end) { | |
174 SkASSERT(first < end); | |
175 fFirst = first; | |
176 fEnd = end; | |
177 fHeight = 0; | |
178 } | |
179 | |
180 virtual SparseNameRange* SK_WARN_UNUSED_RESULT internalAllocate(GrGLuint* ou tName) SK_OVERRIDE { | |
181 *outName = 0; // No internal gaps, we are contiguous. | |
182 return this->ref(); | |
183 } | |
184 | |
185 virtual SparseNameRange* SK_WARN_UNUSED_RESULT removeLeftmostContiguousRange (GrGLuint* removedCount) SK_OVERRIDE { | |
186 *removedCount = fEnd - fFirst; | |
187 return NULL; | |
188 } | |
189 | |
190 virtual GrGLuint SK_WARN_UNUSED_RESULT appendNames(GrGLuint count) SK_OVERRI DE { | |
191 SkASSERT(fEnd + count > fEnd); // Check for integer wrap. | |
192 GrGLuint name = fEnd; | |
193 fEnd += count; | |
194 return name; | |
195 } | |
196 | |
197 virtual SparseNameRange* SK_WARN_UNUSED_RESULT free(GrGLuint name) SK_OVERRI DE { | |
198 SkASSERT(name >= fFirst); | |
199 SkASSERT(name < fEnd); | |
200 | |
201 if (fFirst == name) { | |
202 ++fFirst; | |
203 return (fEnd == fFirst) ? NULL : this->ref(); | |
204 } | |
205 | |
206 if (fEnd == name + 1) { | |
207 --fEnd; | |
208 return this->ref(); | |
209 } | |
210 | |
211 SparseNameRange* left = SkNEW_ARGS(ContiguousNameRange, (fFirst, name)); | |
212 SparseNameRange* right = this->ref(); | |
213 fFirst = name + 1; | |
214 return SkNEW_ARGS(SparseNameTree, (left, right)); | |
215 } | |
216 }; | |
217 | |
218 GrGLNameAllocator::GrGLNameAllocator(GrGLuint names, GrGLuint range) | |
219 : fNames(names), | |
220 fRange(range) { | |
221 SkASSERT(range > 0); | |
222 } | |
223 | |
224 GrGLNameAllocator::~GrGLNameAllocator() { | |
225 } | |
226 | |
227 GrGLuint GrGLNameAllocator::allocateName() { | |
228 if (NULL == fAllocatedNames.get()) { | |
229 fAllocatedNames.reset(SkNEW_ARGS(ContiguousNameRange, (fNames, fNames + 1))); | |
230 return fNames; | |
231 } | |
232 | |
233 GrGLuint name; | |
234 fAllocatedNames.reset(fAllocatedNames->internalAllocate(&name)); | |
235 if (0 != name) { | |
236 return name; | |
237 } | |
238 | |
239 if (fAllocatedNames->end() >= fAllocatedNames->first() + fRange) { | |
240 // Out of names. | |
241 return 0; | |
242 } | |
243 | |
244 return fAllocatedNames->appendNames(1); | |
245 } | |
246 | |
247 void GrGLNameAllocator::freeName(GrGLuint name) { | |
248 SkASSERT(fAllocatedNames.get()); | |
249 SkASSERT(name >= fAllocatedNames->first()); | |
250 SkASSERT(name < fAllocatedNames->end()); // It is invalid to free not-alloca ted names. | |
251 | |
252 fAllocatedNames.reset(fAllocatedNames->free(name)); | |
253 } | |
OLD | NEW |