Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4147)

Unified Diff: cc/tiles/picture_layer_tiling.cc

Issue 2295343005: Improve PictureLayerTiling::CoverageIterator to handle rounding more precisely (Closed)
Patch Set: address comments Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/layers/picture_layer_impl_unittest.cc ('k') | cc/tiles/picture_layer_tiling_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/tiles/picture_layer_tiling.cc
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index c5d2013f3d7855e24b87a5fbae9bafcb6155c445..e382ec8ec106e101999be9ecb309026d749e8139 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -405,27 +405,45 @@ PictureLayerTiling::CoverageIterator::CoverageIterator(
right_(-1),
bottom_(-1) {
DCHECK(tiling_);
+ DCHECK_GE(dest_scale, tiling_->contents_scale_);
+
+ // Clamp dest_rect_ to the bounds of the layer.
+ gfx::Size dest_content_bounds =
+ gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), dest_scale);
+ dest_rect_.Intersect(gfx::Rect(dest_content_bounds));
if (dest_rect_.IsEmpty())
return;
dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
- gfx::Rect content_rect =
- gfx::ScaleToEnclosingRect(dest_rect_,
- dest_to_content_scale_,
- dest_to_content_scale_);
- // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
- // check for non-intersection first.
- content_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
- if (content_rect.IsEmpty())
- return;
-
- left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x());
- top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y());
- right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(
- content_rect.right() - 1);
- bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(
- content_rect.bottom() - 1);
+ // Find the indices of the texel samples that enclose the rect we want to
+ // cover.
+ // Because we don't know the target transform at this point, we have to be
+ // pessimistic, i.e. assume every point (a pair of real number, not necessary
+ // snapped to a pixel sample) inside of the content rect may be sampled.
+ // This code maps the boundary points into contents space, then find out the
+ // enclosing texture samples. For example, assume we have:
+ // dest_scale : content_scale = 1.23 : 1
+ // dest_rect = (l:123, t:234, r:345, b:456)
+ // Then it follows that:
+ // content_rect = (l:100.00, t:190.24, r:280.49, b:370.73)
+ // Without MSAA, the sample point of a texel is at the center of that texel,
+ // thus the sample points we need to cover content_rect are:
+ // wanted_texels(sample coordinates) = (l:99.5, t:189.5, r:280.5, b:371.5)
+ // Or in integer index:
+ // wanted_texels(integer index) = (l:99, t:189, r:280, b:371)
+ gfx::RectF content_rect =
+ gfx::ScaleRect(gfx::RectF(dest_rect_), dest_to_content_scale_);
+ content_rect.Offset(-0.5f, -0.5f);
+ gfx::Rect wanted_texels = gfx::ToEnclosingRect(content_rect);
+
+ const TilingData& data = tiling_->tiling_data_;
+ left_ = data.LastBorderTileXIndexFromSrcCoord(wanted_texels.x());
+ top_ = data.LastBorderTileYIndexFromSrcCoord(wanted_texels.y());
+ right_ = std::max(
+ left_, data.FirstBorderTileXIndexFromSrcCoord(wanted_texels.right()));
+ bottom_ = std::max(
+ top_, data.FirstBorderTileYIndexFromSrcCoord(wanted_texels.bottom()));
tile_i_ = left_ - 1;
tile_j_ = top_;
@@ -455,15 +473,36 @@ PictureLayerTiling::CoverageIterator::operator++() {
current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
- // Calculate the current geometry rect. Due to floating point rounding
- // and ToEnclosingRect, tiles might overlap in destination space on the
- // edges.
+ // Calculate the current geometry rect. As we reserved overlap between tiles
+ // to accommodate bilinear filtering and rounding errors in destination
+ // space, the geometry rect might overlap on the edges.
gfx::Rect last_geometry_rect = current_geometry_rect_;
- gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_);
-
- current_geometry_rect_ =
- gfx::ScaleToEnclosingRect(content_rect, 1 / dest_to_content_scale_);
+ gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
+ {
+ // Adjust tile extent to accommodate numerical errors.
+ //
+ // For internal edges, allow the tile to overreach by 1/1024 texels to
+ // avoid seams between tiles. The constant 1/1024 is picked by the fact
+ // that with bilinear filtering, the maximum error in color value
+ // introduced by clamping error in both u/v axis can't exceed
+ // 255 * (1 - (1 - 1/1024) * (1 - 1/1024)) ~= 0.498
+ // i.e. The color value can never flip over a rounding threshold.
+ //
+ // For external edges, extend the tile to scaled layer bounds. This is
+ // needed to fully cover the dest space because the sample extent doesn't
+ // cover the last 0.5 texel to layer edge, and also the dest space can be
+ // rounded up for up to 1 pixel. This overhang will never be sampled as the
+ // AA fragment shader clamps sample coordinate and antialiasing itself.
+ const TilingData& data = tiling_->tiling_data_;
+ constexpr float epsilon = 1.f / 1024.f;
+ texel_extent.Inset(tile_i_ ? -epsilon : -texel_extent.x(),
+ tile_j_ ? -epsilon : -texel_extent.y(),
+ (tile_i_ != data.num_tiles_x() - 1) ? -epsilon : -1.5,
enne (OOO) 2016/09/16 17:50:48 I thought you were going to remove the 1.5?
trchen 2016/09/21 03:39:27 I thought you only meant the top/left edges. :) Y
+ (tile_j_ != data.num_tiles_y() - 1) ? -epsilon : -1.5);
+ }
+ current_geometry_rect_ = gfx::ToEnclosedRect(
+ gfx::ScaleRect(texel_extent, 1 / dest_to_content_scale_));
current_geometry_rect_.Intersect(dest_rect_);
DCHECK(!current_geometry_rect_.IsEmpty());
« no previous file with comments | « cc/layers/picture_layer_impl_unittest.cc ('k') | cc/tiles/picture_layer_tiling_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698