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