| OLD | NEW |
| (Empty) |
| 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/trees/damage_tracker.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "cc/base/math_util.h" | |
| 10 #include "cc/layers/heads_up_display_layer_impl.h" | |
| 11 #include "cc/layers/layer_impl.h" | |
| 12 #include "cc/layers/render_surface_impl.h" | |
| 13 #include "cc/output/filter_operations.h" | |
| 14 #include "cc/trees/layer_tree_host_common.h" | |
| 15 #include "cc/trees/layer_tree_impl.h" | |
| 16 #include "ui/gfx/geometry/rect_conversions.h" | |
| 17 | |
| 18 namespace cc { | |
| 19 | |
| 20 scoped_ptr<DamageTracker> DamageTracker::Create() { | |
| 21 return make_scoped_ptr(new DamageTracker()); | |
| 22 } | |
| 23 | |
| 24 DamageTracker::DamageTracker() | |
| 25 : mailboxId_(0) {} | |
| 26 | |
| 27 DamageTracker::~DamageTracker() {} | |
| 28 | |
| 29 static inline void ExpandRectWithFilters(gfx::Rect* rect, | |
| 30 const FilterOperations& filters) { | |
| 31 int top, right, bottom, left; | |
| 32 filters.GetOutsets(&top, &right, &bottom, &left); | |
| 33 rect->Inset(-left, -top, -right, -bottom); | |
| 34 } | |
| 35 | |
| 36 static inline void ExpandDamageRectInsideRectWithFilters( | |
| 37 gfx::Rect* damage_rect, | |
| 38 const gfx::Rect& pre_filter_rect, | |
| 39 const FilterOperations& filters) { | |
| 40 gfx::Rect expanded_damage_rect = *damage_rect; | |
| 41 ExpandRectWithFilters(&expanded_damage_rect, filters); | |
| 42 gfx::Rect filter_rect = pre_filter_rect; | |
| 43 ExpandRectWithFilters(&filter_rect, filters); | |
| 44 | |
| 45 expanded_damage_rect.Intersect(filter_rect); | |
| 46 damage_rect->Union(expanded_damage_rect); | |
| 47 } | |
| 48 | |
| 49 void DamageTracker::UpdateDamageTrackingState( | |
| 50 const LayerImplList& layer_list, | |
| 51 int target_surface_layer_id, | |
| 52 bool target_surface_property_changed_only_from_descendant, | |
| 53 const gfx::Rect& target_surface_content_rect, | |
| 54 LayerImpl* target_surface_mask_layer, | |
| 55 const FilterOperations& filters) { | |
| 56 // | |
| 57 // This function computes the "damage rect" of a target surface, and updates | |
| 58 // the state that is used to correctly track damage across frames. The damage | |
| 59 // rect is the region of the surface that may have changed and needs to be | |
| 60 // redrawn. This can be used to scissor what is actually drawn, to save GPU | |
| 61 // computation and bandwidth. | |
| 62 // | |
| 63 // The surface's damage rect is computed as the union of all possible changes | |
| 64 // that have happened to the surface since the last frame was drawn. This | |
| 65 // includes: | |
| 66 // - any changes for existing layers/surfaces that contribute to the target | |
| 67 // surface | |
| 68 // - layers/surfaces that existed in the previous frame, but no longer exist | |
| 69 // | |
| 70 // The basic algorithm for computing the damage region is as follows: | |
| 71 // | |
| 72 // 1. compute damage caused by changes in active/new layers | |
| 73 // for each layer in the layer_list: | |
| 74 // if the layer is actually a render_surface: | |
| 75 // add the surface's damage to our target surface. | |
| 76 // else | |
| 77 // add the layer's damage to the target surface. | |
| 78 // | |
| 79 // 2. compute damage caused by the target surface's mask, if it exists. | |
| 80 // | |
| 81 // 3. compute damage caused by old layers/surfaces that no longer exist | |
| 82 // for each leftover layer: | |
| 83 // add the old layer/surface bounds to the target surface damage. | |
| 84 // | |
| 85 // 4. combine all partial damage rects to get the full damage rect. | |
| 86 // | |
| 87 // Additional important points: | |
| 88 // | |
| 89 // - This algorithm is implicitly recursive; it assumes that descendant | |
| 90 // surfaces have already computed their damage. | |
| 91 // | |
| 92 // - Changes to layers/surfaces indicate "damage" to the target surface; If a | |
| 93 // layer is not changed, it does NOT mean that the layer can skip drawing. | |
| 94 // All layers that overlap the damaged region still need to be drawn. For | |
| 95 // example, if a layer changed its opacity, then layers underneath must be | |
| 96 // re-drawn as well, even if they did not change. | |
| 97 // | |
| 98 // - If a layer/surface property changed, the old bounds and new bounds may | |
| 99 // overlap... i.e. some of the exposed region may not actually be exposing | |
| 100 // anything. But this does not artificially inflate the damage rect. If the | |
| 101 // layer changed, its entire old bounds would always need to be redrawn, | |
| 102 // regardless of how much it overlaps with the layer's new bounds, which | |
| 103 // also need to be entirely redrawn. | |
| 104 // | |
| 105 // - See comments in the rest of the code to see what exactly is considered a | |
| 106 // "change" in a layer/surface. | |
| 107 // | |
| 108 // - To correctly manage exposed rects, SortedRectMap is maintained: | |
| 109 // | |
| 110 // 1. All existing rects from the previous frame are marked as | |
| 111 // not updated. | |
| 112 // 2. The map contains all the layer bounds that contributed to | |
| 113 // the previous frame (even outside the previous damaged area). If a | |
| 114 // layer changes or does not exist anymore, those regions are then | |
| 115 // exposed and damage the target surface. As the algorithm progresses, | |
| 116 // entries are updated in the map until only leftover layers | |
| 117 // that no longer exist stay marked not updated. | |
| 118 // | |
| 119 // 3. After the damage rect is computed, the leftover not marked regions | |
| 120 // in a map are used to compute are damaged by deleted layers and | |
| 121 // erased from map. | |
| 122 // | |
| 123 | |
| 124 PrepareRectHistoryForUpdate(); | |
| 125 // These functions cannot be bypassed with early-exits, even if we know what | |
| 126 // the damage will be for this frame, because we need to update the damage | |
| 127 // tracker state to correctly track the next frame. | |
| 128 gfx::Rect damage_from_active_layers = | |
| 129 TrackDamageFromActiveLayers(layer_list, target_surface_layer_id); | |
| 130 gfx::Rect damage_from_surface_mask = | |
| 131 TrackDamageFromSurfaceMask(target_surface_mask_layer); | |
| 132 gfx::Rect damage_from_leftover_rects = TrackDamageFromLeftoverRects(); | |
| 133 | |
| 134 gfx::Rect damage_rect_for_this_update; | |
| 135 | |
| 136 if (target_surface_property_changed_only_from_descendant) { | |
| 137 damage_rect_for_this_update = target_surface_content_rect; | |
| 138 } else { | |
| 139 // TODO(shawnsingh): can we clamp this damage to the surface's content rect? | |
| 140 // (affects performance, but not correctness) | |
| 141 damage_rect_for_this_update = damage_from_active_layers; | |
| 142 damage_rect_for_this_update.Union(damage_from_surface_mask); | |
| 143 damage_rect_for_this_update.Union(damage_from_leftover_rects); | |
| 144 | |
| 145 if (filters.HasReferenceFilter()) { | |
| 146 // TODO(senorblanco): Once SkImageFilter reports its outsets, use | |
| 147 // those here to limit damage. | |
| 148 damage_rect_for_this_update = target_surface_content_rect; | |
| 149 } else if (filters.HasFilterThatMovesPixels()) { | |
| 150 ExpandRectWithFilters(&damage_rect_for_this_update, filters); | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 // Damage accumulates until we are notified that we actually did draw on that | |
| 155 // frame. | |
| 156 current_damage_rect_.Union(damage_rect_for_this_update); | |
| 157 } | |
| 158 | |
| 159 DamageTracker::RectMapData& DamageTracker::RectDataForLayer( | |
| 160 int layer_id, | |
| 161 bool* layer_is_new) { | |
| 162 | |
| 163 RectMapData data(layer_id); | |
| 164 | |
| 165 SortedRectMap::iterator it = std::lower_bound(rect_history_.begin(), | |
| 166 rect_history_.end(), data); | |
| 167 | |
| 168 if (it == rect_history_.end() || it->layer_id_ != layer_id) { | |
| 169 *layer_is_new = true; | |
| 170 it = rect_history_.insert(it, data); | |
| 171 } | |
| 172 | |
| 173 return *it; | |
| 174 } | |
| 175 | |
| 176 gfx::Rect DamageTracker::TrackDamageFromActiveLayers( | |
| 177 const LayerImplList& layer_list, | |
| 178 int target_surface_layer_id) { | |
| 179 gfx::Rect damage_rect; | |
| 180 | |
| 181 for (size_t layer_index = 0; layer_index < layer_list.size(); ++layer_index) { | |
| 182 // Visit layers in back-to-front order. | |
| 183 LayerImpl* layer = layer_list[layer_index]; | |
| 184 | |
| 185 // We skip damage from the HUD layer because (a) the HUD layer damages the | |
| 186 // whole frame and (b) we don't want HUD layer damage to be shown by the | |
| 187 // HUD damage rect visualization. | |
| 188 if (layer == layer->layer_tree_impl()->hud_layer()) | |
| 189 continue; | |
| 190 if (LayerTreeHostCommon::RenderSurfaceContributesToTarget<LayerImpl>( | |
| 191 layer, target_surface_layer_id)) | |
| 192 ExtendDamageForRenderSurface(layer, &damage_rect); | |
| 193 else | |
| 194 ExtendDamageForLayer(layer, &damage_rect); | |
| 195 } | |
| 196 | |
| 197 return damage_rect; | |
| 198 } | |
| 199 | |
| 200 gfx::Rect DamageTracker::TrackDamageFromSurfaceMask( | |
| 201 LayerImpl* target_surface_mask_layer) { | |
| 202 gfx::Rect damage_rect; | |
| 203 | |
| 204 if (!target_surface_mask_layer) | |
| 205 return damage_rect; | |
| 206 | |
| 207 // Currently, if there is any change to the mask, we choose to damage the | |
| 208 // entire surface. This could potentially be optimized later, but it is not | |
| 209 // expected to be a common case. | |
| 210 if (target_surface_mask_layer->LayerPropertyChanged() || | |
| 211 !target_surface_mask_layer->update_rect().IsEmpty()) { | |
| 212 damage_rect = gfx::Rect(target_surface_mask_layer->bounds()); | |
| 213 } | |
| 214 | |
| 215 return damage_rect; | |
| 216 } | |
| 217 | |
| 218 void DamageTracker::PrepareRectHistoryForUpdate() { | |
| 219 mailboxId_++; | |
| 220 } | |
| 221 | |
| 222 gfx::Rect DamageTracker::TrackDamageFromLeftoverRects() { | |
| 223 // After computing damage for all active layers, any leftover items in the | |
| 224 // current rect history correspond to layers/surfaces that no longer exist. | |
| 225 // So, these regions are now exposed on the target surface. | |
| 226 | |
| 227 gfx::Rect damage_rect; | |
| 228 SortedRectMap::iterator cur_pos = rect_history_.begin(); | |
| 229 SortedRectMap::iterator copy_pos = cur_pos; | |
| 230 | |
| 231 // Loop below basically implements std::remove_if loop with and extra | |
| 232 // processing (adding deleted rect to damage_rect) for deleted items. | |
| 233 // cur_pos iterator runs through all elements of the vector, but copy_pos | |
| 234 // always points to the element after the last not deleted element. If new | |
| 235 // not deleted element found then it is copied to the *copy_pos and copy_pos | |
| 236 // moved to the next position. | |
| 237 // If there are no deleted elements then copy_pos iterator is in sync with | |
| 238 // cur_pos and no copy happens. | |
| 239 while (cur_pos < rect_history_.end()) { | |
| 240 if (cur_pos->mailboxId_ == mailboxId_) { | |
| 241 if (cur_pos != copy_pos) | |
| 242 *copy_pos = *cur_pos; | |
| 243 | |
| 244 ++copy_pos; | |
| 245 } else { | |
| 246 damage_rect.Union(cur_pos->rect_); | |
| 247 } | |
| 248 | |
| 249 ++cur_pos; | |
| 250 } | |
| 251 | |
| 252 if (copy_pos != rect_history_.end()) | |
| 253 rect_history_.erase(copy_pos, rect_history_.end()); | |
| 254 | |
| 255 // If the vector has excessive storage, shrink it | |
| 256 if (rect_history_.capacity() > rect_history_.size() * 4) | |
| 257 SortedRectMap(rect_history_).swap(rect_history_); | |
| 258 | |
| 259 return damage_rect; | |
| 260 } | |
| 261 | |
| 262 void DamageTracker::ExtendDamageForLayer(LayerImpl* layer, | |
| 263 gfx::Rect* target_damage_rect) { | |
| 264 // There are two ways that a layer can damage a region of the target surface: | |
| 265 // 1. Property change (e.g. opacity, position, transforms): | |
| 266 // - the entire region of the layer itself damages the surface. | |
| 267 // - the old layer region also damages the surface, because this region | |
| 268 // is now exposed. | |
| 269 // - note that in many cases the old and new layer rects may overlap, | |
| 270 // which is fine. | |
| 271 // | |
| 272 // 2. Repaint/update: If a region of the layer that was repainted/updated, | |
| 273 // that region damages the surface. | |
| 274 // | |
| 275 // Property changes take priority over update rects. | |
| 276 // | |
| 277 // This method is called when we want to consider how a layer contributes to | |
| 278 // its target RenderSurface, even if that layer owns the target RenderSurface | |
| 279 // itself. To consider how a layer's target surface contributes to the | |
| 280 // ancestor surface, ExtendDamageForRenderSurface() must be called instead. | |
| 281 | |
| 282 bool layer_is_new = false; | |
| 283 RectMapData& data = RectDataForLayer(layer->id(), &layer_is_new); | |
| 284 gfx::Rect old_rect_in_target_space = data.rect_; | |
| 285 | |
| 286 gfx::Rect rect_in_target_space = layer->GetEnclosingRectInTargetSpace(); | |
| 287 data.Update(rect_in_target_space, mailboxId_); | |
| 288 | |
| 289 gfx::RectF damage_rect = | |
| 290 gfx::UnionRects(layer->update_rect(), layer->damage_rect()); | |
| 291 | |
| 292 if (layer_is_new || layer->LayerPropertyChanged()) { | |
| 293 // If a layer is new or has changed, then its entire layer rect affects the | |
| 294 // target surface. | |
| 295 target_damage_rect->Union(rect_in_target_space); | |
| 296 | |
| 297 // The layer's old region is now exposed on the target surface, too. | |
| 298 // Note old_rect_in_target_space is already in target space. | |
| 299 target_damage_rect->Union(old_rect_in_target_space); | |
| 300 } else if (!damage_rect.IsEmpty()) { | |
| 301 // If the layer properties haven't changed, then the the target surface is | |
| 302 // only affected by the layer's damaged area, which could be empty. | |
| 303 gfx::Rect damage_content_rect = layer->LayerRectToContentRect(damage_rect); | |
| 304 gfx::Rect damage_rect_in_target_space = MathUtil::MapEnclosingClippedRect( | |
| 305 layer->draw_transform(), damage_content_rect); | |
| 306 target_damage_rect->Union(damage_rect_in_target_space); | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 void DamageTracker::ExtendDamageForRenderSurface( | |
| 311 LayerImpl* layer, | |
| 312 gfx::Rect* target_damage_rect) { | |
| 313 // There are two ways a "descendant surface" can damage regions of the "target | |
| 314 // surface": | |
| 315 // 1. Property change: | |
| 316 // - a surface's geometry can change because of | |
| 317 // - changes to descendants (i.e. the subtree) that affect the | |
| 318 // surface's content rect | |
| 319 // - changes to ancestor layers that propagate their property | |
| 320 // changes to their entire subtree. | |
| 321 // - just like layers, both the old surface rect and new surface rect | |
| 322 // will damage the target surface in this case. | |
| 323 // | |
| 324 // 2. Damage rect: This surface may have been damaged by its own layer_list | |
| 325 // as well, and that damage should propagate to the target surface. | |
| 326 // | |
| 327 | |
| 328 RenderSurfaceImpl* render_surface = layer->render_surface(); | |
| 329 | |
| 330 bool surface_is_new = false; | |
| 331 RectMapData& data = RectDataForLayer(layer->id(), &surface_is_new); | |
| 332 gfx::Rect old_surface_rect = data.rect_; | |
| 333 | |
| 334 // The drawableContextRect() already includes the replica if it exists. | |
| 335 gfx::Rect surface_rect_in_target_space = | |
| 336 gfx::ToEnclosingRect(render_surface->DrawableContentRect()); | |
| 337 data.Update(surface_rect_in_target_space, mailboxId_); | |
| 338 | |
| 339 gfx::Rect damage_rect_in_local_space; | |
| 340 if (surface_is_new || render_surface->SurfacePropertyChanged()) { | |
| 341 // The entire surface contributes damage. | |
| 342 damage_rect_in_local_space = render_surface->content_rect(); | |
| 343 | |
| 344 // The surface's old region is now exposed on the target surface, too. | |
| 345 target_damage_rect->Union(old_surface_rect); | |
| 346 } else { | |
| 347 // Only the surface's damage_rect will damage the target surface. | |
| 348 damage_rect_in_local_space = | |
| 349 render_surface->damage_tracker()->current_damage_rect(); | |
| 350 } | |
| 351 | |
| 352 // If there was damage, transform it to target space, and possibly contribute | |
| 353 // its reflection if needed. | |
| 354 if (!damage_rect_in_local_space.IsEmpty()) { | |
| 355 const gfx::Transform& draw_transform = render_surface->draw_transform(); | |
| 356 gfx::Rect damage_rect_in_target_space = MathUtil::MapEnclosingClippedRect( | |
| 357 draw_transform, damage_rect_in_local_space); | |
| 358 target_damage_rect->Union(damage_rect_in_target_space); | |
| 359 | |
| 360 if (layer->replica_layer()) { | |
| 361 const gfx::Transform& replica_draw_transform = | |
| 362 render_surface->replica_draw_transform(); | |
| 363 target_damage_rect->Union(MathUtil::MapEnclosingClippedRect( | |
| 364 replica_draw_transform, damage_rect_in_local_space)); | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 // If there was damage on the replica's mask, then the target surface receives | |
| 369 // that damage as well. | |
| 370 if (layer->replica_layer() && layer->replica_layer()->mask_layer()) { | |
| 371 LayerImpl* replica_mask_layer = layer->replica_layer()->mask_layer(); | |
| 372 | |
| 373 bool replica_is_new = false; | |
| 374 RectMapData& data = | |
| 375 RectDataForLayer(replica_mask_layer->id(), &replica_is_new); | |
| 376 | |
| 377 const gfx::Transform& replica_draw_transform = | |
| 378 render_surface->replica_draw_transform(); | |
| 379 gfx::Rect replica_mask_layer_rect = MathUtil::MapEnclosingClippedRect( | |
| 380 replica_draw_transform, gfx::Rect(replica_mask_layer->bounds())); | |
| 381 data.Update(replica_mask_layer_rect, mailboxId_); | |
| 382 | |
| 383 // In the current implementation, a change in the replica mask damages the | |
| 384 // entire replica region. | |
| 385 if (replica_is_new || | |
| 386 replica_mask_layer->LayerPropertyChanged() || | |
| 387 !replica_mask_layer->update_rect().IsEmpty()) | |
| 388 target_damage_rect->Union(replica_mask_layer_rect); | |
| 389 } | |
| 390 | |
| 391 // If the layer has a background filter, this may cause pixels in our surface | |
| 392 // to be expanded, so we will need to expand any damage at or below this | |
| 393 // layer. We expand the damage from this layer too, as we need to readback | |
| 394 // those pixels from the surface with only the contents of layers below this | |
| 395 // one in them. This means we need to redraw any pixels in the surface being | |
| 396 // used for the blur in this layer this frame. | |
| 397 if (layer->background_filters().HasFilterThatMovesPixels()) { | |
| 398 ExpandDamageRectInsideRectWithFilters(target_damage_rect, | |
| 399 surface_rect_in_target_space, | |
| 400 layer->background_filters()); | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 } // namespace cc | |
| OLD | NEW |