tiled_layer_impl.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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::PushPropertiesTo(LayerImpl* layer) {
116  LayerImpl::PushPropertiesTo(layer);
117
118  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
119
120  tiled_layer->set_skips_draw(skips_draw_);
121  tiled_layer->SetTilingData(*tiler_);
122
123  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
124       iter != tiler_->tiles().end();
125       ++iter) {
126    int i = iter->first.first;
127    int j = iter->first.second;
128    DrawableTile* tile = static_cast<DrawableTile*>(iter->second);
129
130    tiled_layer->PushTileProperties(i,
131                                    j,
132                                    tile->resource_id(),
133                                    tile->opaque_rect(),
134                                    tile->contents_swizzled());
135  }
136}
137
138void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
139                                 AppendQuadsData* append_quads_data) {
140  gfx::Rect content_rect = visible_content_rect();
141
142  if (!tiler_ || tiler_->has_empty_bounds() || content_rect.IsEmpty())
143    return;
144
145  SharedQuadState* shared_quad_state =
146      quad_sink->UseSharedQuadState(CreateSharedQuadState());
147  AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
148
149  int left, top, right, bottom;
150  tiler_->ContentRectToTileIndices(content_rect, &left, &top, &right, &bottom);
151
152  if (ShowDebugBorders()) {
153    for (int j = top; j <= bottom; ++j) {
154      for (int i = left; i <= right; ++i) {
155        DrawableTile* tile = TileAt(i, j);
156        gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
157        SkColor border_color;
158        float border_width;
159
160        if (skips_draw_ || !tile || !tile->resource_id()) {
161          border_color = DebugColors::MissingTileBorderColor();
162          border_width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
163        } else {
164          border_color = DebugColors::HighResTileBorderColor();
165          border_width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
166        }
167        scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
168            DebugBorderDrawQuad::Create();
169        debug_border_quad->SetNew(
170            shared_quad_state, tile_rect, border_color, border_width);
171        quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(),
172                          append_quads_data);
173      }
174    }
175  }
176
177  if (skips_draw_)
178    return;
179
180  for (int j = top; j <= bottom; ++j) {
181    for (int i = left; i <= right; ++i) {
182      DrawableTile* tile = TileAt(i, j);
183      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
184      gfx::Rect display_rect = tile_rect;
185      tile_rect.Intersect(content_rect);
186
187      // Skip empty tiles.
188      if (tile_rect.IsEmpty())
189        continue;
190
191      if (!tile || !tile->resource_id()) {
192        if (DrawCheckerboardForMissingTiles()) {
193          SkColor checker_color;
194          if (ShowDebugBorders()) {
195            checker_color =
196                tile ? DebugColors::InvalidatedTileCheckerboardColor()
197                     : DebugColors::EvictedTileCheckerboardColor();
198          } else {
199            checker_color = DebugColors::DefaultCheckerboardColor();
200          }
201
202          scoped_ptr<CheckerboardDrawQuad> checkerboard_quad =
203              CheckerboardDrawQuad::Create();
204          checkerboard_quad->SetNew(
205              shared_quad_state, tile_rect, checker_color);
206          if (quad_sink->Append(checkerboard_quad.PassAs<DrawQuad>(),
207                                append_quads_data))
208            append_quads_data->numMissingTiles++;
209        } else {
210          scoped_ptr<SolidColorDrawQuad> solid_color_quad =
211              SolidColorDrawQuad::Create();
212          solid_color_quad->SetNew(
213              shared_quad_state, tile_rect, background_color());
214          if (quad_sink->Append(solid_color_quad.PassAs<DrawQuad>(),
215                                append_quads_data))
216            append_quads_data->numMissingTiles++;
217        }
218        continue;
219      }
220
221      gfx::Rect tile_opaque_rect = contents_opaque() ? tile_rect :
222        gfx::IntersectRects(tile->opaque_rect(), content_rect);
223
224      // Keep track of how the top left has moved, so the texture can be
225      // offset the same amount.
226      gfx::Vector2d display_offset = tile_rect.origin() - display_rect.origin();
227      gfx::Vector2d texture_offset =
228          tiler_->texture_offset(i, j) + display_offset;
229      gfx::RectF tex_coord_rect = gfx::RectF(tile_rect.size()) + texture_offset;
230
231      float tile_width = static_cast<float>(tiler_->tile_size().width());
232      float tile_height = static_cast<float>(tiler_->tile_size().height());
233      gfx::Size texture_size(tile_width, tile_height);
234
235      scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
236      quad->SetNew(shared_quad_state,
237                   tile_rect,
238                   tile_opaque_rect,
239                   tile->resource_id(),
240                   tex_coord_rect,
241                   texture_size,
242                   tile->contents_swizzled());
243      quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
244    }
245  }
246}
247
248void TiledLayerImpl::SetTilingData(const LayerTilingData& tiler) {
249  s_safe_to_delete_drawable_tile = true;
250
251  if (tiler_) {
252    tiler_->reset();
253  } else {
254    tiler_ = LayerTilingData::Create(tiler.tile_size(),
255                                     tiler.has_border_texels()
256                                         ? LayerTilingData::HAS_BORDER_TEXELS
257                                         : LayerTilingData::NO_BORDER_TEXELS);
258  }
259  *tiler_ = tiler;
260
261  s_safe_to_delete_drawable_tile = false;
262}
263
264void TiledLayerImpl::PushTileProperties(
265    int i,
266    int j,
267    ResourceProvider::ResourceId resource_id,
268    gfx::Rect opaque_rect,
269    bool contents_swizzled) {
270  DrawableTile* tile = TileAt(i, j);
271  if (!tile)
272    tile = CreateTile(i, j);
273  tile->set_resource_id(resource_id);
274  tile->set_opaque_rect(opaque_rect);
275  tile->set_contents_swizzled(contents_swizzled);
276}
277
278void TiledLayerImpl::PushInvalidTile(int i, int j) {
279  DrawableTile* tile = TileAt(i, j);
280  if (!tile)
281    tile = CreateTile(i, j);
282  tile->set_resource_id(0);
283  tile->set_opaque_rect(gfx::Rect());
284  tile->set_contents_swizzled(false);
285}
286
287Region TiledLayerImpl::VisibleContentOpaqueRegion() const {
288  if (skips_draw_)
289    return Region();
290  if (contents_opaque())
291    return visible_content_rect();
292  return tiler_->OpaqueRegionInContentRect(visible_content_rect());
293}
294
295void TiledLayerImpl::DidLoseOutputSurface() {
296  s_safe_to_delete_drawable_tile = true;
297  // Temporary diagnostic check.
298  CHECK(tiler_);
299  tiler_->reset();
300  s_safe_to_delete_drawable_tile = false;
301}
302
303const char* TiledLayerImpl::LayerTypeAsString() const {
304  return "ContentLayer";
305}
306
307}  // namespace cc
308