0

Move second internal recursion to a precomputation in layer_tree_host_common.cc

Asymptotically, the recursive algorithm in calculateDrawTransforms is O(n^2)
because of a secondary recursion that occurs for every layer in
subtreeShouldRenderToSeparateSurface.

This patch moves the internal secondary recursion into a pre-walk, caching
the meaningful result of that recursion, so that the algorithm is O(2 * n).

Review URL: https://codereview.chromium.org/11419284

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@172682 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
shawnsingh@google.com
2012-12-12 22:49:36 +00:00
parent fb817ecdfe
commit b5b1fce737
8 changed files with 47 additions and 53 deletions

@ -22,14 +22,9 @@ DelegatedRendererLayerImpl::~DelegatedRendererLayerImpl()
clearRenderPasses();
}
int DelegatedRendererLayerImpl::descendantsDrawContent()
bool DelegatedRendererLayerImpl::hasDelegatedContent() const
{
// FIXME: This could possibly return false even though there are some
// quads present as they could all be from a single layer (or set of
// layers without children). If this happens, then make a test that
// ensures the opacity is being changed on quads in the root RenderPass
// when this layer doesn't own a RenderSurfaceImpl.
return m_renderPassesInDrawOrder.isEmpty() ? 0 : 2;
return !m_renderPassesInDrawOrder.isEmpty();
}
bool DelegatedRendererLayerImpl::hasContributingDelegatedRenderPasses() const

@ -16,7 +16,7 @@ public:
static scoped_ptr<DelegatedRendererLayerImpl> create(LayerTreeImpl* treeImpl, int id) { return make_scoped_ptr(new DelegatedRendererLayerImpl(treeImpl, id)); }
virtual ~DelegatedRendererLayerImpl();
virtual int descendantsDrawContent() OVERRIDE;
virtual bool hasDelegatedContent() const OVERRIDE;
virtual bool hasContributingDelegatedRenderPasses() const OVERRIDE;
// This gives ownership of the RenderPasses to the layer.

@ -22,6 +22,7 @@ struct CC_EXPORT DrawProperties {
, screen_space_transform_is_animating(false)
, is_clipped(false)
, render_target(0)
, num_descendants_that_draw_content(0)
{
}
@ -67,6 +68,9 @@ struct CC_EXPORT DrawProperties {
// layer. This value is used to avoid unnecessarily changing GL scissor
// state.
gfx::Rect clip_rect;
// Does not include this layer itself, only its children and descendants.
int num_descendants_that_draw_content;
};
} // namespace cc

@ -700,19 +700,6 @@ void Layer::createRenderSurface()
m_drawProperties.render_target = this;
}
int Layer::descendantsDrawContent()
{
int result = 0;
for (size_t i = 0; i < m_children.size(); ++i) {
if (m_children[i]->drawsContent())
++result;
result += m_children[i]->descendantsDrawContent();
if (result > 1)
return result;
}
return result;
}
int Layer::id() const
{
return m_layerId;

@ -198,6 +198,7 @@ public:
virtual void setLayerTreeHost(LayerTreeHost*);
bool hasDelegatedContent() const { return false; }
bool hasContributingDelegatedRenderPasses() const { return false; }
void setIsDrawable(bool);
@ -249,11 +250,6 @@ public:
void setBoundsContainPageScale(bool);
bool boundsContainPageScale() const { return m_boundsContainPageScale; }
// Returns 0 if none of the layer's descendants has content to draw,
// 1 if exactly one descendant has content to draw, or a number >1
// (but necessary the exact number of descendants) otherwise.
int descendantsDrawContent();
LayerTreeHost* layerTreeHost() const { return m_layerTreeHost; }
// Set the priority of all desired textures in this layer.

@ -109,19 +109,6 @@ void LayerImpl::createRenderSurface()
m_drawProperties.render_target = this;
}
int LayerImpl::descendantsDrawContent()
{
int result = 0;
for (size_t i = 0; i < m_children.size(); ++i) {
if (m_children[i]->drawsContent())
++result;
result += m_children[i]->descendantsDrawContent();
if (result > 1)
return result;
}
return result;
}
scoped_ptr<SharedQuadState> LayerImpl::createSharedQuadState() const
{
scoped_ptr<SharedQuadState> state = SharedQuadState::Create();
@ -189,6 +176,11 @@ void LayerImpl::appendDebugBorderQuad(QuadSink& quadList, const SharedQuadState*
quadList.append(debugBorderQuad.PassAs<DrawQuad>(), appendQuadsData);
}
bool LayerImpl::hasDelegatedContent() const
{
return false;
}
bool LayerImpl::hasContributingDelegatedRenderPasses() const
{
return false;

@ -94,6 +94,7 @@ public:
virtual ResourceProvider::ResourceId contentsResourceId() const;
virtual bool hasDelegatedContent() const;
virtual bool hasContributingDelegatedRenderPasses() const;
virtual RenderPass::Id firstContributingRenderPassId() const;
virtual RenderPass::Id nextContributingRenderPassId(RenderPass::Id) const;
@ -105,11 +106,6 @@ public:
bool forceRenderSurface() const { return m_forceRenderSurface; }
void setForceRenderSurface(bool force) { m_forceRenderSurface = force; }
// Returns 0 if none of the layer's descendants has content to draw,
// 1 if exactly one descendant has content to draw, or a number >1
// (but necessary the exact number of descendants) otherwise.
virtual int descendantsDrawContent();
void setAnchorPoint(const gfx::PointF&);
const gfx::PointF& anchorPoint() const { return m_anchorPoint; }

@ -266,21 +266,26 @@ static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlig
if (!layer->filters().isEmpty() || !layer->backgroundFilters().isEmpty() || layer->filter())
return true;
// Cache this value, because otherwise it walks the entire subtree several times.
int descendantsDrawContent = layer->descendantsDrawContent();
int numDescendantsThatDrawContent = layer->drawProperties().num_descendants_that_draw_content;
// If the layer flattens its subtree (i.e. the layer doesn't preserve-3d), but it is
// treated as a 3D object by its parent (i.e. parent does preserve-3d).
if (layerIsInExisting3DRenderingContext(layer) && !layer->preserves3D() && descendantsDrawContent > 0)
if (layerIsInExisting3DRenderingContext(layer) && !layer->preserves3D() && numDescendantsThatDrawContent > 0)
return true;
// If the layer clips its descendants but it is not axis-aligned with respect to its parent.
if (layerClipsSubtree(layer) && !axisAlignedWithRespectToParent && descendantsDrawContent > 0)
if (layerClipsSubtree(layer) && !axisAlignedWithRespectToParent && numDescendantsThatDrawContent > 0)
return true;
// If the layer has opacity != 1 and does not have a preserves-3d transform style.
if (layer->opacity() != 1 && !layer->preserves3D() && descendantsDrawContent > 0
&& (layer->drawsContent() || descendantsDrawContent > 1))
// If the layer has some translucency and does not have a preserves-3d transform style.
// This condition only needs a render surface if two or more layers in the
// subtree overlap. But checking layer overlaps is unnecessarily costly so
// instead we conservatively create a surface whenever at least two layers
// draw content for this subtree.
bool atLeastTwoLayersInSubtreeDrawContent = layer->hasDelegatedContent() ||
(numDescendantsThatDrawContent > 0 && (layer->drawsContent() || numDescendantsThatDrawContent > 1));
if (layer->opacity() != 1 && !layer->preserves3D() && atLeastTwoLayersInSubtreeDrawContent)
return true;
return false;
@ -424,6 +429,23 @@ static inline void removeSurfaceForEarlyExit(LayerType* layerToRemove, LayerList
layerToRemove->clearRenderSurface();
}
// Recursively walks the layer tree to compute any information that is needed
// before doing the main recursion.
template<typename LayerType>
static void preCalculateMetaInformation(LayerType* layer)
{
int numDescendantsThatDrawContent = 0;
for (size_t i = 0; i < layer->children().size(); ++i) {
LayerType* childLayer = layer->children()[i];
preCalculateMetaInformation<LayerType>(childLayer);
numDescendantsThatDrawContent += childLayer->drawsContent() ? 1 : 0;
numDescendantsThatDrawContent += childLayer->drawProperties().num_descendants_that_draw_content;
}
layer->drawProperties().num_descendants_that_draw_content = numDescendantsThatDrawContent;
}
// 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>
@ -887,7 +909,8 @@ void LayerTreeHostCommon::calculateDrawProperties(Layer* rootLayer, const gfx::S
// This function should have received a root layer.
DCHECK(isRootLayer(rootLayer));
cc::calculateDrawPropertiesInternal<Layer, std::vector<scoped_refptr<Layer> >, RenderSurface>(
preCalculateMetaInformation<Layer>(rootLayer);
calculateDrawPropertiesInternal<Layer, std::vector<scoped_refptr<Layer> >, RenderSurface>(
rootLayer, deviceScaleTransform, identityMatrix, identityMatrix,
deviceViewportRect, deviceViewportRect, subtreeShouldBeClipped, 0, renderSurfaceLayerList,
dummyLayerList, 0, maxTextureSize,
@ -915,7 +938,8 @@ void LayerTreeHostCommon::calculateDrawProperties(LayerImpl* rootLayer, const gf
// This function should have received a root layer.
DCHECK(isRootLayer(rootLayer));
cc::calculateDrawPropertiesInternal<LayerImpl, std::vector<LayerImpl*>, RenderSurfaceImpl>(
preCalculateMetaInformation<LayerImpl>(rootLayer);
calculateDrawPropertiesInternal<LayerImpl, std::vector<LayerImpl*>, RenderSurfaceImpl>(
rootLayer, deviceScaleTransform, identityMatrix, identityMatrix,
deviceViewportRect, deviceViewportRect, subtreeShouldBeClipped, 0, renderSurfaceLayerList,
dummyLayerList, &layerSorter, maxTextureSize,