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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/tiles/picture_layer_tiling.h" 5 #include "cc/tiles/picture_layer_tiling.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <cmath> 10 #include <cmath>
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 dest_rect_(dest_rect), 393 dest_rect_(dest_rect),
394 dest_to_content_scale_(0), 394 dest_to_content_scale_(0),
395 current_tile_(NULL), 395 current_tile_(NULL),
396 tile_i_(0), 396 tile_i_(0),
397 tile_j_(0), 397 tile_j_(0),
398 left_(0), 398 left_(0),
399 top_(0), 399 top_(0),
400 right_(-1), 400 right_(-1),
401 bottom_(-1) { 401 bottom_(-1) {
402 DCHECK(tiling_); 402 DCHECK(tiling_);
403 DCHECK_GE(dest_scale, tiling_->contents_scale_);
404
405 // 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
406 gfx::Size dest_content_bounds =
407 gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), dest_scale);
408 dest_rect_.Intersect(gfx::Rect(dest_content_bounds));
403 if (dest_rect_.IsEmpty()) 409 if (dest_rect_.IsEmpty())
404 return; 410 return;
405 411
406 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale; 412 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
407 413
408 gfx::Rect content_rect = 414 // Find the indices of the texel samples that enclose the rect we want to
409 gfx::ScaleToEnclosingRect(dest_rect_, 415 // cover.
410 dest_to_content_scale_, 416 // Without MSAA, the sample point of a texel is at the center of that texel.
411 dest_to_content_scale_); 417 // 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
412 // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to 418 // Instead of trying to snapping to (i+0.5, j+0.5) half grids, just shift
413 // check for non-intersection first. 419 // everything by (-0.5, -0.5).
414 content_rect.Intersect(gfx::Rect(tiling_->tiling_size())); 420 gfx::RectF content_rect =
415 if (content_rect.IsEmpty()) 421 gfx::ScaleRect(gfx::RectF(dest_rect_), dest_to_content_scale_);
416 return; 422 content_rect.Offset(-0.5f, -0.5f);
423 gfx::Rect wanted_texels = gfx::ToEnclosingRect(content_rect);
417 424
418 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x()); 425 const TilingData& data = tiling_->tiling_data_;
419 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y()); 426 left_ = data.LastBorderTileXIndexFromSrcCoord(wanted_texels.x());
420 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord( 427 top_ = data.LastBorderTileYIndexFromSrcCoord(wanted_texels.y());
421 content_rect.right() - 1); 428 right_ = std::max(
422 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord( 429 left_, data.FirstBorderTileXIndexFromSrcCoord(wanted_texels.right()));
423 content_rect.bottom() - 1); 430 bottom_ = std::max(
431 top_, data.FirstBorderTileYIndexFromSrcCoord(wanted_texels.bottom()));
424 432
425 tile_i_ = left_ - 1; 433 tile_i_ = left_ - 1;
426 tile_j_ = top_; 434 tile_j_ = top_;
427 ++(*this); 435 ++(*this);
428 } 436 }
429 437
430 PictureLayerTiling::CoverageIterator::~CoverageIterator() { 438 PictureLayerTiling::CoverageIterator::~CoverageIterator() {
431 } 439 }
432 440
433 PictureLayerTiling::CoverageIterator& 441 PictureLayerTiling::CoverageIterator&
434 PictureLayerTiling::CoverageIterator::operator++() { 442 PictureLayerTiling::CoverageIterator::operator++() {
435 if (tile_j_ > bottom_) 443 if (tile_j_ > bottom_)
436 return *this; 444 return *this;
437 445
438 bool first_time = tile_i_ < left_; 446 bool first_time = tile_i_ < left_;
439 bool new_row = false; 447 bool new_row = false;
440 tile_i_++; 448 tile_i_++;
441 if (tile_i_ > right_) { 449 if (tile_i_ > right_) {
442 tile_i_ = left_; 450 tile_i_ = left_;
443 tile_j_++; 451 tile_j_++;
444 new_row = true; 452 new_row = true;
445 if (tile_j_ > bottom_) { 453 if (tile_j_ > bottom_) {
446 current_tile_ = NULL; 454 current_tile_ = NULL;
447 return *this; 455 return *this;
448 } 456 }
449 } 457 }
450 458
451 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); 459 current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
452 460
453 // Calculate the current geometry rect. Due to floating point rounding 461 // 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
454 // and ToEnclosingRect, tiles might overlap in destination space on the 462 // tiles for error margin, tiles might overlap in destination space on the
455 // edges. 463 // edges.
456 gfx::Rect last_geometry_rect = current_geometry_rect_; 464 gfx::Rect last_geometry_rect = current_geometry_rect_;
457 465
458 gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); 466 gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
459 467 {
460 current_geometry_rect_ = 468 // Adjust tile extent to accommodate numerical errors.
461 gfx::ScaleToEnclosingRect(content_rect, 1 / dest_to_content_scale_); 469 //
470 // For internal edges, allow the tile to overreach by 1/1024 texels to
471 // 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
472 // that with bilinear filtering, the maximum error in color value
473 // introduced by clamping error in both u/v axis can't exceed
474 // 255 * (1 - (1 - 1/1024) * (1 - 1/1024)) ~= 0.498
475 // i.e. The color value can never flip over a rounding threshold.
476 //
477 // For external edges, extend tile bound by 1.5 texels. This is needed to
478 // fully cover the dest space. The number 1.5 came from the fact that the
479 // sample extent doesn't cover the last 0.5 texel to layer edge, and the
480 // dest space can be rounded up for up to 1 pixel. This overhang will never
481 // be sampled as the AA fragment shader clamps sample coordinate and apply
482 // antialiasing itself.
483 const TilingData& data = tiling_->tiling_data_;
484 constexpr float epsilon = 1.f / 1024.f;
485 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
486 tile_j_ ? -epsilon : -1.5,
487 (tile_i_ != data.num_tiles_x() - 1) ? -epsilon : -1.5,
488 (tile_j_ != data.num_tiles_y() - 1) ? -epsilon : -1.5);
489 }
490 current_geometry_rect_ = gfx::ToEnclosedRect(
491 gfx::ScaleRect(texel_extent, 1 / dest_to_content_scale_));
462 492
463 current_geometry_rect_.Intersect(dest_rect_); 493 current_geometry_rect_.Intersect(dest_rect_);
464 DCHECK(!current_geometry_rect_.IsEmpty()); 494 DCHECK(!current_geometry_rect_.IsEmpty());
465 495
466 if (first_time) 496 if (first_time)
467 return *this; 497 return *this;
468 498
469 // Iteration happens left->right, top->bottom. Running off the bottom-right 499 // Iteration happens left->right, top->bottom. Running off the bottom-right
470 // edge is handled by the intersection above with dest_rect_. Here we make 500 // edge is handled by the intersection above with dest_rect_. Here we make
471 // sure that the new current geometry rect doesn't overlap with the last. 501 // sure that the new current geometry rect doesn't overlap with the last.
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after
879 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { 909 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
880 size_t amount = 0; 910 size_t amount = 0;
881 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { 911 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
882 const Tile* tile = it->second.get(); 912 const Tile* tile = it->second.get();
883 amount += tile->GPUMemoryUsageInBytes(); 913 amount += tile->GPUMemoryUsageInBytes();
884 } 914 }
885 return amount; 915 return amount;
886 } 916 }
887 917
888 } // namespace cc 918 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698