Skip to content

Commit

Permalink
cc: Replace Region with SimpleEnclosedRegion for occlusion tracking
Browse files Browse the repository at this point in the history
Instead of using an arbitrary Region, which is costly (slow), use
a new SimpleEnclosedRegion. This class tracks only a single Rect
at a given time so it is very fast and small. It tries to get
something like the largest rect enclosed in the actual Region
(were we to track such a Region) in an online fashion, ie it
doesn't remember anything except its current largest possible
rect.

BUG=405663

Review URL: https://codereview.chromium.org/202523002

Cr-Commit-Position: refs/heads/master@{#291292}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291292 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
danakj@chromium.org committed Aug 22, 2014
1 parent 903cf84 commit d5467eb
Show file tree
Hide file tree
Showing 28 changed files with 1,545 additions and 758 deletions.
3 changes: 3 additions & 0 deletions cc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ component("cc") {
"base/scoped_ptr_algorithm.h",
"base/scoped_ptr_deque.h",
"base/scoped_ptr_vector.h",
"base/simple_enclosed_region.cc",
"base/simple_enclosed_region.h",
"base/swap_promise.h",
"base/swap_promise_monitor.cc",
"base/swap_promise_monitor.h",
Expand Down Expand Up @@ -646,6 +648,7 @@ test("cc_unittests") {
"base/region_unittest.cc",
"base/rolling_time_delta_history_unittest.cc",
"base/scoped_ptr_vector_unittest.cc",
"base/simple_enclosed_region_unittest.cc",
"base/tiling_data_unittest.cc",
"base/util_unittest.cc",
"debug/micro_benchmark_controller_unittest.cc",
Expand Down
9 changes: 9 additions & 0 deletions cc/base/region.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
// found in the LICENSE file.

#include "cc/base/region.h"

#include "base/debug/trace_event_argument.h"
#include "base/values.h"
#include "cc/base/simple_enclosed_region.h"

namespace cc {

Expand Down Expand Up @@ -80,6 +82,13 @@ void Region::Subtract(const Region& region) {
skregion_.op(region.skregion_, SkRegion::kDifference_Op);
}

void Region::Subtract(const SimpleEnclosedRegion& region) {
for (size_t i = 0; i < region.GetRegionComplexity(); ++i) {
skregion_.op(gfx::RectToSkIRect(region.GetRect(i)),
SkRegion::kDifference_Op);
}
}

void Region::Union(const gfx::Rect& rect) {
skregion_.op(gfx::RectToSkIRect(rect), SkRegion::kUnion_Op);
}
Expand Down
3 changes: 2 additions & 1 deletion cc/base/region.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#include <string>

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "third_party/skia/include/core/SkRegion.h"
Expand All @@ -22,6 +21,7 @@ class TracedValue;
}

namespace cc {
class SimpleEnclosedRegion;

class CC_EXPORT Region {
public:
Expand All @@ -47,6 +47,7 @@ class CC_EXPORT Region {

void Subtract(const gfx::Rect& rect);
void Subtract(const Region& region);
void Subtract(const SimpleEnclosedRegion& region);
void Union(const gfx::Rect& rect);
void Union(const Region& region);
void Intersect(const gfx::Rect& rect);
Expand Down
136 changes: 136 additions & 0 deletions cc/base/simple_enclosed_region.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "cc/base/simple_enclosed_region.h"

#include "base/logging.h"
#include "cc/base/region.h"

namespace cc {

static bool RectIsLargerArea(const gfx::Rect& a, const gfx::Rect b) {
int64 a_area = static_cast<int64>(a.width()) * a.height();
int64 b_area = static_cast<int64>(b.width()) * b.height();
return a_area > b_area;
}

SimpleEnclosedRegion::SimpleEnclosedRegion(const Region& region) {
for (Region::Iterator it(region); it.has_rect(); it.next())
Union(it.rect());
}

SimpleEnclosedRegion::~SimpleEnclosedRegion() {
}

void SimpleEnclosedRegion::Subtract(const gfx::Rect& sub_rect) {
// We want to keep as much of the current rect as we can, so find the one
// largest rectangle inside |rect_| that does not intersect with |sub_rect|.
if (!rect_.Intersects(sub_rect))
return;
if (sub_rect.Contains(rect_)) {
rect_ = gfx::Rect();
return;
}

int left = rect_.x();
int right = rect_.right();
int top = rect_.y();
int bottom = rect_.bottom();

int delta_left = sub_rect.x() - left;
int delta_right = right - sub_rect.right();
int delta_top = sub_rect.y() - top;
int delta_bottom = bottom - sub_rect.bottom();

// The horizontal rect is the larger of the two rectangles above or below
// |sub_rect| and inside rect_.
int horizontal_top = top;
int horizontal_bottom = bottom;
if (delta_top > delta_bottom)
horizontal_bottom = sub_rect.y();
else
horizontal_top = sub_rect.bottom();
// The vertical rect is the larger of the two rectangles to the left or the
// right of |sub_rect| and inside rect_.
int vertical_left = left;
int vertical_right = right;
if (delta_left > delta_right)
vertical_right = sub_rect.x();
else
vertical_left = sub_rect.right();

rect_.SetRect(
left, horizontal_top, right - left, horizontal_bottom - horizontal_top);

gfx::Rect vertical_rect(
vertical_left, top, vertical_right - vertical_left, bottom - top);
if (RectIsLargerArea(vertical_rect, rect_))
rect_ = vertical_rect;
}

void SimpleEnclosedRegion::Union(const gfx::Rect& new_rect) {
// We want to keep track of a region but bound its complexity at a constant
// size. We keep track of the largest rectangle seen by area. If we can add
// the |new_rect| to this rectangle then we do that, as that is the cheapest
// way to increase the area returned without increasing the complexity.
if (new_rect.IsEmpty())
return;
if (rect_.Contains(new_rect))
return;
if (new_rect.Contains(rect_)) {
rect_ = new_rect;
return;
}

int left = rect_.x();
int top = rect_.y();
int right = rect_.right();
int bottom = rect_.bottom();

int new_left = new_rect.x();
int new_top = new_rect.y();
int new_right = new_rect.right();
int new_bottom = new_rect.bottom();

// This attempts to expand each edge of |rect_| if the |new_rect| entirely
// covers or is adjacent to an entire edge of |rect_|. If this is true for
// an edge of |rect_| then it can be expanded out to share that edge with the
// same edge of |new_rect|. After, the same thing is done to try expand
// |new_rect| relative to |rect_|.
if (new_top <= top && new_bottom >= bottom) {
if (new_left < left && new_right >= left)
left = new_left;
if (new_right > right && new_left <= right)
right = new_right;
} else if (new_left <= left && new_right >= right) {
if (new_top < top && new_bottom >= top)
top = new_top;
if (new_bottom > bottom && new_top <= bottom)
bottom = new_bottom;
} else if (top <= new_top && bottom >= new_bottom) {
if (left < new_left && right >= new_left)
new_left = left;
if (right > new_right && left <= new_right)
new_right = right;
} else if (left <= new_left && right >= new_right) {
if (top < new_top && bottom >= new_top)
new_top = top;
if (bottom > new_bottom && top <= new_bottom)
new_bottom = bottom;
}

rect_.SetRect(left, top, right - left, bottom - top);

gfx::Rect adjusted_new_rect(
new_left, new_top, new_right - new_left, new_bottom - new_top);
if (RectIsLargerArea(adjusted_new_rect, rect_))
rect_ = adjusted_new_rect;
}

gfx::Rect SimpleEnclosedRegion::GetRect(size_t i) const {
DCHECK_LT(i, GetRegionComplexity());
return rect_;
}

} // namespace cc
122 changes: 122 additions & 0 deletions cc/base/simple_enclosed_region.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_BASE_SIMPLE_ENCLOSED_REGION_H_
#define CC_BASE_SIMPLE_ENCLOSED_REGION_H_

#include <string>

#include "cc/base/cc_export.h"
#include "ui/gfx/rect.h"

namespace cc {

class Region;

// A constant-sized approximation of a Region. The SimpleEnclosedRegion may
// exclude points in its approximation (may have false negatives) but will never
// include a point that would not be in the actual Region (no false positives).
class CC_EXPORT SimpleEnclosedRegion {
public:
SimpleEnclosedRegion() : rect_() {}
SimpleEnclosedRegion(const SimpleEnclosedRegion& region)
: rect_(region.rect_) {}
explicit SimpleEnclosedRegion(const gfx::Rect& rect) : rect_(rect) {}
SimpleEnclosedRegion(int x, int y, int w, int h) : rect_(x, y, w, h) {}
SimpleEnclosedRegion(int w, int h) : rect_(w, h) {}
explicit SimpleEnclosedRegion(const Region& region);
~SimpleEnclosedRegion();

const SimpleEnclosedRegion& operator=(const gfx::Rect& rect) {
rect_ = rect;
return *this;
}
const SimpleEnclosedRegion& operator=(const SimpleEnclosedRegion& region) {
rect_ = region.rect_;
return *this;
}

bool IsEmpty() const { return rect_.IsEmpty(); }
void Clear() { rect_ = gfx::Rect(); }
size_t GetRegionComplexity() const { return rect_.IsEmpty() ? 0 : 1; }

bool Contains(const gfx::Point& point) const { return rect_.Contains(point); }
bool Contains(const gfx::Rect& rect) const { return rect_.Contains(rect); }
bool Contains(const SimpleEnclosedRegion& region) const {
return rect_.Contains(region.rect_);
}

bool Intersects(const gfx::Rect& rect) const {
return rect_.Intersects(rect);
}
bool Intersects(const SimpleEnclosedRegion& region) const {
return rect_.Intersects(region.rect_);
}

void Subtract(const gfx::Rect& sub_rect);
void Subtract(const SimpleEnclosedRegion& sub_region) {
Subtract(sub_region.rect_);
}
void Union(const gfx::Rect& new_rect);
void Union(const SimpleEnclosedRegion& new_region) {
Union(new_region.rect_);
}
void Intersect(const gfx::Rect& in_rect) { return rect_.Intersect(in_rect); }
void Intersect(const SimpleEnclosedRegion& in_region) {
Intersect(in_region.rect_);
}

bool Equals(const SimpleEnclosedRegion& other) const {
bool both_empty = rect_.IsEmpty() && other.rect_.IsEmpty();
return both_empty || rect_ == other.rect_;
}

gfx::Rect bounds() const { return rect_; }

// The value of |i| must be less than GetRegionComplexity().
gfx::Rect GetRect(size_t i) const;

std::string ToString() const { return rect_.ToString(); }

private:
gfx::Rect rect_;
};

inline bool operator==(const SimpleEnclosedRegion& a,
const SimpleEnclosedRegion& b) {
return a.Equals(b);
}

inline bool operator!=(const SimpleEnclosedRegion& a,
const SimpleEnclosedRegion& b) {
return !(a == b);
}

inline SimpleEnclosedRegion SubtractSimpleEnclosedRegions(
const SimpleEnclosedRegion& a,
const SimpleEnclosedRegion& b) {
SimpleEnclosedRegion result = a;
result.Subtract(b);
return result;
}

inline SimpleEnclosedRegion IntersectSimpleEnclosedRegions(
const SimpleEnclosedRegion& a,
const SimpleEnclosedRegion& b) {
SimpleEnclosedRegion result = a;
result.Intersect(b);
return result;
}

inline SimpleEnclosedRegion UnionSimpleEnclosedRegions(
const SimpleEnclosedRegion& a,
const SimpleEnclosedRegion& b) {
SimpleEnclosedRegion result = a;
result.Union(b);
return result;
}

} // namespace cc

#endif // CC_BASE_SIMPLE_ENCLOSED_REGION_H_
Loading

0 comments on commit d5467eb

Please sign in to comment.