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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 387 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 dest_rect_(dest_rect), 398 dest_rect_(dest_rect),
399 dest_to_content_scale_(0), 399 dest_to_content_scale_(0),
400 current_tile_(NULL), 400 current_tile_(NULL),
401 tile_i_(0), 401 tile_i_(0),
402 tile_j_(0), 402 tile_j_(0),
403 left_(0), 403 left_(0),
404 top_(0), 404 top_(0),
405 right_(-1), 405 right_(-1),
406 bottom_(-1) { 406 bottom_(-1) {
407 DCHECK(tiling_); 407 DCHECK(tiling_);
408 DCHECK_GE(dest_scale, tiling_->contents_scale_);
409
410 // Clamp dest_rect_ to the bounds of the layer.
411 gfx::Size dest_content_bounds =
412 gfx::ScaleToCeiledSize(tiling->raster_source_->GetSize(), dest_scale);
413 dest_rect_.Intersect(gfx::Rect(dest_content_bounds));
408 if (dest_rect_.IsEmpty()) 414 if (dest_rect_.IsEmpty())
409 return; 415 return;
410 416
411 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale; 417 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
412 418
413 gfx::Rect content_rect = 419 // Find the indices of the texel samples that enclose the rect we want to
414 gfx::ScaleToEnclosingRect(dest_rect_, 420 // cover.
415 dest_to_content_scale_, 421 // Because we don't know the target transform at this point, we have to be
416 dest_to_content_scale_); 422 // pessimistic, i.e. assume every point (a pair of real number, not necessary
417 // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to 423 // snapped to a pixel sample) inside of the content rect may be sampled.
418 // check for non-intersection first. 424 // This code maps the boundary points into contents space, then find out the
419 content_rect.Intersect(gfx::Rect(tiling_->tiling_size())); 425 // enclosing texture samples. For example, assume we have:
420 if (content_rect.IsEmpty()) 426 // dest_scale : content_scale = 1.23 : 1
421 return; 427 // dest_rect = (l:123, t:234, r:345, b:456)
428 // Then it follows that:
429 // content_rect = (l:100.00, t:190.24, r:280.49, b:370.73)
430 // Without MSAA, the sample point of a texel is at the center of that texel,
431 // thus the sample points we need to cover content_rect are:
432 // wanted_texels(sample coordinates) = (l:99.5, t:189.5, r:280.5, b:371.5)
433 // Or in integer index:
434 // wanted_texels(integer index) = (l:99, t:189, r:280, b:371)
435 gfx::RectF content_rect =
436 gfx::ScaleRect(gfx::RectF(dest_rect_), dest_to_content_scale_);
437 content_rect.Offset(-0.5f, -0.5f);
438 gfx::Rect wanted_texels = gfx::ToEnclosingRect(content_rect);
422 439
423 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x()); 440 const TilingData& data = tiling_->tiling_data_;
424 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y()); 441 left_ = data.LastBorderTileXIndexFromSrcCoord(wanted_texels.x());
425 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord( 442 top_ = data.LastBorderTileYIndexFromSrcCoord(wanted_texels.y());
426 content_rect.right() - 1); 443 right_ = std::max(
427 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord( 444 left_, data.FirstBorderTileXIndexFromSrcCoord(wanted_texels.right()));
428 content_rect.bottom() - 1); 445 bottom_ = std::max(
446 top_, data.FirstBorderTileYIndexFromSrcCoord(wanted_texels.bottom()));
429 447
430 tile_i_ = left_ - 1; 448 tile_i_ = left_ - 1;
431 tile_j_ = top_; 449 tile_j_ = top_;
432 ++(*this); 450 ++(*this);
433 } 451 }
434 452
435 PictureLayerTiling::CoverageIterator::~CoverageIterator() { 453 PictureLayerTiling::CoverageIterator::~CoverageIterator() {
436 } 454 }
437 455
438 PictureLayerTiling::CoverageIterator& 456 PictureLayerTiling::CoverageIterator&
439 PictureLayerTiling::CoverageIterator::operator++() { 457 PictureLayerTiling::CoverageIterator::operator++() {
440 if (tile_j_ > bottom_) 458 if (tile_j_ > bottom_)
441 return *this; 459 return *this;
442 460
443 bool first_time = tile_i_ < left_; 461 bool first_time = tile_i_ < left_;
444 bool new_row = false; 462 bool new_row = false;
445 tile_i_++; 463 tile_i_++;
446 if (tile_i_ > right_) { 464 if (tile_i_ > right_) {
447 tile_i_ = left_; 465 tile_i_ = left_;
448 tile_j_++; 466 tile_j_++;
449 new_row = true; 467 new_row = true;
450 if (tile_j_ > bottom_) { 468 if (tile_j_ > bottom_) {
451 current_tile_ = NULL; 469 current_tile_ = NULL;
452 return *this; 470 return *this;
453 } 471 }
454 } 472 }
455 473
456 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); 474 current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
457 475
458 // Calculate the current geometry rect. Due to floating point rounding 476 // Calculate the current geometry rect. As we reserved overlap between tiles
459 // and ToEnclosingRect, tiles might overlap in destination space on the 477 // to accommodate bilinear filtering and rounding errors in destination
460 // edges. 478 // space, the geometry rect might overlap on the edges.
461 gfx::Rect last_geometry_rect = current_geometry_rect_; 479 gfx::Rect last_geometry_rect = current_geometry_rect_;
462 480
463 gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); 481 gfx::RectF texel_extent = tiling_->tiling_data_.TexelExtent(tile_i_, tile_j_);
464 482 {
465 current_geometry_rect_ = 483 // Adjust tile extent to accommodate numerical errors.
466 gfx::ScaleToEnclosingRect(content_rect, 1 / dest_to_content_scale_); 484 //
485 // For internal edges, allow the tile to overreach by 1/1024 texels to
486 // avoid seams between tiles. The constant 1/1024 is picked by the fact
487 // that with bilinear filtering, the maximum error in color value
488 // introduced by clamping error in both u/v axis can't exceed
489 // 255 * (1 - (1 - 1/1024) * (1 - 1/1024)) ~= 0.498
490 // i.e. The color value can never flip over a rounding threshold.
491 //
492 // For external edges, extend the tile to scaled layer bounds. This is
493 // needed to fully cover the dest space because the sample extent doesn't
494 // cover the last 0.5 texel to layer edge, and also the dest space can be
495 // rounded up for up to 1 pixel. This overhang will never be sampled as the
496 // AA fragment shader clamps sample coordinate and antialiasing itself.
497 const TilingData& data = tiling_->tiling_data_;
498 constexpr float epsilon = 1.f / 1024.f;
499 texel_extent.Inset(tile_i_ ? -epsilon : -texel_extent.x(),
500 tile_j_ ? -epsilon : -texel_extent.y(),
501 (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
502 (tile_j_ != data.num_tiles_y() - 1) ? -epsilon : -1.5);
503 }
504 current_geometry_rect_ = gfx::ToEnclosedRect(
505 gfx::ScaleRect(texel_extent, 1 / dest_to_content_scale_));
467 506
468 current_geometry_rect_.Intersect(dest_rect_); 507 current_geometry_rect_.Intersect(dest_rect_);
469 DCHECK(!current_geometry_rect_.IsEmpty()); 508 DCHECK(!current_geometry_rect_.IsEmpty());
470 509
471 if (first_time) 510 if (first_time)
472 return *this; 511 return *this;
473 512
474 // Iteration happens left->right, top->bottom. Running off the bottom-right 513 // Iteration happens left->right, top->bottom. Running off the bottom-right
475 // edge is handled by the intersection above with dest_rect_. Here we make 514 // edge is handled by the intersection above with dest_rect_. Here we make
476 // sure that the new current geometry rect doesn't overlap with the last. 515 // sure that the new current geometry rect doesn't overlap with the last.
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
904 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { 943 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
905 size_t amount = 0; 944 size_t amount = 0;
906 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { 945 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
907 const Tile* tile = it->second.get(); 946 const Tile* tile = it->second.get();
908 amount += tile->GPUMemoryUsageInBytes(); 947 amount += tile->GPUMemoryUsageInBytes();
909 } 948 }
910 return amount; 949 return amount;
911 } 950 }
912 951
913 } // namespace cc 952 } // namespace cc
OLDNEW
« 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