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

Implement union and intersection for DlRegion #42620

Merged
merged 39 commits into from
Jun 26, 2023
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c06ba33
Implement DlRegion::addRegion and DlRegion::intersects
knopp Jun 6, 2023
28cfa12
Use new AddRects implementation
knopp Jun 8, 2023
2a38c20
Small cleanups
knopp Jun 8, 2023
adc9a4a
Address feedback
knopp Jun 9, 2023
c92fc2f
Rename
knopp Jun 9, 2023
a9f8f4c
Move the DCHECK
knopp Jun 9, 2023
a7f45a8
Add more tests
knopp Jun 9, 2023
ff16ef0
Split AddRect/GetRects benchmarks
knopp Jun 9, 2023
3d1f592
Add DlRegion::MakeIntersection
knopp Jun 10, 2023
730a23a
Rename AddRects in benchmarks to FromRects
knopp Jun 10, 2023
d6c81db
Add more tests
knopp Jun 10, 2023
48a740b
Fix comments
knopp Jun 13, 2023
c47663d
Remove unnecessary lines_ copy
knopp Jun 13, 2023
4061527
Add setChunkSize, use getChunkSize also internally
knopp Jun 13, 2023
518bf1d
Add DCHECK
knopp Jun 13, 2023
d4d001e
Remove redundant check
knopp Jun 13, 2023
e5a42d0
Simplify unionLineSpans
knopp Jun 13, 2023
3dfb25c
Use SkRegion::setRects
knopp Jun 13, 2023
c40bb7c
Fix typo.
knopp Jun 16, 2023
d63212e
Union and intersction optimisations
knopp Jun 16, 2023
bc2ab15
Fix comment typos
knopp Jun 16, 2023
5d53c35
Expose region in DlRTree
knopp Jun 16, 2023
95105b5
Use DlRegion from R-Tree in raster cache
knopp Jun 16, 2023
f6e2a42
Add empty constructor and assignment operators
knopp Jun 23, 2023
9132921
Fix clang-tidy warning
knopp Jun 23, 2023
abca8ef
Use SkRegion::setRects in benchmarks
knopp Jun 24, 2023
0a5ca5f
Nits
knopp Jun 24, 2023
47a257d
Use OrderedSpanAccumulator
knopp Jun 24, 2023
a274cec
Replace upper_bound with lower_bound
knopp Jun 24, 2023
3ccbf2d
Fix comment.
knopp Jun 24, 2023
9326b4f
i => top
knopp Jun 24, 2023
ca48f44
Use assymetric sizes when unit testing
knopp Jun 25, 2023
e7e4fa4
Benchmark speed on assymetric regions (one significantly larger than …
knopp Jun 25, 2023
134bc4a
Use binary search for intersection
knopp Jun 25, 2023
7bd2ae4
Switch units back to microsecond
knopp Jun 25, 2023
1df34ac
Add isEmpty() checks
knopp Jun 25, 2023
618c831
Correct spelling
knopp Jun 25, 2023
88b5012
Extract binary search into separate method
knopp Jun 25, 2023
9568dd2
Add threshold check for single rect intersect
knopp Jun 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
680 changes: 650 additions & 30 deletions display_list/benchmarking/dl_region_benchmarks.cc

Large diffs are not rendered by default.

849 changes: 680 additions & 169 deletions display_list/geometry/dl_region.cc

Large diffs are not rendered by default.

142 changes: 122 additions & 20 deletions display_list/geometry/dl_region.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "third_party/skia/include/core/SkRect.h"

#include <memory>
#include <vector>

namespace flutter {
Expand All @@ -16,48 +17,149 @@ namespace flutter {
/// converting set of overlapping rectangles to non-overlapping rectangles.
class DlRegion {
public:
/// Creates region by bulk adding the rectangles./// Matches
/// SkRegion::op(rect, SkRegion::kUnion_Op) behavior.
explicit DlRegion(std::vector<SkIRect>&& rects);
~DlRegion();
/// Creates an empty region.
DlRegion() = default;

/// Creates region by bulk adding the rectangles.
/// Matches SkRegion::op(rect, SkRegion::kUnion_Op) behavior.
explicit DlRegion(const std::vector<SkIRect>& rects);

/// Creates region covering area of a rectangle.
explicit DlRegion(const SkIRect& rect);

DlRegion(const DlRegion&) = default;
DlRegion(DlRegion&&) = default;

DlRegion& operator=(const DlRegion&) = default;
DlRegion& operator=(DlRegion&&) = default;

/// Creates union region of region a and b.
/// Matches SkRegion a; a.op(b, SkRegion::kUnion_Op) behavior.
static DlRegion MakeUnion(const DlRegion& a, const DlRegion& b);

/// Creates intersection region of region a and b.
/// Matches SkRegion a; a.op(b, SkRegion::kIntersect_Op) behavior.
static DlRegion MakeIntersection(const DlRegion& a, const DlRegion& b);

/// Returns list of non-overlapping rectangles that cover current region.
/// If |deband| is false, each span line will result in separate rectangles,
/// closely matching SkRegion::Iterator behavior.
/// If |deband| is true, matching rectangles from adjacent span lines will be
/// merged into single rectange.
/// merged into single rectangle.
std::vector<SkIRect> getRects(bool deband = true) const;

/// Returns maximum and minimum axis values of rectangles in this region.
/// If region is empty returns SKIRect::MakeEmpty().
const SkIRect& bounds() const { return bounds_; }

/// Returns whether this region intersects with a rectangle.
bool intersects(const SkIRect& rect) const;

/// Returns whether this region intersects with another region.
bool intersects(const DlRegion& region) const;

/// Returns true if region is empty (contains no rectangles).
bool isEmpty() const { return lines_.empty(); }

/// Returns true if region is not empty and contains more than one rectangle.
bool isComplex() const;

/// Returns true if region can be represented by single rectangle or is
/// empty.
bool isSimple() const { return !isComplex(); }

private:
void addRects(std::vector<SkIRect>&& rects);
typedef std::uint32_t SpanChunkHandle;

struct Span {
int32_t left;
int32_t right;

Span() = default;
Span(int32_t left, int32_t right) : left(left), right(right) {}
};
typedef std::vector<Span> SpanVec;

/// Holds spans for the region. Having custom allocated memory that doesn't
/// do zero initialization every time the buffer gets resized improves
/// performance measurably.
class SpanBuffer {
public:
SpanBuffer() = default;
SpanBuffer(const SpanBuffer&);
SpanBuffer(SpanBuffer&& m);
SpanBuffer& operator=(const SpanBuffer&);
SpanBuffer& operator=(SpanBuffer&& m);

void reserve(size_t capacity);
size_t capacity() const { return capacity_; }

SpanChunkHandle storeChunk(const Span* begin, const Span* end);
size_t getChunkSize(SpanChunkHandle handle) const;
void getSpans(SpanChunkHandle handle,
const DlRegion::Span*& begin,
const DlRegion::Span*& end) const;

~SpanBuffer();

private:
void setChunkSize(SpanChunkHandle handle, size_t size);

size_t capacity_ = 0;
size_t size_ = 0;

// Spans for the region chunks. First span in each chunk contains the
// chunk size.
Span* spans_ = nullptr;
};

struct SpanLine {
int32_t top;
int32_t bottom;
SpanVec* spans;

void insertSpan(int32_t left, int32_t right);
bool spansEqual(const SpanLine& l2) const;
SpanChunkHandle chunk_handle;
};

typedef std::vector<SpanLine> LineVec;
void setRects(const std::vector<SkIRect>& rects);

std::vector<SpanLine> lines_;
std::vector<SpanVec*> spanvec_pool_;

void insertLine(size_t position, SpanLine line);
LineVec::iterator removeLine(LineVec::iterator position);
void appendLine(int32_t top,
int32_t bottom,
const Span* begin,
const Span* end);
void appendLine(int32_t top,
int32_t bottom,
const SpanBuffer& buffer,
SpanChunkHandle handle) {
const Span *begin, *end;
buffer.getSpans(handle, begin, end);
appendLine(top, bottom, begin, end);
}

typedef std::vector<Span> SpanVec;
SpanLine makeLine(int32_t top, int32_t bottom, const SpanVec&);
SpanLine makeLine(int32_t top,
int32_t bottom,
int32_t spanLeft,
int32_t spanRight);
SpanLine makeLine(int32_t top, int32_t bottom, const SpanVec& spans);
const Span* begin,
const Span* end);
static size_t unionLineSpans(std::vector<Span>& res,
const SpanBuffer& a_buffer,
SpanChunkHandle a_handle,
const SpanBuffer& b_buffer,
SpanChunkHandle b_handle);
static size_t intersectLineSpans(std::vector<Span>& res,
const SpanBuffer& a_buffer,
SpanChunkHandle a_handle,
const SpanBuffer& b_buffer,
SpanChunkHandle b_handle);

bool spansEqual(SpanLine& line, const Span* begin, const Span* end) const;

static bool spansIntersect(const Span* begin1,
const Span* end1,
const Span* begin2,
const Span* end2);

std::vector<SpanLine> lines_;
SkIRect bounds_ = SkIRect::MakeEmpty();
SpanBuffer span_buffer_;
};

} // namespace flutter
Expand Down
Loading