1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "cc/resources/picture_pile_base.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <vector> 10 11 #include "base/debug/trace_event_argument.h" 12 #include "base/logging.h" 13 #include "base/values.h" 14 #include "cc/base/math_util.h" 15 #include "cc/debug/traced_value.h" 16 #include "third_party/skia/include/core/SkColor.h" 17 #include "ui/gfx/rect_conversions.h" 18 19 namespace { 20 // Dimensions of the tiles in this picture pile as well as the dimensions of 21 // the base picture in each tile. 22 const int kBasePictureSize = 512; 23 const int kTileGridBorderPixels = 1; 24 #ifdef NDEBUG 25 const bool kDefaultClearCanvasSetting = false; 26 #else 27 const bool kDefaultClearCanvasSetting = true; 28 #endif 29 30 // Invalidation frequency settings. kInvalidationFrequencyThreshold is a value 31 // between 0 and 1 meaning invalidation frequency between 0% and 100% that 32 // indicates when to stop invalidating offscreen regions. 33 // kFrequentInvalidationDistanceThreshold defines what it means to be 34 // "offscreen" in terms of distance to visible in css pixels. 35 const float kInvalidationFrequencyThreshold = 0.75f; 36 const int kFrequentInvalidationDistanceThreshold = 512; 37 38 } // namespace 39 40 namespace cc { 41 42 PicturePileBase::PicturePileBase() 43 : min_contents_scale_(0), 44 background_color_(SkColorSetARGBInline(0, 0, 0, 0)), 45 slow_down_raster_scale_factor_for_debug_(0), 46 contents_opaque_(false), 47 contents_fill_bounds_completely_(false), 48 show_debug_picture_borders_(false), 49 clear_canvas_with_debug_color_(kDefaultClearCanvasSetting), 50 has_any_recordings_(false), 51 has_text_(false), 52 is_mask_(false), 53 is_solid_color_(false), 54 solid_color_(SK_ColorTRANSPARENT) { 55 tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize)); 56 tile_grid_info_.fTileInterval.setEmpty(); 57 tile_grid_info_.fMargin.setEmpty(); 58 tile_grid_info_.fOffset.setZero(); 59 } 60 61 PicturePileBase::PicturePileBase(const PicturePileBase* other) 62 : picture_map_(other->picture_map_), 63 tiling_(other->tiling_), 64 recorded_viewport_(other->recorded_viewport_), 65 min_contents_scale_(other->min_contents_scale_), 66 tile_grid_info_(other->tile_grid_info_), 67 background_color_(other->background_color_), 68 slow_down_raster_scale_factor_for_debug_( 69 other->slow_down_raster_scale_factor_for_debug_), 70 contents_opaque_(other->contents_opaque_), 71 contents_fill_bounds_completely_(other->contents_fill_bounds_completely_), 72 show_debug_picture_borders_(other->show_debug_picture_borders_), 73 clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_), 74 has_any_recordings_(other->has_any_recordings_), 75 has_text_(other->has_text_), 76 is_mask_(other->is_mask_), 77 is_solid_color_(other->is_solid_color_), 78 solid_color_(other->solid_color_) { 79 } 80 81 PicturePileBase::~PicturePileBase() { 82 } 83 84 void PicturePileBase::SetMinContentsScale(float min_contents_scale) { 85 DCHECK(min_contents_scale); 86 if (min_contents_scale_ == min_contents_scale) 87 return; 88 89 // Picture contents are played back scaled. When the final contents scale is 90 // less than 1 (i.e. low res), then multiple recorded pixels will be used 91 // to raster one final pixel. To avoid splitting a final pixel across 92 // pictures (which would result in incorrect rasterization due to blending), a 93 // buffer margin is added so that any picture can be snapped to integral 94 // final pixels. 95 // 96 // For example, if a 1/4 contents scale is used, then that would be 3 buffer 97 // pixels, since that's the minimum number of pixels to add so that resulting 98 // content can be snapped to a four pixel aligned grid. 99 int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1); 100 buffer_pixels = std::max(0, buffer_pixels); 101 SetBufferPixels(buffer_pixels); 102 min_contents_scale_ = min_contents_scale; 103 } 104 105 // static 106 void PicturePileBase::ComputeTileGridInfo( 107 const gfx::Size& tile_grid_size, 108 SkTileGridFactory::TileGridInfo* info) { 109 DCHECK(info); 110 info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels, 111 tile_grid_size.height() - 2 * kTileGridBorderPixels); 112 DCHECK_GT(info->fTileInterval.width(), 0); 113 DCHECK_GT(info->fTileInterval.height(), 0); 114 info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels); 115 // Offset the tile grid coordinate space to take into account the fact 116 // that the top-most and left-most tiles do not have top and left borders 117 // respectively. 118 info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels); 119 } 120 121 void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) { 122 ComputeTileGridInfo(tile_grid_size, &tile_grid_info_); 123 } 124 125 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) { 126 if (new_buffer_pixels == buffer_pixels()) 127 return; 128 129 Clear(); 130 tiling_.SetBorderTexels(new_buffer_pixels); 131 } 132 133 void PicturePileBase::Clear() { 134 picture_map_.clear(); 135 recorded_viewport_ = gfx::Rect(); 136 } 137 138 bool PicturePileBase::HasRecordingAt(int x, int y) { 139 PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y)); 140 if (found == picture_map_.end()) 141 return false; 142 return !!found->second.GetPicture(); 143 } 144 145 bool PicturePileBase::CanRaster(float contents_scale, 146 const gfx::Rect& content_rect) { 147 if (tiling_.tiling_size().IsEmpty()) 148 return false; 149 gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( 150 content_rect, 1.f / contents_scale); 151 layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); 152 153 // Common case inside of viewport to avoid the slower map lookups. 154 if (recorded_viewport_.Contains(layer_rect)) { 155 // Sanity check that there are no false positives in recorded_viewport_. 156 DCHECK(CanRasterSlowTileCheck(layer_rect)); 157 return true; 158 } 159 160 return CanRasterSlowTileCheck(layer_rect); 161 } 162 163 bool PicturePileBase::CanRasterSlowTileCheck( 164 const gfx::Rect& layer_rect) const { 165 bool include_borders = false; 166 for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); 167 tile_iter; 168 ++tile_iter) { 169 PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); 170 if (map_iter == picture_map_.end()) 171 return false; 172 if (!map_iter->second.GetPicture()) 173 return false; 174 } 175 return true; 176 } 177 178 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const { 179 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); 180 return PadRect(tile); 181 } 182 183 gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const { 184 gfx::Rect padded_rect = rect; 185 padded_rect.Inset( 186 -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels()); 187 return padded_rect; 188 } 189 190 void PicturePileBase::AsValueInto(base::debug::TracedValue* pictures) const { 191 gfx::Rect tiling_rect(tiling_.tiling_size()); 192 std::set<const void*> appended_pictures; 193 bool include_borders = true; 194 for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders); 195 tile_iter; 196 ++tile_iter) { 197 PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); 198 if (map_iter == picture_map_.end()) 199 continue; 200 201 const Picture* picture = map_iter->second.GetPicture(); 202 if (picture && (appended_pictures.count(picture) == 0)) { 203 appended_pictures.insert(picture); 204 TracedValue::AppendIDRef(picture, pictures); 205 } 206 } 207 } 208 209 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {} 210 211 PicturePileBase::PictureInfo::~PictureInfo() {} 212 213 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory( 214 int frame_number) { 215 DCHECK_GE(frame_number, last_frame_number_); 216 if (frame_number == last_frame_number_) 217 return; 218 219 invalidation_history_ <<= (frame_number - last_frame_number_); 220 last_frame_number_ = frame_number; 221 } 222 223 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) { 224 AdvanceInvalidationHistory(frame_number); 225 invalidation_history_.set(0); 226 227 bool did_invalidate = !!picture_.get(); 228 picture_ = NULL; 229 return did_invalidate; 230 } 231 232 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number, 233 int distance_to_visible) { 234 AdvanceInvalidationHistory(frame_number); 235 236 // We only need recording if we don't have a picture. Furthermore, we only 237 // need a recording if we're within frequent invalidation distance threshold 238 // or the invalidation is not frequent enough (below invalidation frequency 239 // threshold). 240 return !picture_.get() && 241 ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) || 242 (GetInvalidationFrequency() < kInvalidationFrequencyThreshold)); 243 } 244 245 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) { 246 picture_ = picture; 247 } 248 249 const Picture* PicturePileBase::PictureInfo::GetPicture() const { 250 return picture_.get(); 251 } 252 253 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const { 254 return invalidation_history_.count() / 255 static_cast<float>(INVALIDATION_FRAMES_TRACKED); 256 } 257 258 } // namespace cc 259