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 <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <limits> | 9 #include <limits> |
10 #include <set> | 10 #include <set> |
(...skipping 20 matching lines...) Expand all Loading... |
31 const float kSoonBorderDistanceViewportPercentage = 0.15f; | 31 const float kSoonBorderDistanceViewportPercentage = 0.15f; |
32 const float kMaxSoonBorderDistanceInScreenPixels = 312.f; | 32 const float kMaxSoonBorderDistanceInScreenPixels = 312.f; |
33 | 33 |
34 } // namespace | 34 } // namespace |
35 | 35 |
36 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( | 36 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( |
37 WhichTree tree, | 37 WhichTree tree, |
38 float contents_scale, | 38 float contents_scale, |
39 scoped_refptr<RasterSource> raster_source, | 39 scoped_refptr<RasterSource> raster_source, |
40 PictureLayerTilingClient* client, | 40 PictureLayerTilingClient* client, |
41 size_t max_tiles_for_interest_area, | 41 size_t tiling_interest_area_padding, |
42 float skewport_target_time_in_seconds, | 42 float skewport_target_time_in_seconds, |
43 int skewport_extrapolation_limit_in_content_pixels) { | 43 int skewport_extrapolation_limit_in_content_pixels) { |
44 return make_scoped_ptr(new PictureLayerTiling( | 44 return make_scoped_ptr(new PictureLayerTiling( |
45 tree, contents_scale, raster_source, client, max_tiles_for_interest_area, | 45 tree, contents_scale, raster_source, client, tiling_interest_area_padding, |
46 skewport_target_time_in_seconds, | 46 skewport_target_time_in_seconds, |
47 skewport_extrapolation_limit_in_content_pixels)); | 47 skewport_extrapolation_limit_in_content_pixels)); |
48 } | 48 } |
49 | 49 |
50 PictureLayerTiling::PictureLayerTiling( | 50 PictureLayerTiling::PictureLayerTiling( |
51 WhichTree tree, | 51 WhichTree tree, |
52 float contents_scale, | 52 float contents_scale, |
53 scoped_refptr<RasterSource> raster_source, | 53 scoped_refptr<RasterSource> raster_source, |
54 PictureLayerTilingClient* client, | 54 PictureLayerTilingClient* client, |
55 size_t max_tiles_for_interest_area, | 55 size_t tiling_interest_area_padding, |
56 float skewport_target_time_in_seconds, | 56 float skewport_target_time_in_seconds, |
57 int skewport_extrapolation_limit_in_content_pixels) | 57 int skewport_extrapolation_limit_in_content_pixels) |
58 : max_tiles_for_interest_area_(max_tiles_for_interest_area), | 58 : tiling_interest_area_padding_(tiling_interest_area_padding), |
59 skewport_target_time_in_seconds_(skewport_target_time_in_seconds), | 59 skewport_target_time_in_seconds_(skewport_target_time_in_seconds), |
60 skewport_extrapolation_limit_in_content_pixels_( | 60 skewport_extrapolation_limit_in_content_pixels_( |
61 skewport_extrapolation_limit_in_content_pixels), | 61 skewport_extrapolation_limit_in_content_pixels), |
62 contents_scale_(contents_scale), | 62 contents_scale_(contents_scale), |
63 client_(client), | 63 client_(client), |
64 tree_(tree), | 64 tree_(tree), |
65 raster_source_(raster_source), | 65 raster_source_(raster_source), |
66 resolution_(NON_IDEAL_RESOLUTION), | 66 resolution_(NON_IDEAL_RESOLUTION), |
67 tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels), | 67 tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels), |
68 can_require_tiles_for_activation_(false), | 68 can_require_tiles_for_activation_(false), |
(...skipping 550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 return false; | 619 return false; |
620 } | 620 } |
621 | 621 |
622 // Calculate the skewport. | 622 // Calculate the skewport. |
623 gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds, | 623 gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds, |
624 visible_rect_in_content_space); | 624 visible_rect_in_content_space); |
625 DCHECK(skewport.Contains(visible_rect_in_content_space)); | 625 DCHECK(skewport.Contains(visible_rect_in_content_space)); |
626 | 626 |
627 // Calculate the eventually/live tiles rect. | 627 // Calculate the eventually/live tiles rect. |
628 gfx::Size tile_size = tiling_data_.max_texture_size(); | 628 gfx::Size tile_size = tiling_data_.max_texture_size(); |
629 int64 eventually_rect_area = | |
630 max_tiles_for_interest_area_ * tile_size.width() * tile_size.height(); | |
631 | 629 |
632 gfx::Rect eventually_rect = | 630 float content_to_screen_scale = ideal_contents_scale / contents_scale_; |
633 ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space, | 631 int pad_in_content_space = |
634 eventually_rect_area, | 632 static_cast<int>(tiling_interest_area_padding_ / content_to_screen_scale); |
635 gfx::Rect(tiling_size()), | 633 gfx::Rect eventually_rect = visible_rect_in_content_space; |
636 &expansion_cache_); | 634 // If the visible rect is empty, keep the eventually rect as empty. |
| 635 if (!eventually_rect.IsEmpty()) { |
| 636 eventually_rect.Inset(-pad_in_content_space, -pad_in_content_space); |
| 637 eventually_rect = |
| 638 tiling_data_.ExpandRectIgnoringBordersToTileBounds(eventually_rect); |
| 639 } |
637 | 640 |
638 DCHECK(eventually_rect.IsEmpty() || | 641 DCHECK_IMPLIES(!eventually_rect.IsEmpty(), |
639 gfx::Rect(tiling_size()).Contains(eventually_rect)) | 642 gfx::Rect(tiling_size()).Contains(eventually_rect)) |
640 << "tiling_size: " << tiling_size().ToString() | 643 << "tiling_size: " << tiling_size().ToString() |
641 << " eventually_rect: " << eventually_rect.ToString(); | 644 << " eventually_rect: " << eventually_rect.ToString(); |
642 | 645 |
643 // Calculate the soon border rect. | 646 // Calculate the soon border rect. |
644 float content_to_screen_scale = ideal_contents_scale / contents_scale_; | |
645 gfx::Rect soon_border_rect = visible_rect_in_content_space; | 647 gfx::Rect soon_border_rect = visible_rect_in_content_space; |
646 float border = CalculateSoonBorderDistance(visible_rect_in_content_space, | 648 float border = CalculateSoonBorderDistance(visible_rect_in_content_space, |
647 content_to_screen_scale); | 649 content_to_screen_scale); |
648 soon_border_rect.Inset(-border, -border, -border, -border); | 650 soon_border_rect.Inset(-border, -border, -border, -border); |
649 | 651 |
650 UpdateVisibleRectHistory(current_frame_time_in_seconds, | 652 UpdateVisibleRectHistory(current_frame_time_in_seconds, |
651 visible_rect_in_content_space); | 653 visible_rect_in_content_space); |
652 last_viewport_in_layer_space_ = viewport_in_layer_space; | 654 last_viewport_in_layer_space_ = viewport_in_layer_space; |
653 | 655 |
654 SetTilePriorityRects(content_to_screen_scale, visible_rect_in_content_space, | 656 SetTilePriorityRects(content_to_screen_scale, visible_rect_in_content_space, |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
959 | 961 |
960 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { | 962 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const { |
961 size_t amount = 0; | 963 size_t amount = 0; |
962 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { | 964 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
963 const Tile* tile = it->second; | 965 const Tile* tile = it->second; |
964 amount += tile->GPUMemoryUsageInBytes(); | 966 amount += tile->GPUMemoryUsageInBytes(); |
965 } | 967 } |
966 return amount; | 968 return amount; |
967 } | 969 } |
968 | 970 |
969 PictureLayerTiling::RectExpansionCache::RectExpansionCache() | |
970 : previous_target(0) { | |
971 } | |
972 | |
973 namespace { | |
974 | |
975 // This struct represents an event at which the expending rect intersects | |
976 // one of its boundaries. 4 intersection events will occur during expansion. | |
977 struct EdgeEvent { | |
978 enum { BOTTOM, TOP, LEFT, RIGHT } edge; | |
979 int* num_edges; | |
980 int distance; | |
981 }; | |
982 | |
983 // Compute the delta to expand from edges to cover target_area. | |
984 int ComputeExpansionDelta(int num_x_edges, int num_y_edges, | |
985 int width, int height, | |
986 int64 target_area) { | |
987 // Compute coefficients for the quadratic equation: | |
988 // a*x^2 + b*x + c = 0 | |
989 int a = num_y_edges * num_x_edges; | |
990 int b = num_y_edges * width + num_x_edges * height; | |
991 int64 c = static_cast<int64>(width) * height - target_area; | |
992 | |
993 // Compute the delta for our edges using the quadratic equation. | |
994 int delta = | |
995 (a == 0) ? -c / b : (-b + static_cast<int>(std::sqrt( | |
996 static_cast<int64>(b) * b - 4.0 * a * c))) / | |
997 (2 * a); | |
998 return std::max(0, delta); | |
999 } | |
1000 | |
1001 } // namespace | |
1002 | |
1003 gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( | |
1004 const gfx::Rect& starting_rect, | |
1005 int64 target_area, | |
1006 const gfx::Rect& bounding_rect, | |
1007 RectExpansionCache* cache) { | |
1008 if (starting_rect.IsEmpty()) | |
1009 return starting_rect; | |
1010 | |
1011 if (cache && | |
1012 cache->previous_start == starting_rect && | |
1013 cache->previous_bounds == bounding_rect && | |
1014 cache->previous_target == target_area) | |
1015 return cache->previous_result; | |
1016 | |
1017 if (cache) { | |
1018 cache->previous_start = starting_rect; | |
1019 cache->previous_bounds = bounding_rect; | |
1020 cache->previous_target = target_area; | |
1021 } | |
1022 | |
1023 DCHECK(!bounding_rect.IsEmpty()); | |
1024 DCHECK_GT(target_area, 0); | |
1025 | |
1026 // Expand the starting rect to cover target_area, if it is smaller than it. | |
1027 int delta = ComputeExpansionDelta( | |
1028 2, 2, starting_rect.width(), starting_rect.height(), target_area); | |
1029 gfx::Rect expanded_starting_rect = starting_rect; | |
1030 if (delta > 0) | |
1031 expanded_starting_rect.Inset(-delta, -delta); | |
1032 | |
1033 gfx::Rect rect = IntersectRects(expanded_starting_rect, bounding_rect); | |
1034 if (rect.IsEmpty()) { | |
1035 // The starting_rect and bounding_rect are far away. | |
1036 if (cache) | |
1037 cache->previous_result = rect; | |
1038 return rect; | |
1039 } | |
1040 if (delta >= 0 && rect == expanded_starting_rect) { | |
1041 // The starting rect already covers the entire bounding_rect and isn't too | |
1042 // large for the target_area. | |
1043 if (cache) | |
1044 cache->previous_result = rect; | |
1045 return rect; | |
1046 } | |
1047 | |
1048 // Continue to expand/shrink rect to let it cover target_area. | |
1049 | |
1050 // These values will be updated by the loop and uses as the output. | |
1051 int origin_x = rect.x(); | |
1052 int origin_y = rect.y(); | |
1053 int width = rect.width(); | |
1054 int height = rect.height(); | |
1055 | |
1056 // In the beginning we will consider 2 edges in each dimension. | |
1057 int num_y_edges = 2; | |
1058 int num_x_edges = 2; | |
1059 | |
1060 // Create an event list. | |
1061 EdgeEvent events[] = { | |
1062 { EdgeEvent::BOTTOM, &num_y_edges, rect.y() - bounding_rect.y() }, | |
1063 { EdgeEvent::TOP, &num_y_edges, bounding_rect.bottom() - rect.bottom() }, | |
1064 { EdgeEvent::LEFT, &num_x_edges, rect.x() - bounding_rect.x() }, | |
1065 { EdgeEvent::RIGHT, &num_x_edges, bounding_rect.right() - rect.right() } | |
1066 }; | |
1067 | |
1068 // Sort the events by distance (closest first). | |
1069 if (events[0].distance > events[1].distance) std::swap(events[0], events[1]); | |
1070 if (events[2].distance > events[3].distance) std::swap(events[2], events[3]); | |
1071 if (events[0].distance > events[2].distance) std::swap(events[0], events[2]); | |
1072 if (events[1].distance > events[3].distance) std::swap(events[1], events[3]); | |
1073 if (events[1].distance > events[2].distance) std::swap(events[1], events[2]); | |
1074 | |
1075 for (int event_index = 0; event_index < 4; event_index++) { | |
1076 const EdgeEvent& event = events[event_index]; | |
1077 | |
1078 int delta = ComputeExpansionDelta( | |
1079 num_x_edges, num_y_edges, width, height, target_area); | |
1080 | |
1081 // Clamp delta to our event distance. | |
1082 if (delta > event.distance) | |
1083 delta = event.distance; | |
1084 | |
1085 // Adjust the edge count for this kind of edge. | |
1086 --*event.num_edges; | |
1087 | |
1088 // Apply the delta to the edges and edge events. | |
1089 for (int i = event_index; i < 4; i++) { | |
1090 switch (events[i].edge) { | |
1091 case EdgeEvent::BOTTOM: | |
1092 origin_y -= delta; | |
1093 height += delta; | |
1094 break; | |
1095 case EdgeEvent::TOP: | |
1096 height += delta; | |
1097 break; | |
1098 case EdgeEvent::LEFT: | |
1099 origin_x -= delta; | |
1100 width += delta; | |
1101 break; | |
1102 case EdgeEvent::RIGHT: | |
1103 width += delta; | |
1104 break; | |
1105 } | |
1106 events[i].distance -= delta; | |
1107 } | |
1108 | |
1109 // If our delta is less then our event distance, we're done. | |
1110 if (delta < event.distance) | |
1111 break; | |
1112 } | |
1113 | |
1114 gfx::Rect result(origin_x, origin_y, width, height); | |
1115 if (cache) | |
1116 cache->previous_result = result; | |
1117 return result; | |
1118 } | |
1119 | |
1120 } // namespace cc | 971 } // namespace cc |
OLD | NEW |