Home | History | Annotate | Download | only in resources
      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/logging.h"
     12 #include "base/values.h"
     13 #include "cc/base/math_util.h"
     14 #include "cc/debug/traced_value.h"
     15 #include "third_party/skia/include/core/SkColor.h"
     16 #include "ui/gfx/rect_conversions.h"
     17 
     18 namespace {
     19 // Dimensions of the tiles in this picture pile as well as the dimensions of
     20 // the base picture in each tile.
     21 const int kBasePictureSize = 512;
     22 const int kTileGridBorderPixels = 1;
     23 #ifdef NDEBUG
     24 const bool kDefaultClearCanvasSetting = false;
     25 #else
     26 const bool kDefaultClearCanvasSetting = true;
     27 #endif
     28 
     29 // Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
     30 // between 0 and 1 meaning invalidation frequency between 0% and 100% that
     31 // indicates when to stop invalidating offscreen regions.
     32 // kFrequentInvalidationDistanceThreshold defines what it means to be
     33 // "offscreen" in terms of distance to visible in css pixels.
     34 const float kInvalidationFrequencyThreshold = 0.75f;
     35 const int kFrequentInvalidationDistanceThreshold = 512;
     36 
     37 }  // namespace
     38 
     39 namespace cc {
     40 
     41 PicturePileBase::PicturePileBase()
     42     : min_contents_scale_(0),
     43       background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
     44       slow_down_raster_scale_factor_for_debug_(0),
     45       contents_opaque_(false),
     46       contents_fill_bounds_completely_(false),
     47       show_debug_picture_borders_(false),
     48       clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
     49       has_any_recordings_(false) {
     50   tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
     51   tile_grid_info_.fTileInterval.setEmpty();
     52   tile_grid_info_.fMargin.setEmpty();
     53   tile_grid_info_.fOffset.setZero();
     54 }
     55 
     56 PicturePileBase::PicturePileBase(const PicturePileBase* other)
     57     : picture_map_(other->picture_map_),
     58       tiling_(other->tiling_),
     59       recorded_viewport_(other->recorded_viewport_),
     60       min_contents_scale_(other->min_contents_scale_),
     61       tile_grid_info_(other->tile_grid_info_),
     62       background_color_(other->background_color_),
     63       slow_down_raster_scale_factor_for_debug_(
     64           other->slow_down_raster_scale_factor_for_debug_),
     65       contents_opaque_(other->contents_opaque_),
     66       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
     67       show_debug_picture_borders_(other->show_debug_picture_borders_),
     68       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
     69       has_any_recordings_(other->has_any_recordings_) {}
     70 
     71 PicturePileBase::PicturePileBase(const PicturePileBase* other,
     72                                  unsigned thread_index)
     73     : tiling_(other->tiling_),
     74       recorded_viewport_(other->recorded_viewport_),
     75       min_contents_scale_(other->min_contents_scale_),
     76       tile_grid_info_(other->tile_grid_info_),
     77       background_color_(other->background_color_),
     78       slow_down_raster_scale_factor_for_debug_(
     79           other->slow_down_raster_scale_factor_for_debug_),
     80       contents_opaque_(other->contents_opaque_),
     81       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
     82       show_debug_picture_borders_(other->show_debug_picture_borders_),
     83       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
     84       has_any_recordings_(other->has_any_recordings_) {
     85   for (PictureMap::const_iterator it = other->picture_map_.begin();
     86        it != other->picture_map_.end();
     87        ++it) {
     88     picture_map_[it->first] = it->second.CloneForThread(thread_index);
     89   }
     90 }
     91 
     92 PicturePileBase::~PicturePileBase() {
     93 }
     94 
     95 void PicturePileBase::SetTilingRect(const gfx::Rect& new_tiling_rect) {
     96   if (tiling_rect() == new_tiling_rect)
     97     return;
     98 
     99   gfx::Rect old_tiling_rect = tiling_rect();
    100   tiling_.SetTilingRect(new_tiling_rect);
    101 
    102   has_any_recordings_ = false;
    103 
    104   // Don't waste time in Resize figuring out what these hints should be.
    105   recorded_viewport_ = gfx::Rect();
    106 
    107   if (new_tiling_rect.origin() != old_tiling_rect.origin()) {
    108     picture_map_.clear();
    109     return;
    110   }
    111 
    112   // Find all tiles that contain any pixels outside the new rect.
    113   std::vector<PictureMapKey> to_erase;
    114   int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord(
    115       std::min(old_tiling_rect.right(), new_tiling_rect.right()));
    116   int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(
    117       std::min(old_tiling_rect.bottom(), new_tiling_rect.bottom()));
    118   for (PictureMap::const_iterator it = picture_map_.begin();
    119        it != picture_map_.end();
    120        ++it) {
    121     const PictureMapKey& key = it->first;
    122     if (key.first < min_toss_x && key.second < min_toss_y) {
    123       has_any_recordings_ |= !!it->second.GetPicture();
    124       continue;
    125     }
    126     to_erase.push_back(key);
    127   }
    128 
    129   for (size_t i = 0; i < to_erase.size(); ++i)
    130     picture_map_.erase(to_erase[i]);
    131 }
    132 
    133 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
    134   DCHECK(min_contents_scale);
    135   if (min_contents_scale_ == min_contents_scale)
    136     return;
    137 
    138   // Picture contents are played back scaled. When the final contents scale is
    139   // less than 1 (i.e. low res), then multiple recorded pixels will be used
    140   // to raster one final pixel.  To avoid splitting a final pixel across
    141   // pictures (which would result in incorrect rasterization due to blending), a
    142   // buffer margin is added so that any picture can be snapped to integral
    143   // final pixels.
    144   //
    145   // For example, if a 1/4 contents scale is used, then that would be 3 buffer
    146   // pixels, since that's the minimum number of pixels to add so that resulting
    147   // content can be snapped to a four pixel aligned grid.
    148   int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
    149   buffer_pixels = std::max(0, buffer_pixels);
    150   SetBufferPixels(buffer_pixels);
    151   min_contents_scale_ = min_contents_scale;
    152 }
    153 
    154 // static
    155 void PicturePileBase::ComputeTileGridInfo(
    156     const gfx::Size& tile_grid_size,
    157     SkTileGridFactory::TileGridInfo* info) {
    158   DCHECK(info);
    159   info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
    160                           tile_grid_size.height() - 2 * kTileGridBorderPixels);
    161   DCHECK_GT(info->fTileInterval.width(), 0);
    162   DCHECK_GT(info->fTileInterval.height(), 0);
    163   info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
    164   // Offset the tile grid coordinate space to take into account the fact
    165   // that the top-most and left-most tiles do not have top and left borders
    166   // respectively.
    167   info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
    168 }
    169 
    170 void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
    171   ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
    172 }
    173 
    174 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
    175   if (new_buffer_pixels == buffer_pixels())
    176     return;
    177 
    178   Clear();
    179   tiling_.SetBorderTexels(new_buffer_pixels);
    180 }
    181 
    182 void PicturePileBase::Clear() {
    183   picture_map_.clear();
    184   recorded_viewport_ = gfx::Rect();
    185 }
    186 
    187 bool PicturePileBase::HasRecordingAt(int x, int y) {
    188   PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
    189   if (found == picture_map_.end())
    190     return false;
    191   return !!found->second.GetPicture();
    192 }
    193 
    194 bool PicturePileBase::CanRaster(float contents_scale,
    195                                 const gfx::Rect& content_rect) {
    196   if (tiling_.tiling_rect().IsEmpty())
    197     return false;
    198   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
    199       content_rect, 1.f / contents_scale);
    200   layer_rect.Intersect(tiling_.tiling_rect());
    201 
    202   // Common case inside of viewport to avoid the slower map lookups.
    203   if (recorded_viewport_.Contains(layer_rect)) {
    204     // Sanity check that there are no false positives in recorded_viewport_.
    205     DCHECK(CanRasterSlowTileCheck(layer_rect));
    206     return true;
    207   }
    208 
    209   return CanRasterSlowTileCheck(layer_rect);
    210 }
    211 
    212 bool PicturePileBase::CanRasterSlowTileCheck(
    213     const gfx::Rect& layer_rect) const {
    214   bool include_borders = false;
    215   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
    216        tile_iter;
    217        ++tile_iter) {
    218     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
    219     if (map_iter == picture_map_.end())
    220       return false;
    221     if (!map_iter->second.GetPicture())
    222       return false;
    223   }
    224   return true;
    225 }
    226 
    227 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
    228   gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
    229   return PadRect(tile);
    230 }
    231 
    232 gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) {
    233   gfx::Rect padded_rect = rect;
    234   padded_rect.Inset(
    235       -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
    236   return padded_rect;
    237 }
    238 
    239 scoped_ptr<base::Value> PicturePileBase::AsValue() const {
    240   scoped_ptr<base::ListValue> pictures(new base::ListValue());
    241   gfx::Rect tiling_rect(tiling_.tiling_rect());
    242   std::set<void*> appended_pictures;
    243   bool include_borders = true;
    244   for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
    245        tile_iter;
    246        ++tile_iter) {
    247     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
    248     if (map_iter == picture_map_.end())
    249       continue;
    250 
    251     Picture* picture = map_iter->second.GetPicture();
    252     if (picture && (appended_pictures.count(picture) == 0)) {
    253       appended_pictures.insert(picture);
    254       pictures->Append(TracedValue::CreateIDRef(picture).release());
    255     }
    256   }
    257   return pictures.PassAs<base::Value>();
    258 }
    259 
    260 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
    261 
    262 PicturePileBase::PictureInfo::~PictureInfo() {}
    263 
    264 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
    265     int frame_number) {
    266   DCHECK_GE(frame_number, last_frame_number_);
    267   if (frame_number == last_frame_number_)
    268     return;
    269 
    270   invalidation_history_ <<= (frame_number - last_frame_number_);
    271   last_frame_number_ = frame_number;
    272 }
    273 
    274 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
    275   AdvanceInvalidationHistory(frame_number);
    276   invalidation_history_.set(0);
    277 
    278   bool did_invalidate = !!picture_;
    279   picture_ = NULL;
    280   return did_invalidate;
    281 }
    282 
    283 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
    284                                                   int distance_to_visible) {
    285   AdvanceInvalidationHistory(frame_number);
    286 
    287   // We only need recording if we don't have a picture. Furthermore, we only
    288   // need a recording if we're within frequent invalidation distance threshold
    289   // or the invalidation is not frequent enough (below invalidation frequency
    290   // threshold).
    291   return !picture_ &&
    292          ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
    293           (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
    294 }
    295 
    296 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
    297   picture_ = picture;
    298 }
    299 
    300 Picture* PicturePileBase::PictureInfo::GetPicture() const {
    301   return picture_.get();
    302 }
    303 
    304 PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread(
    305     int thread_index) const {
    306   PictureInfo info = *this;
    307   if (picture_.get())
    308     info.picture_ = picture_->GetCloneForDrawingOnThread(thread_index);
    309   return info;
    310 }
    311 
    312 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
    313   return invalidation_history_.count() /
    314          static_cast<float>(INVALIDATION_FRAMES_TRACKED);
    315 }
    316 
    317 }  // namespace cc
    318