Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 5f3cc4b

Browse files
committed
Add DlRegion::MakeIntersection
1 parent 6f9be2b commit 5f3cc4b

File tree

4 files changed

+231
-47
lines changed

4 files changed

+231
-47
lines changed

display_list/benchmarking/dl_region_benchmarks.cc

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ class SkRegionAdapter {
2828
return result;
2929
}
3030

31+
static SkRegionAdapter intersectRegions(const SkRegionAdapter& a1,
32+
const SkRegionAdapter& a2) {
33+
SkRegionAdapter result(a1);
34+
result.region_.op(a2.region_, SkRegion::kIntersect_Op);
35+
return result;
36+
}
37+
3138
bool intersects(const SkRegionAdapter& region) {
3239
return region_.intersects(region.region_);
3340
}
@@ -59,6 +66,12 @@ class DlRegionAdapter {
5966
flutter::DlRegion::MakeUnion(a1.region_, a2.region_));
6067
}
6168

69+
static DlRegionAdapter intersectRegions(const DlRegionAdapter& a1,
70+
const DlRegionAdapter& a2) {
71+
return DlRegionAdapter(
72+
flutter::DlRegion::MakeIntersection(a1.region_, a2.region_));
73+
}
74+
6275
SkIRect getBounds() { return region_.bounds(); }
6376

6477
bool intersects(const DlRegionAdapter& region) {
@@ -118,8 +131,10 @@ void RunGetRectsBenchmark(benchmark::State& state, int maxSize) {
118131
}
119132
}
120133

134+
enum RegionOp { kUnion, kIntersection };
135+
121136
template <typename Region>
122-
void RunUnionRegionBenchmark(benchmark::State& state, int maxSize) {
137+
void RunRegionOpBenchmark(benchmark::State& state, RegionOp op, int maxSize) {
123138
std::random_device d;
124139
std::seed_seq seed{2, 1, 3};
125140
std::mt19937 rng(seed);
@@ -142,8 +157,17 @@ void RunUnionRegionBenchmark(benchmark::State& state, int maxSize) {
142157
}
143158
Region region2(rects);
144159

145-
while (state.KeepRunning()) {
146-
Region::unionRegions(region1, region2);
160+
switch (op) {
161+
case kUnion:
162+
while (state.KeepRunning()) {
163+
Region::unionRegions(region1, region2);
164+
}
165+
break;
166+
case kIntersection:
167+
while (state.KeepRunning()) {
168+
Region::intersectRegions(region1, region2);
169+
}
170+
break;
147171
}
148172
}
149173

@@ -224,12 +248,16 @@ static void BM_SkRegion_GetRects(benchmark::State& state, int maxSize) {
224248
RunGetRectsBenchmark<SkRegionAdapter>(state, maxSize);
225249
}
226250

227-
static void BM_DlRegion_MakeUnion(benchmark::State& state, int maxSize) {
228-
RunUnionRegionBenchmark<DlRegionAdapter>(state, maxSize);
251+
static void BM_DlRegion_Operation(benchmark::State& state,
252+
RegionOp op,
253+
int maxSize) {
254+
RunRegionOpBenchmark<DlRegionAdapter>(state, op, maxSize);
229255
}
230256

231-
static void BM_SkRegion_MakeUnion(benchmark::State& state, int maxSize) {
232-
RunUnionRegionBenchmark<SkRegionAdapter>(state, maxSize);
257+
static void BM_SkRegion_Operation(benchmark::State& state,
258+
RegionOp op,
259+
int maxSize) {
260+
RunRegionOpBenchmark<SkRegionAdapter>(state, op, maxSize);
233261
}
234262

235263
static void BM_DlRegion_IntersectsRegion(benchmark::State& state, int maxSize) {
@@ -284,21 +312,62 @@ BENCHMARK_CAPTURE(BM_DlRegion_IntersectsRegion, Large, 1500)
284312
BENCHMARK_CAPTURE(BM_SkRegion_IntersectsRegion, Large, 1500)
285313
->Unit(benchmark::kNanosecond);
286314

287-
BENCHMARK_CAPTURE(BM_DlRegion_MakeUnion, Tiny, 30)
315+
BENCHMARK_CAPTURE(BM_DlRegion_Operation, Union_Tiny, RegionOp::kUnion, 30)
316+
->Unit(benchmark::kMicrosecond);
317+
BENCHMARK_CAPTURE(BM_SkRegion_Operation, Union_Tiny, RegionOp::kUnion, 30)
318+
->Unit(benchmark::kMicrosecond);
319+
BENCHMARK_CAPTURE(BM_DlRegion_Operation, Union_Small, RegionOp::kUnion, 100)
320+
->Unit(benchmark::kMicrosecond);
321+
BENCHMARK_CAPTURE(BM_SkRegion_Operation, Union_Small, RegionOp::kUnion, 100)
322+
->Unit(benchmark::kMicrosecond);
323+
BENCHMARK_CAPTURE(BM_DlRegion_Operation, Union_Medium, RegionOp::kUnion, 400)
324+
->Unit(benchmark::kMicrosecond);
325+
BENCHMARK_CAPTURE(BM_SkRegion_Operation, Union_Medium, RegionOp::kUnion, 400)
326+
->Unit(benchmark::kMicrosecond);
327+
BENCHMARK_CAPTURE(BM_DlRegion_Operation, Union_Large, RegionOp::kUnion, 1500)
328+
->Unit(benchmark::kMicrosecond);
329+
BENCHMARK_CAPTURE(BM_SkRegion_Operation, Union_Large, RegionOp::kUnion, 1500)
330+
->Unit(benchmark::kMicrosecond);
331+
332+
BENCHMARK_CAPTURE(BM_DlRegion_Operation,
333+
Intersection_Tiny,
334+
RegionOp::kIntersection,
335+
30)
288336
->Unit(benchmark::kMicrosecond);
289-
BENCHMARK_CAPTURE(BM_SkRegion_MakeUnion, Tiny, 30)
337+
BENCHMARK_CAPTURE(BM_SkRegion_Operation,
338+
Intersection_Tiny,
339+
RegionOp::kIntersection,
340+
30)
290341
->Unit(benchmark::kMicrosecond);
291-
BENCHMARK_CAPTURE(BM_DlRegion_MakeUnion, Small, 100)
342+
BENCHMARK_CAPTURE(BM_DlRegion_Operation,
343+
Intersection_Small,
344+
RegionOp::kIntersection,
345+
100)
292346
->Unit(benchmark::kMicrosecond);
293-
BENCHMARK_CAPTURE(BM_SkRegion_MakeUnion, Small, 100)
347+
BENCHMARK_CAPTURE(BM_SkRegion_Operation,
348+
Intersection_Small,
349+
RegionOp::kIntersection,
350+
100)
294351
->Unit(benchmark::kMicrosecond);
295-
BENCHMARK_CAPTURE(BM_DlRegion_MakeUnion, Medium, 400)
352+
BENCHMARK_CAPTURE(BM_DlRegion_Operation,
353+
Intersection_Medium,
354+
RegionOp::kIntersection,
355+
400)
296356
->Unit(benchmark::kMicrosecond);
297-
BENCHMARK_CAPTURE(BM_SkRegion_MakeUnion, Medium, 400)
357+
BENCHMARK_CAPTURE(BM_SkRegion_Operation,
358+
Intersection_Medium,
359+
RegionOp::kIntersection,
360+
400)
298361
->Unit(benchmark::kMicrosecond);
299-
BENCHMARK_CAPTURE(BM_DlRegion_MakeUnion, Large, 1500)
362+
BENCHMARK_CAPTURE(BM_DlRegion_Operation,
363+
Intersection_Large,
364+
RegionOp::kIntersection,
365+
1500)
300366
->Unit(benchmark::kMicrosecond);
301-
BENCHMARK_CAPTURE(BM_SkRegion_MakeUnion, Large, 1500)
367+
BENCHMARK_CAPTURE(BM_SkRegion_Operation,
368+
Intersection_Large,
369+
RegionOp::kIntersection,
370+
1500)
302371
->Unit(benchmark::kMicrosecond);
303372

304373
BENCHMARK_CAPTURE(BM_DlRegion_AddRects, Tiny, 30)

display_list/geometry/dl_region.cc

Lines changed: 120 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,51 @@ size_t DlRegion::unionLineSpans(std::vector<Span>& res,
190190
return new_span - res.data();
191191
}
192192

193+
size_t DlRegion::intersectLineSpans(std::vector<Span>& res,
194+
const SpanBuffer& a_buffer,
195+
SpanChunkHandle a_handle,
196+
const SpanBuffer& b_buffer,
197+
SpanChunkHandle b_handle) {
198+
const Span *begin1, *end1;
199+
a_buffer.getSpans(a_handle, begin1, end1);
200+
201+
const Span *begin2, *end2;
202+
b_buffer.getSpans(b_handle, begin2, end2);
203+
204+
// Worst case scenario, interleaved overlapping spans
205+
// AAAA BBBB CCCC
206+
// XXX YYYY XXXX
207+
size_t min_size = (end1 - begin1) + (end2 - begin2) - 1;
208+
if (res.size() < min_size) {
209+
res.resize(min_size);
210+
}
211+
212+
// Pointer to the next span to be written.
213+
Span* new_span = res.data();
214+
215+
while (begin1 != end1 && begin2 != end2) {
216+
if (begin1->right <= begin2->left) {
217+
++begin1;
218+
} else if (begin2->right <= begin1->left) {
219+
++begin2;
220+
} else {
221+
int32_t left = std::max(begin1->left, begin2->left);
222+
int32_t right = std::min(begin1->right, begin2->right);
223+
FML_DCHECK(left < right);
224+
FML_DCHECK(new_span < res.data() + res.size());
225+
*new_span++ = {left, right};
226+
if (begin1->right == right) {
227+
++begin1;
228+
}
229+
if (begin2->right == right) {
230+
++begin2;
231+
}
232+
}
233+
}
234+
235+
return new_span - res.data();
236+
}
237+
193238
void DlRegion::addRects(const std::vector<SkIRect>& unsorted_rects) {
194239
size_t count = unsorted_rects.size();
195240
std::vector<const SkIRect*> rects(count);
@@ -326,41 +371,35 @@ void DlRegion::addRects(const std::vector<SkIRect>& unsorted_rects) {
326371
#endif
327372
}
328373

374+
void DlRegion::appendLine(int32_t top,
375+
int32_t bottom,
376+
const Span* begin,
377+
const Span* end) {
378+
if (lines_.empty()) {
379+
lines_.push_back(makeLine(top, bottom, begin, end));
380+
} else {
381+
if (lines_.back().bottom == top && spansEqual(lines_.back(), begin, end)) {
382+
lines_.back().bottom = bottom;
383+
} else {
384+
lines_.push_back(makeLine(top, bottom, begin, end));
385+
}
386+
}
387+
}
388+
329389
DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
330390
DlRegion res;
331391

332-
res.span_buffer_.reserve(a.span_buffer_.capacity() +
333-
b.span_buffer_.capacity());
334392
res.bounds_ = a.bounds_;
335393
res.bounds_.join(b.bounds_);
336394

395+
res.span_buffer_.reserve(a.span_buffer_.capacity() +
396+
b.span_buffer_.capacity());
397+
337398
auto& lines = res.lines_;
338399
lines.reserve(a.lines_.size() + b.lines_.size());
339400

340-
auto append_spans = [&](int32_t top, int32_t bottom, const Span* begin,
341-
const Span* end) {
342-
if (lines.empty()) {
343-
lines.push_back(res.makeLine(top, bottom, begin, end));
344-
} else {
345-
if (lines.back().bottom == top &&
346-
res.spansEqual(lines.back(), begin, end)) {
347-
lines.back().bottom = bottom;
348-
} else {
349-
lines.push_back(res.makeLine(top, bottom, begin, end));
350-
}
351-
}
352-
};
353-
354-
auto append_line = [&](int32_t top, int32_t bottom, const SpanBuffer& buffer,
355-
SpanChunkHandle chunk_handle) {
356-
const Span *begin, *end;
357-
buffer.getSpans(chunk_handle, begin, end);
358-
append_spans(top, bottom, begin, end);
359-
};
360-
361401
auto a_lines = a.lines_;
362402
auto b_lines = b.lines_;
363-
364403
auto a_it = a_lines.begin();
365404
auto b_it = b_lines.begin();
366405

@@ -371,20 +410,20 @@ DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
371410

372411
while (a_it != a_lines.end() && b_it != b_lines.end()) {
373412
if (a_it->bottom <= b_it->top) {
374-
append_line(a_it->top, a_it->bottom, a_buffer, a_it->chunk_handle);
413+
res.appendLine(a_it->top, a_it->bottom, a_buffer, a_it->chunk_handle);
375414
++a_it;
376415
} else if (b_it->bottom <= a_it->top) {
377-
append_line(b_it->top, b_it->bottom, b_buffer, b_it->chunk_handle);
416+
res.appendLine(b_it->top, b_it->bottom, b_buffer, b_it->chunk_handle);
378417
++b_it;
379418
} else {
380419
if (a_it->top < b_it->top) {
381-
append_line(a_it->top, b_it->top, a_buffer, a_it->chunk_handle);
420+
res.appendLine(a_it->top, b_it->top, a_buffer, a_it->chunk_handle);
382421
a_it->top = b_it->top;
383422
if (a_it->top == b_it->bottom) {
384423
++a_it;
385424
}
386425
} else if (b_it->top < a_it->top) {
387-
append_line(b_it->top, a_it->top, b_buffer, b_it->chunk_handle);
426+
res.appendLine(b_it->top, a_it->top, b_buffer, b_it->chunk_handle);
388427
b_it->top = a_it->top;
389428
if (b_it->top == a_it->bottom) {
390429
++b_it;
@@ -396,7 +435,7 @@ DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
396435
FML_DCHECK(new_bottom > b_it->top);
397436
auto size = unionLineSpans(tmp, a_buffer, a_it->chunk_handle, b_buffer,
398437
b_it->chunk_handle);
399-
append_spans(a_it->top, new_bottom, tmp.data(), tmp.data() + size);
438+
res.appendLine(a_it->top, new_bottom, tmp.data(), tmp.data() + size);
400439
a_it->top = b_it->top = new_bottom;
401440
if (a_it->top == a_it->bottom) {
402441
++a_it;
@@ -411,18 +450,68 @@ DlRegion DlRegion::MakeUnion(const DlRegion& a, const DlRegion& b) {
411450
FML_DCHECK(a_it == a_lines.end() || b_it == b_lines.end());
412451

413452
while (a_it != a_lines.end()) {
414-
append_line(a_it->top, a_it->bottom, a_buffer, a_it->chunk_handle);
453+
res.appendLine(a_it->top, a_it->bottom, a_buffer, a_it->chunk_handle);
415454
++a_it;
416455
}
417456

418457
while (b_it != b_lines.end()) {
419-
append_line(b_it->top, b_it->bottom, b_buffer, b_it->chunk_handle);
458+
res.appendLine(b_it->top, b_it->bottom, b_buffer, b_it->chunk_handle);
420459
++b_it;
421460
}
422461

423462
return res;
424463
}
425464

465+
DlRegion DlRegion::MakeIntersection(const DlRegion& a, const DlRegion& b) {
466+
DlRegion res;
467+
if (!SkIRect::Intersects(a.bounds_, b.bounds_)) {
468+
return res;
469+
}
470+
471+
res.span_buffer_.reserve(
472+
std::max(a.span_buffer_.capacity(), b.span_buffer_.capacity()));
473+
474+
auto& lines = res.lines_;
475+
lines.reserve(std::min(a.lines_.size(), b.lines_.size()));
476+
477+
auto a_lines = a.lines_;
478+
auto b_lines = b.lines_;
479+
auto a_it = a_lines.begin();
480+
auto b_it = b_lines.begin();
481+
482+
auto& a_buffer = a.span_buffer_;
483+
auto& b_buffer = b.span_buffer_;
484+
485+
std::vector<Span> tmp;
486+
487+
while (a_it != a_lines.end() && b_it != b_lines.end()) {
488+
if (a_it->bottom <= b_it->top) {
489+
++a_it;
490+
} else if (b_it->bottom <= a_it->top) {
491+
++b_it;
492+
} else {
493+
auto top = std::max(a_it->top, b_it->top);
494+
auto bottom = std::min(a_it->bottom, b_it->bottom);
495+
auto size = intersectLineSpans(tmp, a_buffer, a_it->chunk_handle,
496+
b_buffer, b_it->chunk_handle);
497+
if (size > 0) {
498+
res.appendLine(top, bottom, tmp.data(), tmp.data() + size);
499+
res.bounds_.join(SkIRect::MakeLTRB(
500+
tmp.data()->left, top, (tmp.data() + size - 1)->right, bottom));
501+
}
502+
a_it->top = b_it->top = bottom;
503+
if (a_it->top == a_it->bottom) {
504+
++a_it;
505+
}
506+
if (b_it->top == b_it->bottom) {
507+
++b_it;
508+
}
509+
}
510+
}
511+
FML_DCHECK(a_it == a_lines.end() || b_it == b_lines.end());
512+
return res;
513+
}
514+
426515
std::vector<SkIRect> DlRegion::getRects(bool deband) const {
427516
std::vector<SkIRect> rects;
428517
size_t rect_count = 0;

0 commit comments

Comments
 (0)