summaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorshawnsingh@google.com <shawnsingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-12 00:49:47 +0000
committershawnsingh@google.com <shawnsingh@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-12 00:49:47 +0000
commit6af5cab7b079c269ecc2366d84d530376e14a8cf (patch)
tree115bf2578c41650d3fe7042e473432513c5d1a52 /cc
parentb31199ef64e72567c9f66e49d7734e361357e375 (diff)
downloadchromium_src-6af5cab7b079c269ecc2366d84d530376e14a8cf.zip
chromium_src-6af5cab7b079c269ecc2366d84d530376e14a8cf.tar.gz
chromium_src-6af5cab7b079c269ecc2366d84d530376e14a8cf.tar.bz2
Reduce more matrix math in calculateDrawProperties
This patch avoids even more math. cc_perftests on linux desktop improved by about 3-4%. (0) Skip applying the layer's anchorPoint + transform + inverseAnchorPoint if the layer's transform was identity. (1) The surface clipRect, projected from ancestor space to current surface space, is now cached in calcDrawTransforms so it only needs to be computed once, instead of onces for every layer that contributes to the surface. (2) The layer's bounds, transformed into target surface space, are passed into calculateVisibleContentRect, so that this function does not need to redo the mapClippedRect computation unnecessarily. (3) The early exit logic was made more aggressive, to early-out as soon as we realize that none of the layer's drawProperties need to be computed. BUG=163769 Review URL: https://codereview.chromium.org/11534006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172475 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r--cc/layer_tree_host_common.cc129
1 files changed, 80 insertions, 49 deletions
diff --git a/cc/layer_tree_host_common.cc b/cc/layer_tree_host_common.cc
index 4af5717..37ab677 100644
--- a/cc/layer_tree_host_common.cc
+++ b/cc/layer_tree_host_common.cc
@@ -40,18 +40,17 @@ static void sortLayers(std::vector<LayerImpl*>::iterator first, std::vector<Laye
layerSorter->sort(first, end);
}
-gfx::Rect LayerTreeHostCommon::calculateVisibleRect(const gfx::Rect& targetSurfaceRect, const gfx::Rect& layerBoundRect, const gfx::Transform& transform)
+inline gfx::Rect calculateVisibleRectWithCachedLayerRect(const gfx::Rect& targetSurfaceRect, const gfx::Rect& layerBoundRect, const gfx::Rect& layerRectInTargetSpace, const gfx::Transform& transform)
{
// Is this layer fully contained within the target surface?
- gfx::Rect layerInSurfaceSpace = MathUtil::mapClippedRect(transform, layerBoundRect);
- if (targetSurfaceRect.Contains(layerInSurfaceSpace))
+ if (targetSurfaceRect.Contains(layerRectInTargetSpace))
return layerBoundRect;
// If the layer doesn't fill up the entire surface, then find the part of
// the surface rect where the layer could be visible. This avoids trying to
// project surface rect points that are behind the projection point.
gfx::Rect minimalSurfaceRect = targetSurfaceRect;
- minimalSurfaceRect.Intersect(layerInSurfaceSpace);
+ minimalSurfaceRect.Intersect(layerRectInTargetSpace);
// Project the corners of the target surface rect into the layer space.
// This bounding rectangle may be larger than it needs to be (being
@@ -63,6 +62,12 @@ gfx::Rect LayerTreeHostCommon::calculateVisibleRect(const gfx::Rect& targetSurfa
return layerRect;
}
+gfx::Rect LayerTreeHostCommon::calculateVisibleRect(const gfx::Rect& targetSurfaceRect, const gfx::Rect& layerBoundRect, const gfx::Transform& transform)
+{
+ gfx::Rect layerInSurfaceSpace = MathUtil::mapClippedRect(transform, layerBoundRect);
+ return calculateVisibleRectWithCachedLayerRect(targetSurfaceRect, layerBoundRect, layerInSurfaceSpace, transform);
+}
+
template <typename LayerType>
static inline bool isRootLayer(LayerType* layer)
{
@@ -126,7 +131,7 @@ static inline bool layerClipsSubtree(LayerType* layer)
}
template<typename LayerType>
-static gfx::Rect calculateVisibleContentRect(LayerType* layer)
+static gfx::Rect calculateVisibleContentRect(LayerType* layer, const gfx::Rect& ancestorClipRectInDescendantSurfaceSpace, const gfx::Rect& layerRectInTargetSpace)
{
DCHECK(layer->renderTarget());
@@ -134,23 +139,22 @@ static gfx::Rect calculateVisibleContentRect(LayerType* layer)
if (!layer->drawsContent() || layer->contentBounds().IsEmpty() || layer->drawableContentRect().IsEmpty())
return gfx::Rect();
- gfx::Rect targetSurfaceClipRect;
+ // Compute visible bounds in target surface space.
+ gfx::Rect visibleRectInTargetSurfaceSpace = layer->drawableContentRect();
- // First, compute visible bounds in target surface space.
- if (layer->renderTarget()->renderSurface()->clipRect().IsEmpty())
- targetSurfaceClipRect = layer->drawableContentRect();
- else {
- // In this case the target surface does clip layers that contribute to it. So, we
- // have convert the current surface's clipRect from its ancestor surface space to
- // the current surface space.
- targetSurfaceClipRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect(MathUtil::inverse(layer->renderTarget()->renderSurface()->drawTransform()), layer->renderTarget()->renderSurface()->clipRect()));
- targetSurfaceClipRect.Intersect(layer->drawableContentRect());
+ if (!layer->renderTarget()->renderSurface()->clipRect().IsEmpty()) {
+ // In this case the target surface does clip layers that contribute to
+ // it. So, we have to convert the current surface's clipRect from its
+ // ancestor surface space to the current (descendant) surface
+ // space. This conversion is done outside this function so that it can
+ // be cached instead of computing it redundantly for every layer.
+ visibleRectInTargetSurfaceSpace.Intersect(ancestorClipRectInDescendantSurfaceSpace);
}
- if (targetSurfaceClipRect.IsEmpty())
+ if (visibleRectInTargetSurfaceSpace.IsEmpty())
return gfx::Rect();
- return LayerTreeHostCommon::calculateVisibleRect(targetSurfaceClipRect, gfx::Rect(gfx::Point(), layer->contentBounds()), layer->drawTransform());
+ return calculateVisibleRectWithCachedLayerRect(visibleRectInTargetSurfaceSpace, gfx::Rect(gfx::Point(), layer->contentBounds()), layerRectInTargetSpace, layer->drawTransform());
}
static inline bool transformToParentIsKnown(LayerImpl*)
@@ -401,12 +405,31 @@ static inline void updateLayerContentsScale(Layer* layer, const gfx::Transform&
replicaMaskLayer->setContentsScale(contentsScale);
}
+template<typename LayerType, typename LayerList>
+static inline void removeSurfaceForEarlyExit(LayerType* layerToRemove, LayerList& renderSurfaceLayerList)
+{
+ DCHECK(layerToRemove->renderSurface());
+ // Technically, we know that the layer we want to remove should be
+ // at the back of the renderSurfaceLayerList. However, we have had
+ // bugs before that added unnecessary layers here
+ // (https://bugs.webkit.org/show_bug.cgi?id=74147), but that causes
+ // things to crash. So here we proactively remove any additional
+ // layers from the end of the list.
+ while (renderSurfaceLayerList.back() != layerToRemove) {
+ renderSurfaceLayerList.back()->clearRenderSurface();
+ renderSurfaceLayerList.pop_back();
+ }
+ DCHECK(renderSurfaceLayerList.back() == layerToRemove);
+ renderSurfaceLayerList.pop_back();
+ layerToRemove->clearRenderSurface();
+}
+
// Recursively walks the layer tree starting at the given node and computes all the
// necessary transformations, clipRects, render surfaces, etc.
template<typename LayerType, typename LayerList, typename RenderSurfaceType>
static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transform& parentMatrix,
const gfx::Transform& fullHierarchyMatrix, const gfx::Transform& currentScrollCompensationMatrix,
- const gfx::Rect& clipRectFromAncestor, bool ancestorClipsSubtree,
+ const gfx::Rect& clipRectFromAncestor, const gfx::Rect& clipRectFromAncestorInDescendantSpace, bool ancestorClipsSubtree,
RenderSurfaceType* nearestAncestorThatMovesPixels, LayerList& renderSurfaceLayerList, LayerList& layerList,
LayerSorter* layerSorter, int maxTextureSize, float deviceScaleFactor, float pageScaleFactor, gfx::Rect& drawableContentRectOfSubtree)
{
@@ -508,6 +531,13 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
gfx::Rect clipRectForSubtree;
bool subtreeShouldBeClipped = false;
+ // This value is cached on the stack so that we don't have to inverse-project
+ // the surface's clipRect redundantly for every layer. This value is the
+ // same as the surface's clipRect, except that instead of being described
+ // in the target surface space (i.e. the ancestor surface space), it is
+ // described in the current surface space.
+ gfx::Rect clipRectForSubtreeInDescendantSpace;
+
float accumulatedDrawOpacity = layer->opacity();
bool drawOpacityIsAnimating = layer->opacityIsAnimating();
if (layer->parent()) {
@@ -527,12 +557,16 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
gfx::PointF position = layer->position() - layer->scrollDelta();
gfx::Transform combinedTransform = parentMatrix;
- // LT = Tr[origin] * Tr[origin2anchor]
- combinedTransform.Translate3d(position.x() + anchorPoint.x() * bounds.width(), position.y() + anchorPoint.y() * bounds.height(), layer->anchorPointZ());
- // LT = Tr[origin] * Tr[origin2anchor] * M[layer]
- combinedTransform.PreconcatTransform(layer->transform());
- // LT = Tr[origin] * Tr[origin2anchor] * M[layer] * Tr[anchor2origin]
- combinedTransform.Translate3d(-anchorPoint.x() * bounds.width(), -anchorPoint.y() * bounds.height(), -layer->anchorPointZ());
+ if (!layer->transform().IsIdentity()) {
+ // LT = Tr[origin] * Tr[origin2anchor]
+ combinedTransform.Translate3d(position.x() + anchorPoint.x() * bounds.width(), position.y() + anchorPoint.y() * bounds.height(), layer->anchorPointZ());
+ // LT = Tr[origin] * Tr[origin2anchor] * M[layer]
+ combinedTransform.PreconcatTransform(layer->transform());
+ // LT = Tr[origin] * Tr[origin2anchor] * M[layer] * Tr[anchor2origin]
+ combinedTransform.Translate3d(-anchorPoint.x() * bounds.width(), -anchorPoint.y() * bounds.height(), -layer->anchorPointZ());
+ } else {
+ combinedTransform.Translate(position.x(), position.y());
+ }
// The layer's contentsSize is determined from the combinedTransform, which then informs the
// layer's drawTransform.
@@ -643,10 +677,13 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
// The render surface clipRect is expressed in the space where this surface draws, i.e. the same space as clipRectFromAncestor.
renderSurface->setIsClipped(ancestorClipsSubtree);
- if (ancestorClipsSubtree)
+ if (ancestorClipsSubtree) {
renderSurface->setClipRect(clipRectFromAncestor);
- else
+ clipRectForSubtreeInDescendantSpace = gfx::ToEnclosingRect(MathUtil::projectClippedRect(MathUtil::inverse(renderSurface->drawTransform()), renderSurface->clipRect()));
+ } else {
renderSurface->setClipRect(gfx::Rect());
+ clipRectForSubtreeInDescendantSpace = clipRectFromAncestorInDescendantSpace;
+ }
renderSurface->setNearestAncestorThatMovesPixels(nearestAncestorThatMovesPixels);
@@ -669,6 +706,9 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
if (ancestorClipsSubtree)
clipRectForSubtree = clipRectFromAncestor;
+ // The surface's cached clipRect value propagates regardless of what clipping goes on between layers here.
+ clipRectForSubtreeInDescendantSpace = clipRectFromAncestorInDescendantSpace;
+
// Layers that are not their own renderTarget will render into the target of their nearest ancestor.
layerDrawProperties.render_target = layer->parent()->renderTarget();
}
@@ -710,7 +750,7 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
LayerType* child = LayerTreeHostCommon::getChildAsRawPtr(layer->children(), i);
gfx::Rect drawableContentRectOfChildSubtree;
calculateDrawPropertiesInternal<LayerType, LayerList, RenderSurfaceType>(child, sublayerMatrix, nextHierarchyMatrix, nextScrollCompensationMatrix,
- clipRectForSubtree, subtreeShouldBeClipped, nearestAncestorThatMovesPixels,
+ clipRectForSubtree, clipRectForSubtreeInDescendantSpace, subtreeShouldBeClipped, nearestAncestorThatMovesPixels,
renderSurfaceLayerList, descendants, layerSorter, maxTextureSize, deviceScaleFactor, pageScaleFactor, drawableContentRectOfChildSubtree);
if (!drawableContentRectOfChildSubtree.IsEmpty()) {
accumulatedDrawableContentRectOfChildren.Union(drawableContentRectOfChildSubtree);
@@ -719,6 +759,11 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
}
}
+ if (layer->renderSurface() && !isRootLayer(layer) && !layer->renderSurface()->layerList().size()) {
+ removeSurfaceForEarlyExit(layer, renderSurfaceLayerList);
+ return;
+ }
+
// Compute the total drawableContentRect for this subtree (the rect is in targetSurface space)
gfx::Rect localDrawableContentRectOfSubtree = accumulatedDrawableContentRectOfChildren;
if (layer->drawsContent())
@@ -745,7 +790,7 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
}
// Compute the layer's visible content rect (the rect is in content space)
- layerDrawProperties.visible_content_rect = calculateVisibleContentRect(layer);
+ layerDrawProperties.visible_content_rect = calculateVisibleContentRect(layer, clipRectForSubtreeInDescendantSpace, rectInTargetSpace);
// Compute the remaining properties for the render surface, if the layer has one.
if (isRootLayer(layer)) {
@@ -773,9 +818,12 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
clippedContentRect.set_width(std::min(clippedContentRect.width(), maxTextureSize));
clippedContentRect.set_height(std::min(clippedContentRect.height(), maxTextureSize));
- if (clippedContentRect.IsEmpty())
+ if (clippedContentRect.IsEmpty()) {
renderSurface->clearLayerLists();
-
+ removeSurfaceForEarlyExit(layer, renderSurfaceLayerList);
+ return;
+ }
+
renderSurface->setContentRect(clippedContentRect);
// The owning layer's screenSpaceTransform has a scale from content to layer space which we need to undo and
@@ -801,23 +849,6 @@ static void calculateDrawPropertiesInternal(LayerType* layer, const gfx::Transfo
gfx::Transform replicaScreenSpaceTransform = layer->renderSurface()->screenSpaceTransform() * surfaceOriginToReplicaOriginTransform;
renderSurface->setReplicaScreenSpaceTransform(replicaScreenSpaceTransform);
}
-
- // If a render surface has no layer list, then it and none of its children needed to get drawn.
- if (!layer->renderSurface()->layerList().size()) {
- // FIXME: Originally we asserted that this layer was already at the end of the
- // list, and only needed to remove that layer. For now, we remove the
- // entire subtree of surfaces to fix a crash bug. The root cause is
- // https://bugs.webkit.org/show_bug.cgi?id=74147 and we should be able
- // to put the original assert after fixing that.
- while (renderSurfaceLayerList.back() != layer) {
- renderSurfaceLayerList.back()->clearRenderSurface();
- renderSurfaceLayerList.pop_back();
- }
- DCHECK(renderSurfaceLayerList.back() == layer);
- renderSurfaceLayerList.pop_back();
- layer->clearRenderSurface();
- return;
- }
}
markLayerAsUpdated(layer);
@@ -858,7 +889,7 @@ void LayerTreeHostCommon::calculateDrawProperties(Layer* rootLayer, const gfx::S
cc::calculateDrawPropertiesInternal<Layer, std::vector<scoped_refptr<Layer> >, RenderSurface>(
rootLayer, deviceScaleTransform, identityMatrix, identityMatrix,
- deviceViewportRect, subtreeShouldBeClipped, 0, renderSurfaceLayerList,
+ deviceViewportRect, deviceViewportRect, subtreeShouldBeClipped, 0, renderSurfaceLayerList,
dummyLayerList, 0, maxTextureSize,
deviceScaleFactor, pageScaleFactor, totalDrawableContentRect);
@@ -886,7 +917,7 @@ void LayerTreeHostCommon::calculateDrawProperties(LayerImpl* rootLayer, const gf
cc::calculateDrawPropertiesInternal<LayerImpl, std::vector<LayerImpl*>, RenderSurfaceImpl>(
rootLayer, deviceScaleTransform, identityMatrix, identityMatrix,
- deviceViewportRect, subtreeShouldBeClipped, 0, renderSurfaceLayerList,
+ deviceViewportRect, deviceViewportRect, subtreeShouldBeClipped, 0, renderSurfaceLayerList,
dummyLayerList, &layerSorter, maxTextureSize,
deviceScaleFactor, pageScaleFactor, totalDrawableContentRect);