Title: [113561] trunk/Source
Revision
113561
Author
[email protected]
Date
2012-04-09 02:05:50 -0700 (Mon, 09 Apr 2012)

Log Message

[chromium] Make culling work with clipped rects
https://bugs.webkit.org/show_bug.cgi?id=83217

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

Source/WebCore:

Use new CCMathUtil transformation methods to deal with rects that clip
the camera plane. This fixes three things:

1. A layer completely behind the camera is not visible and should not
occlude.
2. A layer that is clipped by the camera is treated like a
non-axis-aligned transform, as the result of a mapClippedRect() is a
bounding box and may contain pixels not in the original rect. This guards
our use of mapRect() when transforming occluded regions.
3. A layer's occlusion must be clipped by its scissor rect. This scissor
rect exists in its target space, so occlusion in screen space is only
possible if its target also is axis aligned in the screen, such that
the layer's scissor rect remains a rect in screen space.

Unit tests: CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude
            CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect

* platform/graphics/chromium/cc/CCOcclusionTracker.cpp:
(WebCore::transformSurfaceOpaqueRegion):
(WebCore::computeOcclusionBehindLayer):
(WebCore::::markOccludedBehindLayer):
(WebCore::testContentRectOccluded):
(WebCore::computeUnoccludedContentRect):

Source/WebKit/chromium:

* tests/CCOcclusionTrackerTest.cpp:
(CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude):
(WebKitTests::CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude::runMyTest):
(WebKitTests):
(CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect):
(WebKitTests::CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect::runMyTest):
* tests/CCQuadCullerTest.cpp:
(WebCore::TestCCOcclusionTrackerImpl::TestCCOcclusionTrackerImpl):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (113560 => 113561)


--- trunk/Source/WebCore/ChangeLog	2012-04-09 08:49:02 UTC (rev 113560)
+++ trunk/Source/WebCore/ChangeLog	2012-04-09 09:05:50 UTC (rev 113561)
@@ -1,3 +1,34 @@
+2012-04-09  Dana Jansens  <[email protected]>
+
+        [chromium] Make culling work with clipped rects
+        https://bugs.webkit.org/show_bug.cgi?id=83217
+
+        Reviewed by Adrienne Walker.
+
+        Use new CCMathUtil transformation methods to deal with rects that clip
+        the camera plane. This fixes three things:
+
+        1. A layer completely behind the camera is not visible and should not
+        occlude.
+        2. A layer that is clipped by the camera is treated like a
+        non-axis-aligned transform, as the result of a mapClippedRect() is a
+        bounding box and may contain pixels not in the original rect. This guards
+        our use of mapRect() when transforming occluded regions.
+        3. A layer's occlusion must be clipped by its scissor rect. This scissor
+        rect exists in its target space, so occlusion in screen space is only
+        possible if its target also is axis aligned in the screen, such that
+        the layer's scissor rect remains a rect in screen space.
+
+        Unit tests: CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude
+                    CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect
+
+        * platform/graphics/chromium/cc/CCOcclusionTracker.cpp:
+        (WebCore::transformSurfaceOpaqueRegion):
+        (WebCore::computeOcclusionBehindLayer):
+        (WebCore::::markOccludedBehindLayer):
+        (WebCore::testContentRectOccluded):
+        (WebCore::computeUnoccludedContentRect):
+
 2012-04-09  Zan Dobersek  <[email protected]>
 
         [Gtk] Web Inspector noinst_DATA images are copied into innacurately named directory

Modified: trunk/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp (113560 => 113561)


--- trunk/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp	2012-04-09 08:49:02 UTC (rev 113560)
+++ trunk/Source/WebCore/platform/graphics/chromium/cc/CCOcclusionTracker.cpp	2012-04-09 09:05:50 UTC (rev 113561)
@@ -115,13 +115,16 @@
     // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then
     // apply |transform| to each rect within |region| in order to transform the entire Region.
 
-    FloatQuad transformedBoundsQuad = transform.mapQuad(FloatQuad(region.bounds()));
-    if (!transformedBoundsQuad.isRectilinear())
+    bool clipped;
+    FloatQuad transformedBoundsQuad = CCMathUtil::mapQuad(transform, FloatQuad(region.bounds()), clipped);
+    // FIXME: Find a rect interior to each transformed quad.
+    if (clipped || !transformedBoundsQuad.isRectilinear())
         return Region();
 
     Region transformedRegion;
 
     Vector<IntRect> rects = region.rects();
+    // Clipping has been verified above, so mapRect will give correct results.
     for (size_t i = 0; i < rects.size(); ++i)
         transformedRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(rects[i]))));
     return transformedRegion;
@@ -195,13 +198,15 @@
 
 // FIXME: Remove usePaintTracking when paint tracking is on for paint culling.
 template<typename LayerType>
-static inline Region computeOcclusionBehindLayer(const LayerType* layer, const TransformationMatrix& transform, bool usePaintTracking)
+static inline Region computeOcclusionBehindLayer(const LayerType* layer, const TransformationMatrix& transform, const IntRect& scissorRect, bool usePaintTracking)
 {
     Region opaqueRegion;
 
-    FloatQuad unoccludedQuad = transform.mapQuad(FloatQuad(layer->visibleLayerRect()));
+    bool clipped;
+    FloatQuad unoccludedQuad = CCMathUtil::mapQuad(transform, FloatQuad(layer->visibleLayerRect()), clipped);
     bool isPaintedAxisAligned = unoccludedQuad.isRectilinear();
-    if (!isPaintedAxisAligned)
+    // FIXME: Find a rect interior to each transformed quad.
+    if (clipped || !isPaintedAxisAligned)
         return opaqueRegion;
 
     if (layer->opaque())
@@ -211,9 +216,11 @@
     else if (usePaintTracking) {
         Region contentRegion = layer->visibleContentOpaqueRegion();
         Vector<IntRect> contentRects = contentRegion.rects();
+        // We verify that the possible bounds of this region are not clipped above, so we can use mapRect() safely here.
         for (size_t i = 0; i < contentRects.size(); ++i)
             opaqueRegion.unite(enclosedIntRect(transform.mapRect(FloatRect(contentRects[i]))));
     }
+    opaqueRegion.intersect(scissorRect);
     return opaqueRegion;
 }
 
@@ -228,16 +235,26 @@
     if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1)
         return;
 
-    // FIXME: Remove m_usePaintTracking when paint tracking is on for paint culling.
-    if (layerTransformsToScreenKnown(layer))
-        m_stack.last().occlusionInScreen.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToScreenSpaceTransform<LayerType>(layer), m_usePaintTracking));
+    IntRect scissorInTarget = layerScissorRectInTargetSurface(layer);
     if (layerTransformsToTargetKnown(layer))
-        m_stack.last().occlusionInTarget.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToTargetSurfaceTransform<LayerType>(layer), m_usePaintTracking));
+        m_stack.last().occlusionInTarget.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToTargetSurfaceTransform<LayerType>(layer), scissorInTarget, m_usePaintTracking));
+
+    // We must clip the occlusion within the layer's scissorInTarget within screen space as well. If the scissor rect can't be moved to screen space and
+    // remain rectilinear, then we don't add any occlusion in screen space.
+
+    if (layerTransformsToScreenKnown(layer)) {
+        TransformationMatrix targetToScreenTransform = m_stack.last().surface->screenSpaceTransform();
+        FloatQuad scissorInScreenQuad = targetToScreenTransform.mapQuad(FloatQuad(FloatRect(scissorInTarget)));
+        if (!scissorInScreenQuad.isRectilinear())
+            return;
+        IntRect scissorInScreenRect = intersection(m_scissorRectInScreenSpace, enclosedIntRect(CCMathUtil::mapClippedRect(targetToScreenTransform, FloatRect(scissorInTarget))));
+        m_stack.last().occlusionInScreen.unite(computeOcclusionBehindLayer<LayerType>(layer, contentToScreenSpaceTransform<LayerType>(layer), scissorInScreenRect, m_usePaintTracking));
+    }
 }
 
 static inline bool testContentRectOccluded(const IntRect& contentRect, const TransformationMatrix& contentSpaceTransform, const IntRect& scissorRect, const Region& occlusion)
 {
-    FloatRect transformedRect = contentSpaceTransform.mapRect(FloatRect(contentRect));
+    FloatRect transformedRect = CCMathUtil::mapClippedRect(contentSpaceTransform, FloatRect(contentRect));
     // Take the enclosingIntRect, as we want to include partial pixels in the test.
     IntRect targetRect = intersection(enclosingIntRect(transformedRect), scissorRect);
     return targetRect.isEmpty() || occlusion.contains(targetRect);
@@ -281,13 +298,10 @@
     if (!contentSpaceTransform.isInvertible())
         return contentRect;
 
-    FloatRect transformedRect = contentSpaceTransform.mapRect(FloatRect(contentRect));
     // Take the enclosingIntRect at each step, as we want to contain any unoccluded partial pixels in the resulting IntRect.
+    FloatRect transformedRect = CCMathUtil::mapClippedRect(contentSpaceTransform, FloatRect(contentRect));
     IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transformedRect), scissorRect), occlusion);
-    bool clipped; // FIXME: We should be able to use projectClippedQuad instead of forcing everything to be unoccluded. https://bugs.webkit.org/show_bug.cgi?id=83217.
-    IntRect unoccludedRect = enclosingIntRect(CCMathUtil::projectQuad(contentSpaceTransform.inverse(), FloatQuad(FloatRect(shrunkRect)), clipped).boundingBox());
-    if (clipped)
-        return contentRect;
+    IntRect unoccludedRect = enclosingIntRect(CCMathUtil::projectClippedRect(contentSpaceTransform.inverse(), FloatRect(shrunkRect)));
     // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds.
     return intersection(unoccludedRect, contentRect);
 }

Modified: trunk/Source/WebKit/chromium/ChangeLog (113560 => 113561)


--- trunk/Source/WebKit/chromium/ChangeLog	2012-04-09 08:49:02 UTC (rev 113560)
+++ trunk/Source/WebKit/chromium/ChangeLog	2012-04-09 09:05:50 UTC (rev 113561)
@@ -1,3 +1,19 @@
+2012-04-09  Dana Jansens  <[email protected]>
+
+        [chromium] Make culling work with clipped rects
+        https://bugs.webkit.org/show_bug.cgi?id=83217
+
+        Reviewed by Adrienne Walker.
+
+        * tests/CCOcclusionTrackerTest.cpp:
+        (CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude):
+        (WebKitTests::CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude::runMyTest):
+        (WebKitTests):
+        (CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect):
+        (WebKitTests::CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect::runMyTest):
+        * tests/CCQuadCullerTest.cpp:
+        (WebCore::TestCCOcclusionTrackerImpl::TestCCOcclusionTrackerImpl):
+
 2012-04-06  Ami Fischman  <[email protected]>
 
         Roll Chromium DEPS

Modified: trunk/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp (113560 => 113561)


--- trunk/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp	2012-04-09 08:49:02 UTC (rev 113560)
+++ trunk/Source/WebKit/chromium/tests/CCOcclusionTrackerTest.cpp	2012-04-09 09:05:50 UTC (rev 113561)
@@ -1674,6 +1674,65 @@
 MAIN_THREAD_TEST(CCOcclusionTrackerTestPerspectiveTransformBehindCamera);
 
 template<class Types, bool opaqueLayers>
+class CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude : public CCOcclusionTrackerTest<Types, opaqueLayers> {
+protected:
+    void runMyTest()
+    {
+        TransformationMatrix transform;
+        transform.translate(50, 50);
+        transform.applyPerspective(100);
+        transform.translate3d(0, 0, 110);
+        transform.translate(-50, -50);
+
+        typename Types::ContentLayerType* parent = this->createRoot(this->identityMatrix, FloatPoint(0, 0), IntSize(100, 100));
+        typename Types::ContentLayerType* layer = this->createDrawingLayer(parent, transform, FloatPoint(0, 0), IntSize(100, 100), true);
+        parent->setPreserves3D(true);
+        this->calcDrawEtc(parent);
+
+        TestCCOcclusionTrackerWithScissor<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion(IntRect(0, 0, 1000, 1000));
+        occlusion.enterTargetRenderSurface(parent->renderSurface());
+
+        // This layer is entirely behind the camera and should not occlude.
+        occlusion.markOccludedBehindLayer(layer);
+        EXPECT_EQ(0u, occlusion.occlusionInTargetSurface().rects().size());
+        EXPECT_EQ(0u, occlusion.occlusionInScreenSpace().rects().size());
+    }
+};
+
+MAIN_THREAD_TEST(CCOcclusionTrackerTestLayerBehindCameraDoesNotOcclude);
+
+template<class Types, bool opaqueLayers>
+class CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect : public CCOcclusionTrackerTest<Types, opaqueLayers> {
+protected:
+    void runMyTest()
+    {
+        TransformationMatrix transform;
+        transform.translate(50, 50);
+        transform.applyPerspective(100);
+        transform.translate3d(0, 0, 99);
+        transform.translate(-50, -50);
+
+        typename Types::ContentLayerType* parent = this->createRoot(this->identityMatrix, FloatPoint(0, 0), IntSize(100, 100));
+        typename Types::ContentLayerType* layer = this->createDrawingLayer(parent, transform, FloatPoint(0, 0), IntSize(100, 100), true);
+        parent->setPreserves3D(true);
+        this->calcDrawEtc(parent);
+
+        TestCCOcclusionTrackerWithScissor<typename Types::LayerType, typename Types::RenderSurfaceType> occlusion(IntRect(0, 0, 1000, 1000));
+        occlusion.enterTargetRenderSurface(parent->renderSurface());
+
+        // This is very close to the camera, so pixels in its visibleLayerRect will actually go outside of the layer's clipRect.
+        // Ensure that those pixels don't occlude things outside the clipRect.
+        occlusion.markOccludedBehindLayer(layer);
+        EXPECT_EQ(IntRect(0, 0, 100, 100), occlusion.occlusionInTargetSurface().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInTargetSurface().rects().size());
+        EXPECT_EQ(IntRect(0, 0, 100, 100), occlusion.occlusionInScreenSpace().bounds());
+        EXPECT_EQ(1u, occlusion.occlusionInScreenSpace().rects().size());
+    }
+};
+
+MAIN_THREAD_TEST(CCOcclusionTrackerTestLargePixelsOccludeInsideClipRect);
+
+template<class Types, bool opaqueLayers>
 class CCOcclusionTrackerTestAnimationOpacity1OnMainThread : public CCOcclusionTrackerTest<Types, opaqueLayers> {
 protected:
     void runMyTest()

Modified: trunk/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp (113560 => 113561)


--- trunk/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp	2012-04-09 08:49:02 UTC (rev 113560)
+++ trunk/Source/WebKit/chromium/tests/CCQuadCullerTest.cpp	2012-04-09 09:05:50 UTC (rev 113561)
@@ -44,8 +44,9 @@
         : CCOcclusionTrackerImpl(scissorRectInScreen, recordMetricsForFrame)
         , m_scissorRectInScreen(scissorRectInScreen)
     {
-        // Pretend we have visited a render surface.
+        // Pretend we have visited the root render surface.
         m_stack.append(StackObject());
+        m_stack.last().surface = new CCRenderSurface(0);
     }
 
 protected:
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to