2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
10 #include "SkQuadTree.h"
14 // confine rectangles to a smallish area, so queries generally hit something, and overlap occurs:
15 static const int GENERATE_EXTENTS = 1000;
16 static const int NUM_BUILD_RECTS = 500;
17 static const int NUM_QUERY_RECTS = 5000;
18 static const int GRID_WIDTH = 100;
19 static const SkIRect QUAD_TREE_BOUNDS = SkIRect::MakeLTRB(
20 -GENERATE_EXTENTS, -GENERATE_EXTENTS, 2 * GENERATE_EXTENTS, 2 * GENERATE_EXTENTS);
22 typedef SkIRect (*MakeRectProc)(SkRandom&, int, int);
24 // Time how long it takes to build an QuadTree
25 class QuadTreeBuildBench : public Benchmark {
27 QuadTreeBuildBench(const char* name, MakeRectProc proc, SkBBoxHierarchy* tree)
30 fName.append("quadtree_");
32 fName.append("_build");
35 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
36 return backend == kNonRendering_Backend;
39 virtual ~QuadTreeBuildBench() {
43 virtual const char* onGetName() SK_OVERRIDE {
46 virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
48 for (int i = 0; i < loops; ++i) {
49 for (int j = 0; j < NUM_BUILD_RECTS; ++j) {
50 fTree->insert(reinterpret_cast<void*>(j), fProc(rand, j, NUM_BUILD_RECTS),
57 SkBBoxHierarchy* fTree;
60 typedef Benchmark INHERITED;
63 // Time how long it takes to perform queries on an QuadTree
64 class QuadTreeQueryBench : public Benchmark {
67 kSmall_QueryType, // small queries
68 kLarge_QueryType, // large queries
69 kRandom_QueryType,// randomly sized queries
70 kFull_QueryType // queries that cover everything
73 QuadTreeQueryBench(const char* name, MakeRectProc proc,
74 QueryType q, SkBBoxHierarchy* tree)
78 fName.append("quadtree_");
80 fName.append("_query");
83 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
84 return backend == kNonRendering_Backend;
87 virtual ~QuadTreeQueryBench() {
91 virtual const char* onGetName() SK_OVERRIDE {
94 virtual void onPreDraw() SK_OVERRIDE {
96 for (int j = 0; j < NUM_QUERY_RECTS; ++j) {
97 fTree->insert(reinterpret_cast<void*>(j),
98 fProc(rand, j, NUM_QUERY_RECTS),
101 fTree->flushDeferredInserts();
104 virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
106 for (int i = 0; i < loops; ++i) {
107 SkTDArray<void*> hits;
110 case kSmall_QueryType:
111 query.fLeft = rand.nextU() % GENERATE_EXTENTS;
112 query.fTop = rand.nextU() % GENERATE_EXTENTS;
113 query.fRight = query.fLeft + (GENERATE_EXTENTS / 20);
114 query.fBottom = query.fTop + (GENERATE_EXTENTS / 20);
116 case kLarge_QueryType:
117 query.fLeft = rand.nextU() % GENERATE_EXTENTS;
118 query.fTop = rand.nextU() % GENERATE_EXTENTS;
119 query.fRight = query.fLeft + (GENERATE_EXTENTS / 2);
120 query.fBottom = query.fTop + (GENERATE_EXTENTS / 2);
122 case kFull_QueryType:
123 query.fLeft = -GENERATE_EXTENTS;
124 query.fTop = -GENERATE_EXTENTS;
125 query.fRight = 2 * GENERATE_EXTENTS;
126 query.fBottom = 2 * GENERATE_EXTENTS;
128 default: // fallthrough
129 case kRandom_QueryType:
130 query.fLeft = rand.nextU() % GENERATE_EXTENTS;
131 query.fTop = rand.nextU() % GENERATE_EXTENTS;
132 query.fRight = query.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 2);
133 query.fBottom = query.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 2);
136 fTree->search(query, &hits);
140 SkBBoxHierarchy* fTree;
144 typedef Benchmark INHERITED;
147 static inline SkIRect make_concentric_rects_increasing(SkRandom&, int index, int numRects) {
148 SkIRect out = {0, 0, index + 1, index + 1};
152 static inline SkIRect make_XYordered_rects(SkRandom& rand, int index, int numRects) {
154 out.fLeft = index % GRID_WIDTH;
155 out.fTop = index / GRID_WIDTH;
156 out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
157 out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
161 static inline SkIRect make_YXordered_rects(SkRandom& rand, int index, int numRects) {
163 out.fLeft = index / GRID_WIDTH;
164 out.fTop = index % GRID_WIDTH;
165 out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
166 out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 3);
170 static inline SkIRect make_random_rects(SkRandom& rand, int index, int numRects) {
172 out.fLeft = rand.nextS() % GENERATE_EXTENTS;
173 out.fTop = rand.nextS() % GENERATE_EXTENTS;
174 out.fRight = out.fLeft + 1 + rand.nextU() % (GENERATE_EXTENTS / 5);
175 out.fBottom = out.fTop + 1 + rand.nextU() % (GENERATE_EXTENTS / 5);
179 ///////////////////////////////////////////////////////////////////////////////
182 return SkNEW_ARGS(QuadTreeBuildBench, ("XYordered", &make_XYordered_rects,
183 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
186 return SkNEW_ARGS(QuadTreeQueryBench, ("XYordered", &make_XYordered_rects,
187 QuadTreeQueryBench::kRandom_QueryType,
188 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
191 return SkNEW_ARGS(QuadTreeBuildBench, ("YXordered", &make_YXordered_rects,
192 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
195 return SkNEW_ARGS(QuadTreeQueryBench, ("YXordered", &make_YXordered_rects,
196 QuadTreeQueryBench::kRandom_QueryType,
197 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
200 return SkNEW_ARGS(QuadTreeBuildBench, ("random", &make_random_rects,
201 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
204 return SkNEW_ARGS(QuadTreeQueryBench, ("random", &make_random_rects,
205 QuadTreeQueryBench::kRandom_QueryType,
206 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
209 return SkNEW_ARGS(QuadTreeBuildBench, ("concentric", &make_concentric_rects_increasing,
210 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));
213 return SkNEW_ARGS(QuadTreeQueryBench, ("concentric", &make_concentric_rects_increasing,
214 QuadTreeQueryBench::kRandom_QueryType,
215 SkNEW_ARGS(SkQuadTree, (QUAD_TREE_BOUNDS))));