tiled_layer_impl.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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
24// Temporary diagnostic.
25static bool s_safe_to_delete_drawable_tile = false;
26
27class 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
53TiledLayerImpl::TiledLayerImpl(LayerTreeImpl* tree_impl, int id)
54    : LayerImpl(tree_impl, id), skips_draw_(true) {}
55
56TiledLayerImpl::~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
63ResourceProvider::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
74bool TiledLayerImpl::HasTileAt(int i, int j) const {
75  return !!tiler_->TileAt(i, j);
76}
77
78bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
79  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
80}
81
82DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
83  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
84}
85
86DrawableTile* 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
98void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
99                                              float* width) const {
100  *color = DebugColors::TiledContentLayerBorderColor();
101  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
102}
103
104scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
105    LayerTreeImpl* tree_impl) {
106  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
107}
108
109void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
110  LayerImpl::AsValueInto(state);
111  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
112}
113
114size_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
129void 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
152bool 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
161void 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
262void 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
278void 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
292void 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
301Region 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
309void 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
317const char* TiledLayerImpl::LayerTypeAsString() const {
318  return "cc::TiledLayerImpl";
319}
320
321}  // namespace cc
322