Commit 889b2a80 authored by trchen's avatar trchen Committed by Commit bot

Add effect node support in PaintArtifactCompositor for layer list mode [4/4]

This CL adds a local EffectStack class similar to ClipManager, that keep track
of effect state and assign generated cc effect node to layers. This is only
used for layer list mode.

BUG=609937

Review-Url: https://codereview.chromium.org/2052763002
Cr-Commit-Position: refs/heads/master@{#404575}
parent 95066c78
......@@ -345,14 +345,27 @@ class PropertyTreeManager {
public:
PropertyTreeManager(cc::PropertyTrees& propertyTrees, cc::Layer* rootLayer)
: m_propertyTrees(propertyTrees)
, m_rootLayer(rootLayer) {}
, m_rootLayer(rootLayer)
#if DCHECK_IS_ON()
, m_isFirstEffectEver(true)
#endif
{
m_effectStack.append(BlinkEffectAndCcIdPair{nullptr, kSecondaryRootNodeId});
}
int compositorIdForTransformNode(const TransformPaintPropertyNode*);
int compositorIdForClipNode(const ClipPaintPropertyNode*);
int switchToEffectNode(const EffectPaintPropertyNode& nextEffect);
int compositorIdForCurrentEffectNode() const { return m_effectStack.last().id; }
private:
void buildEffectNodesRecursively(const EffectPaintPropertyNode* nextEffect);
cc::TransformTree& transformTree() { return m_propertyTrees.transform_tree; }
cc::ClipTree& clipTree() { return m_propertyTrees.clip_tree; }
cc::EffectTree& effectTree() { return m_propertyTrees.effect_tree; }
const EffectPaintPropertyNode* currentEffectNode() const { return m_effectStack.last().effect; }
// Property trees which should be updated by the manager.
cc::PropertyTrees& m_propertyTrees;
......@@ -364,6 +377,17 @@ private:
// Maps from Blink-side property tree nodes to cc property node indices.
HashMap<const TransformPaintPropertyNode*, int> m_transformNodeMap;
HashMap<const ClipPaintPropertyNode*, int> m_clipNodeMap;
struct BlinkEffectAndCcIdPair {
const EffectPaintPropertyNode* effect;
int id;
};
Vector<BlinkEffectAndCcIdPair> m_effectStack;
#if DCHECK_IS_ON()
HashSet<const EffectPaintPropertyNode*> m_effectNodesConverted;
bool m_isFirstEffectEver;
#endif
};
int PropertyTreeManager::compositorIdForTransformNode(const TransformPaintPropertyNode* transformNode)
......@@ -442,6 +466,91 @@ int PropertyTreeManager::compositorIdForClipNode(const ClipPaintPropertyNode* cl
return id;
}
unsigned depth(const EffectPaintPropertyNode* node)
{
unsigned result = 0;
for (; node; node = node->parent())
result++;
return result;
}
const EffectPaintPropertyNode* lowestCommonAncestor(const EffectPaintPropertyNode* nodeA, const EffectPaintPropertyNode* nodeB)
{
// Optimized common case.
if (nodeA == nodeB)
return nodeA;
unsigned depthA = depth(nodeA), depthB = depth(nodeB);
while (depthA > depthB) {
nodeA = nodeA->parent();
depthA--;
}
while (depthB > depthA) {
nodeB = nodeB->parent();
depthB--;
}
DCHECK_EQ(depthA, depthB);
while (nodeA != nodeB) {
nodeA = nodeA->parent();
nodeB = nodeB->parent();
}
return nodeA;
}
int PropertyTreeManager::switchToEffectNode(const EffectPaintPropertyNode& nextEffect)
{
const EffectPaintPropertyNode* ancestor = lowestCommonAncestor(currentEffectNode(), &nextEffect);
while (currentEffectNode() != ancestor)
m_effectStack.removeLast();
#if DCHECK_IS_ON()
DCHECK(m_isFirstEffectEver || currentEffectNode()) << "Malformed effect tree. Nodes in the same property tree should have common root.";
m_isFirstEffectEver = false;
#endif
buildEffectNodesRecursively(&nextEffect);
return compositorIdForCurrentEffectNode();
}
void PropertyTreeManager::buildEffectNodesRecursively(const EffectPaintPropertyNode* nextEffect)
{
if (nextEffect == currentEffectNode())
return;
DCHECK(nextEffect);
buildEffectNodesRecursively(nextEffect->parent());
DCHECK_EQ(nextEffect->parent(), currentEffectNode());
#if DCHECK_IS_ON()
DCHECK(!m_effectNodesConverted.contains(nextEffect)) << "Malformed paint artifact. Paint chunks under the same effect should be contiguous.";
m_effectNodesConverted.add(nextEffect);
#endif
// We currently create dummy layers to host effect nodes and corresponding render surface.
// This should be removed once cc implements better support for freestanding property trees.
scoped_refptr<cc::Layer> dummyLayer = cc::Layer::Create();
m_rootLayer->AddChild(dummyLayer);
// Also cc assumes a clip node is always created by a layer that creates render surface.
cc::ClipNode& dummyClip = *clipTree().Node(clipTree().Insert(cc::ClipNode(), kSecondaryRootNodeId));
dummyClip.owner_id = dummyLayer->id();
dummyClip.transform_id = kRealRootNodeId;
dummyClip.target_transform_id = kRealRootNodeId;
cc::EffectNode& effectNode = *effectTree().Node(effectTree().Insert(cc::EffectNode(), compositorIdForCurrentEffectNode()));
effectNode.owner_id = dummyLayer->id();
effectNode.clip_id = dummyClip.id;
effectNode.has_render_surface = true;
effectNode.opacity = nextEffect->opacity();
m_effectStack.append(BlinkEffectAndCcIdPair{nextEffect, effectNode.id});
dummyLayer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
dummyLayer->SetTransformTreeIndex(kSecondaryRootNodeId);
dummyLayer->SetClipTreeIndex(dummyClip.id);
dummyLayer->SetEffectTreeIndex(effectNode.id);
dummyLayer->SetScrollTreeIndex(kRealRootNodeId);
}
} // namespace
void PaintArtifactCompositor::updateInLayerListMode(const PaintArtifact& paintArtifact)
......@@ -465,6 +574,7 @@ void PaintArtifactCompositor::updateInLayerListMode(const PaintArtifact& paintAr
int transformId = propertyTreeManager.compositorIdForTransformNode(paintChunk.properties.transform.get());
int clipId = propertyTreeManager.compositorIdForClipNode(paintChunk.properties.clip.get());
int effectId = propertyTreeManager.switchToEffectNode(*paintChunk.properties.effect.get());
layer->set_offset_to_transform_parent(layerOffset);
......@@ -472,7 +582,7 @@ void PaintArtifactCompositor::updateInLayerListMode(const PaintArtifact& paintAr
layer->set_property_tree_sequence_number(kPropertyTreeSequenceNumber);
layer->SetTransformTreeIndex(transformId);
layer->SetClipTreeIndex(clipId);
layer->SetEffectTreeIndex(kSecondaryRootNodeId);
layer->SetEffectTreeIndex(effectId);
layer->SetScrollTreeIndex(kRealRootNodeId);
if (m_extraDataForTestingEnabled)
......
......@@ -9,9 +9,11 @@
#include "cc/layers/layer.h"
#include "cc/test/fake_output_surface.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_settings.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/graphics/paint/EffectPaintPropertyNode.h"
#include "platform/graphics/paint/PaintArtifact.h"
#include "platform/testing/PictureMatchers.h"
#include "platform/testing/TestPaintArtifact.h"
......@@ -33,6 +35,12 @@ gfx::Transform translation(SkMScalar x, SkMScalar y)
return transform;
}
EffectPaintPropertyNode* dummyRootEffect()
{
DEFINE_STATIC_REF(EffectPaintPropertyNode, node, EffectPaintPropertyNode::create(1.0));
return node;
}
class PaintArtifactCompositorTest : public ::testing::Test {
protected:
void SetUp() override
......@@ -97,11 +105,11 @@ TEST_F(PaintArtifactCompositorTest, OneTransform)
TransformationMatrix().rotate(90), FloatPoint3D(100, 100, 0));
TestPaintArtifact artifact;
artifact.chunk(transform, nullptr, nullptr)
artifact.chunk(transform, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::white);
artifact.chunk(nullptr, nullptr, nullptr)
artifact.chunk(nullptr, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::gray);
artifact.chunk(transform, nullptr, nullptr)
artifact.chunk(transform, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(100, 100, 200, 100), Color::black);
update(artifact.build());
......@@ -139,9 +147,9 @@ TEST_F(PaintArtifactCompositorTest, TransformCombining)
TransformationMatrix().translate(5, 5), FloatPoint3D(), transform1);
TestPaintArtifact artifact;
artifact.chunk(transform1, nullptr, nullptr)
artifact.chunk(transform1, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 300, 200), Color::white);
artifact.chunk(transform2, nullptr, nullptr)
artifact.chunk(transform2, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 300, 200), Color::black);
update(artifact.build());
......@@ -223,13 +231,13 @@ TEST_F(PaintArtifactCompositorTest, NestedClips)
nullptr, FloatRoundedRect(200, 200, 700, 100), clip1);
TestPaintArtifact artifact;
artifact.chunk(nullptr, clip1, nullptr)
artifact.chunk(nullptr, clip1, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::white);
artifact.chunk(nullptr, clip2, nullptr)
artifact.chunk(nullptr, clip2, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::lightGray);
artifact.chunk(nullptr, clip1, nullptr)
artifact.chunk(nullptr, clip1, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::darkGray);
artifact.chunk(nullptr, clip2, nullptr)
artifact.chunk(nullptr, clip2, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::black);
update(artifact.build());
......@@ -449,11 +457,11 @@ TEST_F(PaintArtifactCompositorTestWithPropertyTrees, OneTransform)
TransformationMatrix().rotate(90), FloatPoint3D(100, 100, 0));
TestPaintArtifact artifact;
artifact.chunk(transform, nullptr, nullptr)
artifact.chunk(transform, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::white);
artifact.chunk(nullptr, nullptr, nullptr)
artifact.chunk(nullptr, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::gray);
artifact.chunk(transform, nullptr, nullptr)
artifact.chunk(transform, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(100, 100, 200, 100), Color::black);
update(artifact.build());
......@@ -491,9 +499,9 @@ TEST_F(PaintArtifactCompositorTestWithPropertyTrees, TransformCombining)
TransformationMatrix().translate(5, 5), FloatPoint3D(), transform1);
TestPaintArtifact artifact;
artifact.chunk(transform1, nullptr, nullptr)
artifact.chunk(transform1, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 300, 200), Color::white);
artifact.chunk(transform2, nullptr, nullptr)
artifact.chunk(transform2, nullptr, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 300, 200), Color::black);
update(artifact.build());
......@@ -549,13 +557,13 @@ TEST_F(PaintArtifactCompositorTestWithPropertyTrees, NestedClips)
nullptr, FloatRoundedRect(200, 200, 700, 100), clip1);
TestPaintArtifact artifact;
artifact.chunk(nullptr, clip1, nullptr)
artifact.chunk(nullptr, clip1, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::white);
artifact.chunk(nullptr, clip2, nullptr)
artifact.chunk(nullptr, clip2, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::lightGray);
artifact.chunk(nullptr, clip1, nullptr)
artifact.chunk(nullptr, clip1, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::darkGray);
artifact.chunk(nullptr, clip2, nullptr)
artifact.chunk(nullptr, clip2, dummyRootEffect())
.rectDrawing(FloatRect(300, 350, 100, 100), Color::black);
update(artifact.build());
......@@ -605,7 +613,7 @@ TEST_F(PaintArtifactCompositorTestWithPropertyTrees, DeeplyNestedClips)
}
TestPaintArtifact artifact;
artifact.chunk(nullptr, clips.last(), nullptr)
artifact.chunk(nullptr, clips.last(), dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 200, 200), Color::white);
update(artifact.build());
......@@ -637,9 +645,9 @@ TEST_F(PaintArtifactCompositorTestWithPropertyTrees, SiblingClips)
nullptr, FloatRoundedRect(400, 0, 400, 600), commonClip);
TestPaintArtifact artifact;
artifact.chunk(nullptr, clip1, nullptr)
artifact.chunk(nullptr, clip1, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 640, 480), Color::white);
artifact.chunk(nullptr, clip2, nullptr)
artifact.chunk(nullptr, clip2, dummyRootEffect())
.rectDrawing(FloatRect(0, 0, 640, 480), Color::black);
update(artifact.build());
......@@ -685,5 +693,47 @@ TEST_F(PaintArtifactCompositorTestWithPropertyTrees, ForeignLayerPassesThrough)
EXPECT_EQ(translation(50, 100), layer->screen_space_transform());
}
TEST_F(PaintArtifactCompositorTestWithPropertyTrees, EffectTreeConversion)
{
RefPtr<EffectPaintPropertyNode> effect1 = EffectPaintPropertyNode::create(0.5, dummyRootEffect());
RefPtr<EffectPaintPropertyNode> effect2 = EffectPaintPropertyNode::create(0.3, effect1.get());
RefPtr<EffectPaintPropertyNode> effect3 = EffectPaintPropertyNode::create(0.2, dummyRootEffect());
TestPaintArtifact artifact;
artifact.chunk(nullptr, nullptr, effect2.get())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::white);
artifact.chunk(nullptr, nullptr, effect1.get())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::white);
artifact.chunk(nullptr, nullptr, effect3.get())
.rectDrawing(FloatRect(0, 0, 100, 100), Color::white);
update(artifact.build());
ASSERT_EQ(3u, contentLayerCount());
const cc::EffectTree& effectTree = propertyTrees().effect_tree;
// Node #0 reserved for null; #1 for root render surface; #2 for dummyRootEffect,
// plus 3 nodes for those created by this test.
ASSERT_EQ(6u, effectTree.size());
const cc::EffectNode& convertedDummyRootEffect = *effectTree.Node(2);
EXPECT_EQ(1, convertedDummyRootEffect.parent_id);
const cc::EffectNode& convertedEffect1 = *effectTree.Node(3);
EXPECT_EQ(convertedDummyRootEffect.id, convertedEffect1.parent_id);
EXPECT_FLOAT_EQ(0.5, convertedEffect1.opacity);
const cc::EffectNode& convertedEffect2 = *effectTree.Node(4);
EXPECT_EQ(convertedEffect1.id, convertedEffect2.parent_id);
EXPECT_FLOAT_EQ(0.3, convertedEffect2.opacity);
const cc::EffectNode& convertedEffect3 = *effectTree.Node(5);
EXPECT_EQ(convertedDummyRootEffect.id, convertedEffect3.parent_id);
EXPECT_FLOAT_EQ(0.2, convertedEffect3.opacity);
EXPECT_EQ(convertedEffect2.id, contentLayerAt(0)->effect_tree_index());
EXPECT_EQ(convertedEffect1.id, contentLayerAt(1)->effect_tree_index());
EXPECT_EQ(convertedEffect3.id, contentLayerAt(2)->effect_tree_index());
}
} // namespace
} // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment