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