Home | History | Annotate | Download | only in layers
      1 // Copyright 2011 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/layers/tiled_layer_impl.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/strings/stringprintf.h"
      9 #include "cc/base/math_util.h"
     10 #include "cc/debug/debug_colors.h"
     11 #include "cc/layers/append_quads_data.h"
     12 #include "cc/layers/quad_sink.h"
     13 #include "cc/quads/checkerboard_draw_quad.h"
     14 #include "cc/quads/debug_border_draw_quad.h"
     15 #include "cc/quads/solid_color_draw_quad.h"
     16 #include "cc/quads/tile_draw_quad.h"
     17 #include "cc/resources/layer_tiling_data.h"
     18 #include "third_party/khronos/GLES2/gl2.h"
     19 #include "third_party/skia/include/core/SkColor.h"
     20 #include "ui/gfx/quad_f.h"
     21 
     22 namespace cc {
     23 
     24 // Temporary diagnostic.
     25 static bool s_safe_to_delete_drawable_tile = false;
     26 
     27 class DrawableTile : public LayerTilingData::Tile {
     28  public:
     29   static scoped_ptr<DrawableTile> Create() {
     30     return make_scoped_ptr(new DrawableTile());
     31   }
     32 
     33   virtual ~DrawableTile() { CHECK(s_safe_to_delete_drawable_tile); }
     34 
     35   ResourceProvider::ResourceId resource_id() const { return resource_id_; }
     36   void set_resource_id(ResourceProvider::ResourceId resource_id) {
     37     resource_id_ = resource_id;
     38   }
     39   bool contents_swizzled() { return contents_swizzled_; }
     40   void set_contents_swizzled(bool contents_swizzled) {
     41     contents_swizzled_ = contents_swizzled;
     42   }
     43 
     44  private:
     45   DrawableTile() : resource_id_(0), contents_swizzled_(false) {}
     46 
     47   ResourceProvider::ResourceId resource_id_;
     48   bool contents_swizzled_;
     49 
     50   DISALLOW_COPY_AND_ASSIGN(DrawableTile);
     51 };
     52 
     53 TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
     54     : LayerImpl(tree_impl, id), skips_draw_(true) {}
     55 
     56 TiledLayerImpl::~TiledLayerImpl() {
     57   s_safe_to_delete_drawable_tile = true;
     58   if (tiler_)
     59     tiler_->reset();
     60   s_safe_to_delete_drawable_tile = false;
     61 }
     62 
     63 ResourceProvider::ResourceId TiledLayerImpl::ContentsResourceId() const {
     64   // This function is only valid for single texture layers, e.g. masks.
     65   DCHECK(tiler_);
     66   DCHECK_EQ(tiler_->num_tiles_x(), 1);
     67   DCHECK_EQ(tiler_->num_tiles_y(), 1);
     68 
     69   DrawableTile* tile = TileAt(0, 0);
     70   ResourceProvider::ResourceId resource_id = tile ? tile->resource_id() : 0;
     71   return resource_id;
     72 }
     73 
     74 bool TiledLayerImpl::HasTileAt(int i, int j) const {
     75   return !!tiler_->TileAt(i, j);
     76 }
     77 
     78 bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
     79   return HasTileAt(i, j) && TileAt(i, j)->resource_id();
     80 }
     81 
     82 DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
     83   return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
     84 }
     85 
     86 DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
     87   scoped_ptr<DrawableTile> tile(DrawableTile::Create());
     88   DrawableTile* added_tile = tile.get();
     89   tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
     90 
     91   // Temporary diagnostic checks.
     92   CHECK(added_tile);
     93   CHECK(TileAt(i, j));
     94 
     95   return added_tile;
     96 }
     97 
     98 void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
     99                                               float* width) const {
    100   *color = DebugColors::TiledContentLayerBorderColor();
    101   *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
    102 }
    103 
    104 scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
    105     LayerTreeImpl* tree_impl) {
    106   return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
    107 }
    108 
    109 void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
    110   LayerImpl::AsValueInto(state);
    111   state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
    112 }
    113 
    114 size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
    115   size_t amount = 0;
    116   const size_t kMemoryUsagePerTileInBytes =
    117       4 * tiler_->tile_size().width() * tiler_->tile_size().height();
    118   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
    119        iter != tiler_->tiles().end();
    120        ++iter) {
    121     const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    122     if (!tile || !tile->resource_id())
    123       continue;
    124     amount += kMemoryUsagePerTileInBytes;
    125   }
    126   return amount;
    127 }
    128 
    129 void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
    130   LayerImpl::PushPropertiesTo(layer);
    131 
    132   TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
    133 
    134   tiled_layer->set_skips_draw(skips_draw_);
    135   tiled_layer->SetTilingData(*tiler_);
    136 
    137   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
    138        iter != tiler_->tiles().end();
    139        ++iter) {
    140     int i = iter->first.first;
    141     int j = iter->first.second;
    142     DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
    143 
    144     tiled_layer->PushTileProperties(i,
    145                                     j,
    146                                     tile->resource_id(),
    147                                     tile->opaque_rect(),
    148                                     tile->contents_swizzled());
    149   }
    150 }
    151 
    152 bool TiledLayerImpl::WillDraw(DrawMode draw_mode,
    153                               ResourceProvider* resource_provider) {
    154   if (!tiler_ || tiler_->has_empty_bounds() ||
    155       visible_content_rect().IsEmpty() ||
    156       draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE)
    157     return false;
    158   return LayerImpl::WillDraw(draw_mode, resource_provider);
    159 }
    160 
    161 void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
    162                                  AppendQuadsData* append_quads_data) {
    163   DCHECK(tiler_);
    164   DCHECK(!tiler_->has_empty_bounds());
    165   DCHECK(!visible_content_rect().IsEmpty());
    166 
    167   gfx::Rect content_rect = visible_content_rect();
    168   SharedQuadState* shared_quad_state =
    169       quad_sink->UseSharedQuadState(CreateSharedQuadState());
    170   AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
    171 
    172   int left, top, right, bottom;
    173   tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);
    174 
    175   if (ShowDebugBorders()) {
    176     for (int j = top; j <= bottom; ++j) {
    177       for (int i = left; i <= right; ++i) {
    178         DrawableTile* tile = TileAt(i, j);
    179         gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
    180         SkColor border_color;
    181         float border_width;
    182 
    183         if (skips_draw_ || !tile || !tile->resource_id()) {
    184           border_color = DebugColors::MissingTileBorderColor();
    185           border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
    186         } else {
    187           border_color = DebugColors::HighResTileBorderColor();
    188           border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
    189         }
    190         scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
    191             DebugBorderDrawQuad::Create();
    192         debug_border_quad->SetNew(
    193             shared_quad_state, tile_rect, border_color, border_width);
    194         quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(),
    195                           append_quads_data);
    196       }
    197     }
    198   }
    199 
    200   if (skips_draw_)
    201     return;
    202 
    203   for (int j = top; j <= bottom; ++j) {
    204     for (int i = left; i <= right; ++i) {
    205       DrawableTile* tile = TileAt(i, j);
    206       gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
    207       gfx::Rect display_rect = tile_rect;
    208       tile_rect.Intersect(content_rect);
    209 
    210       // Skip empty tiles.
    211       if (tile_rect.IsEmpty())
    212         continue;
    213 
    214       if (!tile || !tile->resource_id()) {
    215         SkColor checker_color;
    216         if (ShowDebugBorders()) {
    217           checker_color =
    218               tile ? DebugColors::InvalidatedTileCheckerboardColor()
    219                    : DebugColors::EvictedTileCheckerboardColor();
    220         } else {
    221           checker_color = DebugColors::DefaultCheckerboardColor();
    222         }
    223 
    224         scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
    225             CheckerboardDrawQuad::Create();
    226         checkerboard_quad->SetNew(
    227             shared_quad_state, tile_rect, checker_color);
    228         if (quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>(),
    229                               append_quads_data))
    230           append_quads_data->num_missing_tiles++;
    231 
    232         continue;
    233       }
    234 
    235       gfx::Rect tile_opaque_rect = contents_opaque() ? tile_rect :
    236         gfx::IntersectRects(tile->opaque_rect(), content_rect);
    237 
    238       // Keep track of how the top left has moved, so the texture can be
    239       // offset the same amount.
    240       gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
    241       gfx::Vector2d texture_offset =
    242           tiler_->texture_offset(i, j) + display_offset;
    243       gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;
    244 
    245       float tile_width = static_cast<float>(tiler_->tile_size().width());
    246       float tile_height = static_cast<float>(tiler_->tile_size().height());
    247       gfx::Size texture_size(tile_width, tile_height);
    248 
    249       scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
    250       quad->SetNew(shared_quad_state,
    251                    tile_rect,
    252                    tile_opaque_rect,
    253                    tile->resource_id(),
    254                    tex_coord_rect,
    255                    texture_size,
    256                    tile->contents_swizzled());
    257       quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    258     }
    259   }
    260 }
    261 
    262 void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
    263   s_safe_to_delete_drawable_tile = true;
    264 
    265   if (tiler_) {
    266     tiler_->reset();
    267   } else {
    268     tiler_ = LayerTilingData::Create(tiler.tile_size(),
    269                                      tiler.has_border_texels()
    270                                          ? LayerTilingData::HAS_BORDER_TEXELS
    271                                          : LayerTilingData::NO_BORDER_TEXELS);
    272   }
    273   *tiler_ = tiler;
    274 
    275   s_safe_to_delete_drawable_tile = false;
    276 }
    277 
    278 void TiledLayerImpl::PushTileProperties(
    279     int i,
    280     int j,
    281     ResourceProvider::ResourceId resource_id,
    282     gfx::Rect opaque_rect,
    283     bool contents_swizzled) {
    284   DrawableTile* tile = TileAt(i, j);
    285   if (!tile)
    286     tile = CreateTile(i, j);
    287   tile->set_resource_id(resource_id);
    288   tile->set_opaque_rect(opaque_rect);
    289   tile->set_contents_swizzled(contents_swizzled);
    290 }
    291 
    292 void TiledLayerImpl::PushInvalidTile(int i, int j) {
    293   DrawableTile* tile = TileAt(i, j);
    294   if (!tile)
    295     tile = CreateTile(i, j);
    296   tile->set_resource_id(0);
    297   tile->set_opaque_rect(gfx::Rect());
    298   tile->set_contents_swizzled(false);
    299 }
    300 
    301 Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
    302   if (skips_draw_)
    303     return Region();
    304   if (contents_opaque())
    305     return visible_content_rect();
    306   return tiler_->OpaqueRegionInContentRect(visible_content_rect());
    307 }
    308 
    309 void TiledLayerImpl::DidLoseOutputSurface() {
    310   s_safe_to_delete_drawable_tile = true;
    311   // Temporary diagnostic check.
    312   CHECK(tiler_);
    313   tiler_->reset();
    314   s_safe_to_delete_drawable_tile = false;
    315 }
    316 
    317 const char* TiledLayerImpl::LayerTypeAsString() const {
    318   return "cc::TiledLayerImpl";
    319 }
    320 
    321 }  // namespace cc
    322