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       show_debug_picture_borders_(false),
     47       clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
     48       num_raster_threads_(0),
     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       show_debug_picture_borders_(other->show_debug_picture_borders_),
     67       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
     68       num_raster_threads_(other->num_raster_threads_),
     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       show_debug_picture_borders_(other->show_debug_picture_borders_),
     82       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
     83       num_raster_threads_(other->num_raster_threads_),
     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::Resize(gfx::Size new_size) {
     96   if (size() == new_size)
     97     return;
     98 
     99   gfx::Size old_size = size();
    100   tiling_.SetTotalSize(new_size);
    101 
    102   has_any_recordings_ = false;
    103 
    104   // Find all tiles that contain any pixels outside the new size.
    105   std::vector<PictureMapKey> to_erase;
    106   int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord(
    107       std::min(old_size.width(), new_size.width()));
    108   int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(
    109       std::min(old_size.height(), new_size.height()));
    110   for (PictureMap::const_iterator it = picture_map_.begin();
    111        it != picture_map_.end();
    112        ++it) {
    113     const PictureMapKey& key = it->first;
    114     if (key.first < min_toss_x && key.second < min_toss_y) {
    115       has_any_recordings_ |= !!it->second.GetPicture();
    116       continue;
    117     }
    118     to_erase.push_back(key);
    119   }
    120 
    121   for (size_t i = 0; i < to_erase.size(); ++i)
    122     picture_map_.erase(to_erase[i]);
    123 
    124   // Don't waste time in Resize figuring out what these hints should be.
    125   recorded_viewport_ = gfx::Rect();
    126 }
    127 
    128 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
    129   DCHECK(min_contents_scale);
    130   if (min_contents_scale_ == min_contents_scale)
    131     return;
    132 
    133   // Picture contents are played back scaled. When the final contents scale is
    134   // less than 1 (i.e. low res), then multiple recorded pixels will be used
    135   // to raster one final pixel.  To avoid splitting a final pixel across
    136   // pictures (which would result in incorrect rasterization due to blending), a
    137   // buffer margin is added so that any picture can be snapped to integral
    138   // final pixels.
    139   //
    140   // For example, if a 1/4 contents scale is used, then that would be 3 buffer
    141   // pixels, since that's the minimum number of pixels to add so that resulting
    142   // content can be snapped to a four pixel aligned grid.
    143   int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
    144   buffer_pixels = std::max(0, buffer_pixels);
    145   SetBufferPixels(buffer_pixels);
    146   min_contents_scale_ = min_contents_scale;
    147 }
    148 
    149 // static
    150 void PicturePileBase::ComputeTileGridInfo(
    151     gfx::Size tile_grid_size,
    152     SkTileGridPicture::TileGridInfo* info) {
    153   DCHECK(info);
    154   info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
    155                           tile_grid_size.height() - 2 * kTileGridBorderPixels);
    156   DCHECK_GT(info->fTileInterval.width(), 0);
    157   DCHECK_GT(info->fTileInterval.height(), 0);
    158   info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
    159   // Offset the tile grid coordinate space to take into account the fact
    160   // that the top-most and left-most tiles do not have top and left borders
    161   // respectively.
    162   info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
    163 }
    164 
    165 void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) {
    166   ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
    167 }
    168 
    169 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
    170   if (new_buffer_pixels == buffer_pixels())
    171     return;
    172 
    173   Clear();
    174   tiling_.SetBorderTexels(new_buffer_pixels);
    175 }
    176 
    177 void PicturePileBase::Clear() {
    178   picture_map_.clear();
    179   recorded_viewport_ = gfx::Rect();
    180 }
    181 
    182 bool PicturePileBase::HasRecordingAt(int x, int y) {
    183   PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
    184   if (found == picture_map_.end())
    185     return false;
    186   return !!found->second.GetPicture();
    187 }
    188 
    189 bool PicturePileBase::CanRaster(float contents_scale, gfx::Rect content_rect) {
    190   if (tiling_.total_size().IsEmpty())
    191     return false;
    192   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
    193       content_rect, 1.f / contents_scale);
    194   layer_rect.Intersect(gfx::Rect(tiling_.total_size()));
    195 
    196   // Common case inside of viewport to avoid the slower map lookups.
    197   if (recorded_viewport_.Contains(layer_rect)) {
    198     // Sanity check that there are no false positives in recorded_viewport_.
    199     DCHECK(CanRasterSlowTileCheck(layer_rect));
    200     return true;
    201   }
    202 
    203   return CanRasterSlowTileCheck(layer_rect);
    204 }
    205 
    206 bool PicturePileBase::CanRasterSlowTileCheck(
    207     const gfx::Rect& layer_rect) const {
    208   bool include_borders = false;
    209   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
    210        tile_iter;
    211        ++tile_iter) {
    212     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
    213     if (map_iter == picture_map_.end())
    214       return false;
    215     if (!map_iter->second.GetPicture())
    216       return false;
    217   }
    218   return true;
    219 }
    220 
    221 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
    222   gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
    223   return PadRect(tile);
    224 }
    225 
    226 gfx::Rect PicturePileBase::PadRect(gfx::Rect rect) {
    227   gfx::Rect padded_rect = rect;
    228   padded_rect.Inset(
    229       -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
    230   return padded_rect;
    231 }
    232 
    233 scoped_ptr<base::Value> PicturePileBase::AsValue() const {
    234   scoped_ptr<base::ListValue> pictures(new base::ListValue());
    235   gfx::Rect layer_rect(tiling_.total_size());
    236   std::set<void*> appended_pictures;
    237   bool include_borders = true;
    238   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
    239        tile_iter;
    240        ++tile_iter) {
    241     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
    242     if (map_iter == picture_map_.end())
    243       continue;
    244 
    245     Picture* picture = map_iter->second.GetPicture();
    246     if (picture && (appended_pictures.count(picture) == 0)) {
    247       appended_pictures.insert(picture);
    248       pictures->Append(TracedValue::CreateIDRef(picture).release());
    249     }
    250   }
    251   return pictures.PassAs<base::Value>();
    252 }
    253 
    254 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
    255 
    256 PicturePileBase::PictureInfo::~PictureInfo() {}
    257 
    258 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
    259     int frame_number) {
    260   DCHECK_GE(frame_number, last_frame_number_);
    261   if (frame_number == last_frame_number_)
    262     return;
    263 
    264   invalidation_history_ <<= (frame_number - last_frame_number_);
    265   last_frame_number_ = frame_number;
    266 }
    267 
    268 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
    269   AdvanceInvalidationHistory(frame_number);
    270   invalidation_history_.set(0);
    271 
    272   bool did_invalidate = !!picture_;
    273   picture_ = NULL;
    274   return did_invalidate;
    275 }
    276 
    277 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
    278                                                   int distance_to_visible) {
    279   AdvanceInvalidationHistory(frame_number);
    280 
    281   // We only need recording if we don't have a picture. Furthermore, we only
    282   // need a recording if we're within frequent invalidation distance threshold
    283   // or the invalidation is not frequent enough (below invalidation frequency
    284   // threshold).
    285   return !picture_ &&
    286          ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
    287           (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
    288 }
    289 
    290 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
    291   picture_ = picture;
    292 }
    293 
    294 Picture* PicturePileBase::PictureInfo::GetPicture() const {
    295   return picture_.get();
    296 }
    297 
    298 PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread(
    299     int thread_index) const {
    300   PictureInfo info = *this;
    301   if (picture_.get())
    302     info.picture_ = picture_->GetCloneForDrawingOnThread(thread_index);
    303   return info;
    304 }
    305 
    306 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
    307   return invalidation_history_.count() /
    308          static_cast<float>(INVALIDATION_FRAMES_TRACKED);
    309 }
    310 
    311 }  // namespace cc
    312