Title: [115386] trunk/Source
Revision
115386
Author
[email protected]
Date
2012-04-26 17:00:27 -0700 (Thu, 26 Apr 2012)

Log Message

Source/WebCore: Re-implement backFaceVisibility to avoid dealing with perspective w < 0 problem
https://bugs.webkit.org/show_bug.cgi?id=84059

Reviewed by Adrienne Walker.

Unit tests added to CCMathUtilTest.cpp.

This patch changes the implementation of backFaceIsVisible so that
it doesn't need to deal with the w < 0 problem from of perspective
projections. Instead, it is equally correct to simply use the
inverse-transpose of the matrix, and quickly check the third row,
third column element. Additionally, it was appropriate to move
this function into TransformationMatrix itself.

Making this change fixes some issues related to disappearing
layers in Chromium (where the compositor incorrectly thought that
the back face was visible, and skipped the layer).

* platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
(WebCore::calculateVisibleLayerRect):
(WebCore::layerShouldBeSkipped):
* platform/graphics/transforms/TransformationMatrix.cpp:
(WebCore::TransformationMatrix::isBackFaceVisible):
(WebCore):
* platform/graphics/transforms/TransformationMatrix.h:
(TransformationMatrix):

Source/WebKit/chromium: [chromium] re-implement backFaceVisibility to avoid dealing with perspective w<0 problem
https://bugs.webkit.org/show_bug.cgi?id=84059

Reviewed by Adrienne Walker.

* WebKit.gypi:
* tests/CCMathUtilTest.cpp: Added.
(WebCore):
(WebCore::TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (115385 => 115386)


--- trunk/Source/WebCore/ChangeLog	2012-04-26 23:03:06 UTC (rev 115385)
+++ trunk/Source/WebCore/ChangeLog	2012-04-27 00:00:27 UTC (rev 115386)
@@ -1,3 +1,32 @@
+2012-04-26  Shawn Singh  <[email protected]>
+
+        Re-implement backFaceVisibility to avoid dealing with perspective w < 0 problem
+        https://bugs.webkit.org/show_bug.cgi?id=84059
+
+        Reviewed by Adrienne Walker.
+
+        Unit tests added to CCMathUtilTest.cpp.
+
+        This patch changes the implementation of backFaceIsVisible so that
+        it doesn't need to deal with the w < 0 problem from of perspective
+        projections. Instead, it is equally correct to simply use the
+        inverse-transpose of the matrix, and quickly check the third row,
+        third column element. Additionally, it was appropriate to move
+        this function into TransformationMatrix itself.
+
+        Making this change fixes some issues related to disappearing
+        layers in Chromium (where the compositor incorrectly thought that
+        the back face was visible, and skipped the layer).
+
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
+        (WebCore::calculateVisibleLayerRect):
+        (WebCore::layerShouldBeSkipped):
+        * platform/graphics/transforms/TransformationMatrix.cpp:
+        (WebCore::TransformationMatrix::isBackFaceVisible):
+        (WebCore):
+        * platform/graphics/transforms/TransformationMatrix.h:
+        (TransformationMatrix):
+
 2012-04-26  Martin Robinson  <[email protected]>
 
         [Cairo] Wrap cairo surfaces in a class when storing native images

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


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp	2012-04-26 23:03:06 UTC (rev 115385)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp	2012-04-27 00:00:27 UTC (rev 115386)
@@ -42,20 +42,6 @@
 
 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?
@@ -86,7 +72,7 @@
 
     // 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))
+    if (!layer->doubleSided() && layer->screenSpaceTransform().isBackFaceVisible())
         return IntRect();
 
     IntRect targetSurfaceRect = layer->targetRenderSurface()->contentRect();
@@ -174,7 +160,7 @@
         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))
+    if (!layer->doubleSided() && transformToScreenIsKnown(layer) && layer->screenSpaceTransform().isBackFaceVisible())
         return true;
 
     return false;

Modified: trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp (115385 => 115386)


--- trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp	2012-04-26 23:03:06 UTC (rev 115385)
+++ trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp	2012-04-27 00:00:27 UTC (rev 115386)
@@ -1224,4 +1224,32 @@
     result[15] = m44();
 }
 
+bool TransformationMatrix::isBackFaceVisible() const
+{
+    // Back-face visibility is determined by transforming the normal vector (0, 0, 1) and
+    // checking the sign of the resulting z component. However, normals cannot be
+    // transformed by the original matrix, they require being transformed by the
+    // inverse-transpose.
+    //
+    // Since we know we will be using (0, 0, 1), and we only care about the z-component of
+    // the transformed normal, then we only need the m33() element of the
+    // inverse-transpose. Therefore we do not need the transpose.
+    //
+    // Additionally, if we only need the m33() element, we do not need to compute a full
+    // inverse. Instead, knowing the inverse of a matrix is adjoint(matrix) / determinant,
+    // we can simply compute the m33() of the adjoint (adjugate) matrix, without computing
+    // the full adjoint.
+
+    double determinant = WebCore::determinant4x4(m_matrix);
+
+    // If the matrix is not invertible, then we assume its backface is not visible.
+    if (fabs(determinant) < SMALL_NUMBER)
+        return false;
+
+    double cofactor33 = determinant3x3(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
+    double zComponentOfTransformedNormal = cofactor33 / determinant;
+
+    return zComponentOfTransformedNormal < 0;
 }
+
+}

Modified: trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h (115385 => 115386)


--- trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h	2012-04-26 23:03:06 UTC (rev 115385)
+++ trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h	2012-04-27 00:00:27 UTC (rev 115386)
@@ -360,6 +360,12 @@
     typedef float FloatMatrix4[16];
     void toColumnMajorFloatArray(FloatMatrix4& result) const;
 
+    // A local-space layer is implicitly defined at the z = 0 plane, with its front side
+    // facing the positive z-axis (i.e. a camera looking along the negative z-axis sees
+    // the front side of the layer). This function checks if the transformed layer's back
+    // face would be visible to a camera looking along the negative z-axis in the target space.
+    bool isBackFaceVisible() const;
+
 private:
     // multiply passed 2D point by matrix (assume z=0)
     void multVecMatrix(double x, double y, double& dstX, double& dstY) const;

Modified: trunk/Source/WebKit/chromium/ChangeLog (115385 => 115386)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-04-26 23:03:06 UTC (rev 115385)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-04-27 00:00:27 UTC (rev 115386)
@@ -1,3 +1,15 @@
+2012-04-26  Shawn Singh  <[email protected]>
+
+        [chromium] re-implement backFaceVisibility to avoid dealing with perspective w<0 problem
+        https://bugs.webkit.org/show_bug.cgi?id=84059
+
+        Reviewed by Adrienne Walker.
+
+        * WebKit.gypi:
+        * tests/CCMathUtilTest.cpp: Added.
+        (WebCore):
+        (WebCore::TEST):
+
 2012-04-26  Justin Novosad  <[email protected]>
 
         [Chromium] Single buffered canvas layers with the threaded compositor

Modified: trunk/Source/WebKit/chromium/WebKit.gypi (115385 => 115386)


--- trunk/Source/WebKit/chromium/WebKit.gypi	2012-04-26 23:03:06 UTC (rev 115385)
+++ trunk/Source/WebKit/chromium/WebKit.gypi	2012-04-27 00:00:27 UTC (rev 115386)
@@ -78,6 +78,7 @@
             'tests/CCLayerTreeHostImplTest.cpp',
             'tests/CCLayerTreeHostTest.cpp',
             'tests/CCLayerTreeTestCommon.h',
+            'tests/CCMathUtilTest.cpp',
             'tests/CCOcclusionTrackerTest.cpp',
             'tests/CCOcclusionTrackerTestCommon.h',
             'tests/CCQuadCullerTest.cpp',

Added: trunk/Source/WebKit/chromium/tests/CCMathUtilTest.cpp (0 => 115386)


--- trunk/Source/WebKit/chromium/tests/CCMathUtilTest.cpp	                        (rev 0)
+++ trunk/Source/WebKit/chromium/tests/CCMathUtilTest.cpp	2012-04-27 00:00:27 UTC (rev 115386)
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "cc/CCMathUtil.h"
+
+#include "TransformationMatrix.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace WebCore;
+
+namespace {
+
+TEST(CCMathUtilTest, verifyBackfaceVisibilityBasicCases)
+{
+    TransformationMatrix transform;
+
+    transform.makeIdentity();
+    EXPECT_FALSE(transform.isBackFaceVisible());
+
+    transform.makeIdentity();
+    transform.rotate3d(0, 80, 0);
+    EXPECT_FALSE(transform.isBackFaceVisible());
+
+    transform.makeIdentity();
+    transform.rotate3d(0, 100, 0);
+    EXPECT_TRUE(transform.isBackFaceVisible());
+
+    // Edge case, 90 degree rotation should return false.
+    transform.makeIdentity();
+    transform.rotate3d(0, 90, 0);
+    EXPECT_FALSE(transform.isBackFaceVisible());
+}
+
+TEST(CCMathUtilTest, verifyBackfaceVisibilityForPerspective)
+{
+    TransformationMatrix layerSpaceToProjectionPlane;
+
+    // This tests if isBackFaceVisible works properly under perspective transforms.
+    // Specifically, layers that may have their back face visible in orthographic
+    // projection, may not actually have back face visible under perspective projection.
+
+    // Case 1: Layer is rotated by slightly more than 90 degrees, at the center of the
+    //         prespective projection. In this case, the layer's back-side is visible to
+    //         the camera.
+    layerSpaceToProjectionPlane.makeIdentity();
+    layerSpaceToProjectionPlane.applyPerspective(1);
+    layerSpaceToProjectionPlane.translate3d(0, 0, 0);
+    layerSpaceToProjectionPlane.rotate3d(0, 100, 0);
+    EXPECT_TRUE(layerSpaceToProjectionPlane.isBackFaceVisible());
+
+    // Case 2: Layer is rotated by slightly more than 90 degrees, but shifted off to the
+    //         side of the camera. Because of the wide field-of-view, the layer's front
+    //         side is still visible.
+    //
+    //                       |<-- front side of layer is visible to perspective camera
+    //                    \  |            /
+    //                     \ |           /
+    //                      \|          /
+    //                       |         /
+    //                       |\       /<-- camera field of view
+    //                       | \     /
+    // back side of layer -->|  \   /
+    //                           \./ <-- camera origin
+    //
+    layerSpaceToProjectionPlane.makeIdentity();
+    layerSpaceToProjectionPlane.applyPerspective(1);
+    layerSpaceToProjectionPlane.translate3d(-10, 0, 0);
+    layerSpaceToProjectionPlane.rotate3d(0, 100, 0);
+    EXPECT_FALSE(layerSpaceToProjectionPlane.isBackFaceVisible());
+
+    // Case 3: Additionally rotating the layer by 180 degrees should of course show the
+    //         opposite result of case 2.
+    layerSpaceToProjectionPlane.rotate3d(0, 180, 0);
+    EXPECT_TRUE(layerSpaceToProjectionPlane.isBackFaceVisible());
+}
+
+} // namespace
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to