Title: [234330] trunk
Revision
234330
Author
simon.fra...@apple.com
Date
2018-07-27 15:20:26 -0700 (Fri, 27 Jul 2018)

Log Message

Be more conservative with compositing layer creation when memory is low
https://bugs.webkit.org/show_bug.cgi?id=187866
rdar://problem/42366345

Reviewed by Zalan Bujtas.

Source/WebCore:

When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
compositing layers. We avoid compositing for these situations:
1. Layers with 3D transforms which are affine (like translateZ(0)).
2. Layers with will-change
3. Layers for canvases (other than WebGL/WebGPU)

We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.

Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
flakily falling into a different mode, and so that we can impose the conservative
mode for testing.

Test: compositing/layer-creation/compositing-policy.html

* page/Page.h:
(WebCore::Page::compositingPolicyOverride const):
(WebCore::Page::setCompositingPolicyOverride):
* platform/graphics/transforms/Matrix3DTransformOperation.cpp:
(WebCore::Matrix3DTransformOperation::isRepresentableIn2D const):
* platform/graphics/transforms/Matrix3DTransformOperation.h:
* platform/graphics/transforms/PerspectiveTransformOperation.h:
* platform/graphics/transforms/RotateTransformOperation.h:
* platform/graphics/transforms/ScaleTransformOperation.h:
* platform/graphics/transforms/TransformOperation.h:
(WebCore::TransformOperation::isRepresentableIn2D const):
* platform/graphics/transforms/TransformOperations.h:
(WebCore::TransformOperations::has3DOperation const):
(WebCore::TransformOperations::isRepresentableIn2D const):
* platform/graphics/transforms/TranslateTransformOperation.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateGeometry):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::cacheAcceleratedCompositingFlags):
(WebCore::RenderLayerCompositor::updateCompositingPolicy):
(WebCore::RenderLayerCompositor::updateCompositingLayers):
(WebCore::RenderLayerCompositor::requiresCompositingForTransform const):
(WebCore::RenderLayerCompositor::requiresCompositingForVideo const):
(WebCore::RenderLayerCompositor::requiresCompositingForCanvas const):
(WebCore::RenderLayerCompositor::requiresCompositingForPlugin const):
(WebCore::RenderLayerCompositor::requiresCompositingForWillChange const):
(WebCore::RenderLayerCompositor::needsFixedRootBackgroundLayer const):
(WebCore::operator<<):
* rendering/RenderLayerCompositor.h:
* testing/Internals.cpp:
(WebCore::Internals::setCompositingPolicyOverride):
(WebCore::Internals::compositingPolicyOverride const):
* testing/Internals.h:
* testing/Internals.idl:

Source/WebKit:

When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
compositing layers. We avoid compositing for these situations:
1. Layers with 3D transforms which are affine (like translateZ(0)).
2. Layers with will-change
3. Layers for canvases (other than WebGL/WebGPU)

We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.

Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
flakily falling into a different mode, and so that we can impose the conservative
mode for testing.

* WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:
(WKBundlePageSetCompositingPolicyOverride):
* WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h:

Source/WTF:

When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
compositing layers. We avoid compositing for these situations:
1. Layers with 3D transforms which are affine (like translateZ(0)).
2. Layers with will-change
3. Layers for canvases (other than WebGL/WebGPU)

We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.

Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
flakily falling into a different mode, and so that we can impose the conservative
mode for testing.

* wtf/MemoryPressureHandler.cpp:
(WTF::thresholdForPolicy):
(WTF::MemoryPressureHandler::currentMemoryUsagePolicy):
* wtf/MemoryPressureHandler.h:

Tools:

When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
compositing layers. We avoid compositing for these situations:
1. Layers with 3D transforms which are affine (like translateZ(0)).
2. Layers with will-change
3. Layers for canvases (other than WebGL/WebGPU)

We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.

Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
flakily falling into a different mode, and so that we can impose the conservative
mode for testing.

* WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
(WTR::InjectedBundlePage::prepare):

LayoutTests:

* compositing/layer-creation/compositing-policy-expected.txt: Added.
* compositing/layer-creation/compositing-policy.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (234329 => 234330)


--- trunk/LayoutTests/ChangeLog	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/LayoutTests/ChangeLog	2018-07-27 22:20:26 UTC (rev 234330)
@@ -1,3 +1,14 @@
+2018-07-27  Simon Fraser  <simon.fra...@apple.com>
+
+        Be more conservative with compositing layer creation when memory is low
+        https://bugs.webkit.org/show_bug.cgi?id=187866
+        rdar://problem/42366345
+
+        Reviewed by Zalan Bujtas.
+        
+        * compositing/layer-creation/compositing-policy-expected.txt: Added.
+        * compositing/layer-creation/compositing-policy.html: Added.
+
 2018-07-27  Zalan Bujtas  <za...@apple.com>
 
         [WK1] ASSERTION FAILED: renderer().repaintLayoutRects().m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()) in WebCore::RenderLayer::updateLayerPositionsAfterScroll

Added: trunk/LayoutTests/compositing/layer-creation/compositing-policy-expected.txt (0 => 234330)


--- trunk/LayoutTests/compositing/layer-creation/compositing-policy-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/compositing/layer-creation/compositing-policy-expected.txt	2018-07-27 22:20:26 UTC (rev 234330)
@@ -0,0 +1,28 @@
+transform: translate3d(10px, 1px, 1px)
+Has backing under low memory.
+transform: translateZ(0)
+translateZ(0): No backing under low memory.
+transform: translate3d(10px, 1px, 0)
+No backing under low memory.
+will-change: transform
+No backing under low memory.
+ (GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 1018.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 1018.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 18.00 10.00)
+          (bounds 308.00 108.00)
+          (contentsOpaque 1)
+          (drawsContent 1)
+          (transform [1.00 0.00 0.00 0.00] [0.00 1.00 0.00 0.00] [0.00 0.00 1.00 0.00] [10.00 1.00 1.00 1.00])
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/compositing/layer-creation/compositing-policy.html (0 => 234330)


--- trunk/LayoutTests/compositing/layer-creation/compositing-policy.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/layer-creation/compositing-policy.html	2018-07-27 22:20:26 UTC (rev 234330)
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        body {
+            overflow:hidden; /* prevent scrollbars and document height from affecting test output */
+            height: 1000px;
+        }
+        .box {
+            margin: 10px;
+            height: 100px;
+            width: 300px;
+            padding: 4px;
+            background-color: silver;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.dumpAsText();
+
+        if (window.internals)
+            internals.compositingPolicyOverride = 'conservative';
+
+        function dumpLayers()
+        {
+            let canvas = document.getElementsByTagName('canvas')[0];
+            var ctx = canvas.getContext('2d');
+            ctx.fillStyle = 'white';
+            ctx.fillRect(0, 0, canvas.width, canvas.height);
+            if (window.testRunner)
+                document.getElementById('layers').innerText = window.internals.layerTreeAsText(document);
+        }
+
+        window.addEventListener('load', dumpLayers, false);
+    </script>
+</head>
+<body>
+
+<div class="box" style="transform: translate3d(10px, 1px, 1px)">
+    <pre>transform: translate3d(10px, 1px, 1px)</pre>
+    Has backing under low memory.
+</div>
+
+<div class="box" style="transform: translateZ(0)">
+    <pre>transform: translateZ(0)</pre>
+    translateZ(0): No backing under low memory.
+</div>
+
+<div class="box" style="transform: translate3d(10px, 1px, 0)">
+    <pre>transform: translate3d(10px, 1px, 0)</pre>
+    No backing under low memory.
+</div>
+
+<div class="box" style="will-change: transform">
+    <pre>will-change: transform</pre>
+    No backing under low memory.
+</div>
+
+<canvas class="box" style="box-shadow: 0 0 10px black">
+</canvas>
+
+<pre id="layers"></pre>
+
+</body>
+</html>

Modified: trunk/Source/WTF/ChangeLog (234329 => 234330)


--- trunk/Source/WTF/ChangeLog	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WTF/ChangeLog	2018-07-27 22:20:26 UTC (rev 234330)
@@ -1,3 +1,30 @@
+2018-07-27  Simon Fraser  <simon.fra...@apple.com>
+
+        Be more conservative with compositing layer creation when memory is low
+        https://bugs.webkit.org/show_bug.cgi?id=187866
+        rdar://problem/42366345
+
+        Reviewed by Zalan Bujtas.
+        
+        When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
+        compositing layers. We avoid compositing for these situations:
+        1. Layers with 3D transforms which are affine (like translateZ(0)).
+        2. Layers with will-change
+        3. Layers for canvases (other than WebGL/WebGPU)
+        
+        We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
+        falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
+        Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.
+        
+        Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
+        flakily falling into a different mode, and so that we can impose the conservative
+        mode for testing.
+
+        * wtf/MemoryPressureHandler.cpp:
+        (WTF::thresholdForPolicy):
+        (WTF::MemoryPressureHandler::currentMemoryUsagePolicy):
+        * wtf/MemoryPressureHandler.h:
+
 2018-07-26  Andy VanWagoner  <andy@vanwagoner.family>
 
         [INTL] Remove INTL sub-feature compile flags

Modified: trunk/Source/WTF/wtf/MemoryPressureHandler.cpp (234329 => 234330)


--- trunk/Source/WTF/wtf/MemoryPressureHandler.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WTF/wtf/MemoryPressureHandler.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -113,12 +113,22 @@
 static size_t thresholdForPolicy(MemoryUsagePolicy policy)
 {
     const size_t baseThresholdForPolicy = std::min(3 * GB, ramSize());
+
+#if PLATFORM(IOS)
+    const double conservativeThresholdFraction = 0.5;
+    const double strictThresholdFraction = 0.65;
+#else
+    const double conservativeThresholdFraction = 0.33;
+    const double strictThresholdFraction = 0.5;
+#endif
+
     switch (policy) {
+    case MemoryUsagePolicy::Unrestricted:
+        return 0;
     case MemoryUsagePolicy::Conservative:
-        return baseThresholdForPolicy / 3;
+        return baseThresholdForPolicy * conservativeThresholdFraction;
     case MemoryUsagePolicy::Strict:
-        return baseThresholdForPolicy / 2;
-    case MemoryUsagePolicy::Unrestricted:
+        return baseThresholdForPolicy * strictThresholdFraction;
     default:
         ASSERT_NOT_REACHED();
         return 0;
@@ -134,6 +144,11 @@
     return MemoryUsagePolicy::Unrestricted;
 }
 
+MemoryUsagePolicy MemoryPressureHandler::currentMemoryUsagePolicy()
+{
+    return policyForFootprint(memoryFootprint().value_or(0));
+}
+
 void MemoryPressureHandler::shrinkOrDie()
 {
     RELEASE_LOG(MemoryPressure, "Process is above the memory kill threshold. Trying to shrink down.");

Modified: trunk/Source/WTF/wtf/MemoryPressureHandler.h (234329 => 234330)


--- trunk/Source/WTF/wtf/MemoryPressureHandler.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WTF/wtf/MemoryPressureHandler.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -92,6 +92,8 @@
     }
     void setUnderMemoryPressure(bool);
 
+    WTF_EXPORT_PRIVATE static MemoryUsagePolicy currentMemoryUsagePolicy();
+
     class ReliefLogger {
     public:
         explicit ReliefLogger(const char *log)

Modified: trunk/Source/WebCore/ChangeLog (234329 => 234330)


--- trunk/Source/WebCore/ChangeLog	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/ChangeLog	2018-07-27 22:20:26 UTC (rev 234330)
@@ -1,3 +1,62 @@
+2018-07-27  Simon Fraser  <simon.fra...@apple.com>
+
+        Be more conservative with compositing layer creation when memory is low
+        https://bugs.webkit.org/show_bug.cgi?id=187866
+        rdar://problem/42366345
+
+        Reviewed by Zalan Bujtas.
+        
+        When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
+        compositing layers. We avoid compositing for these situations:
+        1. Layers with 3D transforms which are affine (like translateZ(0)).
+        2. Layers with will-change
+        3. Layers for canvases (other than WebGL/WebGPU)
+        
+        We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
+        falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
+        Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.
+        
+        Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
+        flakily falling into a different mode, and so that we can impose the conservative
+        mode for testing.
+
+        Test: compositing/layer-creation/compositing-policy.html
+
+        * page/Page.h:
+        (WebCore::Page::compositingPolicyOverride const):
+        (WebCore::Page::setCompositingPolicyOverride):
+        * platform/graphics/transforms/Matrix3DTransformOperation.cpp:
+        (WebCore::Matrix3DTransformOperation::isRepresentableIn2D const):
+        * platform/graphics/transforms/Matrix3DTransformOperation.h:
+        * platform/graphics/transforms/PerspectiveTransformOperation.h:
+        * platform/graphics/transforms/RotateTransformOperation.h:
+        * platform/graphics/transforms/ScaleTransformOperation.h:
+        * platform/graphics/transforms/TransformOperation.h:
+        (WebCore::TransformOperation::isRepresentableIn2D const):
+        * platform/graphics/transforms/TransformOperations.h:
+        (WebCore::TransformOperations::has3DOperation const):
+        (WebCore::TransformOperations::isRepresentableIn2D const):
+        * platform/graphics/transforms/TranslateTransformOperation.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateGeometry):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::cacheAcceleratedCompositingFlags):
+        (WebCore::RenderLayerCompositor::updateCompositingPolicy):
+        (WebCore::RenderLayerCompositor::updateCompositingLayers):
+        (WebCore::RenderLayerCompositor::requiresCompositingForTransform const):
+        (WebCore::RenderLayerCompositor::requiresCompositingForVideo const):
+        (WebCore::RenderLayerCompositor::requiresCompositingForCanvas const):
+        (WebCore::RenderLayerCompositor::requiresCompositingForPlugin const):
+        (WebCore::RenderLayerCompositor::requiresCompositingForWillChange const):
+        (WebCore::RenderLayerCompositor::needsFixedRootBackgroundLayer const):
+        (WebCore::operator<<):
+        * rendering/RenderLayerCompositor.h:
+        * testing/Internals.cpp:
+        (WebCore::Internals::setCompositingPolicyOverride):
+        (WebCore::Internals::compositingPolicyOverride const):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
 2018-07-27  Zalan Bujtas  <za...@apple.com>
 
         [WK1] ASSERTION FAILED: renderer().repaintLayoutRects().m_repaintRect == renderer().clippedOverflowRectForRepaint(renderer().containerForRepaint()) in WebCore::RenderLayer::updateLayerPositionsAfterScroll

Modified: trunk/Source/WebCore/page/Page.h (234329 => 234330)


--- trunk/Source/WebCore/page/Page.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/page/Page.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -154,6 +154,11 @@
     Unresponsive
 };
 
+enum class CompositingPolicy : uint8_t {
+    Normal,
+    Conservative, // Used in low memory situations.
+};
+
 enum class CanWrap : bool;
 enum class DidWrap : bool;
 enum class RouteSharingPolicy;
@@ -636,6 +641,9 @@
     std::optional<EventThrottlingBehavior> eventThrottlingBehaviorOverride() const { return m_eventThrottlingBehaviorOverride; }
     void setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior> throttling) { m_eventThrottlingBehaviorOverride = throttling; }
 
+    std::optional<CompositingPolicy> compositingPolicyOverride() const { return m_compositingPolicyOverride; }
+    void setCompositingPolicyOverride(std::optional<CompositingPolicy> policy) { m_compositingPolicyOverride = policy; }
+
     WebGLStateTracker* webGLStateTracker() const { return m_webGLStateTracker.get(); }
 
     bool isOnlyNonUtilityPage() const;
@@ -873,6 +881,7 @@
     
     // For testing.
     std::optional<EventThrottlingBehavior> m_eventThrottlingBehaviorOverride;
+    std::optional<CompositingPolicy> m_compositingPolicyOverride;
 
     std::unique_ptr<PerformanceMonitor> m_performanceMonitor;
     std::unique_ptr<LowPowerModeNotifier> m_lowPowerModeNotifier;

Modified: trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -61,6 +61,11 @@
     return createOperation(toT, fromT, progress);
 }
 
+bool Matrix3DTransformOperation::isRepresentableIn2D() const
+{
+    return m_matrix.isAffine();
+}
+
 void Matrix3DTransformOperation::dump(TextStream& ts) const
 {
     ts << type() << "(" << m_matrix << ")";

Modified: trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -46,8 +46,10 @@
 
 private:    
     bool isIdentity() const override { return m_matrix.isIdentity(); }
-    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
+    bool isAffectedByTransformOrigin() const final { return !isIdentity(); }
 
+    bool isRepresentableIn2D() const final;
+
     bool operator==(const TransformOperation&) const override;
 
     bool apply(TransformationMatrix& transform, const FloatSize&) const override

Modified: trunk/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -49,6 +49,7 @@
 private:
     bool isIdentity() const override { return !floatValueForLength(m_p, 1); }
     bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
+    bool isRepresentableIn2D() const final { return false; }
 
     bool operator==(const TransformOperation&) const override;
 

Modified: trunk/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -54,6 +54,7 @@
 private:
     bool isIdentity() const override { return m_angle == 0; }
     bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
+    bool isRepresentableIn2D() const final { return (!m_x && !m_y) || !m_angle; }
 
     bool operator==(const TransformOperation&) const override;
 

Modified: trunk/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -53,6 +53,7 @@
 private:
     bool isIdentity() const override { return m_x == 1 &&  m_y == 1 &&  m_z == 1; }
     bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
+    bool isRepresentableIn2D() const final { return m_z == 1; }
 
     bool operator==(const TransformOperation&) const override;
 

Modified: trunk/Source/WebCore/platform/graphics/transforms/TransformOperation.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/TransformOperation.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/TransformOperation.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -87,6 +87,8 @@
                opType == MATRIX_3D ||
                opType == PERSPECTIVE;
     }
+    
+    virtual bool isRepresentableIn2D() const { return true; }
 
     bool isRotateTransformOperationType() const
     {

Modified: trunk/Source/WebCore/platform/graphics/transforms/TransformOperations.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/TransformOperations.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/TransformOperations.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -22,8 +22,7 @@
  *
  */
 
-#ifndef TransformOperations_h
-#define TransformOperations_h
+#pragma once
 
 #include "LayoutSize.h"
 #include "TransformOperation.h"
@@ -53,12 +52,22 @@
     // values describe affine transforms)
     bool has3DOperation() const
     {
-        for (unsigned i = 0; i < m_operations.size(); ++i)
-            if (m_operations[i]->is3DOperation())
+        for (const auto& operation : m_operations) {
+            if (operation->is3DOperation())
                 return true;
+        }
         return false;
     }
-    
+
+    bool isRepresentableIn2D() const
+    {
+        for (const auto& operation : m_operations) {
+            if (!operation->isRepresentableIn2D())
+                return false;
+        }
+        return true;
+    }
+
     bool operationsMatch(const TransformOperations&) const;
     
     void clear()
@@ -86,4 +95,3 @@
 
 } // namespace WebCore
 
-#endif // TransformOperations_h

Modified: trunk/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h (234329 => 234330)


--- trunk/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -59,6 +59,8 @@
 private:
     bool isIdentity() const override { return !floatValueForLength(m_x, 1) && !floatValueForLength(m_y, 1) && !floatValueForLength(m_z, 1); }
 
+    bool isRepresentableIn2D() const final { return m_z.isZero(); }
+
     bool operator==(const TransformOperation&) const override;
 
     bool apply(TransformationMatrix& transform, const FloatSize& borderBoxSize) const override

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (234329 => 234330)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -950,8 +950,6 @@
 
 void RenderLayerBacking::updateGeometry()
 {
-    LOG_WITH_STREAM(Compositing, stream << "updateGeometry " << m_owningLayer);
-
     // If we haven't built z-order lists yet, wait until later.
     if (m_owningLayer.isStackingContainer() && m_owningLayer.m_zOrderListsDirty)
         return;

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (234329 => 234330)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -60,6 +60,7 @@
 #include "Settings.h"
 #include "TiledBacking.h"
 #include "TransformState.h"
+#include <wtf/MemoryPressureHandler.h>
 #include <wtf/SetForScope.h>
 #include <wtf/text/CString.h>
 #include <wtf/text/StringBuilder.h>
@@ -346,6 +347,9 @@
         if (m_layerForScrollCorner)
             m_layerForScrollCorner->setShowDebugBorder(m_showDebugBorders);
     }
+    
+    if (updateCompositingPolicy())
+        setCompositingLayersNeedRebuild();
 }
 
 void RenderLayerCompositor::cacheAcceleratedCompositingFlagsAfterLayout()
@@ -362,6 +366,19 @@
     }
 }
 
+bool RenderLayerCompositor::updateCompositingPolicy()
+{
+    auto currentPolicy = m_compositingPolicy;
+    if (page().compositingPolicyOverride()) {
+        m_compositingPolicy = page().compositingPolicyOverride().value();
+        return m_compositingPolicy != currentPolicy;
+    }
+    
+    auto memoryPolicy = MemoryPressureHandler::currentMemoryUsagePolicy();
+    m_compositingPolicy = memoryPolicy == WTF::MemoryUsagePolicy::Unrestricted ? CompositingPolicy::Normal : CompositingPolicy::Conservative;
+    return m_compositingPolicy != currentPolicy;
+}
+
 bool RenderLayerCompositor::canRender3DTransforms() const
 {
     return hasAcceleratedCompositing() && (m_compositingTriggers & ChromeClient::ThreeDTransformTrigger);
@@ -732,7 +749,7 @@
 
         auto& frame = m_renderView.frameView().frame();
         bool isMainFrame = isMainFrameCompositor();
-        LOG(Compositing, "\nUpdate %d of %s.\n", m_rootLayerUpdateCount, isMainFrame ? "main frame" : frame.tree().uniqueName().string().utf8().data());
+        LOG_WITH_STREAM(Compositing, stream << "\nUpdate " << m_rootLayerUpdateCount << " of " << (isMainFrame ? "main frame" : frame.tree().uniqueName().string().utf8().data()) << " - compositing policy is " << m_compositingPolicy);
     }
 #endif
 
@@ -2389,7 +2406,19 @@
 
     // Note that we ask the renderer if it has a transform, because the style may have transforms,
     // but the renderer may be an inline that doesn't suppport them.
-    return renderer.hasTransform() && renderer.style().transform().has3DOperation();
+    if (!renderer.hasTransform())
+        return false;
+    
+    switch (m_compositingPolicy) {
+    case CompositingPolicy::Normal:
+        return renderer.style().transform().has3DOperation();
+    case CompositingPolicy::Conservative:
+        // Continue to allow pages to avoid the very slow software filter path.
+        if (renderer.style().transform().has3DOperation() && renderer.hasFilter())
+            return true;
+        return !renderer.style().transform().isRepresentableIn2D();
+    }
+    return false;
 }
 
 bool RenderLayerCompositor::requiresCompositingForBackfaceVisibility(RenderLayerModelObject& renderer) const
@@ -2415,15 +2444,17 @@
 {
     if (!(m_compositingTriggers & ChromeClient::VideoTrigger))
         return false;
+
 #if ENABLE(VIDEO)
-    if (is<RenderVideo>(renderer)) {
-        auto& video = downcast<RenderVideo>(renderer);
-        return (video.requiresImmediateCompositing() || video.shouldDisplayVideo()) && canAccelerateVideoRendering(video);
-    }
+    if (!is<RenderVideo>(renderer))
+        return false;
+
+    auto& video = downcast<RenderVideo>(renderer);
+    return (video.requiresImmediateCompositing() || video.shouldDisplayVideo()) && canAccelerateVideoRendering(video);
 #else
     UNUSED_PARAM(renderer);
+    return false;
 #endif
-    return false;
 }
 
 bool RenderLayerCompositor::requiresCompositingForCanvas(RenderLayerModelObject& renderer) const
@@ -2431,18 +2462,23 @@
     if (!(m_compositingTriggers & ChromeClient::CanvasTrigger))
         return false;
 
-    if (renderer.isCanvas()) {
-#if USE(COMPOSITING_FOR_SMALL_CANVASES)
-        bool isCanvasLargeEnoughToForceCompositing = true;
-#else
-        auto* canvas = downcast<HTMLCanvasElement>(renderer.element());
-        auto canvasArea = canvas->size().area<RecordOverflow>();
-        bool isCanvasLargeEnoughToForceCompositing = !canvasArea.hasOverflowed() && canvasArea.unsafeGet() >= canvasAreaThresholdRequiringCompositing;
+    if (!renderer.isCanvas())
+        return false;
+
+    bool isCanvasLargeEnoughToForceCompositing = true;
+#if !USE(COMPOSITING_FOR_SMALL_CANVASES)
+    auto* canvas = downcast<HTMLCanvasElement>(renderer.element());
+    auto canvasArea = canvas->size().area<RecordOverflow>();
+    isCanvasLargeEnoughToForceCompositing = !canvasArea.hasOverflowed() && canvasArea.unsafeGet() >= canvasAreaThresholdRequiringCompositing;
 #endif
-        CanvasCompositingStrategy compositingStrategy = canvasCompositingStrategy(renderer);
-        return compositingStrategy == CanvasAsLayerContents || (compositingStrategy == CanvasPaintedToLayer && isCanvasLargeEnoughToForceCompositing);
-    }
 
+    CanvasCompositingStrategy compositingStrategy = canvasCompositingStrategy(renderer);
+    if (compositingStrategy == CanvasAsLayerContents)
+        return true;
+
+    if (m_compositingPolicy == CompositingPolicy::Normal)
+        return compositingStrategy == CanvasPaintedToLayer && isCanvasLargeEnoughToForceCompositing;
+
     return false;
 }
 
@@ -2451,8 +2487,8 @@
     if (!(m_compositingTriggers & ChromeClient::PluginTrigger))
         return false;
 
-    bool composite = is<RenderEmbeddedObject>(renderer) && downcast<RenderEmbeddedObject>(renderer).allowsAcceleratedCompositing();
-    if (!composite)
+    bool isCompositedPlugin = is<RenderEmbeddedObject>(renderer) && downcast<RenderEmbeddedObject>(renderer).allowsAcceleratedCompositing();
+    if (!isCompositedPlugin)
         return false;
 
     m_reevaluateCompositingAfterLayout = true;
@@ -2589,6 +2625,9 @@
         return false;
 #endif
 
+    if (m_compositingPolicy == CompositingPolicy::Conservative)
+        return false;
+
     if (is<RenderBox>(renderer))
         return true;
 
@@ -2836,8 +2875,6 @@
     if (m_renderView.settings().fixedBackgroundsPaintRelativeToDocument())
         return false;
 
-    LOG(Compositing, "RenderLayerCompositor %p needsFixedRootBackgroundLayer returning %d", this, supportsFixedRootBackgroundCompositing() && m_renderView.rootBackgroundIsEntirelyFixed());
-
     return supportsFixedRootBackgroundCompositing() && m_renderView.rootBackgroundIsEntirelyFixed();
 }
 
@@ -4120,4 +4157,13 @@
     return ts;
 }
 
+TextStream& operator<<(TextStream& ts, CompositingPolicy compositingPolicy)
+{
+    switch (compositingPolicy) {
+    case CompositingPolicy::Normal: ts << "normal"; break;
+    case CompositingPolicy::Conservative: ts << "conservative"; break;
+    }
+    return ts;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.h (234329 => 234330)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -333,6 +333,9 @@
     struct CompositingState;
     struct OverlapExtent;
 
+    // Returns true if the policy changed.
+    bool updateCompositingPolicy();
+    
     // GraphicsLayerClient implementation
     void notifyFlushRequired(const GraphicsLayer*) override;
     void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior) override;
@@ -490,6 +493,8 @@
 
     ChromeClient::CompositingTriggerFlags m_compositingTriggers { static_cast<ChromeClient::CompositingTriggerFlags>(ChromeClient::AllTriggers) };
     bool m_hasAcceleratedCompositing { true };
+    
+    CompositingPolicy m_compositingPolicy { CompositingPolicy::Normal };
 
     bool m_showDebugBorders { false };
     bool m_showRepaintCounter { false };
@@ -572,5 +577,6 @@
 void paintScrollbar(Scrollbar*, GraphicsContext&, const IntRect& clip);
 
 WTF::TextStream& operator<<(WTF::TextStream&, CompositingUpdateType);
+WTF::TextStream& operator<<(WTF::TextStream&, CompositingPolicy);
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/testing/Internals.cpp (234329 => 234330)


--- trunk/Source/WebCore/testing/Internals.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/testing/Internals.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -3001,6 +3001,49 @@
     return document->renderView()->compositor().compositingUpdateCount();
 }
 
+ExceptionOr<void> Internals::setCompositingPolicyOverride(std::optional<CompositingPolicy> policyOverride)
+{
+    Document* document = contextDocument();
+    if (!document)
+        return Exception { InvalidAccessError };
+
+    if (!policyOverride) {
+        document->page()->setCompositingPolicyOverride(std::nullopt);
+        return { };
+    }
+
+    switch (policyOverride.value()) {
+    case Internals::CompositingPolicy::Normal:
+        document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Normal);
+        break;
+    case Internals::CompositingPolicy::Conservative:
+        document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Conservative);
+        break;
+    }
+    
+    return { };
+}
+
+ExceptionOr<std::optional<Internals::CompositingPolicy>> Internals::compositingPolicyOverride() const
+{
+    Document* document = contextDocument();
+    if (!document)
+        return Exception { InvalidAccessError };
+
+    auto policyOverride = document->page()->compositingPolicyOverride();
+    if (!policyOverride)
+        return { std::nullopt };
+
+    switch (policyOverride.value()) {
+    case WebCore::CompositingPolicy::Normal:
+        return { Internals::CompositingPolicy::Normal };
+    case WebCore::CompositingPolicy::Conservative:
+        return { Internals::CompositingPolicy::Conservative };
+    }
+
+    return { Internals::CompositingPolicy::Normal };
+}
+
 ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node)
 {
     Document* document;

Modified: trunk/Source/WebCore/testing/Internals.h (234329 => 234330)


--- trunk/Source/WebCore/testing/Internals.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/testing/Internals.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -440,6 +440,10 @@
     ExceptionOr<void> startTrackingCompositingUpdates();
     ExceptionOr<unsigned> compositingUpdateCount();
 
+    enum CompositingPolicy { Normal, Conservative };
+    ExceptionOr<void> setCompositingPolicyOverride(std::optional<CompositingPolicy>);
+    ExceptionOr<std::optional<CompositingPolicy>> compositingPolicyOverride() const;
+
     ExceptionOr<void> updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node*);
     unsigned layoutCount() const;
 

Modified: trunk/Source/WebCore/testing/Internals.idl (234329 => 234330)


--- trunk/Source/WebCore/testing/Internals.idl	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebCore/testing/Internals.idl	2018-07-27 22:20:26 UTC (rev 234330)
@@ -81,6 +81,11 @@
     "unresponsive"
 };
 
+enum CompositingPolicy {
+    "normal",
+    "conservative"
+};
+
 [Conditional=VIDEO] enum PlaybackControlsPurpose {
     "ControlsManager",
     "NowPlaying"
@@ -433,6 +438,8 @@
     [MayThrowException] void startTrackingCompositingUpdates();
     [MayThrowException] unsigned long compositingUpdateCount();
 
+    attribute CompositingPolicy? compositingPolicyOverride;
+
     // |node| should be Document, HTMLIFrameElement, or unspecified.
     // If |node| is an HTMLIFrameElement, it assumes node.contentDocument is
     // specified without security checks. Unspecified or null means this document.

Modified: trunk/Source/WebKit/ChangeLog (234329 => 234330)


--- trunk/Source/WebKit/ChangeLog	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebKit/ChangeLog	2018-07-27 22:20:26 UTC (rev 234330)
@@ -1,3 +1,29 @@
+2018-07-27  Simon Fraser  <simon.fra...@apple.com>
+
+        Be more conservative with compositing layer creation when memory is low
+        https://bugs.webkit.org/show_bug.cgi?id=187866
+        rdar://problem/42366345
+
+        Reviewed by Zalan Bujtas.
+        
+        When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
+        compositing layers. We avoid compositing for these situations:
+        1. Layers with 3D transforms which are affine (like translateZ(0)).
+        2. Layers with will-change
+        3. Layers for canvases (other than WebGL/WebGPU)
+        
+        We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
+        falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
+        Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.
+        
+        Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
+        flakily falling into a different mode, and so that we can impose the conservative
+        mode for testing.
+
+        * WebProcess/InjectedBundle/API/c/WKBundlePage.cpp:
+        (WKBundlePageSetCompositingPolicyOverride):
+        * WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h:
+
 2018-07-27  Alex Christensen  <achristen...@webkit.org>
 
         Add RefCounted CompletionHandler wrapping abstraction for sending policy decisions back to WebProcess

Modified: trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp (234329 => 234330)


--- trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -63,6 +63,7 @@
 #include <WebCore/Page.h>
 #include <WebCore/PageOverlay.h>
 #include <WebCore/PageOverlayController.h>
+#include <WebCore/RenderLayerCompositor.h>
 #include <WebCore/SecurityOriginData.h>
 #include <WebCore/URL.h>
 #include <WebCore/WheelEventTestTrigger.h>
@@ -713,3 +714,21 @@
 
     toImpl(page)->corePage()->setEventThrottlingBehaviorOverride(behaviorValue);
 }
+
+void WKBundlePageSetCompositingPolicyOverride(WKBundlePageRef page, WKCompositingPolicy* policy)
+{
+    std::optional<WebCore::CompositingPolicy> policyValue;
+    if (policy) {
+        switch (*policy) {
+        case kWKCompositingPolicyNormal:
+            policyValue = WebCore::CompositingPolicy::Normal;
+            break;
+        case kWKCompositingPolicyConservative:
+            policyValue = WebCore::CompositingPolicy::Conservative;
+            break;
+        }
+    }
+
+    toImpl(page)->corePage()->setCompositingPolicyOverride(policyValue);
+}
+

Modified: trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h (234329 => 234330)


--- trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h	2018-07-27 22:20:26 UTC (rev 234330)
@@ -120,6 +120,16 @@
 // Passing null in the second parameter clears the override.
 WK_EXPORT void WKBundlePageSetEventThrottlingBehaviorOverride(WKBundlePageRef, WKEventThrottlingBehavior*);
 
+enum {
+    kWKCompositingPolicyNormal = 0,
+    kWKCompositingPolicyConservative
+};
+
+typedef uint32_t WKCompositingPolicy;
+
+// Passing null in the second parameter clears the override.
+WK_EXPORT void WKBundlePageSetCompositingPolicyOverride(WKBundlePageRef, WKCompositingPolicy*);
+
 #if TARGET_OS_IPHONE
 WK_EXPORT void WKBundlePageSetUseTestingViewportConfiguration(WKBundlePageRef, bool);
 #endif

Modified: trunk/Tools/ChangeLog (234329 => 234330)


--- trunk/Tools/ChangeLog	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Tools/ChangeLog	2018-07-27 22:20:26 UTC (rev 234330)
@@ -1,3 +1,28 @@
+2018-07-27  Simon Fraser  <simon.fra...@apple.com>
+
+        Be more conservative with compositing layer creation when memory is low
+        https://bugs.webkit.org/show_bug.cgi?id=187866
+        rdar://problem/42366345
+
+        Reviewed by Zalan Bujtas.
+        
+        When process physical footprint is above a fraction of the jetsam limit, be more conservative in making
+        compositing layers. We avoid compositing for these situations:
+        1. Layers with 3D transforms which are affine (like translateZ(0)).
+        2. Layers with will-change
+        3. Layers for canvases (other than WebGL/WebGPU)
+        
+        We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
+        falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
+        Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.
+        
+        Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
+        flakily falling into a different mode, and so that we can impose the conservative
+        mode for testing.
+
+        * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+        (WTR::InjectedBundlePage::prepare):
+
 2018-07-27  Michael Catanzaro  <mcatanz...@igalia.com>
 
         Unreviewed GTK test gardening

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp (234329 => 234330)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp	2018-07-27 22:11:32 UTC (rev 234329)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp	2018-07-27 22:20:26 UTC (rev 234330)
@@ -426,6 +426,10 @@
     // Force consistent "responsive" behavior for WebPage::eventThrottlingDelay() for testing. Tests can override via internals.
     WKEventThrottlingBehavior behavior = kWKEventThrottlingBehaviorResponsive;
     WKBundlePageSetEventThrottlingBehaviorOverride(m_page, &behavior);
+    
+    // Force consistent compositing behavior, even if the test runner is under memory pressure. Tests can override via internals.
+    WKCompositingPolicy policy = kWKCompositingPolicyNormal;
+    WKBundlePageSetCompositingPolicyOverride(m_page, &policy);
 }
 
 void InjectedBundlePage::resetAfterTest()
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to