blob: 3985fb12859280f187774764df704ba1d0d51e07 [file] [log] [blame]
rileya@google.com1f45e932012-09-05 16:10:59 +00001/*
2 * Copyright 2012 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 "SkRTree.h"
9#include "SkTSort.h"
10
11static inline uint32_t get_area(const SkIRect& rect);
12static inline uint32_t get_overlap(const SkIRect& rect1, const SkIRect& rect2);
13static inline uint32_t get_margin(const SkIRect& rect);
rileya@google.com1f45e932012-09-05 16:10:59 +000014static inline uint32_t get_area_increase(const SkIRect& rect1, SkIRect rect2);
15static inline void join_no_empty_check(const SkIRect& joinWith, SkIRect* out);
16
17///////////////////////////////////////////////////////////////////////////////////////////////////
18
sglez@google.com8c902122013-08-30 17:27:47 +000019SkRTree* SkRTree::Create(int minChildren, int maxChildren, SkScalar aspectRatio,
20 bool sortWhenBulkLoading) {
rileya@google.com1f45e932012-09-05 16:10:59 +000021 if (minChildren < maxChildren && (maxChildren + 1) / 2 >= minChildren &&
22 minChildren > 0 && maxChildren < static_cast<int>(SK_MaxU16)) {
sglez@google.com8c902122013-08-30 17:27:47 +000023 return new SkRTree(minChildren, maxChildren, aspectRatio, sortWhenBulkLoading);
rileya@google.com1f45e932012-09-05 16:10:59 +000024 }
25 return NULL;
26}
27
sglez@google.com8c902122013-08-30 17:27:47 +000028SkRTree::SkRTree(int minChildren, int maxChildren, SkScalar aspectRatio,
29 bool sortWhenBulkLoading)
rileya@google.com1f45e932012-09-05 16:10:59 +000030 : fMinChildren(minChildren)
31 , fMaxChildren(maxChildren)
32 , fNodeSize(sizeof(Node) + sizeof(Branch) * maxChildren)
33 , fCount(0)
rileya@google.comb839f0f2012-09-10 17:31:05 +000034 , fNodes(fNodeSize * 256)
sglez@google.com8c902122013-08-30 17:27:47 +000035 , fAspectRatio(aspectRatio)
36 , fSortWhenBulkLoading(sortWhenBulkLoading) {
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000037 SkASSERT(minChildren < maxChildren && minChildren > 0 && maxChildren <
rileya@google.com1f45e932012-09-05 16:10:59 +000038 static_cast<int>(SK_MaxU16));
39 SkASSERT((maxChildren + 1) / 2 >= minChildren);
40 this->validate();
41}
42
43SkRTree::~SkRTree() {
44 this->clear();
45}
46
47void SkRTree::insert(void* data, const SkIRect& bounds, bool defer) {
48 this->validate();
skia.committer@gmail.com6c778162012-09-06 02:01:13 +000049 if (bounds.isEmpty()) {
rileya@google.com1f45e932012-09-05 16:10:59 +000050 SkASSERT(false);
51 return;
52 }
53 Branch newBranch;
54 newBranch.fBounds = bounds;
55 newBranch.fChild.data = data;
56 if (this->isEmpty()) {
57 // since a bulk-load into an existing tree is as of yet unimplemented (and arguably not
58 // of vital importance right now), we only batch up inserts if the tree is empty.
59 if (defer) {
60 fDeferredInserts.push(newBranch);
61 return;
62 } else {
63 fRoot.fChild.subtree = allocateNode(0);
64 fRoot.fChild.subtree->fNumChildren = 0;
65 }
66 }
67
68 Branch* newSibling = insert(fRoot.fChild.subtree, &newBranch);
69 fRoot.fBounds = this->computeBounds(fRoot.fChild.subtree);
70
71 if (NULL != newSibling) {
72 Node* oldRoot = fRoot.fChild.subtree;
73 Node* newRoot = this->allocateNode(oldRoot->fLevel + 1);
74 newRoot->fNumChildren = 2;
75 *newRoot->child(0) = fRoot;
76 *newRoot->child(1) = *newSibling;
77 fRoot.fChild.subtree = newRoot;
78 fRoot.fBounds = this->computeBounds(fRoot.fChild.subtree);
79 }
80
81 ++fCount;
82 this->validate();
83}
84
85void SkRTree::flushDeferredInserts() {
86 this->validate();
87 if (this->isEmpty() && fDeferredInserts.count() > 0) {
88 fCount = fDeferredInserts.count();
89 if (1 == fCount) {
90 fRoot.fChild.subtree = allocateNode(0);
91 fRoot.fChild.subtree->fNumChildren = 0;
92 this->insert(fRoot.fChild.subtree, &fDeferredInserts[0]);
93 fRoot.fBounds = fDeferredInserts[0].fBounds;
94 } else {
95 fRoot = this->bulkLoad(&fDeferredInserts);
96 }
97 } else {
98 // TODO: some algorithm for bulk loading into an already populated tree
99 SkASSERT(0 == fDeferredInserts.count());
100 }
101 fDeferredInserts.rewind();
102 this->validate();
103}
104
mtklein8875a042014-08-08 11:49:39 -0700105void SkRTree::search(const SkIRect& query, SkTDArray<void*>* results) const {
rileya@google.com1f45e932012-09-05 16:10:59 +0000106 this->validate();
mtklein8875a042014-08-08 11:49:39 -0700107 SkASSERT(0 == fDeferredInserts.count()); // If this fails, you should have flushed.
rileya@google.com1f45e932012-09-05 16:10:59 +0000108 if (!this->isEmpty() && SkIRect::IntersectsNoEmptyCheck(fRoot.fBounds, query)) {
109 this->search(fRoot.fChild.subtree, query, results);
110 }
111 this->validate();
112}
113
114void SkRTree::clear() {
115 this->validate();
116 fNodes.reset();
117 fDeferredInserts.rewind();
118 fCount = 0;
119 this->validate();
120}
121
122SkRTree::Node* SkRTree::allocateNode(uint16_t level) {
123 Node* out = static_cast<Node*>(fNodes.allocThrow(fNodeSize));
124 out->fNumChildren = 0;
125 out->fLevel = level;
126 return out;
127}
128
129SkRTree::Branch* SkRTree::insert(Node* root, Branch* branch, uint16_t level) {
130 Branch* toInsert = branch;
131 if (root->fLevel != level) {
132 int childIndex = this->chooseSubtree(root, branch);
133 toInsert = this->insert(root->child(childIndex)->fChild.subtree, branch, level);
134 root->child(childIndex)->fBounds = this->computeBounds(
135 root->child(childIndex)->fChild.subtree);
136 }
137 if (NULL != toInsert) {
138 if (root->fNumChildren == fMaxChildren) {
139 // handle overflow by splitting. TODO: opportunistic reinsertion
140
141 // decide on a distribution to divide with
142 Node* newSibling = this->allocateNode(root->fLevel);
143 Branch* toDivide = SkNEW_ARRAY(Branch, fMaxChildren + 1);
144 for (int i = 0; i < fMaxChildren; ++i) {
145 toDivide[i] = *root->child(i);
146 }
147 toDivide[fMaxChildren] = *toInsert;
148 int splitIndex = this->distributeChildren(toDivide);
149
150 // divide up the branches
151 root->fNumChildren = splitIndex;
152 newSibling->fNumChildren = fMaxChildren + 1 - splitIndex;
153 for (int i = 0; i < splitIndex; ++i) {
154 *root->child(i) = toDivide[i];
155 }
156 for (int i = splitIndex; i < fMaxChildren + 1; ++i) {
157 *newSibling->child(i - splitIndex) = toDivide[i];
158 }
159 SkDELETE_ARRAY(toDivide);
160
161 // pass the new sibling branch up to the parent
162 branch->fChild.subtree = newSibling;
163 branch->fBounds = this->computeBounds(newSibling);
164 return branch;
165 } else {
166 *root->child(root->fNumChildren) = *toInsert;
167 ++root->fNumChildren;
168 return NULL;
169 }
170 }
171 return NULL;
172}
173
174int SkRTree::chooseSubtree(Node* root, Branch* branch) {
175 SkASSERT(!root->isLeaf());
176 if (1 < root->fLevel) {
177 // root's child pointers do not point to leaves, so minimize area increase
178 int32_t minAreaIncrease = SK_MaxS32;
179 int32_t minArea = SK_MaxS32;
180 int32_t bestSubtree = -1;
181 for (int i = 0; i < root->fNumChildren; ++i) {
182 const SkIRect& subtreeBounds = root->child(i)->fBounds;
183 int32_t areaIncrease = get_area_increase(subtreeBounds, branch->fBounds);
184 // break ties in favor of subtree with smallest area
185 if (areaIncrease < minAreaIncrease || (areaIncrease == minAreaIncrease &&
186 static_cast<int32_t>(get_area(subtreeBounds)) < minArea)) {
187 minAreaIncrease = areaIncrease;
188 minArea = get_area(subtreeBounds);
189 bestSubtree = i;
190 }
191 }
192 SkASSERT(-1 != bestSubtree);
193 return bestSubtree;
194 } else if (1 == root->fLevel) {
195 // root's child pointers do point to leaves, so minimize overlap increase
196 int32_t minOverlapIncrease = SK_MaxS32;
197 int32_t minAreaIncrease = SK_MaxS32;
198 int32_t bestSubtree = -1;
199 for (int32_t i = 0; i < root->fNumChildren; ++i) {
200 const SkIRect& subtreeBounds = root->child(i)->fBounds;
201 SkIRect expandedBounds = subtreeBounds;
202 join_no_empty_check(branch->fBounds, &expandedBounds);
203 int32_t overlap = 0;
204 for (int32_t j = 0; j < root->fNumChildren; ++j) {
205 if (j == i) continue;
206 // Note: this would be more correct if we subtracted the original pre-expanded
207 // overlap, but computing overlaps is expensive and omitting it doesn't seem to
208 // hurt query performance. See get_overlap_increase()
209 overlap += get_overlap(expandedBounds, root->child(j)->fBounds);
210 }
211 // break ties with lowest area increase
212 if (overlap < minOverlapIncrease || (overlap == minOverlapIncrease &&
skia.committer@gmail.com6c778162012-09-06 02:01:13 +0000213 static_cast<int32_t>(get_area_increase(branch->fBounds, subtreeBounds)) <
rileya@google.com1f45e932012-09-05 16:10:59 +0000214 minAreaIncrease)) {
215 minOverlapIncrease = overlap;
216 minAreaIncrease = get_area_increase(branch->fBounds, subtreeBounds);
217 bestSubtree = i;
218 }
219 }
220 return bestSubtree;
221 } else {
222 SkASSERT(false);
223 return 0;
224 }
225}
226
227SkIRect SkRTree::computeBounds(Node* n) {
228 SkIRect r = n->child(0)->fBounds;
229 for (int i = 1; i < n->fNumChildren; ++i) {
230 join_no_empty_check(n->child(i)->fBounds, &r);
231 }
232 return r;
233}
234
235int SkRTree::distributeChildren(Branch* children) {
236 // We have two sides to sort by on each of two axes:
237 const static SortSide sorts[2][2] = {
238 {&SkIRect::fLeft, &SkIRect::fRight},
239 {&SkIRect::fTop, &SkIRect::fBottom}
240 };
241
242 // We want to choose an axis to split on, then a distribution along that axis; we'll need
243 // three pieces of info: the split axis, the side to sort by on that axis, and the index
244 // to split the sorted array on.
245 int32_t sortSide = -1;
246 int32_t k = -1;
247 int32_t axis = -1;
248 int32_t bestS = SK_MaxS32;
249
250 // Evaluate each axis, we want the min summed margin-value (s) over all distributions
251 for (int i = 0; i < 2; ++i) {
252 int32_t minOverlap = SK_MaxS32;
253 int32_t minArea = SK_MaxS32;
254 int32_t axisBestK = 0;
255 int32_t axisBestSide = 0;
256 int32_t s = 0;
257
258 // Evaluate each sort
259 for (int j = 0; j < 2; ++j) {
bungeman@google.come83e9942013-01-30 21:01:26 +0000260 SkTQSort(children, children + fMaxChildren, RectLessThan(sorts[i][j]));
rileya@google.com1f45e932012-09-05 16:10:59 +0000261
262 // Evaluate each split index
263 for (int32_t k = 1; k <= fMaxChildren - 2 * fMinChildren + 2; ++k) {
264 SkIRect r1 = children[0].fBounds;
265 SkIRect r2 = children[fMinChildren + k - 1].fBounds;
266 for (int32_t l = 1; l < fMinChildren - 1 + k; ++l) {
267 join_no_empty_check(children[l].fBounds, &r1);
skia.committer@gmail.com6c778162012-09-06 02:01:13 +0000268 }
rileya@google.com1f45e932012-09-05 16:10:59 +0000269 for (int32_t l = fMinChildren + k; l < fMaxChildren + 1; ++l) {
270 join_no_empty_check(children[l].fBounds, &r2);
271 }
272
273 int32_t area = get_area(r1) + get_area(r2);
274 int32_t overlap = get_overlap(r1, r2);
275 s += get_margin(r1) + get_margin(r2);
276
277 if (overlap < minOverlap || (overlap == minOverlap && area < minArea)) {
278 minOverlap = overlap;
279 minArea = area;
280 axisBestSide = j;
281 axisBestK = k;
282 }
283 }
284 }
285
286 if (s < bestS) {
287 bestS = s;
288 axis = i;
289 sortSide = axisBestSide;
290 k = axisBestK;
291 }
292 }
293
294 // replicate the sort of the winning distribution, (we can skip this if the last
295 // sort ended up being best)
296 if (!(axis == 1 && sortSide == 1)) {
bungeman@google.come83e9942013-01-30 21:01:26 +0000297 SkTQSort(children, children + fMaxChildren, RectLessThan(sorts[axis][sortSide]));
rileya@google.com1f45e932012-09-05 16:10:59 +0000298 }
skia.committer@gmail.com6c778162012-09-06 02:01:13 +0000299
rileya@google.com1f45e932012-09-05 16:10:59 +0000300 return fMinChildren - 1 + k;
301}
302
303void SkRTree::search(Node* root, const SkIRect query, SkTDArray<void*>* results) const {
304 for (int i = 0; i < root->fNumChildren; ++i) {
305 if (SkIRect::IntersectsNoEmptyCheck(root->child(i)->fBounds, query)) {
306 if (root->isLeaf()) {
307 results->push(root->child(i)->fChild.data);
308 } else {
309 this->search(root->child(i)->fChild.subtree, query, results);
310 }
311 }
312 }
313}
314
315SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) {
316 if (branches->count() == 1) {
317 // Only one branch: it will be the root
318 Branch out = (*branches)[0];
319 branches->rewind();
320 return out;
321 } else {
sglez@google.com8c902122013-08-30 17:27:47 +0000322 // We sort the whole list by y coordinates, if we are told to do so.
323 //
324 // We expect Webkit / Blink to give us a reasonable x,y order.
325 // Avoiding this call resulted in a 17% win for recording with
326 // negligible difference in playback speed.
327 if (fSortWhenBulkLoading) {
328 SkTQSort(branches->begin(), branches->end() - 1, RectLessY());
329 }
skia.committer@gmail.com6c778162012-09-06 02:01:13 +0000330
rileya@google.com1f45e932012-09-05 16:10:59 +0000331 int numBranches = branches->count() / fMaxChildren;
332 int remainder = branches->count() % fMaxChildren;
333 int newBranches = 0;
334
335 if (0 != remainder) {
336 ++numBranches;
337 // If the remainder isn't enough to fill a node, we'll need to add fewer nodes to
338 // some other branches to make up for it
339 if (remainder >= fMinChildren) {
340 remainder = 0;
341 } else {
342 remainder = fMinChildren - remainder;
343 }
344 }
345
reed@google.come1ca7052013-12-17 19:22:07 +0000346 int numStrips = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(numBranches) *
rileya@google.comb839f0f2012-09-10 17:31:05 +0000347 SkScalarInvert(fAspectRatio)));
reed@google.come1ca7052013-12-17 19:22:07 +0000348 int numTiles = SkScalarCeilToInt(SkIntToScalar(numBranches) /
rileya@google.com0ab78652012-09-10 18:11:17 +0000349 SkIntToScalar(numStrips));
rileya@google.com1f45e932012-09-05 16:10:59 +0000350 int currentBranch = 0;
351
352 for (int i = 0; i < numStrips; ++i) {
sglez@google.com8c902122013-08-30 17:27:47 +0000353 // Once again, if we are told to do so, we sort by x.
354 if (fSortWhenBulkLoading) {
355 int begin = currentBranch;
356 int end = currentBranch + numTiles * fMaxChildren - SkMin32(remainder,
357 (fMaxChildren - fMinChildren) * numTiles);
358 if (end > branches->count()) {
359 end = branches->count();
360 }
rileya@google.com1f45e932012-09-05 16:10:59 +0000361
sglez@google.com8c902122013-08-30 17:27:47 +0000362 // Now we sort horizontal strips of rectangles by their x coords
363 SkTQSort(branches->begin() + begin, branches->begin() + end - 1, RectLessX());
364 }
rileya@google.com1f45e932012-09-05 16:10:59 +0000365
rileya@google.comb839f0f2012-09-10 17:31:05 +0000366 for (int j = 0; j < numTiles && currentBranch < branches->count(); ++j) {
rileya@google.com1f45e932012-09-05 16:10:59 +0000367 int incrementBy = fMaxChildren;
368 if (remainder != 0) {
369 // if need be, omit some nodes to make up for remainder
370 if (remainder <= fMaxChildren - fMinChildren) {
371 incrementBy -= remainder;
372 remainder = 0;
373 } else {
374 incrementBy = fMinChildren;
375 remainder -= fMaxChildren - fMinChildren;
376 }
377 }
378 Node* n = allocateNode(level);
379 n->fNumChildren = 1;
380 *n->child(0) = (*branches)[currentBranch];
381 Branch b;
382 b.fBounds = (*branches)[currentBranch].fBounds;
383 b.fChild.subtree = n;
384 ++currentBranch;
385 for (int k = 1; k < incrementBy && currentBranch < branches->count(); ++k) {
386 b.fBounds.join((*branches)[currentBranch].fBounds);
387 *n->child(k) = (*branches)[currentBranch];
388 ++n->fNumChildren;
389 ++currentBranch;
390 }
391 (*branches)[newBranches] = b;
392 ++newBranches;
393 }
394 }
395 branches->setCount(newBranches);
396 return this->bulkLoad(branches, level + 1);
397 }
398}
399
mtklein8875a042014-08-08 11:49:39 -0700400void SkRTree::validate() const {
rileya@google.com1f45e932012-09-05 16:10:59 +0000401#ifdef SK_DEBUG
402 if (this->isEmpty()) {
403 return;
404 }
robertphillips@google.comadacc702013-10-14 21:53:24 +0000405 SkASSERT(fCount == this->validateSubtree(fRoot.fChild.subtree, fRoot.fBounds, true));
rileya@google.com1f45e932012-09-05 16:10:59 +0000406#endif
407}
408
mtklein8875a042014-08-08 11:49:39 -0700409int SkRTree::validateSubtree(Node* root, SkIRect bounds, bool isRoot) const {
rileya@google.com1f45e932012-09-05 16:10:59 +0000410 // make sure the pointer is pointing to a valid place
411 SkASSERT(fNodes.contains(static_cast<void*>(root)));
412
413 if (isRoot) {
414 // If the root of this subtree is the overall root, we have looser standards:
415 if (root->isLeaf()) {
416 SkASSERT(root->fNumChildren >= 1 && root->fNumChildren <= fMaxChildren);
417 } else {
418 SkASSERT(root->fNumChildren >= 2 && root->fNumChildren <= fMaxChildren);
419 }
420 } else {
421 SkASSERT(root->fNumChildren >= fMinChildren && root->fNumChildren <= fMaxChildren);
422 }
423
424 for (int i = 0; i < root->fNumChildren; ++i) {
425 SkASSERT(bounds.contains(root->child(i)->fBounds));
426 }
427
428 if (root->isLeaf()) {
429 SkASSERT(0 == root->fLevel);
430 return root->fNumChildren;
431 } else {
432 int childCount = 0;
433 for (int i = 0; i < root->fNumChildren; ++i) {
434 SkASSERT(root->child(i)->fChild.subtree->fLevel == root->fLevel - 1);
435 childCount += this->validateSubtree(root->child(i)->fChild.subtree,
436 root->child(i)->fBounds);
437 }
438 return childCount;
439 }
440}
441
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000442void SkRTree::rewindInserts() {
443 SkASSERT(this->isEmpty()); // Currently only supports deferred inserts
444 while (!fDeferredInserts.isEmpty() &&
445 fClient->shouldRewind(fDeferredInserts.top().fChild.data)) {
446 fDeferredInserts.pop();
447 }
448}
449
rileya@google.com1f45e932012-09-05 16:10:59 +0000450///////////////////////////////////////////////////////////////////////////////////////////////////
451
452static inline uint32_t get_area(const SkIRect& rect) {
453 return rect.width() * rect.height();
454}
455
456static inline uint32_t get_overlap(const SkIRect& rect1, const SkIRect& rect2) {
457 // I suspect there's a more efficient way of computing this...
458 return SkMax32(0, SkMin32(rect1.fRight, rect2.fRight) - SkMax32(rect1.fLeft, rect2.fLeft)) *
459 SkMax32(0, SkMin32(rect1.fBottom, rect2.fBottom) - SkMax32(rect1.fTop, rect2.fTop));
460}
461
462// Get the margin (aka perimeter)
463static inline uint32_t get_margin(const SkIRect& rect) {
464 return 2 * (rect.width() + rect.height());
465}
466
rileya@google.com1f45e932012-09-05 16:10:59 +0000467static inline uint32_t get_area_increase(const SkIRect& rect1, SkIRect rect2) {
468 join_no_empty_check(rect1, &rect2);
469 return get_area(rect2) - get_area(rect1);
470}
471
472// Expand 'out' to include 'joinWith'
473static inline void join_no_empty_check(const SkIRect& joinWith, SkIRect* out) {
474 // since we check for empty bounds on insert, we know we'll never have empty rects
475 // and we can save the empty check that SkIRect::join requires
476 if (joinWith.fLeft < out->fLeft) { out->fLeft = joinWith.fLeft; }
477 if (joinWith.fTop < out->fTop) { out->fTop = joinWith.fTop; }
478 if (joinWith.fRight > out->fRight) { out->fRight = joinWith.fRight; }
479 if (joinWith.fBottom > out->fBottom) { out->fBottom = joinWith.fBottom; }
480}