Chromium Code Reviews| 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 |