Commit c8357ff5 authored by danakj's avatar danakj Committed by Commit bot

cc: Stop converting Rect to QuadF to map to an enclosed rect.

Occlusion tracker converts Rects to QuadF, then does MapClippedQuad,
then BoundingBox(), then ToEnclosedRect(). Instead, add methods to
MathUtil that mirror the {Map,Project}EnclosingClippedRect
methods but for an enclosed rect instead, that work only when the
transform preserves 2d axis alignment.

In the common case, this avoids converting the integers to floats just
to convert back to ints using the costly safe conversion methods.

R=enne

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

Cr-Commit-Position: refs/heads/master@{#291785}
parent 38c3ae72
...@@ -121,11 +121,9 @@ static inline void AddVertexToClippedQuad3d(const gfx::Point3F& new_vertex, ...@@ -121,11 +121,9 @@ static inline void AddVertexToClippedQuad3d(const gfx::Point3F& new_vertex,
gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform, gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform,
const gfx::Rect& src_rect) { const gfx::Rect& src_rect) {
if (transform.IsIdentityOrIntegerTranslation()) { if (transform.IsIdentityOrIntegerTranslation()) {
return src_rect + gfx::Vector2d offset(static_cast<int>(transform.matrix().getFloat(0, 3)),
gfx::Vector2d( static_cast<int>(transform.matrix().getFloat(1, 3)));
static_cast<int>(SkMScalarToFloat(transform.matrix().get(0, 3))), return src_rect + offset;
static_cast<int>(
SkMScalarToFloat(transform.matrix().get(1, 3))));
} }
return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect))); return gfx::ToEnclosingRect(MapClippedRect(transform, gfx::RectF(src_rect)));
} }
...@@ -133,9 +131,9 @@ gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform, ...@@ -133,9 +131,9 @@ gfx::Rect MathUtil::MapEnclosingClippedRect(const gfx::Transform& transform,
gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform, gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
const gfx::RectF& src_rect) { const gfx::RectF& src_rect) {
if (transform.IsIdentityOrTranslation()) { if (transform.IsIdentityOrTranslation()) {
return src_rect + gfx::Vector2dF offset(transform.matrix().getFloat(0, 3),
gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)), transform.matrix().getFloat(1, 3));
SkMScalarToFloat(transform.matrix().get(1, 3))); return src_rect + offset;
} }
// Apply the transform, but retain the result in homogeneous coordinates. // Apply the transform, but retain the result in homogeneous coordinates.
...@@ -163,11 +161,9 @@ gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform, ...@@ -163,11 +161,9 @@ gfx::RectF MathUtil::MapClippedRect(const gfx::Transform& transform,
gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform, gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform,
const gfx::Rect& src_rect) { const gfx::Rect& src_rect) {
if (transform.IsIdentityOrIntegerTranslation()) { if (transform.IsIdentityOrIntegerTranslation()) {
return src_rect + gfx::Vector2d offset(static_cast<int>(transform.matrix().getFloat(0, 3)),
gfx::Vector2d( static_cast<int>(transform.matrix().getFloat(1, 3)));
static_cast<int>(SkMScalarToFloat(transform.matrix().get(0, 3))), return src_rect + offset;
static_cast<int>(
SkMScalarToFloat(transform.matrix().get(1, 3))));
} }
return gfx::ToEnclosingRect( return gfx::ToEnclosingRect(
ProjectClippedRect(transform, gfx::RectF(src_rect))); ProjectClippedRect(transform, gfx::RectF(src_rect)));
...@@ -176,9 +172,9 @@ gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform, ...@@ -176,9 +172,9 @@ gfx::Rect MathUtil::ProjectEnclosingClippedRect(const gfx::Transform& transform,
gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform, gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& src_rect) { const gfx::RectF& src_rect) {
if (transform.IsIdentityOrTranslation()) { if (transform.IsIdentityOrTranslation()) {
return src_rect + gfx::Vector2dF offset(transform.matrix().getFloat(0, 3),
gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)), transform.matrix().getFloat(1, 3));
SkMScalarToFloat(transform.matrix().get(1, 3))); return src_rect + offset;
} }
// Perform the projection, but retain the result in homogeneous coordinates. // Perform the projection, but retain the result in homogeneous coordinates.
...@@ -191,6 +187,41 @@ gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform, ...@@ -191,6 +187,41 @@ gfx::RectF MathUtil::ProjectClippedRect(const gfx::Transform& transform,
return ComputeEnclosingClippedRect(h1, h2, h3, h4); return ComputeEnclosingClippedRect(h1, h2, h3, h4);
} }
gfx::Rect MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
const gfx::Transform& transform,
const gfx::Rect& rect) {
DCHECK(transform.Preserves2dAxisAlignment());
if (transform.IsIdentityOrIntegerTranslation()) {
gfx::Vector2d offset(static_cast<int>(transform.matrix().getFloat(0, 3)),
static_cast<int>(transform.matrix().getFloat(1, 3)));
return rect + offset;
}
if (transform.IsIdentityOrTranslation()) {
gfx::Vector2dF offset(transform.matrix().getFloat(0, 3),
transform.matrix().getFloat(1, 3));
return gfx::ToEnclosedRect(rect + offset);
}
SkMScalar quad[2 * 2]; // input: 2 x 2D points
quad[0] = rect.x();
quad[1] = rect.y();
quad[2] = rect.right();
quad[3] = rect.bottom();
SkMScalar result[4 * 2]; // output: 2 x 4D homogeneous points
transform.matrix().map2(quad, 2, result);
HomogeneousCoordinate hc0(result[0], result[1], result[2], result[3]);
HomogeneousCoordinate hc1(result[4], result[5], result[6], result[7]);
DCHECK(!hc0.ShouldBeClipped());
DCHECK(!hc1.ShouldBeClipped());
gfx::PointF top_left(hc0.CartesianPoint2d());
gfx::PointF bottom_right(hc1.CartesianPoint2d());
return gfx::ToEnclosedRect(gfx::BoundingRect(top_left, bottom_right));
}
void MathUtil::MapClippedQuad(const gfx::Transform& transform, void MathUtil::MapClippedQuad(const gfx::Transform& transform,
const gfx::QuadF& src_quad, const gfx::QuadF& src_quad,
gfx::PointF clipped_quad[8], gfx::PointF clipped_quad[8],
...@@ -436,9 +467,8 @@ gfx::QuadF MathUtil::MapQuad(const gfx::Transform& transform, ...@@ -436,9 +467,8 @@ gfx::QuadF MathUtil::MapQuad(const gfx::Transform& transform,
bool* clipped) { bool* clipped) {
if (transform.IsIdentityOrTranslation()) { if (transform.IsIdentityOrTranslation()) {
gfx::QuadF mapped_quad(q); gfx::QuadF mapped_quad(q);
mapped_quad += mapped_quad += gfx::Vector2dF(transform.matrix().getFloat(0, 3),
gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)), transform.matrix().getFloat(1, 3));
SkMScalarToFloat(transform.matrix().get(1, 3)));
*clipped = false; *clipped = false;
return mapped_quad; return mapped_quad;
} }
...@@ -469,9 +499,8 @@ gfx::QuadF MathUtil::MapQuad3d(const gfx::Transform& transform, ...@@ -469,9 +499,8 @@ gfx::QuadF MathUtil::MapQuad3d(const gfx::Transform& transform,
bool* clipped) { bool* clipped) {
if (transform.IsIdentityOrTranslation()) { if (transform.IsIdentityOrTranslation()) {
gfx::QuadF mapped_quad(q); gfx::QuadF mapped_quad(q);
mapped_quad += mapped_quad += gfx::Vector2dF(transform.matrix().getFloat(0, 3),
gfx::Vector2dF(SkMScalarToFloat(transform.matrix().get(0, 3)), transform.matrix().getFloat(1, 3));
SkMScalarToFloat(transform.matrix().get(1, 3)));
*clipped = false; *clipped = false;
p[0] = gfx::Point3F(mapped_quad.p1().x(), mapped_quad.p1().y(), 0.0f); p[0] = gfx::Point3F(mapped_quad.p1().x(), mapped_quad.p1().y(), 0.0f);
p[1] = gfx::Point3F(mapped_quad.p2().x(), mapped_quad.p2().y(), 0.0f); p[1] = gfx::Point3F(mapped_quad.p2().x(), mapped_quad.p2().y(), 0.0f);
......
...@@ -115,6 +115,12 @@ class CC_EXPORT MathUtil { ...@@ -115,6 +115,12 @@ class CC_EXPORT MathUtil {
static gfx::RectF ProjectClippedRect(const gfx::Transform& transform, static gfx::RectF ProjectClippedRect(const gfx::Transform& transform,
const gfx::RectF& rect); const gfx::RectF& rect);
// This function is only valid when the transform preserves 2d axis
// alignment and the resulting rect will not be clipped.
static gfx::Rect MapEnclosedRectWith2dAxisAlignedTransform(
const gfx::Transform& transform,
const gfx::Rect& rect);
// Returns an array of vertices that represent the clipped polygon. After // Returns an array of vertices that represent the clipped polygon. After
// returning, indexes from 0 to num_vertices_in_clipped_quad are valid in the // returning, indexes from 0 to num_vertices_in_clipped_quad are valid in the
// clipped_quad array. Note that num_vertices_in_clipped_quad may be zero, // clipped_quad array. Note that num_vertices_in_clipped_quad may be zero,
......
...@@ -120,5 +120,78 @@ TEST(MathUtilTest, VectorProjection) { ...@@ -120,5 +120,78 @@ TEST(MathUtilTest, VectorProjection) {
projected_vector.y() / target_vector.y()); projected_vector.y() / target_vector.y());
} }
TEST(MathUtilTest, MapEnclosedRectWith2dAxisAlignedTransform) {
gfx::Rect input(1, 2, 3, 4);
gfx::Rect output;
gfx::Transform transform;
// Identity.
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(input, output);
// Integer translate.
transform.Translate(2.0, 3.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(3, 5, 3, 4), output);
// Non-integer translate.
transform.Translate(0.5, 0.5);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(4, 6, 2, 3), output);
// Scale.
transform = gfx::Transform();
transform.Scale(2.0, 3.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(2, 6, 6, 12), output);
// Rotate Z.
transform = gfx::Transform();
transform.Translate(1.0, 2.0);
transform.RotateAboutZAxis(90.0);
transform.Translate(-1.0, -2.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(-3, 2, 4, 3), output);
// Rotate X.
transform = gfx::Transform();
transform.RotateAboutXAxis(90.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_TRUE(output.IsEmpty());
transform = gfx::Transform();
transform.RotateAboutXAxis(180.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(1, -6, 3, 4), output);
// Rotate Y.
transform = gfx::Transform();
transform.RotateAboutYAxis(90.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_TRUE(output.IsEmpty());
transform = gfx::Transform();
transform.RotateAboutYAxis(180.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(-4, 2, 3, 4), output);
// Translate Z.
transform = gfx::Transform();
transform.ApplyPerspectiveDepth(10.0);
transform.Translate3d(0.0, 0.0, 5.0);
output =
MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, input);
EXPECT_EQ(gfx::Rect(2, 4, 6, 8), output);
}
} // namespace } // namespace
} // namespace cc } // namespace cc
...@@ -84,12 +84,9 @@ static SimpleEnclosedRegion TransformSurfaceOpaqueRegion( ...@@ -84,12 +84,9 @@ static SimpleEnclosedRegion TransformSurfaceOpaqueRegion(
SimpleEnclosedRegion transformed_region; SimpleEnclosedRegion transformed_region;
for (size_t i = 0; i < region.GetRegionComplexity(); ++i) { for (size_t i = 0; i < region.GetRegionComplexity(); ++i) {
bool clipped;
gfx::QuadF transformed_quad =
MathUtil::MapQuad(transform, gfx::QuadF(region.GetRect(i)), &clipped);
gfx::Rect transformed_rect = gfx::Rect transformed_rect =
gfx::ToEnclosedRect(transformed_quad.BoundingBox()); MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform,
DCHECK(!clipped); // We only map if the transform preserves axis alignment. region.GetRect(i));
if (have_clip_rect) if (have_clip_rect)
transformed_rect.Intersect(clip_rect_in_new_target); transformed_rect.Intersect(clip_rect_in_new_target);
transformed_region.Union(transformed_rect); transformed_region.Union(transformed_rect);
...@@ -432,14 +429,9 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer( ...@@ -432,14 +429,9 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
} }
for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) { for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) {
bool clipped;
gfx::QuadF transformed_quad =
MathUtil::MapQuad(layer->draw_transform(),
gfx::QuadF(opaque_contents.GetRect(i)),
&clipped);
gfx::Rect transformed_rect = gfx::Rect transformed_rect =
gfx::ToEnclosedRect(transformed_quad.BoundingBox()); MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
DCHECK(!clipped); // We only map if the transform preserves axis alignment. layer->draw_transform(), opaque_contents.GetRect(i));
transformed_rect.Intersect(clip_rect_in_target); transformed_rect.Intersect(clip_rect_in_target);
if (transformed_rect.width() < minimum_tracking_size_.width() && if (transformed_rect.width() < minimum_tracking_size_.width() &&
transformed_rect.height() < minimum_tracking_size_.height()) transformed_rect.height() < minimum_tracking_size_.height())
...@@ -450,6 +442,7 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer( ...@@ -450,6 +442,7 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
continue; continue;
// Save the occluding area in screen space for debug visualization. // Save the occluding area in screen space for debug visualization.
bool clipped;
gfx::QuadF screen_space_quad = MathUtil::MapQuad( gfx::QuadF screen_space_quad = MathUtil::MapQuad(
layer->render_target()->render_surface()->screen_space_transform(), layer->render_target()->render_surface()->screen_space_transform(),
gfx::QuadF(transformed_rect), &clipped); gfx::QuadF(transformed_rect), &clipped);
...@@ -469,11 +462,9 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer( ...@@ -469,11 +462,9 @@ void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
for (Region::Iterator non_opaque_content_rects(non_opaque_contents); for (Region::Iterator non_opaque_content_rects(non_opaque_contents);
non_opaque_content_rects.has_rect(); non_opaque_content_rects.has_rect();
non_opaque_content_rects.next()) { non_opaque_content_rects.next()) {
// We've already checked for clipping in the MapQuad call above, these calls gfx::Rect transformed_rect =
// should not clip anything further. MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
gfx::Rect transformed_rect = gfx::ToEnclosedRect( layer->draw_transform(), non_opaque_content_rects.rect());
MathUtil::MapClippedRect(layer->draw_transform(),
gfx::RectF(non_opaque_content_rects.rect())));
transformed_rect.Intersect(clip_rect_in_target); transformed_rect.Intersect(clip_rect_in_target);
if (transformed_rect.IsEmpty()) if (transformed_rect.IsEmpty())
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment