Title: [113602] trunk/Source
Revision
113602
Author
[email protected]
Date
2012-04-09 11:58:08 -0700 (Mon, 09 Apr 2012)

Log Message

[chromium] Flip transition painting delayed with threaded animations
https://bugs.webkit.org/show_bug.cgi?id=82571

Patch by Dana Jansens <[email protected]> on 2012-04-09
Reviewed by Adrienne Walker.

Source/WebCore:

This allows for prepainting to see and paint layers that are not facing
the camera but have animating transforms. This is needed to prepaint
animations that "flip" layers around to make the front visible.

The changes are to add a backFaceIsVisible() helper function in
CCLTHCommon. This is used like before to cull non-double sided
layers, but culling is prevented on main thread when the screen
space transform is unknown due to animation. We add new
helper methods transformToScreenIsKnown() to identify this.

However the layer is not actually visible, so we set the
visibleLayerRect to be empty in this case.

The calculateVisibleLayerRect needs to use the backFaceIsVisible()
helper, so we move it into the .cpp file where it belongs, and make
it static to the file since it is not used outide of CCLTHCommon.cpp
at all.

Unit test: CCLayerTreeHostCommonTest.verifyBackFaceCulling

* platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
(WebCore):
(WebCore::backFaceIsVisible):
(WebCore::calculateVisibleLayerRect):
(WebCore::layerOpacityIsOpaque):
(WebCore::transformToParentIsKnown):
(WebCore::transformToScreenIsKnown):
(WebCore::layerShouldBeSkipped):
(WebCore::calculateDrawTransformsAndVisibilityInternal):
(WebCore::walkLayersAndCalculateVisibleLayerRects):
* platform/graphics/chromium/cc/CCLayerTreeHostCommon.h:
(WebCore):

Source/WebKit/chromium:

* tests/CCLayerTreeHostCommonTest.cpp:
(WebKitTests::TEST):
(WebKitTests):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (113601 => 113602)


--- trunk/Source/WebCore/ChangeLog	2012-04-09 18:56:26 UTC (rev 113601)
+++ trunk/Source/WebCore/ChangeLog	2012-04-09 18:58:08 UTC (rev 113602)
@@ -1,3 +1,43 @@
+2012-04-09  Dana Jansens  <[email protected]>
+
+        [chromium] Flip transition painting delayed with threaded animations
+        https://bugs.webkit.org/show_bug.cgi?id=82571
+
+        Reviewed by Adrienne Walker.
+
+        This allows for prepainting to see and paint layers that are not facing
+        the camera but have animating transforms. This is needed to prepaint
+        animations that "flip" layers around to make the front visible.
+
+        The changes are to add a backFaceIsVisible() helper function in
+        CCLTHCommon. This is used like before to cull non-double sided
+        layers, but culling is prevented on main thread when the screen
+        space transform is unknown due to animation. We add new
+        helper methods transformToScreenIsKnown() to identify this.
+
+        However the layer is not actually visible, so we set the
+        visibleLayerRect to be empty in this case.
+
+        The calculateVisibleLayerRect needs to use the backFaceIsVisible()
+        helper, so we move it into the .cpp file where it belongs, and make
+        it static to the file since it is not used outide of CCLTHCommon.cpp
+        at all.
+
+        Unit test: CCLayerTreeHostCommonTest.verifyBackFaceCulling
+
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
+        (WebCore):
+        (WebCore::backFaceIsVisible):
+        (WebCore::calculateVisibleLayerRect):
+        (WebCore::layerOpacityIsOpaque):
+        (WebCore::transformToParentIsKnown):
+        (WebCore::transformToScreenIsKnown):
+        (WebCore::layerShouldBeSkipped):
+        (WebCore::calculateDrawTransformsAndVisibilityInternal):
+        (WebCore::walkLayersAndCalculateVisibleLayerRects):
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.h:
+        (WebCore):
+
 2012-04-09  Martin Robinson  <[email protected]>
 
         [GTK] Toggle buttons do not size appropriately in some themes

Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp (113601 => 113602)


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp	2012-04-09 18:56:26 UTC (rev 113601)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp	2012-04-09 18:58:08 UTC (rev 113602)
@@ -42,6 +42,20 @@
 
 namespace WebCore {
 
+template<typename LayerType>
+static inline bool backFaceIsVisible(LayerType* layer)
+{
+    // This is checked by computing the transformed normal of the layer in screen space.
+    FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds()));
+    FloatQuad mappedLayer = layer->screenSpaceTransform().mapQuad(FloatQuad(layerRect));
+    FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1();
+    FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1();
+    FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0);
+    FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0);
+    FloatPoint3D zAxis = xAxis.cross(yAxis);
+    return zAxis.z() < 0;
+}
+
 IntRect CCLayerTreeHostCommon::calculateVisibleRect(const IntRect& targetSurfaceRect, const IntRect& layerBoundRect, const TransformationMatrix& transform)
 {
     // Is this layer fully contained within the target surface?
@@ -65,6 +79,39 @@
     return layerRect;
 }
 
+template<typename LayerType>
+static IntRect calculateVisibleLayerRect(LayerType* layer)
+{
+    ASSERT(layer->targetRenderSurface());
+
+    // Animated layers can exist in the render surface tree that are not visible currently
+    // and have their back face showing. In this case, their visible rect should be empty.
+    if (!layer->doubleSided() && backFaceIsVisible(layer))
+        return IntRect();
+
+    IntRect targetSurfaceRect = layer->targetRenderSurface()->contentRect();
+
+    if (layer->usesLayerClipping())
+        targetSurfaceRect.intersect(layer->clipRect());
+
+    if (targetSurfaceRect.isEmpty() || layer->contentBounds().isEmpty())
+        return targetSurfaceRect;
+
+    // Note carefully these are aliases
+    const IntSize& bounds = layer->bounds();
+    const IntSize& contentBounds = layer->contentBounds();
+
+    const IntRect layerBoundRect = IntRect(IntPoint(), contentBounds);
+    TransformationMatrix transform = layer->drawTransform();
+
+    transform.scaleNonUniform(bounds.width() / static_cast<double>(contentBounds.width()),
+                              bounds.height() / static_cast<double>(contentBounds.height()));
+    transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
+
+    IntRect visibleLayerRect = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerBoundRect, transform);
+    return visibleLayerRect;
+}
+
 static bool isScaleOrTranslation(const TransformationMatrix& m)
 {
     return !m.m12() && !m.m13() && !m.m14()
@@ -73,6 +120,39 @@
            && m.m44();
 }
 
+static inline bool layerOpacityIsOpaque(CCLayerImpl* layer)
+{
+    return layer->opacity() == 1;
+}
+
+static inline bool layerOpacityIsOpaque(LayerChromium* layer)
+{
+    // If the opacity is being animated then the opacity on the main thread is unreliable
+    // (since the impl thread may be using a different opacity), so it should not be trusted.
+    // In particular, it should not be treated as opaque.
+    return layer->opacity() == 1 && !layer->opacityIsAnimating();
+}
+
+static inline bool transformToParentIsKnown(CCLayerImpl*)
+{
+    return true;
+}
+
+static inline bool transformToParentIsKnown(LayerChromium* layer)
+{
+    return !layer->transformIsAnimating();
+}
+
+static inline bool transformToScreenIsKnown(CCLayerImpl*)
+{
+    return true;
+}
+
+static inline bool transformToScreenIsKnown(LayerChromium* layer)
+{
+    return !layer->screenSpaceTransformIsAnimating();
+}
+
 template<typename LayerType>
 static bool layerShouldBeSkipped(LayerType* layer)
 {
@@ -93,19 +173,9 @@
     if (!layer->drawsContent() || layer->bounds().isEmpty())
         return true;
 
-    // The layer should not be drawn if (1) it is not double-sided and (2) the back of the layer is facing the screen.
-    // This second condition is checked by computing the transformed normal of the layer.
-    if (!layer->doubleSided()) {
-        FloatRect layerRect(FloatPoint(0, 0), FloatSize(layer->bounds()));
-        FloatQuad mappedLayer = layer->screenSpaceTransform().mapQuad(FloatQuad(layerRect));
-        FloatSize horizontalDir = mappedLayer.p2() - mappedLayer.p1();
-        FloatSize verticalDir = mappedLayer.p4() - mappedLayer.p1();
-        FloatPoint3D xAxis(horizontalDir.width(), horizontalDir.height(), 0);
-        FloatPoint3D yAxis(verticalDir.width(), verticalDir.height(), 0);
-        FloatPoint3D zAxis = xAxis.cross(yAxis);
-        if (zAxis.z() < 0)
-            return true;
-    }
+    // The layer should not be drawn if (1) it is not double-sided and (2) the back of the layer is known to be facing the screen.
+    if (!layer->doubleSided() && transformToScreenIsKnown(layer) && backFaceIsVisible(layer))
+        return true;
 
     return false;
 }
@@ -126,29 +196,6 @@
     return !layer->opacity() && !layer->opacityIsAnimating();
 }
 
-static inline bool layerOpacityIsOpaque(CCLayerImpl* layer)
-{
-    return layer->opacity() == 1;
-}
-
-static inline bool layerOpacityIsOpaque(LayerChromium* layer)
-{
-    // If the opacity is being animated then the opacity on the main thread is unreliable
-    // (since the impl thread may be using a different opacity), so it should not be trusted.
-    // In particular, it should not be treated as opaque.
-    return layer->opacity() == 1 && !layer->opacityIsAnimating();
-}
-
-static inline bool transformToParentIsKnown(CCLayerImpl*)
-{
-    return true;
-}
-
-static inline bool transformToParentIsKnown(LayerChromium* layer)
-{
-    return !layer->transformIsAnimating();
-}
-
 template<typename LayerType>
 static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlignedWithRespectToParent)
 {
@@ -615,7 +662,7 @@
     CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
     for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
         if (!it.representsTargetRenderSurface()) {
-            IntRect visibleLayerRect = CCLayerTreeHostCommon::calculateVisibleLayerRect<LayerType>(*it);
+            IntRect visibleLayerRect = calculateVisibleLayerRect(*it);
             it->setVisibleLayerRect(visibleLayerRect);
         }
     }

Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.h (113601 => 113602)


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.h	2012-04-09 18:56:26 UTC (rev 113601)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.h	2012-04-09 18:58:08 UTC (rev 113602)
@@ -40,7 +40,6 @@
 class CCLayerTreeHostCommon {
 public:
     static IntRect calculateVisibleRect(const IntRect& targetSurfaceRect, const IntRect& layerBoundRect, const TransformationMatrix&);
-    template<typename LayerType> static IntRect calculateVisibleLayerRect(LayerType*);
 
     static void calculateDrawTransformsAndVisibility(LayerChromium*, LayerChromium* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize);
     static void calculateDrawTransformsAndVisibility(CCLayerImpl*, CCLayerImpl* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter*, int maxTextureSize);
@@ -59,33 +58,6 @@
 };
 
 template<typename LayerType>
-IntRect CCLayerTreeHostCommon::calculateVisibleLayerRect(LayerType* layer)
-{
-    ASSERT(layer->targetRenderSurface());
-    IntRect targetSurfaceRect = layer->targetRenderSurface()->contentRect();
-
-    if (layer->usesLayerClipping())
-        targetSurfaceRect.intersect(layer->clipRect());
-
-    if (targetSurfaceRect.isEmpty() || layer->contentBounds().isEmpty())
-        return targetSurfaceRect;
-
-    // Note carefully these are aliases
-    const IntSize& bounds = layer->bounds();
-    const IntSize& contentBounds = layer->contentBounds();
-
-    const IntRect layerBoundRect = IntRect(IntPoint(), contentBounds);
-    TransformationMatrix transform = layer->drawTransform();
-
-    transform.scaleNonUniform(bounds.width() / static_cast<double>(contentBounds.width()),
-                              bounds.height() / static_cast<double>(contentBounds.height()));
-    transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
-
-    IntRect visibleLayerRect = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerBoundRect, transform);
-    return visibleLayerRect;
-}
-
-template<typename LayerType>
 bool CCLayerTreeHostCommon::renderSurfaceContributesToTarget(LayerType* layer, int targetSurfaceLayerID)
 {
     // A layer will either contribute its own content, or its render surface's content, to

Modified: trunk/Source/WebKit/chromium/ChangeLog (113601 => 113602)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-04-09 18:56:26 UTC (rev 113601)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-04-09 18:58:08 UTC (rev 113602)
@@ -1,3 +1,14 @@
+2012-04-09  Dana Jansens  <[email protected]>
+
+        [chromium] Flip transition painting delayed with threaded animations
+        https://bugs.webkit.org/show_bug.cgi?id=82571
+
+        Reviewed by Adrienne Walker.
+
+        * tests/CCLayerTreeHostCommonTest.cpp:
+        (WebKitTests::TEST):
+        (WebKitTests):
+
 2012-04-09  Sheriff Bot  <[email protected]>
 
         Unreviewed, rolling out r113561.

Modified: trunk/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp (113601 => 113602)


--- trunk/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp	2012-04-09 18:56:26 UTC (rev 113601)
+++ trunk/Source/WebKit/chromium/tests/CCLayerTreeHostCommonTest.cpp	2012-04-09 18:58:08 UTC (rev 113602)
@@ -1238,6 +1238,93 @@
     EXPECT_INT_RECT_EQ(expected, actual);
 }
 
+TEST(CCLayerTreeHostCommonTest, verifyBackFaceCulling)
+{
+    // Verify that layers are appropriately culled when their back face is showing and they are not double sided.
+    //
+    // Layers that are animating do not get culled on the main thread, as their transforms should be
+    // treated as "unknown" so we can not be sure that their back face is really showing.
+    //
+
+    const TransformationMatrix identityMatrix;
+    RefPtr<LayerChromium> parent = LayerChromium::create();
+    RefPtr<LayerChromiumWithForcedDrawsContent> child = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> animatingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> childOfAnimatingSurface = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> animatingChild = adoptRef(new LayerChromiumWithForcedDrawsContent());
+    RefPtr<LayerChromiumWithForcedDrawsContent> child2 = adoptRef(new LayerChromiumWithForcedDrawsContent());
+
+    parent->createRenderSurface();
+    parent->addChild(child);
+    parent->addChild(animatingSurface);
+    animatingSurface->addChild(childOfAnimatingSurface);
+    parent->addChild(animatingChild);
+    parent->addChild(child2);
+
+    // Nothing is double-sided
+    child->setDoubleSided(false);
+    child2->setDoubleSided(false);
+    animatingSurface->setDoubleSided(false);
+    childOfAnimatingSurface->setDoubleSided(false);
+    animatingChild->setDoubleSided(false);
+
+    TransformationMatrix backfaceMatrix;
+    backfaceMatrix.translate(50, 50);
+    backfaceMatrix.rotate3d(0, 1, 0, 180);
+    backfaceMatrix.translate(-50, -50);
+
+    // Having a descendent, and animating transforms, will make the animatingSurface own a render surface.
+    addAnimatedTransformToController(*animatingSurface->layerAnimationController(), 10, 30, 0);
+    // This is just an animating layer, not a surface.
+    addAnimatedTransformToController(*animatingChild->layerAnimationController(), 10, 30, 0);
+
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), true);
+    setLayerPropertiesForTesting(child.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false);
+    setLayerPropertiesForTesting(animatingSurface.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false);
+    setLayerPropertiesForTesting(childOfAnimatingSurface.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false);
+    setLayerPropertiesForTesting(animatingChild.get(), backfaceMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false);
+    setLayerPropertiesForTesting(child2.get(), identityMatrix, identityMatrix, FloatPoint(0, 0), FloatPoint(0, 0), IntSize(100, 100), false);
+
+    Vector<RefPtr<LayerChromium> > renderSurfaceLayerList;
+    Vector<RefPtr<LayerChromium> > dummyLayerList;
+    int dummyMaxTextureSize = 512;
+
+    parent->renderSurface()->setContentRect(IntRect(IntPoint(), parent->bounds()));
+    parent->setClipRect(IntRect(IntPoint::zero(), parent->bounds()));
+    renderSurfaceLayerList.append(parent.get());
+
+    CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(parent.get(), parent.get(), identityMatrix, identityMatrix, renderSurfaceLayerList, dummyLayerList, dummyMaxTextureSize);
+
+    EXPECT_FALSE(child->renderSurface());
+    EXPECT_TRUE(animatingSurface->renderSurface());
+    EXPECT_FALSE(childOfAnimatingSurface->renderSurface());
+    EXPECT_FALSE(animatingChild->renderSurface());
+    EXPECT_FALSE(child2->renderSurface());
+
+    // Verify that the animatingChild and childOfAnimatingSurface were not culled, but that child was.
+    ASSERT_EQ(2u, renderSurfaceLayerList.size());
+    EXPECT_EQ(parent->id(), renderSurfaceLayerList[0]->id());
+    EXPECT_EQ(animatingSurface->id(), renderSurfaceLayerList[1]->id());
+
+    // The non-animating child be culled from the layer list for the parent render surface.
+    ASSERT_EQ(3u, renderSurfaceLayerList[0]->renderSurface()->layerList().size());
+    EXPECT_EQ(animatingSurface->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[0]->id());
+    EXPECT_EQ(animatingChild->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[1]->id());
+    EXPECT_EQ(child2->id(), renderSurfaceLayerList[0]->renderSurface()->layerList()[2]->id());
+
+    ASSERT_EQ(2u, renderSurfaceLayerList[1]->renderSurface()->layerList().size());
+    EXPECT_EQ(animatingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[0]->id());
+    EXPECT_EQ(childOfAnimatingSurface->id(), renderSurfaceLayerList[1]->renderSurface()->layerList()[1]->id());
+
+    EXPECT_FALSE(child2->visibleLayerRect().isEmpty());
+
+    // But if the back face is visible, then the visibleLayerRect should be empty.
+    EXPECT_TRUE(animatingChild->visibleLayerRect().isEmpty());
+    EXPECT_TRUE(animatingSurface->visibleLayerRect().isEmpty());
+    // And any layers in the subtree should not be considered visible either.
+    EXPECT_TRUE(childOfAnimatingSurface->visibleLayerRect().isEmpty());
+}
+
 // FIXME:
 // continue working on https://bugs.webkit.org/show_bug.cgi?id=68942
 //  - add a test to verify clipping that changes the "center point"
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to