#include <algorithm>
#include "cc/base/math_util.h"
-#include "cc/debug/overdraw_metrics.h"
+#include "cc/base/region.h"
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/render_surface.h"
#include "cc/layers/render_surface_impl.h"
-#include "ui/gfx/quad_f.h"
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
-template <typename LayerType, typename RenderSurfaceType>
-OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(
- const gfx::Rect& screen_space_clip_rect, bool record_metrics_for_frame)
+template <typename LayerType>
+OcclusionTracker<LayerType>::OcclusionTracker(
+ const gfx::Rect& screen_space_clip_rect)
: screen_space_clip_rect_(screen_space_clip_rect),
- overdraw_metrics_(OverdrawMetrics::Create(record_metrics_for_frame)),
occluding_screen_space_rects_(NULL),
non_occluding_screen_space_rects_(NULL) {}
-template <typename LayerType, typename RenderSurfaceType>
-OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase() {}
+template <typename LayerType>
+OcclusionTracker<LayerType>::~OcclusionTracker() {}
+
+template <typename LayerType>
+Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer(
+ const gfx::Transform& draw_transform) const {
+ DCHECK(!stack_.empty());
+ const StackObject& back = stack_.back();
+ return Occlusion(draw_transform,
+ back.occlusion_from_outside_target,
+ back.occlusion_from_inside_target);
+}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterLayer(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::EnterLayer(
const LayerIteratorPosition<LayerType>& layer_iterator) {
LayerType* render_target = layer_iterator.target_render_surface_layer;
FinishedRenderTarget(render_target);
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveLayer(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::LeaveLayer(
const LayerIteratorPosition<LayerType>& layer_iterator) {
LayerType* render_target = layer_iterator.target_render_surface_layer;
}
template <typename RenderSurfaceType>
-static Region TransformSurfaceOpaqueRegion(
- const Region& region,
+static SimpleEnclosedRegion TransformSurfaceOpaqueRegion(
+ const SimpleEnclosedRegion& region,
bool have_clip_rect,
const gfx::Rect& clip_rect_in_new_target,
const gfx::Transform& transform) {
if (region.IsEmpty())
- return Region();
+ return region;
// Verify that rects within the |surface| will remain rects in its target
// surface after applying |transform|. If this is true, then apply |transform|
// TODO(danakj): Find a rect interior to each transformed quad.
if (!transform.Preserves2dAxisAlignment())
- return Region();
+ return SimpleEnclosedRegion();
- // TODO(danakj): If the Region is too complex, degrade gracefully here by
- // skipping rects in it.
- Region transformed_region;
- for (Region::Iterator rects(region); rects.has_rect(); rects.next()) {
- bool clipped;
- gfx::QuadF transformed_quad =
- MathUtil::MapQuad(transform, gfx::QuadF(rects.rect()), &clipped);
+ SimpleEnclosedRegion transformed_region;
+ for (size_t i = 0; i < region.GetRegionComplexity(); ++i) {
gfx::Rect transformed_rect =
- gfx::ToEnclosedRect(transformed_quad.BoundingBox());
- DCHECK(!clipped); // We only map if the transform preserves axis alignment.
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform,
+ region.GetRect(i));
if (have_clip_rect)
transformed_rect.Intersect(clip_rect_in_new_target);
transformed_region.Union(transformed_rect);
}
static inline bool LayerIsInUnsorted3dRenderingContext(const Layer* layer) {
- return layer->is_3d_sorted();
+ return layer->Is3dSorted();
}
static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) {
return false;
(layer->parent() && LayerIsHidden(layer->parent()));
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::EnterRenderTarget(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::EnterRenderTarget(
const LayerType* new_target) {
if (!stack_.empty() && stack_.back().target == new_target)
return;
const LayerType* old_target = NULL;
- const RenderSurfaceType* old_occlusion_immune_ancestor = NULL;
+ const typename LayerType::RenderSurfaceType* old_occlusion_immune_ancestor =
+ NULL;
if (!stack_.empty()) {
old_target = stack_.back().target;
old_occlusion_immune_ancestor =
old_target->render_surface()->nearest_occlusion_immune_ancestor();
}
- const RenderSurfaceType* new_occlusion_immune_ancestor =
+ const typename LayerType::RenderSurfaceType* new_occlusion_immune_ancestor =
new_target->render_surface()->nearest_occlusion_immune_ancestor();
stack_.push_back(StackObject(new_target));
inverse_new_target_screen_space_transform,
old_target->render_surface()->screen_space_transform());
stack_[last_index].occlusion_from_outside_target =
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index - 1].occlusion_from_outside_target,
false,
gfx::Rect(),
old_target_to_new_target_transform);
stack_[last_index].occlusion_from_outside_target.Union(
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index - 1].occlusion_from_inside_target,
false,
gfx::Rect(),
old_target_to_new_target_transform));
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::FinishedRenderTarget(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::FinishedRenderTarget(
const LayerType* finished_target) {
// Make sure we know about the target surface.
EnterRenderTarget(finished_target);
- RenderSurfaceType* surface = finished_target->render_surface();
+ typename LayerType::RenderSurfaceType* surface =
+ finished_target->render_surface();
// Readbacks always happen on render targets so we only need to check
// for readbacks here.
}
template <typename LayerType>
-static void ReduceOcclusionBelowSurface(LayerType* contributing_layer,
- const gfx::Rect& surface_rect,
- const gfx::Transform& surface_transform,
- LayerType* render_target,
- Region* occlusion_from_inside_target) {
+static void ReduceOcclusionBelowSurface(
+ LayerType* contributing_layer,
+ const gfx::Rect& surface_rect,
+ const gfx::Transform& surface_transform,
+ LayerType* render_target,
+ SimpleEnclosedRegion* occlusion_from_inside_target) {
if (surface_rect.IsEmpty())
return;
// to expand outside the clip.
affected_area_in_target.Inset(
-outset_left, -outset_top, -outset_right, -outset_bottom);
- Region affected_occlusion = IntersectRegions(*occlusion_from_inside_target,
- affected_area_in_target);
- Region::Iterator affected_occlusion_rects(affected_occlusion);
+ SimpleEnclosedRegion affected_occlusion = *occlusion_from_inside_target;
+ affected_occlusion.Intersect(affected_area_in_target);
occlusion_from_inside_target->Subtract(affected_area_in_target);
- for (; affected_occlusion_rects.has_rect(); affected_occlusion_rects.next()) {
- gfx::Rect occlusion_rect = affected_occlusion_rects.rect();
+ for (size_t i = 0; i < affected_occlusion.GetRegionComplexity(); ++i) {
+ gfx::Rect occlusion_rect = affected_occlusion.GetRect(i);
// Shrink the rect by expanding the non-opaque pixels outside the rect.
}
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::LeaveToRenderTarget(
+template <typename LayerType>
+void OcclusionTracker<LayerType>::LeaveToRenderTarget(
const LayerType* new_target) {
int last_index = stack_.size() - 1;
bool surface_will_be_at_top_after_pop =
// merged out as well but needs to be transformed to the new target.
const LayerType* old_target = stack_[last_index].target;
- const RenderSurfaceType* old_surface = old_target->render_surface();
+ const typename LayerType::RenderSurfaceType* old_surface =
+ old_target->render_surface();
- Region old_occlusion_from_inside_target_in_new_target =
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ SimpleEnclosedRegion old_occlusion_from_inside_target_in_new_target =
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index].occlusion_from_inside_target,
old_surface->is_clipped(),
old_surface->clip_rect(),
old_surface->draw_transform());
if (old_target->has_replica() && !old_target->replica_has_mask()) {
old_occlusion_from_inside_target_in_new_target.Union(
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index].occlusion_from_inside_target,
old_surface->is_clipped(),
old_surface->clip_rect(),
old_surface->replica_draw_transform()));
}
- Region old_occlusion_from_outside_target_in_new_target =
- TransformSurfaceOpaqueRegion<RenderSurfaceType>(
+ SimpleEnclosedRegion old_occlusion_from_outside_target_in_new_target =
+ TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>(
stack_[last_index].occlusion_from_outside_target,
false,
gfx::Rect(),
gfx::Rect unoccluded_replica_rect;
if (old_target->background_filters().HasFilterThatMovesPixels()) {
unoccluded_surface_rect = UnoccludedContributingSurfaceContentRect(
- old_target, false, old_surface->content_rect());
+ old_surface->content_rect(), old_surface->draw_transform());
if (old_target->has_replica()) {
unoccluded_replica_rect = UnoccludedContributingSurfaceContentRect(
- old_target, true, old_surface->content_rect());
+ old_surface->content_rect(),
+ old_surface->replica_draw_transform());
}
}
&stack_.back().occlusion_from_outside_target);
}
-template <typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::
- MarkOccludedBehindLayer(const LayerType* layer) {
+template <typename LayerType>
+void OcclusionTracker<LayerType>::MarkOccludedBehindLayer(
+ const LayerType* layer) {
DCHECK(!stack_.empty());
DCHECK_EQ(layer->render_target(), stack_.back().target);
- if (stack_.empty())
- return;
-
- if (!layer->DrawsContent())
- return;
if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1)
return;
if (!LayerTransformsToTargetKnown(layer))
return;
- Region opaque_contents = layer->VisibleContentOpaqueRegion();
+ SimpleEnclosedRegion opaque_contents = layer->VisibleContentOpaqueRegion();
if (opaque_contents.IsEmpty())
return;
layer->render_target()->render_surface()->content_rect());
}
- for (Region::Iterator opaque_content_rects(opaque_contents);
- opaque_content_rects.has_rect();
- opaque_content_rects.next()) {
- bool clipped;
- gfx::QuadF transformed_quad = MathUtil::MapQuad(
- layer->draw_transform(),
- gfx::QuadF(opaque_content_rects.rect()),
- &clipped);
+ for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) {
gfx::Rect transformed_rect =
- gfx::ToEnclosedRect(transformed_quad.BoundingBox());
- DCHECK(!clipped); // We only map if the transform preserves axis alignment.
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ layer->draw_transform(), opaque_contents.GetRect(i));
transformed_rect.Intersect(clip_rect_in_target);
if (transformed_rect.width() < minimum_tracking_size_.width() &&
transformed_rect.height() < minimum_tracking_size_.height())
continue;
// Save the occluding area in screen space for debug visualization.
+ bool clipped;
gfx::QuadF screen_space_quad = MathUtil::MapQuad(
layer->render_target()->render_surface()->screen_space_transform(),
gfx::QuadF(transformed_rect), &clipped);
if (!non_occluding_screen_space_rects_)
return;
- Region non_opaque_contents =
- SubtractRegions(gfx::Rect(layer->content_bounds()), opaque_contents);
+ Region non_opaque_contents(gfx::Rect(layer->content_bounds()));
+ non_opaque_contents.Subtract(opaque_contents);
+
for (Region::Iterator non_opaque_content_rects(non_opaque_contents);
non_opaque_content_rects.has_rect();
non_opaque_content_rects.next()) {
- // We've already checked for clipping in the MapQuad call above, these calls
- // should not clip anything further.
- gfx::Rect transformed_rect = gfx::ToEnclosedRect(
- MathUtil::MapClippedRect(layer->draw_transform(),
- gfx::RectF(non_opaque_content_rects.rect())));
+ gfx::Rect transformed_rect =
+ MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ layer->draw_transform(), non_opaque_content_rects.rect());
transformed_rect.Intersect(clip_rect_in_target);
if (transformed_rect.IsEmpty())
continue;
}
}
-template <typename LayerType, typename RenderSurfaceType>
-bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::Occluded(
- const LayerType* render_target,
+template <typename LayerType>
+gfx::Rect OcclusionTracker<LayerType>::UnoccludedContributingSurfaceContentRect(
const gfx::Rect& content_rect,
- const gfx::Transform& draw_transform,
- bool impl_draw_transform_is_unknown) const {
- DCHECK(!stack_.empty());
- if (stack_.empty())
- return false;
- if (content_rect.IsEmpty())
- return true;
- if (impl_draw_transform_is_unknown)
- return false;
-
- // For tests with no render target.
- if (!render_target)
- return false;
-
- DCHECK_EQ(render_target->render_target(), render_target);
- DCHECK(render_target->render_surface());
- DCHECK_EQ(render_target, stack_.back().target);
-
- if (stack_.back().occlusion_from_inside_target.IsEmpty() &&
- stack_.back().occlusion_from_outside_target.IsEmpty()) {
- return false;
- }
-
- gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
- if (!draw_transform.GetInverse(&inverse_draw_transform))
- return false;
-
- // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
- // partial pixels in the resulting Rect.
- Region unoccluded_region_in_target_surface =
- MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
- unoccluded_region_in_target_surface.Subtract(
- stack_.back().occlusion_from_inside_target);
- gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion =
- unoccluded_region_in_target_surface.bounds();
- unoccluded_region_in_target_surface.Subtract(
- stack_.back().occlusion_from_outside_target);
-
- gfx::RectF unoccluded_rect_in_target_surface =
- unoccluded_region_in_target_surface.bounds();
-
- return unoccluded_rect_in_target_surface.IsEmpty();
-}
-
-template <typename LayerType, typename RenderSurfaceType>
-gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::
- UnoccludedContentRect(
- const LayerType* render_target,
- const gfx::Rect& content_rect,
- const gfx::Transform& draw_transform,
- bool impl_draw_transform_is_unknown) const {
- DCHECK(!stack_.empty());
- if (stack_.empty())
- return content_rect;
+ const gfx::Transform& draw_transform) const {
if (content_rect.IsEmpty())
return content_rect;
- if (impl_draw_transform_is_unknown)
- return content_rect;
- // For tests with no render target.
- if (!render_target)
+ // A contributing surface doesn't get occluded by things inside its own
+ // surface, so only things outside the surface can occlude it. That occlusion
+ // is found just below the top of the stack (if it exists).
+ bool has_occlusion = stack_.size() > 1;
+ if (!has_occlusion)
return content_rect;
- DCHECK_EQ(render_target->render_target(), render_target);
- DCHECK(render_target->render_surface());
- DCHECK_EQ(render_target, stack_.back().target);
-
- if (stack_.back().occlusion_from_inside_target.IsEmpty() &&
- stack_.back().occlusion_from_outside_target.IsEmpty()) {
+ const StackObject& second_last = stack_[stack_.size() - 2];
+ if (second_last.occlusion_from_inside_target.IsEmpty() &&
+ second_last.occlusion_from_outside_target.IsEmpty())
return content_rect;
- }
gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
- if (!draw_transform.GetInverse(&inverse_draw_transform))
- return content_rect;
+ bool ok = draw_transform.GetInverse(&inverse_draw_transform);
+ DCHECK(ok);
// Take the ToEnclosingRect at each step, as we want to contain any unoccluded
// partial pixels in the resulting Rect.
- Region unoccluded_region_in_target_surface =
+ gfx::Rect unoccluded_rect_in_target_surface =
MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
- unoccluded_region_in_target_surface.Subtract(
- stack_.back().occlusion_from_inside_target);
- unoccluded_region_in_target_surface.Subtract(
- stack_.back().occlusion_from_outside_target);
+ DCHECK_LE(second_last.occlusion_from_inside_target.GetRegionComplexity(), 1u);
+ DCHECK_LE(second_last.occlusion_from_outside_target.GetRegionComplexity(),
+ 1u);
+ // These subtract operations are more lossy than if we did both operations at
+ // once.
+ unoccluded_rect_in_target_surface.Subtract(
+ second_last.occlusion_from_inside_target.bounds());
+ unoccluded_rect_in_target_surface.Subtract(
+ second_last.occlusion_from_outside_target.bounds());
+
+ if (unoccluded_rect_in_target_surface.IsEmpty())
+ return gfx::Rect();
- gfx::Rect unoccluded_rect_in_target_surface =
- unoccluded_region_in_target_surface.bounds();
gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect(
inverse_draw_transform, unoccluded_rect_in_target_surface);
unoccluded_rect.Intersect(content_rect);
return unoccluded_rect;
}
-template <typename LayerType, typename RenderSurfaceType>
-gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::
- UnoccludedContributingSurfaceContentRect(
- const LayerType* layer,
- bool for_replica,
- const gfx::Rect& content_rect) const {
- DCHECK(!stack_.empty());
- // The layer is a contributing render_target so it should have a surface.
- DCHECK(layer->render_surface());
- // The layer is a contributing render_target so its target should be itself.
- DCHECK_EQ(layer->render_target(), layer);
- // The layer should not be the root, else what is is contributing to?
- DCHECK(layer->parent());
- // This should be called while the layer is still considered the current
- // target in the occlusion tracker.
- DCHECK_EQ(layer, stack_.back().target);
-
- if (content_rect.IsEmpty())
- return content_rect;
-
- const RenderSurfaceType* surface = layer->render_surface();
- const LayerType* contributing_surface_render_target =
- layer->parent()->render_target();
-
- if (!SurfaceTransformsToTargetKnown(surface))
- return content_rect;
-
- gfx::Transform draw_transform =
- for_replica ? surface->replica_draw_transform()
- : surface->draw_transform();
- gfx::Transform inverse_draw_transform(gfx::Transform::kSkipInitialization);
- if (!draw_transform.GetInverse(&inverse_draw_transform))
- return content_rect;
-
- // A contributing surface doesn't get occluded by things inside its own
- // surface, so only things outside the surface can occlude it. That occlusion
- // is found just below the top of the stack (if it exists).
- bool has_occlusion = stack_.size() > 1;
-
- // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
- // partial pixels in the resulting Rect.
- Region unoccluded_region_in_target_surface =
- MathUtil::MapEnclosingClippedRect(draw_transform, content_rect);
- // Layers can't clip across surfaces, so count this as internal occlusion.
- if (surface->is_clipped())
- unoccluded_region_in_target_surface.Intersect(surface->clip_rect());
- if (has_occlusion) {
- const StackObject& second_last = stack_[stack_.size() - 2];
- unoccluded_region_in_target_surface.Subtract(
- second_last.occlusion_from_inside_target);
- unoccluded_region_in_target_surface.Subtract(
- second_last.occlusion_from_outside_target);
- }
-
- // Treat other clipping as occlusion from outside the target surface.
- unoccluded_region_in_target_surface.Intersect(
- contributing_surface_render_target->render_surface()->content_rect());
- unoccluded_region_in_target_surface.Intersect(
- ScreenSpaceClipRectInTargetSurface(
- contributing_surface_render_target->render_surface(),
- screen_space_clip_rect_));
-
- gfx::Rect unoccluded_rect_in_target_surface =
- unoccluded_region_in_target_surface.bounds();
- gfx::Rect unoccluded_rect = MathUtil::ProjectEnclosingClippedRect(
- inverse_draw_transform, unoccluded_rect_in_target_surface);
- unoccluded_rect.Intersect(content_rect);
-
- return unoccluded_rect;
+template <typename LayerType>
+Region OcclusionTracker<LayerType>::ComputeVisibleRegionInScreen() const {
+ DCHECK(!stack_.back().target->parent());
+ const SimpleEnclosedRegion& occluded =
+ stack_.back().occlusion_from_inside_target;
+ Region visible_region(screen_space_clip_rect_);
+ for (size_t i = 0; i < occluded.GetRegionComplexity(); ++i)
+ visible_region.Subtract(occluded.GetRect(i));
+ return visible_region;
}
// Instantiate (and export) templates here for the linker.
-template class OcclusionTrackerBase<Layer, RenderSurface>;
-template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>;
+template class OcclusionTracker<Layer>;
+template class OcclusionTracker<LayerImpl>;
} // namespace cc