Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3417)

Unified Diff: cc/occlusion_tracker.cc

Issue 11583005: cc: Make occlusion tracker always work in target space. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: cc/occlusion_tracker.cc
diff --git a/cc/occlusion_tracker.cc b/cc/occlusion_tracker.cc
index 4ea3d3cff553a072df89ef97178ce9c49e17e110..9686a6225e4590633fadd03d9c196e9ee65d234d 100644
--- a/cc/occlusion_tracker.cc
+++ b/cc/occlusion_tracker.cc
@@ -18,8 +18,8 @@ using namespace std;
namespace cc {
template<typename LayerType, typename RenderSurfaceType>
-OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(gfx::Rect rootTargetRect, bool recordMetricsForFrame)
- : m_rootTargetRect(rootTargetRect)
+OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(gfx::Rect screenSpaceClipRect, bool recordMetricsForFrame)
+ : m_screenSpaceClipRect(screenSpaceClipRect)
, m_overdrawMetrics(OverdrawMetrics::create(recordMetricsForFrame))
, m_occludingScreenSpaceRects(0)
, m_nonOccludingScreenSpaceRects(0)
@@ -53,39 +53,47 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const LayerI
leaveToRenderTarget(renderTarget);
}
-template<typename LayerType, typename RenderSurfaceType>
-void OcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget)
+template<typename RenderSurfaceType>
+static gfx::Rect screenSpaceClipRectInTargetSurface(const RenderSurfaceType* targetSurface, gfx::Rect screenSpaceClipRect)
enne (OOO) 2012/12/16 19:44:25 Do we not make this projection anywhere in LayerTr
danakj 2012/12/16 20:16:52 This looks a lot like clipRectFromAncestor for con
{
- if (!m_stack.empty() && m_stack.back().target == newTarget)
- return;
+ gfx::Transform inverseScreenSpaceTransform;
+ if (!targetSurface->screenSpaceTransform().GetInverse(&inverseScreenSpaceTransform))
+ return targetSurface->contentRect();
- const LayerType* oldTarget = m_stack.empty() ? 0 : m_stack.back().target;
- const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTarget->renderSurface()->nearestAncestorThatMovesPixels();
- const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurface()->nearestAncestorThatMovesPixels();
+ return gfx::ToEnclosingRect(MathUtil::projectClippedRect(inverseScreenSpaceTransform, screenSpaceClipRect));
+}
- m_stack.push_back(StackObject(newTarget));
+template<typename RenderSurfaceType>
+static Region transformSurfaceOpaqueRegion(const Region& region, bool haveClipRect, gfx::Rect clipRectInNewTarget, const gfx::Transform& transform)
+{
+ if (region.IsEmpty())
+ return Region();
- // We copy the screen occlusion into the new RenderSurfaceImpl subtree, but we never copy in the
- // target occlusion, since we are looking at a new RenderSurfaceImpl target.
+ // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then
+ // apply |transform| to each rect within |region| in order to transform the entire Region.
- // If we are entering a subtree that is going to move pixels around, then the occlusion we've computed
- // so far won't apply to the pixels we're drawing here in the same way. We discard the occlusion thus
- // far to be safe, and ensure we don't cull any pixels that are moved such that they become visible.
- bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAncestorThatMovesPixels != oldAncestorThatMovesPixels;
+ bool clipped;
+ gfx::QuadF transformedBoundsQuad = MathUtil::mapQuad(transform, gfx::QuadF(region.bounds()), clipped);
+ // FIXME: Find a rect interior to each transformed quad.
+ if (clipped || !transformedBoundsQuad.IsRectilinear())
+ return Region();
- bool copyScreenOcclusionForward = m_stack.size() > 1 && !enteringSubtreeThatMovesPixels;
- if (copyScreenOcclusionForward) {
- int lastIndex = m_stack.size() - 1;
- m_stack[lastIndex].occlusionInScreen = m_stack[lastIndex - 1].occlusionInScreen;
+ // TODO(danakj): If the Region is too complex, degrade gracefully here by skipping rects in it.
enne (OOO) 2012/12/16 19:44:25 I think it'd be great if we had a Region-derived c
danakj 2012/12/16 20:16:52 I will make a bug for this too.
+ Region transformedRegion;
+ for (Region::Iterator rects(region); rects.has_rect(); rects.next()) {
+ gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapQuad(transform, gfx::QuadF(rects.rect()), clipped).BoundingBox());
+ DCHECK(!clipped); // We only map if the transform preserves axis alignment.
+ if (haveClipRect)
+ transformedRect.Intersect(clipRectInNewTarget);
+ transformedRegion.Union(transformedRect);
}
+ return transformedRegion;
}
static inline bool layerOpacityKnown(const Layer* layer) { return !layer->drawOpacityIsAnimating(); }
static inline bool layerOpacityKnown(const LayerImpl*) { return true; }
static inline bool layerTransformsToTargetKnown(const Layer* layer) { return !layer->drawTransformIsAnimating(); }
static inline bool layerTransformsToTargetKnown(const LayerImpl*) { return true; }
-static inline bool layerTransformsToScreenKnown(const Layer* layer) { return !layer->screenSpaceTransformIsAnimating(); }
-static inline bool layerTransformsToScreenKnown(const LayerImpl*) { return true; }
static inline bool surfaceOpacityKnown(const RenderSurface* surface) { return !surface->drawOpacityIsAnimating(); }
static inline bool surfaceOpacityKnown(const RenderSurfaceImpl*) { return true; }
@@ -98,6 +106,51 @@ static inline bool layerIsInUnsorted3dRenderingContext(const Layer* layer) { ret
static inline bool layerIsInUnsorted3dRenderingContext(const LayerImpl*) { return false; }
template<typename LayerType, typename RenderSurfaceType>
+void OcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget)
+{
+ if (!m_stack.empty() && m_stack.back().target == newTarget)
+ return;
+
+ const LayerType* oldTarget = m_stack.empty() ? 0 : m_stack.back().target;
+ const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTarget->renderSurface()->nearestAncestorThatMovesPixels();
+ const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurface()->nearestAncestorThatMovesPixels();
+
+ m_stack.push_back(StackObject(newTarget));
+
+ // We copy the screen occlusion into the new RenderSurface subtree, but we never copy in the
+ // occlusion from inside the target, since we are looking at a new RenderSurface target.
+
+ // If we are entering a subtree that is going to move pixels around, then the occlusion we've computed
+ // so far won't apply to the pixels we're drawing here in the same way. We discard the occlusion thus
+ // far to be safe, and ensure we don't cull any pixels that are moved such that they become visible.
+ bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAncestorThatMovesPixels != oldAncestorThatMovesPixels;
+
+ bool haveTransformFromScreenToNewTarget = false;
+ gfx::Transform inverseNewTargetScreenSpaceTransform;
+ if (surfaceTransformsToScreenKnown(newTarget->renderSurface()))
+ haveTransformFromScreenToNewTarget = newTarget->renderSurface()->screenSpaceTransform().GetInverse(&inverseNewTargetScreenSpaceTransform);
+
+ bool enteringRootTarget = newTarget->parent() == NULL;
+
+ bool copyOutsideOcclusionForward = m_stack.size() > 1 && !enteringSubtreeThatMovesPixels && haveTransformFromScreenToNewTarget && !enteringRootTarget;
+ if (!copyOutsideOcclusionForward)
+ return;
+
+ int lastIndex = m_stack.size() - 1;
+ gfx::Transform oldTargetToNewTargetTransform(inverseNewTargetScreenSpaceTransform, oldTarget->renderSurface()->screenSpaceTransform());
+ m_stack[lastIndex].occlusionFromOutsideTarget = transformSurfaceOpaqueRegion<RenderSurfaceType>(
+ m_stack[lastIndex - 1].occlusionFromOutsideTarget,
+ false,
+ gfx::Rect(),
+ oldTargetToNewTargetTransform);
+ m_stack[lastIndex].occlusionFromOutsideTarget.Union(transformSurfaceOpaqueRegion<RenderSurfaceType>(
+ m_stack[lastIndex - 1].occlusionFromInsideTarget,
+ false,
+ gfx::Rect(),
+ oldTargetToNewTargetTransform));
+}
+
+template<typename LayerType, typename RenderSurfaceType>
void OcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(const LayerType* finishedTarget)
{
// Make sure we know about the target surface.
@@ -109,102 +162,56 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(co
// TODO(senorblanco): Make this smarter for SkImageFilter case: once
// SkImageFilters can report affectsOpacity(), call that.
if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface->drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity() || finishedTarget->filter()) {
- m_stack.back().occlusionInScreen.Clear();
- m_stack.back().occlusionInTarget.Clear();
- } else {
- if (!surfaceTransformsToTargetKnown(surface))
- m_stack.back().occlusionInTarget.Clear();
- if (!surfaceTransformsToScreenKnown(surface))
- m_stack.back().occlusionInScreen.Clear();
+ m_stack.back().occlusionFromOutsideTarget.Clear();
+ m_stack.back().occlusionFromInsideTarget.Clear();
+ } else if (!surfaceTransformsToTargetKnown(surface)) {
+ m_stack.back().occlusionFromInsideTarget.Clear();
+ m_stack.back().occlusionFromOutsideTarget.Clear();
}
}
-template<typename RenderSurfaceType>
-static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surface, const Region& region, const gfx::Transform& transform)
+template<typename LayerType>
+static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const gfx::Rect& surfaceRect, const gfx::Transform& surfaceTransform, LayerType* renderTarget, Region& occlusionFromInsideTarget)
{
- // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then
- // apply |transform| to each rect within |region| in order to transform the entire Region.
+ if (surfaceRect.IsEmpty())
+ return;
- bool clipped;
- gfx::QuadF transformedBoundsQuad = MathUtil::mapQuad(transform, gfx::QuadF(region.bounds()), clipped);
- // FIXME: Find a rect interior to each transformed quad.
- if (clipped || !transformedBoundsQuad.IsRectilinear())
- return Region();
+ gfx::Rect affectedAreaInTarget = gfx::ToEnclosingRect(MathUtil::mapClippedRect(surfaceTransform, gfx::RectF(surfaceRect)));
+ if (contributingLayer->renderSurface()->isClipped())
+ affectedAreaInTarget.Intersect(contributingLayer->renderSurface()->clipRect());
+ if (affectedAreaInTarget.IsEmpty())
+ return;
- Region transformedRegion;
+ int outsetTop, outsetRight, outsetBottom, outsetLeft;
+ contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft);
- for (Region::Iterator rects(region); rects.has_rect(); rects.next()) {
- // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
- gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect(transform, gfx::RectF(rects.rect())));
- if (!surface->clipRect().IsEmpty())
- transformedRect.Intersect(surface->clipRect());
- transformedRegion.Union(transformedRect);
- }
- return transformedRegion;
-}
+ // The filter can move pixels from outside of the clip, so allow affectedArea to expand outside the clip.
+ affectedAreaInTarget.Inset(-outsetLeft, -outsetTop, -outsetRight, -outsetBottom);
-static inline void reduceOcclusion(const gfx::Rect& affectedArea, const gfx::Rect& expandedPixel, Region& occlusion)
-{
- if (affectedArea.IsEmpty())
- return;
+ gfx::Rect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outsetRight, outsetTop + outsetBottom);
- Region affectedOcclusion = IntersectRegions(occlusion, affectedArea);
+ Region affectedOcclusion = IntersectRegions(occlusionFromInsideTarget, affectedAreaInTarget);
Region::Iterator affectedOcclusionRects(affectedOcclusion);
- occlusion.Subtract(affectedArea);
+ occlusionFromInsideTarget.Subtract(affectedAreaInTarget);
for (; affectedOcclusionRects.has_rect(); affectedOcclusionRects.next()) {
gfx::Rect occlusionRect = affectedOcclusionRects.rect();
// Shrink the rect by expanding the non-opaque pixels outside the rect.
- // The expandedPixel is the Rect for a single pixel after being
- // expanded by filters on the layer. The original pixel would be
- // Rect(0, 0, 1, 1), and the expanded pixel is the rect, relative
- // to this original rect, that the original pixel can influence after
- // being filtered.
- // To convert the expandedPixel Rect back to filter outsets:
- // x = -leftOutset
- // width = leftOutset + rightOutset
- // right = x + width = -leftOutset + leftOutset + rightOutset = rightOutset
-
- // The leftOutset of the filters moves pixels on the right side of
+ // The left outset of the filters moves pixels on the right side of
// the occlusionRect into it, shrinking its right edge.
- int shrinkLeft = occlusionRect.x() == affectedArea.x() ? 0 : expandedPixel.right();
- int shrinkTop = occlusionRect.y() == affectedArea.y() ? 0 : expandedPixel.bottom();
- int shrinkRight = occlusionRect.right() == affectedArea.right() ? 0 : -expandedPixel.x();
- int shrinkBottom = occlusionRect.bottom() == affectedArea.bottom() ? 0 : -expandedPixel.y();
+ int shrinkLeft = occlusionRect.x() == affectedAreaInTarget.x() ? 0 : outsetRight;
+ int shrinkTop = occlusionRect.y() == affectedAreaInTarget.y() ? 0 : outsetBottom;
+ int shrinkRight = occlusionRect.right() == affectedAreaInTarget.right() ? 0 : outsetLeft;
+ int shrinkBottom = occlusionRect.bottom() == affectedAreaInTarget.bottom() ? 0 : outsetTop;
occlusionRect.Inset(shrinkLeft, shrinkTop, shrinkRight, shrinkBottom);
- occlusion.Union(occlusionRect);
+ occlusionFromInsideTarget.Union(occlusionRect);
}
}
-template<typename LayerType>
-static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const gfx::Rect& surfaceRect, const gfx::Transform& surfaceTransform, LayerType* renderTarget, Region& occlusionInTarget, Region& occlusionInScreen)
-{
- if (surfaceRect.IsEmpty())
- return;
-
- gfx::Rect boundsInTarget = gfx::ToEnclosingRect(MathUtil::mapClippedRect(surfaceTransform, gfx::RectF(surfaceRect)));
- if (!contributingLayer->renderSurface()->clipRect().IsEmpty())
- boundsInTarget.Intersect(contributingLayer->renderSurface()->clipRect());
-
- int outsetTop, outsetRight, outsetBottom, outsetLeft;
- contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft);
-
- // The filter can move pixels from outside of the clip, so allow affectedArea to expand outside the clip.
- boundsInTarget.Inset(-outsetLeft, -outsetTop, -outsetRight, -outsetBottom);
-
- gfx::Rect boundsInScreen = gfx::ToEnclosingRect(MathUtil::mapClippedRect(renderTarget->renderSurface()->screenSpaceTransform(), gfx::RectF(boundsInTarget)));
-
- gfx::Rect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outsetRight, outsetTop + outsetBottom);
- gfx::Rect filterOutsetsInScreen = gfx::ToEnclosingRect(MathUtil::mapClippedRect(renderTarget->renderSurface()->screenSpaceTransform(), gfx::RectF(filterOutsetsInTarget)));
-
- reduceOcclusion(boundsInTarget, filterOutsetsInTarget, occlusionInTarget);
- reduceOcclusion(boundsInScreen, filterOutsetsInScreen, occlusionInScreen);
-}
-
template<typename LayerType, typename RenderSurfaceType>
void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(const LayerType* newTarget)
{
@@ -216,9 +223,12 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(con
const LayerType* oldTarget = m_stack[lastIndex].target;
const RenderSurfaceType* oldSurface = oldTarget->renderSurface();
- Region oldTargetOcclusionInNewTarget = transformSurfaceOpaqueRegion<RenderSurfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->drawTransform());
+
+ Region oldOcclusionFromInsideTargetInNewTarget = transformSurfaceOpaqueRegion<RenderSurfaceType>(m_stack[lastIndex].occlusionFromInsideTarget, oldSurface->isClipped(), oldSurface->clipRect(), oldSurface->drawTransform());
if (oldTarget->hasReplica() && !oldTarget->replicaHasMask())
- oldTargetOcclusionInNewTarget.Union(transformSurfaceOpaqueRegion<RenderSurfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->replicaDrawTransform()));
+ oldOcclusionFromInsideTargetInNewTarget.Union(transformSurfaceOpaqueRegion<RenderSurfaceType>(m_stack[lastIndex].occlusionFromInsideTarget, oldSurface->isClipped(), oldSurface->clipRect(), oldSurface->replicaDrawTransform()));
+
+ Region oldOcclusionFromOutsideTargetInNewTarget = transformSurfaceOpaqueRegion<RenderSurfaceType>(m_stack[lastIndex].occlusionFromOutsideTarget, false, gfx::Rect(), oldSurface->drawTransform());
gfx::Rect unoccludedSurfaceRect;
gfx::Rect unoccludedReplicaRect;
@@ -230,56 +240,31 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(con
if (surfaceWillBeAtTopAfterPop) {
// Merge the top of the stack down.
- m_stack[lastIndex - 1].occlusionInScreen.Union(m_stack[lastIndex].occlusionInScreen);
- m_stack[lastIndex - 1].occlusionInTarget.Union(oldTargetOcclusionInNewTarget);
+ m_stack[lastIndex - 1].occlusionFromInsideTarget.Union(oldOcclusionFromInsideTargetInNewTarget);
+ // TODO(danakj): Strictly this should subtract the inside target occlusion before union.
+ if (newTarget->parent())
+ m_stack[lastIndex - 1].occlusionFromOutsideTarget.Union(oldOcclusionFromOutsideTargetInNewTarget);
m_stack.pop_back();
} else {
- // Replace the top of the stack with the new pushed surface. Copy the occluded screen region to the top.
+ // Replace the top of the stack with the new pushed surface.
m_stack.back().target = newTarget;
- m_stack.back().occlusionInTarget = oldTargetOcclusionInNewTarget;
- }
-
- if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) {
- reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->drawTransform(), newTarget, m_stack.back().occlusionInTarget, m_stack.back().occlusionInScreen);
- if (oldTarget->hasReplica())
- reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->replicaDrawTransform(), newTarget, m_stack.back().occlusionInTarget, m_stack.back().occlusionInScreen);
+ m_stack.back().occlusionFromInsideTarget = oldOcclusionFromInsideTargetInNewTarget;
+ if (newTarget->parent())
+ m_stack.back().occlusionFromOutsideTarget = oldOcclusionFromOutsideTargetInNewTarget;
+ else
+ m_stack.back().occlusionFromOutsideTarget.Clear();
}
-}
-// FIXME: Remove usePaintTracking when paint tracking is on for paint culling.
-template<typename LayerType>
-static inline void addOcclusionBehindLayer(Region& region, const LayerType* layer, const gfx::Transform& transform, const Region& opaqueContents, const gfx::Rect& clipRectInTarget, const gfx::Size& minimumTrackingSize, std::vector<gfx::Rect>* occludingScreenSpaceRects, std::vector<gfx::Rect>* nonOccludingScreenSpaceRects)
-{
- DCHECK(layer->visibleContentRect().Contains(opaqueContents.bounds()));
-
- bool clipped;
- gfx::QuadF visibleTransformedQuad = MathUtil::mapQuad(transform, gfx::QuadF(layer->visibleContentRect()), clipped);
- // FIXME: Find a rect interior to each transformed quad.
- if (clipped || !visibleTransformedQuad.IsRectilinear())
+ if (!oldTarget->backgroundFilters().hasFilterThatMovesPixels())
return;
- for (Region::Iterator opaqueContentRects(opaqueContents); opaqueContentRects.has_rect(); opaqueContentRects.next()) {
- // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
- gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect(transform, gfx::RectF(opaqueContentRects.rect())));
- transformedRect.Intersect(clipRectInTarget);
- if (transformedRect.width() >= minimumTrackingSize.width() || transformedRect.height() >= minimumTrackingSize.height()) {
- if (occludingScreenSpaceRects)
- occludingScreenSpaceRects->push_back(transformedRect);
- region.Union(transformedRect);
- }
- }
+ reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->drawTransform(), newTarget, m_stack.back().occlusionFromInsideTarget);
+ reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->drawTransform(), newTarget, m_stack.back().occlusionFromOutsideTarget);
- if (nonOccludingScreenSpaceRects) {
- Region nonOpaqueContents = SubtractRegions(gfx::Rect(layer->contentBounds()), opaqueContents);
- for (Region::Iterator nonOpaqueContentRects(nonOpaqueContents); nonOpaqueContentRects.has_rect(); nonOpaqueContentRects.next()) {
- // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
- gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect(transform, gfx::RectF(nonOpaqueContentRects.rect())));
- transformedRect.Intersect(clipRectInTarget);
- if (transformedRect.IsEmpty())
- continue;
- nonOccludingScreenSpaceRects->push_back(transformedRect);
- }
- }
+ if (!oldTarget->hasReplica())
+ return;
+ reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->replicaDrawTransform(), newTarget, m_stack.back().occlusionFromInsideTarget);
+ reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->replicaDrawTransform(), newTarget, m_stack.back().occlusionFromOutsideTarget);
}
template<typename LayerType, typename RenderSurfaceType>
@@ -300,84 +285,98 @@ void OcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer
if (opaqueContents.IsEmpty())
return;
- gfx::Rect clipRectInTarget = layerClipRectInTarget(layer);
- if (layerTransformsToTargetKnown(layer))
- addOcclusionBehindLayer<LayerType>(m_stack.back().occlusionInTarget, layer, layer->drawTransform(), opaqueContents, clipRectInTarget, m_minimumTrackingSize, 0, 0);
-
- // We must clip the occlusion within the layer's clipRectInTarget within screen space as well. If the clip rect can't be moved to screen space and
- // remain rectilinear, then we don't add any occlusion in screen space.
-
- if (layerTransformsToScreenKnown(layer)) {
- gfx::Transform targetToScreenTransform = m_stack.back().target->renderSurface()->screenSpaceTransform();
- bool clipped;
- gfx::QuadF clipQuadInScreen = MathUtil::mapQuad(targetToScreenTransform, gfx::QuadF(clipRectInTarget), clipped);
- // FIXME: Find a rect interior to the transformed clip quad.
- if (clipped || !clipQuadInScreen.IsRectilinear())
- return;
- gfx::Rect clipRectInScreen = gfx::IntersectRects(m_rootTargetRect, gfx::ToEnclosedRect(clipQuadInScreen.BoundingBox()));
- addOcclusionBehindLayer<LayerType>(m_stack.back().occlusionInScreen, layer, layer->screenSpaceTransform(), opaqueContents, clipRectInScreen, m_minimumTrackingSize, m_occludingScreenSpaceRects, m_nonOccludingScreenSpaceRects);
+ DCHECK(layer->visibleContentRect().Contains(opaqueContents.bounds()));
+
+ if (!layerTransformsToTargetKnown(layer))
+ return;
+
+ bool clipped;
+ gfx::QuadF visibleTransformedQuad = MathUtil::mapQuad(layer->drawTransform(), gfx::QuadF(opaqueContents.bounds()), clipped);
+ // FIXME: Find a rect interior to each transformed quad.
+ if (clipped || !visibleTransformedQuad.IsRectilinear())
+ return;
+
+ gfx::Rect clipRectInTarget = gfx::IntersectRects(
+ layerClipRectInTarget(layer),
+ screenSpaceClipRectInTargetSurface(layer->renderTarget()->renderSurface(), m_screenSpaceClipRect));
+
+ for (Region::Iterator opaqueContentRects(opaqueContents); opaqueContentRects.has_rect(); opaqueContentRects.next()) {
+ gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapQuad(layer->drawTransform(), gfx::QuadF(opaqueContentRects.rect()), clipped).BoundingBox());
+ DCHECK(!clipped); // We only map if the transform preserves axis alignment.
+ transformedRect.Intersect(clipRectInTarget);
+ if (transformedRect.width() < m_minimumTrackingSize.width() && transformedRect.height() < m_minimumTrackingSize.height())
+ continue;
+ m_stack.back().occlusionFromInsideTarget.Union(transformedRect);
+
+ if (!m_occludingScreenSpaceRects)
+ continue;
+
+ // Save the occluding area in screen space for debug visualization.
+ gfx::QuadF screenSpaceQuad = MathUtil::mapQuad(layer->renderTarget()->renderSurface()->screenSpaceTransform(), gfx::QuadF(transformedRect), clipped);
+ // TODO(danakj): Store the quad in the debug info instead of the bounding box.
+ gfx::Rect screenSpaceRect = gfx::ToEnclosedRect(screenSpaceQuad.BoundingBox());
+ m_occludingScreenSpaceRects->push_back(screenSpaceRect);
}
-}
-static inline bool testContentRectOccluded(const gfx::Rect& contentRect, const gfx::Transform& contentSpaceTransform, const gfx::Rect& clipRectInTarget, const Region& occlusion)
-{
- gfx::RectF transformedRect = MathUtil::mapClippedRect(contentSpaceTransform, gfx::RectF(contentRect));
- // Take the gfx::ToEnclosingRect, as we want to include partial pixels in the test.
- gfx::Rect targetRect = gfx::IntersectRects(gfx::ToEnclosingRect(transformedRect), clipRectInTarget);
- return occlusion.Contains(targetRect);
+ if (!m_nonOccludingScreenSpaceRects)
+ return;
+
+ Region nonOpaqueContents = SubtractRegions(gfx::Rect(layer->contentBounds()), opaqueContents);
+ for (Region::Iterator nonOpaqueContentRects(nonOpaqueContents); nonOpaqueContentRects.has_rect(); nonOpaqueContentRects.next()) {
+ // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
+ gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect(layer->drawTransform(), gfx::RectF(nonOpaqueContentRects.rect())));
+ transformedRect.Intersect(clipRectInTarget);
+ if (transformedRect.IsEmpty())
+ continue;
+
+ gfx::QuadF screenSpaceQuad = MathUtil::mapQuad(layer->renderTarget()->renderSurface()->screenSpaceTransform(), gfx::QuadF(transformedRect), clipped);
+ // TODO(danakj): Store the quad in the debug info instead of the bounding box.
+ gfx::Rect screenSpaceRect = gfx::ToEnclosedRect(screenSpaceQuad.BoundingBox());
+ m_nonOccludingScreenSpaceRects->push_back(screenSpaceRect);
+ }
}
template<typename LayerType, typename RenderSurfaceType>
bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerType* renderTarget, const gfx::Rect& contentRect, const gfx::Transform& drawTransform, bool implDrawTransformIsUnknown, const gfx::Rect& clippedRectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const
{
- if (hasOcclusionFromOutsideTargetSurface)
- *hasOcclusionFromOutsideTargetSurface = false;
-
DCHECK(!m_stack.empty());
if (m_stack.empty())
return false;
if (contentRect.IsEmpty())
return true;
+ if (implDrawTransformIsUnknown)
+ return false;
- DCHECK(renderTarget == m_stack.back().target);
+ // For tests with no render target.
+ if (!renderTarget)
+ return false;
- if (!implDrawTransformIsUnknown && testContentRectOccluded(contentRect, drawTransform, clippedRectInTarget, m_stack.back().occlusionInTarget))
- return true;
+ DCHECK(renderTarget->renderTarget() == renderTarget);
+ DCHECK(renderTarget->renderSurface());
+ DCHECK(renderTarget == m_stack.back().target);
- // renderTarget can be NULL in some tests.
- bool transformToScreenKnown = renderTarget && !implDrawTransformIsUnknown && layerTransformsToScreenKnown(renderTarget);
- if (transformToScreenKnown && testContentRectOccluded(contentRect, renderTarget->renderSurface()->screenSpaceTransform() * drawTransform, m_rootTargetRect, m_stack.back().occlusionInScreen)) {
- if (hasOcclusionFromOutsideTargetSurface)
- *hasOcclusionFromOutsideTargetSurface = true;
- return true;
- }
+ gfx::Transform inverseDrawTransform;
+ if (!drawTransform.GetInverse(&inverseDrawTransform))
+ return false;
- return false;
-}
+ // Take the ToEnclosingRect at each step, as we want to contain any unoccluded partial pixels in the resulting Rect.
+ gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapClippedRect(drawTransform, gfx::RectF(contentRect)));
+ contentRectInTargetSurface.Intersect(clippedRectInTarget);
+ contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(renderTarget->renderSurface(), m_screenSpaceClipRect));
-// Determines what portion of rect, if any, is unoccluded (not occluded by region). If
-// the resulting unoccluded region is not rectangular, we return a rect containing it.
-static inline gfx::Rect rectSubtractRegion(const gfx::Rect& rect, const Region& region)
-{
- if (region.IsEmpty())
- return rect;
+ Region unoccludedRegionInTargetSurface = contentRectInTargetSurface;
+ unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromInsideTarget);
+ gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccludedRegionInTargetSurface.bounds();
+ unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromOutsideTarget);
- Region rectRegion(rect);
- rectRegion.Subtract(region);
- return rectRegion.bounds();
-}
+ gfx::RectF unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.bounds();
-static inline gfx::Rect computeUnoccludedContentRect(const gfx::Rect& contentRect, const gfx::Transform& contentSpaceTransform, const gfx::Rect& clipRectInTarget, const Region& occlusion)
-{
- if (!contentSpaceTransform.IsInvertible())
- return contentRect;
+ if (hasOcclusionFromOutsideTargetSurface) {
+ // Check if the unoccluded rect shank when applying outside occlusion.
+ *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRectInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty();
+ }
- // Take the ToEnclosingRect at each step, as we want to contain any unoccluded partial pixels in the resulting Rect.
- gfx::RectF transformedRect = MathUtil::mapClippedRect(contentSpaceTransform, gfx::RectF(contentRect));
- gfx::Rect shrunkRect = rectSubtractRegion(gfx::IntersectRects(gfx::ToEnclosingRect(transformedRect), clipRectInTarget), occlusion);
- gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect(MathUtil::inverse(contentSpaceTransform), gfx::RectF(shrunkRect)));
- // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds.
- return gfx::IntersectRects(unoccludedRect, contentRect);
+ return unoccludedRectInTargetSurface.IsEmpty();
}
template<typename LayerType, typename RenderSurfaceType>
@@ -388,26 +387,41 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR
return contentRect;
if (contentRect.IsEmpty())
return contentRect;
+ if (implDrawTransformIsUnknown)
+ return contentRect;
+
+ // For tests with no render target.
+ if (!renderTarget)
+ return contentRect;
DCHECK(renderTarget->renderTarget() == renderTarget);
DCHECK(renderTarget->renderSurface());
DCHECK(renderTarget == m_stack.back().target);
- // We want to return a rect that contains all the visible parts of |contentRect| in both screen space and in the target surface.
- // So we find the visible parts of |contentRect| in each space, and take the intersection.
-
- gfx::Rect unoccludedInScreen = contentRect;
- if (layerTransformsToScreenKnown(renderTarget) && !implDrawTransformIsUnknown)
- unoccludedInScreen = computeUnoccludedContentRect(contentRect, renderTarget->renderSurface()->screenSpaceTransform() * drawTransform, m_rootTargetRect, m_stack.back().occlusionInScreen);
-
- gfx::Rect unoccludedInTarget = contentRect;
- if (!implDrawTransformIsUnknown)
- unoccludedInTarget = computeUnoccludedContentRect(contentRect, drawTransform, clippedRectInTarget, m_stack.back().occlusionInTarget);
+ gfx::Transform inverseDrawTransform;
+ if (!drawTransform.GetInverse(&inverseDrawTransform))
+ return contentRect;
- if (hasOcclusionFromOutsideTargetSurface)
- *hasOcclusionFromOutsideTargetSurface = (gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget) != unoccludedInTarget);
+ // Take the ToEnclosingRect at each step, as we want to contain any unoccluded partial pixels in the resulting Rect.
+ gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapClippedRect(drawTransform, gfx::RectF(contentRect)));
+ contentRectInTargetSurface.Intersect(clippedRectInTarget);
+ contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(renderTarget->renderSurface(), m_screenSpaceClipRect));
+
+ Region unoccludedRegionInTargetSurface = contentRectInTargetSurface;
+ unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromInsideTarget);
+ gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccludedRegionInTargetSurface.bounds();
+ unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromOutsideTarget);
+
+ gfx::RectF unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.bounds();
+ gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect(inverseDrawTransform, unoccludedRectInTargetSurface));
+ unoccludedRect.Intersect(contentRect);
+
+ if (hasOcclusionFromOutsideTargetSurface) {
+ // Check if the unoccluded rect shank when applying outside occlusion.
jamesr 2012/12/16 00:27:54 typo shank -> shrank
danakj 2012/12/16 21:30:03 Done.
+ *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRectInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty();
+ }
- return gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget);
+ return unoccludedRect;
}
template<typename LayerType, typename RenderSurfaceType>
@@ -426,50 +440,61 @@ gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContribu
if (contentRect.IsEmpty())
return contentRect;
- RenderSurfaceType* surface = layer->renderSurface();
+ const RenderSurfaceType* surface = layer->renderSurface();
+ const LayerType* contributingSurfaceRenderTarget = layer->parent()->renderTarget();
+
+ if (!surfaceTransformsToTargetKnown(surface))
+ return contentRect;
+
+ gfx::Transform drawTransform = forReplica ? surface->replicaDrawTransform() : surface->drawTransform();
+ gfx::Transform inverseDrawTransform;
+ if (!drawTransform.GetInverse(&inverseDrawTransform))
+ return contentRect;
- gfx::Rect surfaceClipRect = surface->clipRect();
- if (surfaceClipRect.IsEmpty()) {
- const LayerType* contributingSurfaceRenderTarget = layer->parent()->renderTarget();
- surfaceClipRect = gfx::IntersectRects(contributingSurfaceRenderTarget->renderSurface()->contentRect(), gfx::ToEnclosingRect(surface->drawableContentRect()));
+ // Take the ToEnclosingRect at each step, as we want to contain any unoccluded partial pixels in the resulting Rect.
+ gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapClippedRect(drawTransform, gfx::RectF(contentRect)));
+ if (surface->isClipped()) {
+ contentRectInTargetSurface.Intersect(surface->clipRect());
+ } else {
+ contentRectInTargetSurface.Intersect(contributingSurfaceRenderTarget->renderSurface()->contentRect());
+ contentRectInTargetSurface.Intersect(gfx::ToEnclosingRect(surface->drawableContentRect()));
}
+ contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(contributingSurfaceRenderTarget->renderSurface(), m_screenSpaceClipRect));
+
+ gfx::RectF unoccludedRectInTargetSurface;
// 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 hasOcclusion = m_stack.size() > 1;
-
- const gfx::Transform& transformToScreen = forReplica ? surface->replicaScreenSpaceTransform() : surface->screenSpaceTransform();
- const gfx::Transform& transformToTarget = forReplica ? surface->replicaDrawTransform() : surface->drawTransform();
-
- gfx::Rect unoccludedInScreen = contentRect;
- if (surfaceTransformsToScreenKnown(surface)) {
- if (hasOcclusion) {
- const StackObject& secondLast = m_stack[m_stack.size() - 2];
- unoccludedInScreen = computeUnoccludedContentRect(contentRect, transformToScreen, m_rootTargetRect, secondLast.occlusionInScreen);
- } else
- unoccludedInScreen = computeUnoccludedContentRect(contentRect, transformToScreen, m_rootTargetRect, Region());
- }
-
- gfx::Rect unoccludedInTarget = contentRect;
- if (surfaceTransformsToTargetKnown(surface)) {
- if (hasOcclusion) {
- const StackObject& secondLast = m_stack[m_stack.size() - 2];
- unoccludedInTarget = computeUnoccludedContentRect(contentRect, transformToTarget, surfaceClipRect, secondLast.occlusionInTarget);
- } else
- unoccludedInTarget = computeUnoccludedContentRect(contentRect, transformToTarget, surfaceClipRect, Region());
+ if (hasOcclusion) {
+ const StackObject& secondLast = m_stack[m_stack.size() - 2];
+ Region unoccludedRegionInTargetSurface = contentRectInTargetSurface;
+ unoccludedRegionInTargetSurface.Subtract(secondLast.occlusionFromInsideTarget);
+ gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccludedRegionInTargetSurface.bounds();
+ unoccludedRegionInTargetSurface.Subtract(secondLast.occlusionFromOutsideTarget);
+
+ unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.bounds();
+
+ if (hasOcclusionFromOutsideTargetSurface) {
+ // Check if the unoccluded rect shank when applying outside occlusion.
jamesr 2012/12/16 00:27:54 same typo
danakj 2012/12/16 21:30:03 Done.
+ *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRectInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty();
+ }
+ } else {
+ unoccludedRectInTargetSurface = contentRectInTargetSurface;
+ if (hasOcclusionFromOutsideTargetSurface)
+ *hasOcclusionFromOutsideTargetSurface = false;
}
- if (hasOcclusionFromOutsideTargetSurface)
- *hasOcclusionFromOutsideTargetSurface = (gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget) != unoccludedInTarget);
+ gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect(inverseDrawTransform, unoccludedRectInTargetSurface));
+ unoccludedRect.Intersect(contentRect);
- return gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget);
+ return unoccludedRect;
}
template<typename LayerType, typename RenderSurfaceType>
gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTarget(const LayerType* layer) const
{
- // FIXME: we could remove this helper function, but unit tests currently override this
- // function, and they need to be verified/adjusted before this can be removed.
+ // TODO(danakj): Can we remove this use of drawableContentRect and just use the clipRect() and target surface contentRect?
return layer->drawableContentRect();
}

Powered by Google App Engine
This is Rietveld 408576698