| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/trees/occlusion_tracker.h" | 5 #include "cc/trees/occlusion_tracker.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "cc/base/math_util.h" | 9 #include "cc/base/math_util.h" |
| 10 #include "cc/base/region.h" | 10 #include "cc/base/region.h" |
| 11 #include "cc/layers/layer.h" | 11 #include "cc/layers/layer.h" |
| 12 #include "cc/layers/layer_impl.h" | 12 #include "cc/layers/layer_impl.h" |
| 13 #include "cc/layers/render_surface.h" | 13 #include "cc/layers/render_surface.h" |
| 14 #include "cc/layers/render_surface_impl.h" | 14 #include "cc/layers/render_surface_impl.h" |
| 15 #include "ui/gfx/geometry/quad_f.h" | 15 #include "ui/gfx/geometry/quad_f.h" |
| 16 #include "ui/gfx/geometry/rect_conversions.h" | 16 #include "ui/gfx/geometry/rect_conversions.h" |
| 17 | 17 |
| 18 namespace cc { | 18 namespace cc { |
| 19 | 19 |
| 20 template <typename LayerType> | 20 template <typename LayerType> |
| 21 OcclusionTracker<LayerType>::OcclusionTracker( | 21 OcclusionTracker<LayerType>::OcclusionTracker( |
| 22 const gfx::Rect& screen_space_clip_rect) | 22 const gfx::Rect& screen_space_clip_rect) |
| 23 : screen_space_clip_rect_(screen_space_clip_rect), | 23 : screen_space_clip_rect_(screen_space_clip_rect) { |
| 24 occluding_screen_space_rects_(NULL), | 24 } |
| 25 non_occluding_screen_space_rects_(NULL) {} | |
| 26 | 25 |
| 27 template <typename LayerType> | 26 template <typename LayerType> |
| 28 OcclusionTracker<LayerType>::~OcclusionTracker() {} | 27 OcclusionTracker<LayerType>::~OcclusionTracker() { |
| 28 } |
| 29 | 29 |
| 30 template <typename LayerType> | 30 template <typename LayerType> |
| 31 Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer( | 31 Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer( |
| 32 const gfx::Transform& draw_transform) const { | 32 const gfx::Transform& draw_transform) const { |
| 33 DCHECK(!stack_.empty()); | 33 DCHECK(!stack_.empty()); |
| 34 const StackObject& back = stack_.back(); | 34 const StackObject& back = stack_.back(); |
| 35 return Occlusion(draw_transform, | 35 return Occlusion(draw_transform, |
| 36 back.occlusion_from_outside_target, | 36 back.occlusion_from_outside_target, |
| 37 back.occlusion_from_inside_target); | 37 back.occlusion_from_inside_target); |
| 38 } | 38 } |
| 39 | 39 |
| 40 template <typename LayerType> | 40 template <typename LayerType> |
| 41 Occlusion |
| 42 OcclusionTracker<LayerType>::GetCurrentOcclusionForContributingSurface( |
| 43 const gfx::Transform& draw_transform) const { |
| 44 DCHECK(!stack_.empty()); |
| 45 if (stack_.size() < 2) |
| 46 return Occlusion(); |
| 47 // A contributing surface doesn't get occluded by things inside its own |
| 48 // surface, so only things outside the surface can occlude it. That occlusion |
| 49 // is found just below the top of the stack (if it exists). |
| 50 const StackObject& second_last = stack_[stack_.size() - 2]; |
| 51 return Occlusion(draw_transform, second_last.occlusion_from_outside_target, |
| 52 second_last.occlusion_from_inside_target); |
| 53 } |
| 54 |
| 55 template <typename LayerType> |
| 41 void OcclusionTracker<LayerType>::EnterLayer( | 56 void OcclusionTracker<LayerType>::EnterLayer( |
| 42 const LayerIteratorPosition<LayerType>& layer_iterator) { | 57 const LayerIteratorPosition<LayerType>& layer_iterator) { |
| 43 LayerType* render_target = layer_iterator.target_render_surface_layer; | 58 LayerType* render_target = layer_iterator.target_render_surface_layer; |
| 44 | 59 |
| 45 if (layer_iterator.represents_itself) | 60 if (layer_iterator.represents_itself) |
| 46 EnterRenderTarget(render_target); | 61 EnterRenderTarget(render_target); |
| 47 else if (layer_iterator.represents_target_render_surface) | 62 else if (layer_iterator.represents_target_render_surface) |
| 48 FinishedRenderTarget(render_target); | 63 FinishedRenderTarget(render_target); |
| 49 } | 64 } |
| 50 | 65 |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 SimpleEnclosedRegion old_occlusion_from_outside_target_in_new_target = | 348 SimpleEnclosedRegion old_occlusion_from_outside_target_in_new_target = |
| 334 TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( | 349 TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( |
| 335 stack_[last_index].occlusion_from_outside_target, | 350 stack_[last_index].occlusion_from_outside_target, |
| 336 false, | 351 false, |
| 337 gfx::Rect(), | 352 gfx::Rect(), |
| 338 old_surface->draw_transform()); | 353 old_surface->draw_transform()); |
| 339 | 354 |
| 340 gfx::Rect unoccluded_surface_rect; | 355 gfx::Rect unoccluded_surface_rect; |
| 341 gfx::Rect unoccluded_replica_rect; | 356 gfx::Rect unoccluded_replica_rect; |
| 342 if (old_target->background_filters().HasFilterThatMovesPixels()) { | 357 if (old_target->background_filters().HasFilterThatMovesPixels()) { |
| 343 unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect( | 358 Occlusion surface_occlusion = GetCurrentOcclusionForContributingSurface( |
| 344 old_surface->content_rect(), old_surface->draw_transform()); | 359 old_surface->draw_transform()); |
| 360 unoccluded_surface_rect = |
| 361 surface_occlusion.GetUnoccludedContentRect(old_surface->content_rect()); |
| 345 if (old_target->has_replica()) { | 362 if (old_target->has_replica()) { |
| 346 unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect( | 363 Occlusion replica_occlusion = GetCurrentOcclusionForContributingSurface( |
| 347 old_surface->content_rect(), | |
| 348 old_surface->replica_draw_transform()); | 364 old_surface->replica_draw_transform()); |
| 365 unoccluded_replica_rect = replica_occlusion.GetUnoccludedContentRect( |
| 366 old_surface->content_rect()); |
| 349 } | 367 } |
| 350 } | 368 } |
| 351 | 369 |
| 352 if (surface_will_be_at_top_after_pop) { | 370 if (surface_will_be_at_top_after_pop) { |
| 353 // Merge the top of the stack down. | 371 // Merge the top of the stack down. |
| 354 stack_[last_index - 1].occlusion_from_inside_target.Union( | 372 stack_[last_index - 1].occlusion_from_inside_target.Union( |
| 355 old_occlusion_from_inside_target_in_new_target); | 373 old_occlusion_from_inside_target_in_new_target); |
| 356 // TODO(danakj): Strictly this should subtract the inside target occlusion | 374 // TODO(danakj): Strictly this should subtract the inside target occlusion |
| 357 // before union. | 375 // before union. |
| 358 if (new_target->parent()) { | 376 if (new_target->parent()) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 | 458 |
| 441 for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) { | 459 for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) { |
| 442 gfx::Rect transformed_rect = | 460 gfx::Rect transformed_rect = |
| 443 MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( | 461 MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( |
| 444 layer->draw_transform(), opaque_contents.GetRect(i)); | 462 layer->draw_transform(), opaque_contents.GetRect(i)); |
| 445 transformed_rect.Intersect(clip_rect_in_target); | 463 transformed_rect.Intersect(clip_rect_in_target); |
| 446 if (transformed_rect.width() < minimum_tracking_size_.width() && | 464 if (transformed_rect.width() < minimum_tracking_size_.width() && |
| 447 transformed_rect.height() < minimum_tracking_size_.height()) | 465 transformed_rect.height() < minimum_tracking_size_.height()) |
| 448 continue; | 466 continue; |
| 449 stack_.back().occlusion_from_inside_target.Union(transformed_rect); | 467 stack_.back().occlusion_from_inside_target.Union(transformed_rect); |
| 450 | |
| 451 if (!occluding_screen_space_rects_) | |
| 452 continue; | |
| 453 | |
| 454 // Save the occluding area in screen space for debug visualization. | |
| 455 bool clipped; | |
| 456 gfx::QuadF screen_space_quad = MathUtil::MapQuad( | |
| 457 layer->render_target()->render_surface()->screen_space_transform(), | |
| 458 gfx::QuadF(transformed_rect), &clipped); | |
| 459 // TODO(danakj): Store the quad in the debug info instead of the bounding | |
| 460 // box. | |
| 461 gfx::Rect screen_space_rect = | |
| 462 gfx::ToEnclosedRect(screen_space_quad.BoundingBox()); | |
| 463 occluding_screen_space_rects_->push_back(screen_space_rect); | |
| 464 } | 468 } |
| 465 | |
| 466 if (!non_occluding_screen_space_rects_) | |
| 467 return; | |
| 468 | |
| 469 Region non_opaque_contents(gfx::Rect(layer->content_bounds())); | |
| 470 non_opaque_contents.Subtract(opaque_contents); | |
| 471 | |
| 472 for (Region::Iterator non_opaque_content_rects(non_opaque_contents); | |
| 473 non_opaque_content_rects.has_rect(); | |
| 474 non_opaque_content_rects.next()) { | |
| 475 gfx::Rect transformed_rect = | |
| 476 MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( | |
| 477 layer->draw_transform(), non_opaque_content_rects.rect()); | |
| 478 transformed_rect.Intersect(clip_rect_in_target); | |
| 479 if (transformed_rect.IsEmpty()) | |
| 480 continue; | |
| 481 | |
| 482 bool clipped; | |
| 483 gfx::QuadF screen_space_quad = MathUtil::MapQuad( | |
| 484 layer->render_target()->render_surface()->screen_space_transform(), | |
| 485 gfx::QuadF(transformed_rect), | |
| 486 &clipped); | |
| 487 // TODO(danakj): Store the quad in the debug info instead of the bounding | |
| 488 // box. | |
| 489 gfx::Rect screen_space_rect = | |
| 490 gfx::ToEnclosedRect(screen_space_quad.BoundingBox()); | |
| 491 non_occluding_screen_space_rects_->push_back(screen_space_rect); | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 template <typename LayerType> | |
| 496 gfx::Rect OcclusionTracker<LayerType>::UnoccludedContributingSurfaceContentRect( | |
| 497 const gfx::Rect& content_rect, | |
| 498 const gfx::Transform& draw_transform) const { | |
| 499 if (content_rect.IsEmpty()) | |
| 500 return content_rect; | |
| 501 | |
| 502 // A contributing surface doesn't get occluded by things inside its own | |
| 503 // surface, so only things outside the surface can occlude it. That occlusion | |
| 504 // is found just below the top of the stack (if it exists). | |
| 505 bool has_occlusion = stack_.size() > 1; | |
| 506 if (!has_occlusion) | |
| 507 return content_rect; | |
| 508 | |
| 509 const StackObject& second_last = stack_[stack_.size() - 2]; | |
| 510 if (second_last.occlusion_from_inside_target.IsEmpty() && | |
| 511 second_last.occlusion_from_outside_target.IsEmpty()) | |
| 512 return content_rect; | |
| 513 | |
| 514 gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization); | |
| 515 bool ok = draw_transform.GetInverse(&inverse_draw_transform); | |
| 516 DCHECK(ok); | |
| 517 | |
| 518 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded | |
| 519 // partial pixels in the resulting Rect. | |
| 520 gfx::Rect unoccluded_rect_in_target_surface = | |
| 521 MathUtil::MapEnclosingClippedRect(draw_transform, content_rect); | |
| 522 DCHECK_LE(second_last.occlusion_from_inside_target.GetRegionComplexity(), 1u); | |
| 523 DCHECK_LE(second_last.occlusion_from_outside_target.GetRegionComplexity(), | |
| 524 1u); | |
| 525 // These subtract operations are more lossy than if we did both operations at | |
| 526 // once. | |
| 527 unoccluded_rect_in_target_surface.Subtract( | |
| 528 second_last.occlusion_from_inside_target.bounds()); | |
| 529 unoccluded_rect_in_target_surface.Subtract( | |
| 530 second_last.occlusion_from_outside_target.bounds()); | |
| 531 | |
| 532 if (unoccluded_rect_in_target_surface.IsEmpty()) | |
| 533 return gfx::Rect(); | |
| 534 | |
| 535 gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect( | |
| 536 inverse_draw_transform, unoccluded_rect_in_target_surface); | |
| 537 unoccluded_rect.Intersect(content_rect); | |
| 538 | |
| 539 return unoccluded_rect; | |
| 540 } | 469 } |
| 541 | 470 |
| 542 template <typename LayerType> | 471 template <typename LayerType> |
| 543 Region OcclusionTracker<LayerType>::ComputeVisibleRegionInScreen() const { | 472 Region OcclusionTracker<LayerType>::ComputeVisibleRegionInScreen() const { |
| 544 DCHECK(!stack_.back().target->parent()); | 473 DCHECK(!stack_.back().target->parent()); |
| 545 const SimpleEnclosedRegion& occluded = | 474 const SimpleEnclosedRegion& occluded = |
| 546 stack_.back().occlusion_from_inside_target; | 475 stack_.back().occlusion_from_inside_target; |
| 547 Region visible_region(screen_space_clip_rect_); | 476 Region visible_region(screen_space_clip_rect_); |
| 548 for (size_t i = 0; i < occluded.GetRegionComplexity(); ++i) | 477 for (size_t i = 0; i < occluded.GetRegionComplexity(); ++i) |
| 549 visible_region.Subtract(occluded.GetRect(i)); | 478 visible_region.Subtract(occluded.GetRect(i)); |
| 550 return visible_region; | 479 return visible_region; |
| 551 } | 480 } |
| 552 | 481 |
| 553 // Instantiate (and export) templates here for the linker. | 482 // Instantiate (and export) templates here for the linker. |
| 554 template class OcclusionTracker<Layer>; | 483 template class OcclusionTracker<Layer>; |
| 555 template class OcclusionTracker<LayerImpl>; | 484 template class OcclusionTracker<LayerImpl>; |
| 556 | 485 |
| 557 } // namespace cc | 486 } // namespace cc |
| OLD | NEW |