tiled_layer_impl.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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/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
74void TiledLayerImpl::DumpLayerProperties(std::string* str, int indent) const {
75  str->append(IndentString(indent));
76  base::StringAppendF(str, "skipsDraw: %d\n", (!tiler_ || skips_draw_));
77  LayerImpl::DumpLayerProperties(str, indent);
78}
79
80bool TiledLayerImpl::HasTileAt(int i, int j) const {
81  return !!tiler_->TileAt(i, j);
82}
83
84bool TiledLayerImpl::HasResourceIdForTileAt(int i, int j) const {
85  return HasTileAt(i, j) && TileAt(i, j)->resource_id();
86}
87
88DrawableTile* TiledLayerImpl::TileAt(int i, int j) const {
89  return static_cast<DrawableTile*>(tiler_->TileAt(i, j));
90}
91
92DrawableTile* TiledLayerImpl::CreateTile(int i, int j) {
93  scoped_ptr<DrawableTile> tile(DrawableTile::Create());
94  DrawableTile* added_tile = tile.get();
95  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
96
97  // Temporary diagnostic checks.
98  CHECK(added_tile);
99  CHECK(TileAt(i, j));
100
101  return added_tile;
102}
103
104void TiledLayerImpl::GetDebugBorderProperties(SkColor* color,
105                                              float* width) const {
106  *color = DebugColors::TiledContentLayerBorderColor();
107  *width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
108}
109
110scoped_ptr<LayerImpl> TiledLayerImpl::CreateLayerImpl(
111    LayerTreeImpl* tree_impl) {
112  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
113}
114
115void TiledLayerImpl::AsValueInto(base::DictionaryValue* state) const {
116  LayerImpl::AsValueInto(state);
117  state->Set("invalidation", MathUtil::AsValue(update_rect()).release());
118}
119
120size_t TiledLayerImpl::GPUMemoryUsageInBytes() const {
121  size_t amount = 0;
122  const size_t kMemoryUsagePerTileInBytes =
123      4 * tiler_->tile_size().width() * tiler_->tile_size().height();
124  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
125       iter != tiler_->tiles().end();
126       ++iter) {
127    const DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
128    if (!tile || !tile->resource_id())
129      continue;
130    amount += kMemoryUsagePerTileInBytes;
131  }
132  return amount;
133}
134
135void TiledLayerImpl::PushPropertiesTo(LayerImpl* layer) {
136  LayerImpl::PushPropertiesTo(layer);
137
138  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
139
140  tiled_layer->set_skips_draw(skips_draw_);
141  tiled_layer->SetTilingData(*tiler_);
142
143  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
144       iter != tiler_->tiles().end();
145       ++iter) {
146    int i = iter->first.first;
147    int j = iter->first.second;
148    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
149
150    tiled_layer->PushTileProperties(i,
151                                    j,
152                                    tile->resource_id(),
153                                    tile->opaque_rect(),
154                                    tile->contents_swizzled());
155  }
156}
157
158void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
159                                 AppendQuadsData* append_quads_data) {
160  gfx::Rect content_rect = visible_content_rect();
161
162  if (!tiler_ || tiler_->has_empty_bounds() || content_rect.IsEmpty())
163    return;
164
165  SharedQuadState* shared_quad_state =
166      quad_sink->UseSharedQuadState(CreateSharedQuadState());
167  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
168
169  int left, top, right, bottom;
170  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);
171
172  if (ShowDebugBorders()) {
173    for (int j = top; j <= bottom; ++j) {
174      for (int i = left; i <= right; ++i) {
175        DrawableTile* tile = TileAt(i, j);
176        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
177        SkColor border_color;
178        float border_width;
179
180        if (skips_draw_ || !tile || !tile->resource_id()) {
181          border_color = DebugColors::MissingTileBorderColor();
182          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
183        } else {
184          border_color = DebugColors::HighResTileBorderColor();
185          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
186        }
187        scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
188            DebugBorderDrawQuad::Create();
189        debug_border_quad->SetNew(
190            shared_quad_state, tile_rect, border_color, border_width);
191        quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(),
192                          append_quads_data);
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      if (!tile || !tile->resource_id()) {
212        SkColor checker_color;
213        if (ShowDebugBorders()) {
214          checker_color =
215              tile ? DebugColors::InvalidatedTileCheckerboardColor()
216                   : DebugColors::EvictedTileCheckerboardColor();
217        } else {
218          checker_color = DebugColors::DefaultCheckerboardColor();
219        }
220
221        scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
222            CheckerboardDrawQuad::Create();
223        checkerboard_quad->SetNew(
224            shared_quad_state, tile_rect, checker_color);
225        if (quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>(),
226                              append_quads_data))
227          append_quads_data->num_missing_tiles++;
228
229        continue;
230      }
231
232      gfx::Rect tile_opaque_rect = contents_opaque() ? tile_rect :
233        gfx::IntersectRects(tile->opaque_rect(), content_rect);
234
235      // Keep track of how the top left has moved, so the texture can be
236      // offset the same amount.
237      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
238      gfx::Vector2d texture_offset =
239          tiler_->texture_offset(i, j) + display_offset;
240      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;
241
242      float tile_width = static_cast<float>(tiler_->tile_size().width());
243      float tile_height = static_cast<float>(tiler_->tile_size().height());
244      gfx::Size texture_size(tile_width, tile_height);
245
246      scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
247      quad->SetNew(shared_quad_state,
248                   tile_rect,
249                   tile_opaque_rect,
250                   tile->resource_id(),
251                   tex_coord_rect,
252                   texture_size,
253                   tile->contents_swizzled());
254      quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
255    }
256  }
257}
258
259void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
260  s_safe_to_delete_drawable_tile = true;
261
262  if (tiler_) {
263    tiler_->reset();
264  } else {
265    tiler_ = LayerTilingData::Create(tiler.tile_size(),
266                                     tiler.has_border_texels()
267                                         ? LayerTilingData::HAS_BORDER_TEXELS
268                                         : LayerTilingData::NO_BORDER_TEXELS);
269  }
270  *tiler_ = tiler;
271
272  s_safe_to_delete_drawable_tile = false;
273}
274
275void TiledLayerImpl::PushTileProperties(
276    int i,
277    int j,
278    ResourceProvider::ResourceId resource_id,
279    gfx::Rect opaque_rect,
280    bool contents_swizzled) {
281  DrawableTile* tile = TileAt(i, j);
282  if (!tile)
283    tile = CreateTile(i, j);
284  tile->set_resource_id(resource_id);
285  tile->set_opaque_rect(opaque_rect);
286  tile->set_contents_swizzled(contents_swizzled);
287}
288
289void TiledLayerImpl::PushInvalidTile(int i, int j) {
290  DrawableTile* tile = TileAt(i, j);
291  if (!tile)
292    tile = CreateTile(i, j);
293  tile->set_resource_id(0);
294  tile->set_opaque_rect(gfx::Rect());
295  tile->set_contents_swizzled(false);
296}
297
298Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
299  if (skips_draw_)
300    return Region();
301  if (contents_opaque())
302    return visible_content_rect();
303  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
304}
305
306void TiledLayerImpl::DidLoseOutputSurface() {
307  s_safe_to_delete_drawable_tile = true;
308  // Temporary diagnostic check.
309  CHECK(tiler_);
310  tiler_->reset();
311  s_safe_to_delete_drawable_tile = false;
312}
313
314const char* TiledLayerImpl::LayerTypeAsString() const {
315  return "cc::TiledLayerImpl";
316}
317
318}  // namespace cc
319