diff options
author | sglez@google.com <sglez@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-08-30 17:27:47 +0000 |
---|---|---|
committer | sglez@google.com <sglez@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-08-30 17:27:47 +0000 |
commit | 8c902126a90f37b6a038a78488c6215fa0c34b7d (patch) | |
tree | 2697cadd11b02c99a3d775241d801dcb227a9bc1 | |
parent | 6be61ce03947b7d69305c37c1efa389160afada5 (diff) |
R-Tree -- Don't sort draw commands unless specified.
We expect Webkit and Bink to give us draw commands in a reasonable x,y order.
We can maintain correctness and get a 17% recording speedup for the R-Tree by
not sorting in x and y when bulk-loading.
R=caryclark@google.com, reed@google.com
Review URL: https://codereview.chromium.org/23480002
git-svn-id: http://skia.googlecode.com/svn/trunk@11037 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | bench/RTreeBench.cpp | 112 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 4 | ||||
-rw-r--r-- | src/core/SkRTree.cpp | 40 | ||||
-rw-r--r-- | src/core/SkRTree.h | 6 | ||||
-rw-r--r-- | tests/RTreeTest.cpp | 26 | ||||
-rw-r--r-- | tools/PictureRenderer.cpp | 3 |
6 files changed, 155 insertions, 36 deletions
diff --git a/bench/RTreeBench.cpp b/bench/RTreeBench.cpp index bce1b67513..d017f39972 100644 --- a/bench/RTreeBench.cpp +++ b/bench/RTreeBench.cpp @@ -17,6 +17,7 @@ static const int GENERATE_EXTENTS = 1000; static const int NUM_BUILD_RECTS = 500; static const int NUM_QUERY_RECTS = 5000; static const int NUM_QUERIES = 1000; +static const int GRID_WIDTH = 100; typedef SkIRect (*MakeRectProc)(SkMWCRandom&, int, int); @@ -163,6 +164,23 @@ static inline SkIRect make_concentric_rects_decreasing(SkMWCRandom&, int index, return out; } +static inline SkIRect make_XYordered_rects(SkMWCRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = index % GRID_WIDTH; + out.fTop = index / GRID_WIDTH; + out.fRight = 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + out.fBottom = 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + return out; +} +static inline SkIRect make_YXordered_rects(SkMWCRandom& rand, int index, int numRects) { + SkIRect out; + out.fLeft = index / GRID_WIDTH; + out.fTop = index % GRID_WIDTH; + out.fRight = 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + out.fBottom = 1 + rand.nextU() % (GENERATE_EXTENTS / 3); + return out; +} + static inline SkIRect make_point_rects(SkMWCRandom& rand, int index, int numRects) { SkIRect out; out.fLeft = rand.nextU() % GENERATE_EXTENTS; @@ -193,28 +211,102 @@ static inline SkIRect make_large_rects(SkMWCRandom& rand, int index, int numRect /////////////////////////////////////////////////////////////////////////////// static inline SkBenchmark* Fact0(void* p) { - return SkNEW_ARGS(BBoxBuildBench, (p, "random", &make_random_rects, true, + return SkNEW_ARGS(BBoxBuildBench, (p, "XYordered", &make_XYordered_rects, false, SkRTree::Create(5, 16))); } static inline SkBenchmark* Fact1(void* p) { - return SkNEW_ARGS(BBoxBuildBench, (p, "random", &make_random_rects, false, + return SkNEW_ARGS(BBoxBuildBench, (p, "XYordered", &make_XYordered_rects, true, SkRTree::Create(5, 16))); } static inline SkBenchmark* Fact2(void* p) { - return SkNEW_ARGS(BBoxBuildBench, (p, "concentric", - &make_concentric_rects_increasing, true, SkRTree::Create(5, 16))); + return SkNEW_ARGS(BBoxBuildBench, (p, "(unsorted)XYordered", &make_XYordered_rects, true, + SkRTree::Create(5, 16, 1, false))); } static inline SkBenchmark* Fact3(void* p) { - return SkNEW_ARGS(BBoxQueryBench, (p, "random", &make_random_rects, true, + return SkNEW_ARGS(BBoxQueryBench, (p, "XYordered", &make_XYordered_rects, true, BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); } static inline SkBenchmark* Fact4(void* p) { - return SkNEW_ARGS(BBoxQueryBench, (p, "random", &make_random_rects, false, + return SkNEW_ARGS(BBoxQueryBench, (p, "(unsorted)XYordered", &make_XYordered_rects, true, + BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +} + +static inline SkBenchmark* Fact5(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "YXordered", &make_YXordered_rects, false, + SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact6(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "YXordered", &make_YXordered_rects, true, + SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact7(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "(unsorted)YXordered", &make_YXordered_rects, true, + SkRTree::Create(5, 16, 1, false))); +} +static inline SkBenchmark* Fact8(void* p) { + return SkNEW_ARGS(BBoxQueryBench, (p, "YXordered", &make_YXordered_rects, true, BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); } +static inline SkBenchmark* Fact9(void* p) { + return SkNEW_ARGS(BBoxQueryBench, (p, "(unsorted)YXordered", &make_YXordered_rects, true, + BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +} -static BenchRegistry gReg0(Fact0); -static BenchRegistry gReg1(Fact1); -static BenchRegistry gReg2(Fact2); -static BenchRegistry gReg3(Fact3); +static inline SkBenchmark* Fact10(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "random", &make_random_rects, false, + SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact11(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "random", &make_random_rects, true, + SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact12(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "(unsorted)random", &make_random_rects, true, + SkRTree::Create(5, 16, 1, false))); +} +static inline SkBenchmark* Fact13(void* p) { + return SkNEW_ARGS(BBoxQueryBench, (p, "random", &make_random_rects, true, + BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact14(void* p) { + return SkNEW_ARGS(BBoxQueryBench, (p, "(unsorted)random", &make_random_rects, true, + BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +} + +static inline SkBenchmark* Fact15(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "concentric", + &make_concentric_rects_increasing, true, SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact16(void* p) { + return SkNEW_ARGS(BBoxBuildBench, (p, "(unsorted)concentric", + &make_concentric_rects_increasing, true, SkRTree::Create(5, 16, 1, false))); +} +static inline SkBenchmark* Fact17(void* p) { + return SkNEW_ARGS(BBoxQueryBench, (p, "concentric", &make_concentric_rects_increasing, true, + BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16))); +} +static inline SkBenchmark* Fact18(void* p) { + return SkNEW_ARGS(BBoxQueryBench, (p, "(unsorted)concentric", &make_concentric_rects_increasing, true, + BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16, 1, false))); +} + +static BenchRegistry gReg18(Fact18); +static BenchRegistry gReg17(Fact17); +static BenchRegistry gReg16(Fact16); +static BenchRegistry gReg15(Fact15); +static BenchRegistry gReg14(Fact14); +static BenchRegistry gReg13(Fact13); +static BenchRegistry gReg12(Fact12); +static BenchRegistry gReg11(Fact11); +static BenchRegistry gReg10(Fact10); +static BenchRegistry gReg9(Fact9); +static BenchRegistry gReg8(Fact8); +static BenchRegistry gReg7(Fact7); +static BenchRegistry gReg6(Fact6); +static BenchRegistry gReg5(Fact5); static BenchRegistry gReg4(Fact4); +static BenchRegistry gReg3(Fact3); +static BenchRegistry gReg2(Fact2); +static BenchRegistry gReg1(Fact1); +static BenchRegistry gReg0(Fact0); + diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 1aa45284aa..f70f16ee5f 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -232,8 +232,10 @@ SkBBoxHierarchy* SkPicture::createBBoxHierarchy() const { SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), SkIntToScalar(fHeight)); + bool sortDraws = false; // Do not sort draw calls when bulk loading. + return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, - aspectRatio); + aspectRatio, sortDraws); } SkCanvas* SkPicture::getRecordingCanvas() const { diff --git a/src/core/SkRTree.cpp b/src/core/SkRTree.cpp index d7a15d5957..95e4336ac7 100644 --- a/src/core/SkRTree.cpp +++ b/src/core/SkRTree.cpp @@ -21,21 +21,24 @@ static inline void join_no_empty_check(const SkIRect& joinWith, SkIRect* out); SK_DEFINE_INST_COUNT(SkRTree) -SkRTree* SkRTree::Create(int minChildren, int maxChildren, SkScalar aspectRatio) { +SkRTree* SkRTree::Create(int minChildren, int maxChildren, SkScalar aspectRatio, + bool sortWhenBulkLoading) { if (minChildren < maxChildren && (maxChildren + 1) / 2 >= minChildren && minChildren > 0 && maxChildren < static_cast<int>(SK_MaxU16)) { - return new SkRTree(minChildren, maxChildren, aspectRatio); + return new SkRTree(minChildren, maxChildren, aspectRatio, sortWhenBulkLoading); } return NULL; } -SkRTree::SkRTree(int minChildren, int maxChildren, SkScalar aspectRatio) +SkRTree::SkRTree(int minChildren, int maxChildren, SkScalar aspectRatio, + bool sortWhenBulkLoading) : fMinChildren(minChildren) , fMaxChildren(maxChildren) , fNodeSize(sizeof(Node) + sizeof(Branch) * maxChildren) , fCount(0) , fNodes(fNodeSize * 256) - , fAspectRatio(aspectRatio) { + , fAspectRatio(aspectRatio) + , fSortWhenBulkLoading(sortWhenBulkLoading) { SkASSERT(minChildren < maxChildren && minChildren > 0 && maxChildren < static_cast<int>(SK_MaxU16)); SkASSERT((maxChildren + 1) / 2 >= minChildren); @@ -323,8 +326,14 @@ SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) { branches->rewind(); return out; } else { - // First we sort the whole list by y coordinates - SkTQSort(branches->begin(), branches->end() - 1, RectLessY()); + // We sort the whole list by y coordinates, if we are told to do so. + // + // We expect Webkit / Blink to give us a reasonable x,y order. + // Avoiding this call resulted in a 17% win for recording with + // negligible difference in playback speed. + if (fSortWhenBulkLoading) { + SkTQSort(branches->begin(), branches->end() - 1, RectLessY()); + } int numBranches = branches->count() / fMaxChildren; int remainder = branches->count() % fMaxChildren; @@ -348,15 +357,18 @@ SkRTree::Branch SkRTree::bulkLoad(SkTDArray<Branch>* branches, int level) { int currentBranch = 0; for (int i = 0; i < numStrips; ++i) { - int begin = currentBranch; - int end = currentBranch + numTiles * fMaxChildren - SkMin32(remainder, - (fMaxChildren - fMinChildren) * numTiles); - if (end > branches->count()) { - end = branches->count(); - } + // Once again, if we are told to do so, we sort by x. + if (fSortWhenBulkLoading) { + int begin = currentBranch; + int end = currentBranch + numTiles * fMaxChildren - SkMin32(remainder, + (fMaxChildren - fMinChildren) * numTiles); + if (end > branches->count()) { + end = branches->count(); + } - // Now we sort horizontal strips of rectangles by their x coords - SkTQSort(branches->begin() + begin, branches->begin() + end - 1, RectLessX()); + // Now we sort horizontal strips of rectangles by their x coords + SkTQSort(branches->begin() + begin, branches->begin() + end - 1, RectLessX()); + } for (int j = 0; j < numTiles && currentBranch < branches->count(); ++j) { int incrementBy = fMaxChildren; diff --git a/src/core/SkRTree.h b/src/core/SkRTree.h index 2d11f28a57..54421de14c 100644 --- a/src/core/SkRTree.h +++ b/src/core/SkRTree.h @@ -55,7 +55,8 @@ public: * can provide an optional aspect ratio parameter. This allows the bulk-load algorithm to create * better proportioned tiles of rectangles. */ - static SkRTree* Create(int minChildren, int maxChildren, SkScalar aspectRatio = 1); + static SkRTree* Create(int minChildren, int maxChildren, SkScalar aspectRatio = 1, + bool orderWhenBulkLoading = true); virtual ~SkRTree(); /** @@ -144,7 +145,7 @@ private: } }; - SkRTree(int minChildren, int maxChildren, SkScalar aspectRatio); + SkRTree(int minChildren, int maxChildren, SkScalar aspectRatio, bool orderWhenBulkLoading); /** * Recursively descend the tree to find an insertion position for 'branch', updates @@ -184,6 +185,7 @@ private: SkChunkAlloc fNodes; SkTDArray<Branch> fDeferredInserts; SkScalar fAspectRatio; + bool fSortWhenBulkLoading; Node* allocateNode(uint16_t level); diff --git a/tests/RTreeTest.cpp b/tests/RTreeTest.cpp index 6296c4e7b8..655336c676 100644 --- a/tests/RTreeTest.cpp +++ b/tests/RTreeTest.cpp @@ -68,7 +68,7 @@ static bool verify_query(SkIRect query, DataRect rects[], return found == expected; } -static void runQueries(skiatest::Reporter* reporter, SkMWCRandom& rand, DataRect rects[], +static void run_queries(skiatest::Reporter* reporter, SkMWCRandom& rand, DataRect rects[], SkRTree& tree) { for (size_t i = 0; i < NUM_QUERIES; ++i) { SkTDArray<void*> hits; @@ -78,11 +78,9 @@ static void runQueries(skiatest::Reporter* reporter, SkMWCRandom& rand, DataRect } } -static void TestRTree(skiatest::Reporter* reporter) { +static void rtree_test_main(SkRTree* rtree, skiatest::Reporter* reporter) { DataRect rects[NUM_RECTS]; SkMWCRandom rand; - SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN); - SkAutoUnref au(rtree); REPORTER_ASSERT(reporter, NULL != rtree); int expectedDepthMin = -1; @@ -110,7 +108,7 @@ static void TestRTree(skiatest::Reporter* reporter) { rtree->insert(rects[i].data, rects[i].rect, true); } rtree->flushDeferredInserts(); - runQueries(reporter, rand, rects, *rtree); + run_queries(reporter, rand, rects, *rtree); REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount()); REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() && expectedDepthMax >= rtree->getDepth()); @@ -121,7 +119,7 @@ static void TestRTree(skiatest::Reporter* reporter) { for (int i = 0; i < NUM_RECTS; ++i) { rtree->insert(rects[i].data, rects[i].rect); } - runQueries(reporter, rand, rects, *rtree); + run_queries(reporter, rand, rects, *rtree); REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount()); REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() && expectedDepthMax >= rtree->getDepth()); @@ -132,7 +130,7 @@ static void TestRTree(skiatest::Reporter* reporter) { for (int i = NUM_RECTS - 1; i >= 0; --i) { rtree->insert(rects[i].data, rects[i].rect); } - runQueries(reporter, rand, rects, *rtree); + run_queries(reporter, rand, rects, *rtree); REPORTER_ASSERT(reporter, NUM_RECTS == rtree->getCount()); REPORTER_ASSERT(reporter, expectedDepthMin <= rtree->getDepth() && expectedDepthMax >= rtree->getDepth()); @@ -141,5 +139,17 @@ static void TestRTree(skiatest::Reporter* reporter) { } } +static void test_rtree(skiatest::Reporter* reporter) { + SkRTree* rtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN); + SkAutoUnref au(rtree); + rtree_test_main(rtree, reporter); + + // Rtree that orders input rectangles on deferred insert. + SkRTree* unsortedRtree = SkRTree::Create(MIN_CHILDREN, MAX_CHILDREN, false); + SkAutoUnref auo(orderedRtree); + rtree_test_main(orderedRtree, reporter); +} + + #include "TestClassDef.h" -DEFINE_TESTCLASS("RTree", RTreeTestClass, TestRTree) +DEFINE_TESTCLASS("RTree", RTreeTestClass, test_rtree) diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp index 2730a23f52..c53bd08265 100644 --- a/tools/PictureRenderer.cpp +++ b/tools/PictureRenderer.cpp @@ -790,8 +790,9 @@ public: static const int kRTreeMaxChildren = 11; SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), SkIntToScalar(fHeight)); + bool sortDraws = false; return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, - aspectRatio); + aspectRatio, sortDraws); } }; |