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/picture_layer_tiling.h" | 5 #include "cc/picture_layer_tiling.h" |
6 | 6 |
7 #include <cmath> | |
8 | |
7 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
8 #include "cc/math_util.h" | 10 #include "cc/math_util.h" |
9 #include "ui/gfx/point_conversions.h" | 11 #include "ui/gfx/point_conversions.h" |
10 #include "ui/gfx/rect_conversions.h" | 12 #include "ui/gfx/rect_conversions.h" |
11 #include "ui/gfx/safe_integer_conversions.h" | 13 #include "ui/gfx/safe_integer_conversions.h" |
12 #include "ui/gfx/size_conversions.h" | 14 #include "ui/gfx/size_conversions.h" |
13 | 15 |
14 namespace cc { | 16 namespace cc { |
15 | 17 |
16 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( | 18 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
384 if (last_impl_frame_time_ != 0 && | 386 if (last_impl_frame_time_ != 0 && |
385 last_layer_bounds == current_layer_bounds && | 387 last_layer_bounds == current_layer_bounds && |
386 last_layer_content_bounds == current_layer_content_bounds && | 388 last_layer_content_bounds == current_layer_content_bounds && |
387 last_layer_contents_scale == current_layer_contents_scale) { | 389 last_layer_contents_scale == current_layer_contents_scale) { |
388 time_delta = current_frame_time - last_impl_frame_time_; | 390 time_delta = current_frame_time - last_impl_frame_time_; |
389 } | 391 } |
390 | 392 |
391 gfx::Rect viewport_in_content_space = | 393 gfx::Rect viewport_in_content_space = |
392 gfx::ToEnclosingRect(gfx::ScaleRect(viewport_in_layer_space, | 394 gfx::ToEnclosingRect(gfx::ScaleRect(viewport_in_layer_space, |
393 contents_scale_)); | 395 contents_scale_)); |
394 gfx::Rect inflated_rect = viewport_in_content_space; | 396 |
395 float adjusted_inset = TilePriority::kMaxDistanceInContentSpace / | 397 gfx::Size tile_size = tiling_data_.max_texture_size(); |
396 std::max(contents_scale_, 1.f); | 398 int64 prioritized_rect_area = |
397 inflated_rect.Inset( | 399 TilePriority::kNumTilesToCoverWithInflatedViewportRectForPrioritization * |
398 -adjusted_inset, | 400 tile_size.width() * tile_size.height(); |
399 -adjusted_inset, | 401 |
400 -adjusted_inset, | 402 gfx::Rect prioritized_rect = ExpandRectEquallyToAreaBoundedBy( |
401 -adjusted_inset); | 403 viewport_in_content_space, |
402 inflated_rect.Intersect(ContentRect()); | 404 prioritized_rect_area, |
405 ContentRect()); | |
406 DCHECK(ContentRect().Contains(prioritized_rect)); | |
403 | 407 |
404 // Iterate through all of the tiles that were live last frame but will | 408 // Iterate through all of the tiles that were live last frame but will |
405 // not be live this frame, and mark them as being dead. | 409 // not be live this frame, and mark them as being dead. |
406 for (TilingData::DifferenceIterator iter(&tiling_data_, | 410 for (TilingData::DifferenceIterator iter(&tiling_data_, |
407 last_prioritized_rect_, | 411 last_prioritized_rect_, |
408 inflated_rect); | 412 prioritized_rect); |
409 iter; | 413 iter; |
410 ++iter) { | 414 ++iter) { |
411 TileMap::iterator find = tiles_.find(iter.index()); | 415 TileMap::iterator find = tiles_.find(iter.index()); |
412 if (find == tiles_.end()) | 416 if (find == tiles_.end()) |
413 continue; | 417 continue; |
414 | 418 |
415 TilePriority priority; | 419 TilePriority priority; |
416 DCHECK(!priority.is_live); | 420 DCHECK(!priority.is_live); |
417 Tile* tile = find->second.get(); | 421 Tile* tile = find->second.get(); |
418 tile->set_priority(tree, priority); | 422 tile->set_priority(tree, priority); |
419 } | 423 } |
420 last_prioritized_rect_ = inflated_rect; | 424 last_prioritized_rect_ = prioritized_rect; |
421 | 425 |
422 gfx::Rect view_rect(device_viewport); | 426 gfx::Rect view_rect(device_viewport); |
423 float current_scale = current_layer_contents_scale / contents_scale_; | 427 float current_scale = current_layer_contents_scale / contents_scale_; |
424 float last_scale = last_layer_contents_scale / contents_scale_; | 428 float last_scale = last_layer_contents_scale / contents_scale_; |
425 | 429 |
426 // Fast path tile priority calculation when both transforms are translations. | 430 // Fast path tile priority calculation when both transforms are translations. |
427 if (last_screen_transform.IsIdentityOrTranslation() && | 431 if (last_screen_transform.IsIdentityOrTranslation() && |
428 current_screen_transform.IsIdentityOrTranslation()) | 432 current_screen_transform.IsIdentityOrTranslation()) |
429 { | 433 { |
430 gfx::Vector2dF current_offset( | 434 gfx::Vector2dF current_offset( |
431 current_screen_transform.matrix().get(0, 3), | 435 current_screen_transform.matrix().get(0, 3), |
432 current_screen_transform.matrix().get(1, 3)); | 436 current_screen_transform.matrix().get(1, 3)); |
433 gfx::Vector2dF last_offset( | 437 gfx::Vector2dF last_offset( |
434 last_screen_transform.matrix().get(0, 3), | 438 last_screen_transform.matrix().get(0, 3), |
435 last_screen_transform.matrix().get(1, 3)); | 439 last_screen_transform.matrix().get(1, 3)); |
436 | 440 |
437 for (TilingData::Iterator iter(&tiling_data_, inflated_rect); | 441 for (TilingData::Iterator iter(&tiling_data_, prioritized_rect); |
438 iter; ++iter) { | 442 iter; ++iter) { |
439 TileMap::iterator find = tiles_.find(iter.index()); | 443 TileMap::iterator find = tiles_.find(iter.index()); |
440 if (find == tiles_.end()) | 444 if (find == tiles_.end()) |
441 continue; | 445 continue; |
442 Tile* tile = find->second.get(); | 446 Tile* tile = find->second.get(); |
443 | 447 |
444 gfx::Rect tile_bounds = | 448 gfx::Rect tile_bounds = |
445 tiling_data_.TileBounds(iter.index_x(), iter.index_y()); | 449 tiling_data_.TileBounds(iter.index_x(), iter.index_y()); |
446 gfx::RectF current_screen_rect = gfx::ScaleRect( | 450 gfx::RectF current_screen_rect = gfx::ScaleRect( |
447 tile_bounds, | 451 tile_bounds, |
(...skipping 12 matching lines...) Expand all Loading... | |
460 last_screen_rect, current_screen_rect, time_delta, view_rect); | 464 last_screen_rect, current_screen_rect, time_delta, view_rect); |
461 TilePriority priority( | 465 TilePriority priority( |
462 resolution_, | 466 resolution_, |
463 time_to_visible_in_seconds, | 467 time_to_visible_in_seconds, |
464 distance_to_visible_in_pixels); | 468 distance_to_visible_in_pixels); |
465 if (store_screen_space_quads_on_tiles) | 469 if (store_screen_space_quads_on_tiles) |
466 priority.set_current_screen_quad(gfx::QuadF(current_screen_rect)); | 470 priority.set_current_screen_quad(gfx::QuadF(current_screen_rect)); |
467 tile->set_priority(tree, priority); | 471 tile->set_priority(tree, priority); |
468 } | 472 } |
469 } else { | 473 } else { |
470 for (TilingData::Iterator iter(&tiling_data_, inflated_rect); | 474 for (TilingData::Iterator iter(&tiling_data_, prioritized_rect); |
471 iter; ++iter) { | 475 iter; ++iter) { |
472 TileMap::iterator find = tiles_.find(iter.index()); | 476 TileMap::iterator find = tiles_.find(iter.index()); |
473 if (find == tiles_.end()) | 477 if (find == tiles_.end()) |
474 continue; | 478 continue; |
475 Tile* tile = find->second.get(); | 479 Tile* tile = find->second.get(); |
476 | 480 |
477 gfx::Rect tile_bounds = | 481 gfx::Rect tile_bounds = |
478 tiling_data_.TileBounds(iter.index_x(), iter.index_y()); | 482 tiling_data_.TileBounds(iter.index_x(), iter.index_y()); |
479 gfx::RectF current_layer_content_rect = gfx::ScaleRect( | 483 gfx::RectF current_layer_content_rect = gfx::ScaleRect( |
480 tile_bounds, | 484 tile_bounds, |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
532 | 536 |
533 scoped_ptr<base::Value> PictureLayerTiling::AsValue() const { | 537 scoped_ptr<base::Value> PictureLayerTiling::AsValue() const { |
534 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); | 538 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); |
535 state->SetInteger("num_tiles", tiles_.size()); | 539 state->SetInteger("num_tiles", tiles_.size()); |
536 state->SetDouble("content_scale", contents_scale_); | 540 state->SetDouble("content_scale", contents_scale_); |
537 state->Set("content_bounds", | 541 state->Set("content_bounds", |
538 MathUtil::asValue(ContentRect().size()).release()); | 542 MathUtil::asValue(ContentRect().size()).release()); |
539 return state.PassAs<base::Value>(); | 543 return state.PassAs<base::Value>(); |
540 } | 544 } |
541 | 545 |
546 namespace { | |
547 | |
548 int ComputeOffsetToExpand4EdgesEqually(int old_width, | |
549 int old_height, | |
550 int64 target_area) { | |
551 // We need to expand the rect in 4 directions, we can compute the | |
552 // amount to expand along each axis with a quadratic equation: | |
553 // (old_w + add) * (old_h + add) = target_area | |
554 // old_w * old_h + old_w * add + add * old_h + add * add = target_area | |
555 // add^2 + add * (old_w + old_h) - target_area + old_w * old_h = 0 | |
556 // Therefore, we solve the quadratic equation with: | |
557 // a = 1 | |
558 // b = old_w + old_h | |
559 // c = -target_area + old_w * old_h | |
560 int a = 1; | |
561 int64 b = old_width + old_height; | |
562 int64 c = -target_area + old_width * old_height; | |
563 int sqrt_part = std::sqrt(b * b - 4.0 * a * c); | |
564 int add_each_axis = (-b + sqrt_part) / 2 / a; | |
565 return add_each_axis / 2; | |
566 } | |
567 | |
568 int ComputeOffsetToExpand3EdgesEqually(int old_width, | |
569 int old_height, | |
570 int64 target_area, | |
571 bool left_complete, | |
572 bool top_complete, | |
573 bool right_complete, | |
574 bool bottom_complete) { | |
575 // We need to expand the rect in three directions, so we will have to | |
576 // expand along one axis twice as much as the other. Otherwise, this | |
577 // is very similar to the case where we expand in all 4 directions. | |
578 | |
579 if (left_complete || right_complete) { | |
580 // Expanding twice as much vertically as horizontally. | |
581 // (old_w + add) * (old_h + add*2) = target_area | |
582 // old_w * old_h + old_w * add*2 + add * old_h + add * add*2 = target_area | |
583 // (add^2)*2 + add * (old_w*2 + old_h) - target_area + old_w * old_h = 0 | |
584 // Therefore, we solve the quadratic equation with: | |
585 // a = 2 | |
586 // b = old_w*2 + old_h | |
587 // c = -target_area + old_w * old_h | |
588 int a = 2; | |
589 int64 b = old_width * 2 + old_height; | |
590 int64 c = -target_area + old_width * old_height; | |
591 int sqrt_part = std::sqrt(b * b - 4.0 * a * c); | |
592 int add_each_direction = (-b + sqrt_part) / 2 / a; | |
593 return add_each_direction; | |
594 } else { | |
595 // Expanding twice as much horizontally as vertically. | |
596 // (old_w + add*2) * (old_h + add) = target_area | |
597 // old_w * old_h + old_w * add + add*2 * old_h + add*2 * add = target_area | |
598 // (add^2)*2 + add * (old_w + old_h*2) - target_area + old_w * old_h = 0 | |
599 // Therefore, we solve the quadratic equation with: | |
600 // a = 2 | |
601 // b = old_w + old_h*2 | |
602 // c = -target_area + old_w * old_h | |
603 int a = 2; | |
604 int64 b = old_width + old_height * 2; | |
605 int64 c = -target_area + old_width * old_height; | |
606 int sqrt_part = std::sqrt(b * b - 4.0 * a * c); | |
607 int add_each_direction = (-b + sqrt_part) / 2 / a; | |
608 return add_each_direction; | |
609 } | |
610 } | |
611 | |
612 int ComputeOffsetToExpand2EdgesEqually(int old_width, | |
613 int old_height, | |
614 int64 target_area, | |
615 bool left_complete, | |
616 bool top_complete, | |
617 bool right_complete, | |
618 bool bottom_complete) { | |
619 // We need to expand the rect along two directions. If the two directions | |
620 // are opposite from each other then we only need to compute a distance | |
621 // along a single axis. | |
622 if (left_complete && right_complete) { | |
623 // Expanding along the vertical axis only: | |
624 // old_w * (old_h + add) = target_area | |
625 // old_w * old_h + old_w * add = target_area | |
626 // add_vertically = (target_area - old_w * old_h) / old_w | |
627 int add_vertically = target_area / old_width - old_height; | |
628 return add_vertically / 2; | |
629 } else if (top_complete && bottom_complete) { | |
630 // Expanding along the horizontal axis only: | |
631 // (old_w + add) * old_h = target_area | |
632 // old_w * old_h + add * old_h = target_area | |
633 // add_horizontally = (target_area - old_w * old_h) / old_h | |
634 int add_horizontally = target_area / old_height - old_width; | |
635 return add_horizontally / 2; | |
636 } else { | |
637 // If we need to expand along both horizontal and vertical axes, we can use | |
638 // the same result as if we were expanding all four edges. But we apply the | |
639 // offset computed for opposing edges to a single edge. | |
640 int add_each_direction = ComputeOffsetToExpand4EdgesEqually( | |
641 old_width, old_height, target_area); | |
642 return add_each_direction * 2; | |
643 } | |
644 } | |
645 | |
646 int ComputeOffsetToExpand1Edge(int old_width, | |
647 int old_height, | |
648 int64 target_area, | |
649 bool left_complete, | |
650 bool top_complete, | |
651 bool right_complete, | |
652 bool bottom_complete) { | |
653 // We need to expand the rect in a single direction, so we are either | |
654 // moving just a verical edge, or just a horizontal edge. | |
655 if (!top_complete || !bottom_complete) { | |
656 // Moving a vertical edge: | |
657 // old_w * (old_h + add) = target_area | |
658 // old_w * old_h + old_w * add = target_area | |
659 // add_vertically = (target_area - old_w * old_h) / old_w | |
660 int add_vertically = target_area / old_width - old_height; | |
661 return add_vertically; | |
662 } else { | |
663 // Moving a horizontal edge: | |
664 // (old_w + add) * old_h = target_area | |
665 // old_w * old_h + add * old_h = target_area | |
666 // add_horizontally = (target_area - old_w * old_h) / old_h | |
667 int add_horizontally = target_area / old_height - old_width; | |
668 return add_horizontally; | |
669 } | |
670 } | |
671 | |
672 } // namespace | |
673 | |
674 // static | |
675 gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( | |
676 gfx::Rect starting_rect, | |
677 int64 target_area, | |
678 gfx::Rect bounding_rect) { | |
679 | |
ccameron
2013/02/19 20:01:10
Very nice solution.
| |
680 bool left_complete = false; | |
681 bool top_complete = false; | |
682 bool right_complete = false; | |
683 bool bottom_complete = false; | |
684 int num_edges_complete = 0; | |
685 | |
686 gfx::Rect working_rect = starting_rect; | |
687 for (int i = 0; i < 4; ++i) { | |
688 if (num_edges_complete != i) | |
689 continue; | |
690 int offset_for_each_edge = 0; | |
691 switch (num_edges_complete) { | |
692 case 0: | |
693 offset_for_each_edge = ComputeOffsetToExpand4EdgesEqually( | |
694 working_rect.width(), | |
695 working_rect.height(), | |
696 target_area); | |
697 break; | |
698 case 1: | |
699 offset_for_each_edge = ComputeOffsetToExpand3EdgesEqually( | |
700 working_rect.width(), | |
701 working_rect.height(), | |
702 target_area, | |
703 left_complete, | |
704 top_complete, | |
705 right_complete, | |
706 bottom_complete); | |
707 break; | |
708 case 2: | |
709 offset_for_each_edge = ComputeOffsetToExpand2EdgesEqually( | |
710 working_rect.width(), | |
711 working_rect.height(), | |
712 target_area, | |
713 left_complete, | |
714 top_complete, | |
715 right_complete, | |
716 bottom_complete); | |
717 break; | |
718 case 3: | |
719 offset_for_each_edge = ComputeOffsetToExpand1Edge( | |
720 working_rect.width(), | |
721 working_rect.height(), | |
722 target_area, | |
723 left_complete, | |
724 top_complete, | |
725 right_complete, | |
726 bottom_complete); | |
727 } | |
728 | |
729 working_rect.Inset((left_complete ? 0 : -offset_for_each_edge), | |
730 (top_complete ? 0 : -offset_for_each_edge), | |
731 (right_complete ? 0 : -offset_for_each_edge), | |
732 (bottom_complete ? 0 : -offset_for_each_edge)); | |
733 | |
734 if (bounding_rect.Contains(working_rect)) | |
735 return working_rect; | |
736 working_rect.Intersect(bounding_rect); | |
737 | |
738 if (working_rect.x() == bounding_rect.x()) left_complete = true; | |
739 if (working_rect.y() == bounding_rect.y()) top_complete = true; | |
740 if (working_rect.right() == bounding_rect.right()) right_complete = true; | |
741 if (working_rect.bottom() == bounding_rect.bottom()) bottom_complete = true; | |
742 | |
743 num_edges_complete = (left_complete ? 1 : 0) + | |
744 (top_complete ? 1 : 0) + | |
745 (right_complete ? 1 : 0) + | |
746 (bottom_complete ? 1 : 0); | |
747 if (num_edges_complete == 4) | |
748 return working_rect; | |
749 } | |
750 | |
751 NOTREACHED(); | |
752 return starting_rect; | |
753 } | |
754 | |
542 } // namespace cc | 755 } // namespace cc |
OLD | NEW |