blob: bae2fdce3f86f79806a44423009cd11c6286021f [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"
rileya@google.com1f45e932012-09-05 16:10:59 +00009
mtkleina06a9532014-11-18 09:27:49 -080010SkRTree::SkRTree(SkScalar aspectRatio) : fCount(0), fAspectRatio(aspectRatio) {}
rileya@google.com1f45e932012-09-05 16:10:59 +000011
schenney23d85932015-03-06 16:20:28 -080012SkRect SkRTree::getRootBound() const {
13 if (fCount) {
14 return fRoot.fBounds;
15 } else {
16 return SkRect::MakeEmpty();
17 }
18}
19
mtkleinbfd5bff2015-02-10 13:44:27 -080020void SkRTree::insert(const SkRect boundsArray[], int N) {
mtkleina06a9532014-11-18 09:27:49 -080021 SkASSERT(0 == fCount);
mtklein4477c3c2014-10-27 10:27:10 -070022
mtkleina06a9532014-11-18 09:27:49 -080023 SkTDArray<Branch> branches;
24 branches.setReserve(N);
mtklein4477c3c2014-10-27 10:27:10 -070025
26 for (int i = 0; i < N; i++) {
mtkleinbfd5bff2015-02-10 13:44:27 -080027 const SkRect& bounds = boundsArray[i];
mtklein4477c3c2014-10-27 10:27:10 -070028 if (bounds.isEmpty()) {
29 continue;
rileya@google.com1f45e932012-09-05 16:10:59 +000030 }
mtklein4477c3c2014-10-27 10:27:10 -070031
mtkleina06a9532014-11-18 09:27:49 -080032 Branch* b = branches.push();
33 b->fBounds = bounds;
34 b->fOpIndex = i;
rileya@google.com1f45e932012-09-05 16:10:59 +000035 }
36
mtkleina06a9532014-11-18 09:27:49 -080037 fCount = branches.count();
mtklein4477c3c2014-10-27 10:27:10 -070038 if (fCount) {
rileya@google.com1f45e932012-09-05 16:10:59 +000039 if (1 == fCount) {
mtkleina06a9532014-11-18 09:27:49 -080040 fNodes.setReserve(1);
41 Node* n = this->allocateNodeAtLevel(0);
42 n->fNumChildren = 1;
43 n->fChildren[0] = branches[0];
44 fRoot.fSubtree = n;
45 fRoot.fBounds = branches[0].fBounds;
rileya@google.com1f45e932012-09-05 16:10:59 +000046 } else {
mtkleina06a9532014-11-18 09:27:49 -080047 fNodes.setReserve(CountNodes(fCount, fAspectRatio));
48 fRoot = this->bulkLoad(&branches);
rileya@google.com1f45e932012-09-05 16:10:59 +000049 }
rileya@google.com1f45e932012-09-05 16:10:59 +000050 }
rileya@google.com1f45e932012-09-05 16:10:59 +000051}
52
mtkleina06a9532014-11-18 09:27:49 -080053SkRTree::Node* SkRTree::allocateNodeAtLevel(uint16_t level) {
54 SkDEBUGCODE(Node* p = fNodes.begin());
55 Node* out = fNodes.push();
56 SkASSERT(fNodes.begin() == p); // If this fails, we didn't setReserve() enough.
rileya@google.com1f45e932012-09-05 16:10:59 +000057 out->fNumChildren = 0;
58 out->fLevel = level;
59 return out;
60}
61
mtkleina06a9532014-11-18 09:27:49 -080062// This function parallels bulkLoad, but just counts how many nodes bulkLoad would allocate.
63int SkRTree::CountNodes(int branches, SkScalar aspectRatio) {
64 if (branches == 1) {
65 return 1;
rileya@google.com1f45e932012-09-05 16:10:59 +000066 }
mtkleina06a9532014-11-18 09:27:49 -080067 int numBranches = branches / kMaxChildren;
68 int remainder = branches % kMaxChildren;
69 if (remainder > 0) {
70 numBranches++;
71 if (remainder >= kMinChildren) {
72 remainder = 0;
rileya@google.com1f45e932012-09-05 16:10:59 +000073 } else {
mtkleina06a9532014-11-18 09:27:49 -080074 remainder = kMinChildren - remainder;
rileya@google.com1f45e932012-09-05 16:10:59 +000075 }
76 }
mtkleina06a9532014-11-18 09:27:49 -080077 int numStrips = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(numBranches) / aspectRatio));
78 int numTiles = SkScalarCeilToInt(SkIntToScalar(numBranches) / SkIntToScalar(numStrips));
79 int currentBranch = 0;
80 int nodes = 0;
81 for (int i = 0; i < numStrips; ++i) {
82 for (int j = 0; j < numTiles && currentBranch < branches; ++j) {
83 int incrementBy = kMaxChildren;
84 if (remainder != 0) {
85 if (remainder <= kMaxChildren - kMinChildren) {
86 incrementBy -= remainder;
87 remainder = 0;
88 } else {
89 incrementBy = kMinChildren;
90 remainder -= kMaxChildren - kMinChildren;
rileya@google.com1f45e932012-09-05 16:10:59 +000091 }
92 }
mtkleina06a9532014-11-18 09:27:49 -080093 nodes++;
94 currentBranch++;
95 for (int k = 1; k < incrementBy && currentBranch < branches; ++k) {
96 currentBranch++;
rileya@google.com1f45e932012-09-05 16:10:59 +000097 }
98 }
99 }
mtkleina06a9532014-11-18 09:27:49 -0800100 return nodes + CountNodes(nodes, aspectRatio);
rileya@google.com1f45e932012-09-05 16:10:59 +0000101}
102
103SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) {
mtkleina06a9532014-11-18 09:27:49 -0800104 if (branches->count() == 1) { // Only one branch. It will be the root.
105 return (*branches)[0];
rileya@google.com1f45e932012-09-05 16:10:59 +0000106 }
rileya@google.com1f45e932012-09-05 16:10:59 +0000107
mtkleina06a9532014-11-18 09:27:49 -0800108 // We might sort our branches here, but we expect Blink gives us a reasonable x,y order.
109 // Skipping a call to sort (in Y) here resulted in a 17% win for recording with negligible
110 // difference in playback speed.
111 int numBranches = branches->count() / kMaxChildren;
112 int remainder = branches->count() % kMaxChildren;
113 int newBranches = 0;
rileya@google.com1f45e932012-09-05 16:10:59 +0000114
mtkleina06a9532014-11-18 09:27:49 -0800115 if (remainder > 0) {
116 ++numBranches;
117 // If the remainder isn't enough to fill a node, we'll add fewer nodes to other branches.
118 if (remainder >= kMinChildren) {
119 remainder = 0;
rileya@google.com1f45e932012-09-05 16:10:59 +0000120 } else {
mtkleina06a9532014-11-18 09:27:49 -0800121 remainder = kMinChildren - remainder;
rileya@google.com1f45e932012-09-05 16:10:59 +0000122 }
rileya@google.com1f45e932012-09-05 16:10:59 +0000123 }
124
mtkleina06a9532014-11-18 09:27:49 -0800125 int numStrips = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(numBranches) / fAspectRatio));
126 int numTiles = SkScalarCeilToInt(SkIntToScalar(numBranches) / SkIntToScalar(numStrips));
127 int currentBranch = 0;
rileya@google.com1f45e932012-09-05 16:10:59 +0000128
mtkleina06a9532014-11-18 09:27:49 -0800129 for (int i = 0; i < numStrips; ++i) {
130 // Might be worth sorting by X here too.
131 for (int j = 0; j < numTiles && currentBranch < branches->count(); ++j) {
132 int incrementBy = kMaxChildren;
133 if (remainder != 0) {
134 // if need be, omit some nodes to make up for remainder
135 if (remainder <= kMaxChildren - kMinChildren) {
136 incrementBy -= remainder;
137 remainder = 0;
138 } else {
139 incrementBy = kMinChildren;
140 remainder -= kMaxChildren - kMinChildren;
141 }
142 }
143 Node* n = allocateNodeAtLevel(level);
144 n->fNumChildren = 1;
145 n->fChildren[0] = (*branches)[currentBranch];
146 Branch b;
147 b.fBounds = (*branches)[currentBranch].fBounds;
148 b.fSubtree = n;
149 ++currentBranch;
150 for (int k = 1; k < incrementBy && currentBranch < branches->count(); ++k) {
151 b.fBounds.join((*branches)[currentBranch].fBounds);
152 n->fChildren[k] = (*branches)[currentBranch];
153 ++n->fNumChildren;
154 ++currentBranch;
155 }
156 (*branches)[newBranches] = b;
157 ++newBranches;
rileya@google.com1f45e932012-09-05 16:10:59 +0000158 }
mtkleina06a9532014-11-18 09:27:49 -0800159 }
160 branches->setCount(newBranches);
161 return this->bulkLoad(branches, level + 1);
162}
163
mtkleinc6ad06a2015-08-19 09:51:00 -0700164void SkRTree::search(const SkRect& query, SkTDArray<int>* results) const {
mtkleina06a9532014-11-18 09:27:49 -0800165 if (fCount > 0 && SkRect::Intersects(fRoot.fBounds, query)) {
166 this->search(fRoot.fSubtree, query, results);
rileya@google.com1f45e932012-09-05 16:10:59 +0000167 }
168}
169
mtkleinc6ad06a2015-08-19 09:51:00 -0700170void SkRTree::search(Node* node, const SkRect& query, SkTDArray<int>* results) const {
mtkleina06a9532014-11-18 09:27:49 -0800171 for (int i = 0; i < node->fNumChildren; ++i) {
172 if (SkRect::Intersects(node->fChildren[i].fBounds, query)) {
173 if (0 == node->fLevel) {
174 results->push(node->fChildren[i].fOpIndex);
175 } else {
176 this->search(node->fChildren[i].fSubtree, query, results);
177 }
178 }
179 }
rileya@google.com1f45e932012-09-05 16:10:59 +0000180}
tomhudson158fcaa2014-11-19 10:41:14 -0800181
182size_t SkRTree::bytesUsed() const {
183 size_t byteCount = sizeof(SkRTree);
184
185 byteCount += fNodes.reserved() * sizeof(Node);
186
187 return byteCount;
188}