Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |