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 |