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

Unified Diff: cc/tiles/picture_layer_tiling.cc

Issue 2295343005: Improve PictureLayerTiling::CoverageIterator to handle rounding more precisely (Closed)
Patch Set: simplify & add tests 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
Index: cc/tiles/picture_layer_tiling.cc
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 94a36cdde51411ad70db1f54187c9c44e042301d..6ef7a709e671b17fd13bd5fd8c6b95f24213b67e 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -400,27 +400,35 @@ 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.
enne (OOO) 2016/09/09 21:46:34 What code was passing in a larger dest rect than t
trchen 2016/09/09 23:39:19 I don't know if we ever do that in real code, but
enne (OOO) 2016/09/15 18:06:23 This is fine. The code before was intersecting to
+ 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.
+ // Without MSAA, the sample point of a texel is at the center of that texel.
+ // For example, texel (12, 34) has sample point at (12.5, 34.5).
enne (OOO) 2016/09/09 21:46:34 This isn't true when the layer is not aligned with
trchen 2016/09/09 23:39:19 It is referring to texels in the texture space. Ea
enne (OOO) 2016/09/15 18:06:23 Your description makes sense to me, but I don't fe
+ // Instead of trying to snapping to (i+0.5, j+0.5) half grids, just shift
+ // everything by (-0.5, -0.5).
+ 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_;
@@ -450,15 +458,37 @@ 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
+ // Calculate the current geometry rect. As we reserved 2px overlap between
enne (OOO) 2016/09/09 21:46:34 I thought we reserved an extra border texel for bi
trchen 2016/09/09 23:39:19 Actually both... I don't know how to word this mor
enne (OOO) 2016/09/15 18:06:23 Maybe just say "due to border texels and floating
+ // tiles for error margin, tiles might overlap in destination space 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
enne (OOO) 2016/09/09 21:46:34 This is really because scaling from texture coordi
trchen 2016/09/09 23:39:19 It could happen due to FP error. right_edge_of_ti
+ // 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 tile bound by 1.5 texels. This is needed to
+ // fully cover the dest space. The number 1.5 came from the fact that the
+ // sample extent doesn't cover the last 0.5 texel to layer edge, and 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 apply
+ // antialiasing itself.
+ const TilingData& data = tiling_->tiling_data_;
+ constexpr float epsilon = 1.f / 1024.f;
+ texel_extent.Inset(tile_i_ ? -epsilon : -1.5,
enne (OOO) 2016/09/09 21:46:34 Can you set the texel_extent to be 0 if it's the l
trchen 2016/09/09 23:39:19 Yes I've considered that. That's more correct. How
enne (OOO) 2016/09/15 18:06:23 I'd rather be simple first and optimize later, sor
+ tile_j_ ? -epsilon : -1.5,
+ (tile_i_ != data.num_tiles_x() - 1) ? -epsilon : -1.5,
+ (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());

Powered by Google App Engine
This is Rietveld 408576698