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

Unified Diff: cc/tiles/picture_layer_tiling.cc

Issue 2295343005: Improve PictureLayerTiling::CoverageIterator to handle rounding more precisely (Closed)
Patch Set: remove the 1.5 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/tiles/picture_layer_tiling.h ('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..a54a7ccab2bdbafc62977865541b1817a7198508 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.
+ dest_layer_bounds_ =
+ gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), dest_scale);
+ dest_rect_.Intersect(gfx::Rect(dest_layer_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,46 @@ 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_);
+ gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
+ {
+ // Adjust tile extent to accommodate numerical errors.
+ //
+ // 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.
+ constexpr float epsilon = 1.f / 1024.f;
+ texel_extent.Inset(-epsilon, -epsilon);
+ }
- current_geometry_rect_ =
- gfx::ScaleToEnclosingRect(content_rect, 1 / dest_to_content_scale_);
+ current_geometry_rect_ = gfx::ToEnclosedRect(
+ gfx::ScaleRect(texel_extent, 1 / dest_to_content_scale_));
+ {
+ // Adjust external edges to cover the whole layer in dest space.
+ //
+ // 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_;
+ current_geometry_rect_.Inset(
+ tile_i_ ? 0 : -current_geometry_rect_.x(),
+ tile_j_ ? 0 : -current_geometry_rect_.y(),
+ (tile_i_ != data.num_tiles_x() - 1)
+ ? 0
+ : current_geometry_rect_.right() - dest_layer_bounds_.width(),
+ (tile_j_ != data.num_tiles_y() - 1)
+ ? 0
+ : current_geometry_rect_.bottom() - dest_layer_bounds_.height());
+ }
current_geometry_rect_.Intersect(dest_rect_);
DCHECK(!current_geometry_rect_.IsEmpty());
« no previous file with comments | « cc/tiles/picture_layer_tiling.h ('k') | cc/tiles/picture_layer_tiling_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698