зеркало из https://github.com/mozilla/moz-skia.git
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
This commit is contained in:
Родитель
6be61ce039
Коммит
8c902126a9
|
@ -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,
|
||||
BBoxQueryBench::kRandom_QueryType, SkRTree::Create(5, 16)));
|
||||
return SkNEW_ARGS(BBoxQueryBench, (p, "(unsorted)XYordered", &make_XYordered_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* 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 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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче