tiled_layer_impl.cc revision 010d83a9304c5a91596085d917d248abff47903a
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
22namespace cc {
23
24class 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
48TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
49    : LayerImpl(tree_impl, id), skips_draw_(true) {}
50
51TiledLayerImpl::~TiledLayerImpl() {
52}
53
54ResourceProvider::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
71bool TiledLayerImpl::HasTileAt(int i, int j) const {
72  return !!tiler_->TileAt(i, j);
73}
74
75bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
76  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
77}
78
79DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
80  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
81}
82
83DrawableTile* 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
91void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
92                                              float* width) const {
93  *color = DebugColors::TiledContentLayerBorderColor();
94  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
95}
96
97scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
98    LayerTreeImpl* tree_impl) {
99  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
100}
101
102void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
103  LayerImpl::AsValueInto(state);
104  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
105}
106
107size_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
122void 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
145bool 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
154void 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(quad_sink, shared_quad_state, append_quads_data);
165
166  int left, top, right, bottom;
167  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);
168
169  if (ShowDebugBorders()) {
170    for (int j = top; j <= bottom; ++j) {
171      for (int i = left; i <= right; ++i) {
172        DrawableTile* tile = TileAt(i, j);
173        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
174        gfx::Rect visible_tile_rect = tile_rect;
175        SkColor border_color;
176        float border_width;
177
178        if (skips_draw_ || !tile || !tile->resource_id()) {
179          border_color = DebugColors::MissingTileBorderColor();
180          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
181        } else {
182          border_color = DebugColors::HighResTileBorderColor();
183          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
184        }
185        scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
186            DebugBorderDrawQuad::Create();
187        debug_border_quad->SetNew(shared_quad_state,
188                                  tile_rect,
189                                  visible_tile_rect,
190                                  border_color,
191                                  border_width);
192        quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
193      }
194    }
195  }
196
197  if (skips_draw_)
198    return;
199
200  for (int j = top; j <= bottom; ++j) {
201    for (int i = left; i <= right; ++i) {
202      DrawableTile* tile = TileAt(i, j);
203      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
204      gfx::Rect display_rect = tile_rect;
205      tile_rect.Intersect(content_rect);
206
207      // Skip empty tiles.
208      if (tile_rect.IsEmpty())
209        continue;
210
211      gfx::Rect visible_tile_rect =
212          quad_sink->UnoccludedContentRect(tile_rect, draw_transform());
213      if (visible_tile_rect.IsEmpty())
214        continue;
215
216      if (!tile || !tile->resource_id()) {
217        SkColor checker_color;
218        if (ShowDebugBorders()) {
219          checker_color =
220              tile ? DebugColors::InvalidatedTileCheckerboardColor()
221                   : DebugColors::EvictedTileCheckerboardColor();
222        } else {
223          checker_color = DebugColors::DefaultCheckerboardColor();
224        }
225
226        scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
227            CheckerboardDrawQuad::Create();
228        checkerboard_quad->SetNew(
229            shared_quad_state, tile_rect, visible_tile_rect, checker_color);
230        quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>());
231        append_quads_data->num_missing_tiles++;
232        continue;
233      }
234
235      gfx::Rect tile_opaque_rect =
236          contents_opaque() ? tile_rect : gfx::IntersectRects(
237                                              tile->opaque_rect(), tile_rect);
238
239      // Keep track of how the top left has moved, so the texture can be
240      // offset the same amount.
241      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
242      gfx::Vector2d texture_offset =
243          tiler_->texture_offset(i, j) + display_offset;
244      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;
245
246      float tile_width = static_cast<float>(tiler_->tile_size().width());
247      float tile_height = static_cast<float>(tiler_->tile_size().height());
248      gfx::Size texture_size(tile_width, tile_height);
249
250      scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
251      quad->SetNew(shared_quad_state,
252                   tile_rect,
253                   tile_opaque_rect,
254                   visible_tile_rect,
255                   tile->resource_id(),
256                   tex_coord_rect,
257                   texture_size,
258                   tile->contents_swizzled());
259      quad_sink->Append(quad.PassAs<DrawQuad>());
260    }
261  }
262}
263
264void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
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
276void TiledLayerImpl::PushTileProperties(
277    int i,
278    int j,
279    ResourceProvider::ResourceId resource_id,
280    const gfx::Rect& opaque_rect,
281    bool contents_swizzled) {
282  DrawableTile* tile = TileAt(i, j);
283  if (!tile)
284    tile = CreateTile(i, j);
285  tile->set_resource_id(resource_id);
286  tile->set_opaque_rect(opaque_rect);
287  tile->set_contents_swizzled(contents_swizzled);
288}
289
290void TiledLayerImpl::PushInvalidTile(int i, int j) {
291  DrawableTile* tile = TileAt(i, j);
292  if (!tile)
293    tile = CreateTile(i, j);
294  tile->set_resource_id(0);
295  tile->set_opaque_rect(gfx::Rect());
296  tile->set_contents_swizzled(false);
297}
298
299Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
300  if (skips_draw_)
301    return Region();
302  if (contents_opaque())
303    return visible_content_rect();
304  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
305}
306
307void TiledLayerImpl::ReleaseResources() {
308  tiler_->reset();
309}
310
311const char* TiledLayerImpl::LayerTypeAsString() const {
312  return "cc::TiledLayerImpl";
313}
314
315}  // namespace cc
316