| Differences between
and this patch
- a/Source/WebCore/ChangeLog +51 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2018-07-20  Simon Fraser  <simon.fraser@apple.com>
2
3
        Be more conservative with compositing layer creation when memory is low
4
        https://bugs.webkit.org/show_bug.cgi?id=187866
5
        rdar://problem/42366345
6
7
        Reviewed by NOBODY (OOPS!).
8
        
9
        When process physical footprint is above a fraction of the jetsam limit (currently
10
        hardcoded to be 840MB), be more conservative in making
11
        compositing layers. We avoid compositing for these situations:
12
        1. Layers with 3D transforms which are affine (like translateZ(0)).
13
        2. Layers with will-change
14
        3. Layers for canvases (other than WebGL/WebGPU)
15
        
16
        We reuse some macOS code in MemoryPressureHandler() but choose different thresholds for iOS,
17
        falling into "conservative mode" at 50% of jetsam limit, and "strict mode" at 65%.
18
        Compositing chooses to be more conservative in either "conservative" or "strict" memory modes.
19
        
20
        Plumb through a "compositingPolicyOverride" both so that on-device testing isn't
21
        flakily falling into a different mode, and so that we can impose the conservative
22
        mode for testing.
23
24
        Test: compositing/layer-creation/compositing-policy.html
25
26
        * platform/graphics/transforms/Matrix3DTransformOperation.cpp:
27
        (WebCore::Matrix3DTransformOperation::isRepresentableIn2D const):
28
        * platform/graphics/transforms/Matrix3DTransformOperation.h:
29
        * platform/graphics/transforms/PerspectiveTransformOperation.h:
30
        * platform/graphics/transforms/RotateTransformOperation.h:
31
        * platform/graphics/transforms/ScaleTransformOperation.h:
32
        * platform/graphics/transforms/TransformOperation.h:
33
        (WebCore::TransformOperation::isRepresentableIn2D const):
34
        * platform/graphics/transforms/TransformOperations.h:
35
        (WebCore::TransformOperations::has3DOperation const):
36
        (WebCore::TransformOperations::isRepresentableIn2D const):
37
        * platform/graphics/transforms/TranslateTransformOperation.h:
38
        * rendering/RenderLayerBacking.cpp:
39
        (WebCore::RenderLayerBacking::updateGeometry):
40
        * rendering/RenderLayerCompositor.cpp:
41
        (WebCore::RenderLayerCompositor::cacheAcceleratedCompositingFlags):
42
        (WebCore::RenderLayerCompositor::updateCompositingLayers):
43
        (WebCore::RenderLayerCompositor::requiresCompositingForTransform const):
44
        (WebCore::RenderLayerCompositor::requiresCompositingForVideo const):
45
        (WebCore::RenderLayerCompositor::requiresCompositingForCanvas const):
46
        (WebCore::RenderLayerCompositor::requiresCompositingForPlugin const):
47
        (WebCore::RenderLayerCompositor::requiresCompositingForWillChange const):
48
        (WebCore::RenderLayerCompositor::needsFixedRootBackgroundLayer const):
49
        (WebCore::operator<<):
50
        * rendering/RenderLayerCompositor.h:
51
1
2018-07-19  Simon Fraser  <simon.fraser@apple.com>
52
2018-07-19  Simon Fraser  <simon.fraser@apple.com>
2
53
3
        Remove completed animations from GraphicsLayer, thus avoiding excessive backing store allocation
54
        Remove completed animations from GraphicsLayer, thus avoiding excessive backing store allocation
- a/Source/WTF/wtf/MemoryPressureHandler.cpp -3 / +18 lines
Lines 113-124 size_t MemoryPressureHandler::thresholdForMemoryKill() a/Source/WTF/wtf/MemoryPressureHandler.cpp_sec1
113
static size_t thresholdForPolicy(MemoryUsagePolicy policy)
113
static size_t thresholdForPolicy(MemoryUsagePolicy policy)
114
{
114
{
115
    const size_t baseThresholdForPolicy = std::min(3 * GB, ramSize());
115
    const size_t baseThresholdForPolicy = std::min(3 * GB, ramSize());
116
117
#if PLATFORM(IOS)
118
    const double conservativeThresholdFraction = 0.5;
119
    const double strictThresholdFraction = 0.65;
120
#else
121
    const double conservativeThresholdFraction = 0.33;
122
    const double strictThresholdFraction = 0.5;
123
#endif
124
116
    switch (policy) {
125
    switch (policy) {
126
    case MemoryUsagePolicy::Unrestricted:
127
        return 0;
117
    case MemoryUsagePolicy::Conservative:
128
    case MemoryUsagePolicy::Conservative:
118
        return baseThresholdForPolicy / 3;
129
        return baseThresholdForPolicy * conservativeThresholdFraction;
119
    case MemoryUsagePolicy::Strict:
130
    case MemoryUsagePolicy::Strict:
120
        return baseThresholdForPolicy / 2;
131
        return baseThresholdForPolicy * strictThresholdFraction;
121
    case MemoryUsagePolicy::Unrestricted:
122
    default:
132
    default:
123
        ASSERT_NOT_REACHED();
133
        ASSERT_NOT_REACHED();
124
        return 0;
134
        return 0;
Lines 134-139 static MemoryUsagePolicy policyForFootprint(size_t footprint) a/Source/WTF/wtf/MemoryPressureHandler.cpp_sec2
134
    return MemoryUsagePolicy::Unrestricted;
144
    return MemoryUsagePolicy::Unrestricted;
135
}
145
}
136
146
147
MemoryUsagePolicy MemoryPressureHandler::currentMemoryUsagePolicy()
148
{
149
    return policyForFootprint(memoryFootprint().value_or(0));
150
}
151
137
void MemoryPressureHandler::shrinkOrDie()
152
void MemoryPressureHandler::shrinkOrDie()
138
{
153
{
139
    RELEASE_LOG(MemoryPressure, "Process is above the memory kill threshold. Trying to shrink down.");
154
    RELEASE_LOG(MemoryPressure, "Process is above the memory kill threshold. Trying to shrink down.");
- a/Source/WTF/wtf/MemoryPressureHandler.h +2 lines
Lines 92-97 public: a/Source/WTF/wtf/MemoryPressureHandler.h_sec1
92
    }
92
    }
93
    void setUnderMemoryPressure(bool);
93
    void setUnderMemoryPressure(bool);
94
94
95
    WTF_EXPORT_PRIVATE static MemoryUsagePolicy currentMemoryUsagePolicy();
96
95
    class ReliefLogger {
97
    class ReliefLogger {
96
    public:
98
    public:
97
        explicit ReliefLogger(const char *log)
99
        explicit ReliefLogger(const char *log)
- a/Source/WebCore/page/Page.h +9 lines
Lines 154-159 enum class EventThrottlingBehavior { a/Source/WebCore/page/Page.h_sec1
154
    Unresponsive
154
    Unresponsive
155
};
155
};
156
156
157
enum class CompositingPolicy : uint8_t {
158
    Normal,
159
    Conservative, // Used in low memory situations.
160
};
161
157
enum class CanWrap : bool;
162
enum class CanWrap : bool;
158
enum class DidWrap : bool;
163
enum class DidWrap : bool;
159
enum class RouteSharingPolicy;
164
enum class RouteSharingPolicy;
Lines 633-638 public: a/Source/WebCore/page/Page.h_sec2
633
    std::optional<EventThrottlingBehavior> eventThrottlingBehaviorOverride() const { return m_eventThrottlingBehaviorOverride; }
638
    std::optional<EventThrottlingBehavior> eventThrottlingBehaviorOverride() const { return m_eventThrottlingBehaviorOverride; }
634
    void setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior> throttling) { m_eventThrottlingBehaviorOverride = throttling; }
639
    void setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior> throttling) { m_eventThrottlingBehaviorOverride = throttling; }
635
640
641
    std::optional<CompositingPolicy> compositingPolicyOverride() const { return m_compositingPolicyOverride; }
642
    void setCompositingPolicyOverride(std::optional<CompositingPolicy> policy) { m_compositingPolicyOverride = policy; }
643
636
    WebGLStateTracker* webGLStateTracker() const { return m_webGLStateTracker.get(); }
644
    WebGLStateTracker* webGLStateTracker() const { return m_webGLStateTracker.get(); }
637
645
638
    bool isOnlyNonUtilityPage() const;
646
    bool isOnlyNonUtilityPage() const;
Lines 869-874 private: a/Source/WebCore/page/Page.h_sec3
869
    
877
    
870
    // For testing.
878
    // For testing.
871
    std::optional<EventThrottlingBehavior> m_eventThrottlingBehaviorOverride;
879
    std::optional<EventThrottlingBehavior> m_eventThrottlingBehaviorOverride;
880
    std::optional<CompositingPolicy> m_compositingPolicyOverride;
872
881
873
    std::unique_ptr<PerformanceMonitor> m_performanceMonitor;
882
    std::unique_ptr<PerformanceMonitor> m_performanceMonitor;
874
    std::unique_ptr<LowPowerModeNotifier> m_lowPowerModeNotifier;
883
    std::unique_ptr<LowPowerModeNotifier> m_lowPowerModeNotifier;
- a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp +5 lines
Lines 61-66 Ref<TransformOperation> Matrix3DTransformOperation::blend(const TransformOperati a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.cpp_sec1
61
    return createOperation(toT, fromT, progress);
61
    return createOperation(toT, fromT, progress);
62
}
62
}
63
63
64
bool Matrix3DTransformOperation::isRepresentableIn2D() const
65
{
66
    return m_matrix.isAffine();
67
}
68
64
void Matrix3DTransformOperation::dump(TextStream& ts) const
69
void Matrix3DTransformOperation::dump(TextStream& ts) const
65
{
70
{
66
    ts << type() << "(" << m_matrix << ")";
71
    ts << type() << "(" << m_matrix << ")";
- a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h -1 / +3 lines
Lines 46-52 public: a/Source/WebCore/platform/graphics/transforms/Matrix3DTransformOperation.h_sec1
46
46
47
private:    
47
private:    
48
    bool isIdentity() const override { return m_matrix.isIdentity(); }
48
    bool isIdentity() const override { return m_matrix.isIdentity(); }
49
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
49
    bool isAffectedByTransformOrigin() const final { return !isIdentity(); }
50
51
    bool isRepresentableIn2D() const final;
50
52
51
    bool operator==(const TransformOperation&) const override;
53
    bool operator==(const TransformOperation&) const override;
52
54
- a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h +1 lines
Lines 49-54 public: a/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.h_sec1
49
private:
49
private:
50
    bool isIdentity() const override { return !floatValueForLength(m_p, 1); }
50
    bool isIdentity() const override { return !floatValueForLength(m_p, 1); }
51
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
51
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
52
    bool isRepresentableIn2D() const final { return false; }
52
53
53
    bool operator==(const TransformOperation&) const override;
54
    bool operator==(const TransformOperation&) const override;
54
55
- a/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h +1 lines
Lines 54-59 public: a/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.h_sec1
54
private:
54
private:
55
    bool isIdentity() const override { return m_angle == 0; }
55
    bool isIdentity() const override { return m_angle == 0; }
56
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
56
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
57
    bool isRepresentableIn2D() const final { return (!m_x && !m_y) || !m_angle; }
57
58
58
    bool operator==(const TransformOperation&) const override;
59
    bool operator==(const TransformOperation&) const override;
59
60
- a/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h +1 lines
Lines 53-58 public: a/Source/WebCore/platform/graphics/transforms/ScaleTransformOperation.h_sec1
53
private:
53
private:
54
    bool isIdentity() const override { return m_x == 1 &&  m_y == 1 &&  m_z == 1; }
54
    bool isIdentity() const override { return m_x == 1 &&  m_y == 1 &&  m_z == 1; }
55
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
55
    bool isAffectedByTransformOrigin() const override { return !isIdentity(); }
56
    bool isRepresentableIn2D() const final { return m_z == 1; }
56
57
57
    bool operator==(const TransformOperation&) const override;
58
    bool operator==(const TransformOperation&) const override;
58
59
- a/Source/WebCore/platform/graphics/transforms/TransformOperation.h +2 lines
Lines 87-92 public: a/Source/WebCore/platform/graphics/transforms/TransformOperation.h_sec1
87
               opType == MATRIX_3D ||
87
               opType == MATRIX_3D ||
88
               opType == PERSPECTIVE;
88
               opType == PERSPECTIVE;
89
    }
89
    }
90
    
91
    virtual bool isRepresentableIn2D() const { return true; }
90
92
91
    bool isRotateTransformOperationType() const
93
    bool isRotateTransformOperationType() const
92
    {
94
    {
- a/Source/WebCore/platform/graphics/transforms/TransformOperations.h -6 / +14 lines
Lines 22-29 a/Source/WebCore/platform/graphics/transforms/TransformOperations.h_sec1
22
 *
22
 *
23
 */
23
 */
24
24
25
#ifndef TransformOperations_h
25
#pragma once
26
#define TransformOperations_h
27
26
28
#include "LayoutSize.h"
27
#include "LayoutSize.h"
29
#include "TransformOperation.h"
28
#include "TransformOperation.h"
Lines 53-64 public: a/Source/WebCore/platform/graphics/transforms/TransformOperations.h_sec2
53
    // values describe affine transforms)
52
    // values describe affine transforms)
54
    bool has3DOperation() const
53
    bool has3DOperation() const
55
    {
54
    {
56
        for (unsigned i = 0; i < m_operations.size(); ++i)
55
        for (const auto& operation : m_operations) {
57
            if (m_operations[i]->is3DOperation())
56
            if (operation->is3DOperation())
58
                return true;
57
                return true;
58
        }
59
        return false;
59
        return false;
60
    }
60
    }
61
    
61
62
    bool isRepresentableIn2D() const
63
    {
64
        for (const auto& operation : m_operations) {
65
            if (!operation->isRepresentableIn2D())
66
                return false;
67
        }
68
        return true;
69
    }
70
62
    bool operationsMatch(const TransformOperations&) const;
71
    bool operationsMatch(const TransformOperations&) const;
63
    
72
    
64
    void clear()
73
    void clear()
Lines 86-89 WTF::TextStream& operator<<(WTF::TextStream&, const TransformOperations&); a/Source/WebCore/platform/graphics/transforms/TransformOperations.h_sec3
86
95
87
} // namespace WebCore
96
} // namespace WebCore
88
97
89
#endif // TransformOperations_h
- a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h +2 lines
Lines 59-64 public: a/Source/WebCore/platform/graphics/transforms/TranslateTransformOperation.h_sec1
59
private:
59
private:
60
    bool isIdentity() const override { return !floatValueForLength(m_x, 1) && !floatValueForLength(m_y, 1) && !floatValueForLength(m_z, 1); }
60
    bool isIdentity() const override { return !floatValueForLength(m_x, 1) && !floatValueForLength(m_y, 1) && !floatValueForLength(m_z, 1); }
61
61
62
    bool isRepresentableIn2D() const final { return m_z.isZero(); }
63
62
    bool operator==(const TransformOperation&) const override;
64
    bool operator==(const TransformOperation&) const override;
63
65
64
    bool apply(TransformationMatrix& transform, const FloatSize& borderBoxSize) const override
66
    bool apply(TransformationMatrix& transform, const FloatSize& borderBoxSize) const override
- a/Source/WebCore/rendering/RenderLayerBacking.cpp -2 lines
Lines 950-957 LayoutRect RenderLayerBacking::computeParentGraphicsLayerRect(RenderLayer* compo a/Source/WebCore/rendering/RenderLayerBacking.cpp_sec1
950
950
951
void RenderLayerBacking::updateGeometry()
951
void RenderLayerBacking::updateGeometry()
952
{
952
{
953
    LOG_WITH_STREAM(Compositing, stream << "updateGeometry " << m_owningLayer);
954
955
    // If we haven't built z-order lists yet, wait until later.
953
    // If we haven't built z-order lists yet, wait until later.
956
    if (m_owningLayer.isStackingContainer() && m_owningLayer.m_zOrderListsDirty)
954
    if (m_owningLayer.isStackingContainer() && m_owningLayer.m_zOrderListsDirty)
957
        return;
955
        return;
- a/Source/WebCore/rendering/RenderLayerCompositor.cpp -21 / +79 lines
Lines 60-65 a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec1
60
#include "Settings.h"
60
#include "Settings.h"
61
#include "TiledBacking.h"
61
#include "TiledBacking.h"
62
#include "TransformState.h"
62
#include "TransformState.h"
63
#include <wtf/MemoryPressureHandler.h>
63
#include <wtf/SetForScope.h>
64
#include <wtf/SetForScope.h>
64
#include <wtf/text/CString.h>
65
#include <wtf/text/CString.h>
65
#include <wtf/text/StringBuilder.h>
66
#include <wtf/text/StringBuilder.h>
Lines 346-351 void RenderLayerCompositor::cacheAcceleratedCompositingFlags() a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec2
346
        if (m_layerForScrollCorner)
347
        if (m_layerForScrollCorner)
347
            m_layerForScrollCorner->setShowDebugBorder(m_showDebugBorders);
348
            m_layerForScrollCorner->setShowDebugBorder(m_showDebugBorders);
348
    }
349
    }
350
    
351
    computeCompositingPolicy();
349
}
352
}
350
353
351
void RenderLayerCompositor::cacheAcceleratedCompositingFlagsAfterLayout()
354
void RenderLayerCompositor::cacheAcceleratedCompositingFlagsAfterLayout()
Lines 362-367 void RenderLayerCompositor::cacheAcceleratedCompositingFlagsAfterLayout() a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec3
362
    }
365
    }
363
}
366
}
364
367
368
void RenderLayerCompositor::setCompositingPolicy(CompositingPolicy policy)
369
{
370
    if (policy == m_compositingPolicy)
371
        return;
372
373
    m_compositingPolicy = policy;
374
    compositingPolicyChanged();
375
}
376
377
void RenderLayerCompositor::compositingPolicyChanged()
378
{
379
    LOG_WITH_STREAM(Compositing, stream << "RenderLayerCompositor " << this << " compositingPolicyChanged - current policy is " << m_compositingPolicy);
380
381
    scheduleCompositingLayerUpdate();
382
}
383
384
void RenderLayerCompositor::computeCompositingPolicy()
385
{
386
    if (page().compositingPolicyOverride()) {
387
        setCompositingPolicy(page().compositingPolicyOverride().value());
388
        return;
389
    }
390
    
391
    auto memoryPolicy = MemoryPressureHandler::currentMemoryUsagePolicy();
392
    setCompositingPolicy(memoryPolicy == WTF::MemoryUsagePolicy::Unrestricted ? CompositingPolicy::Normal : CompositingPolicy::Conservative);
393
394
    WTFLogAlways("SMFR - RenderLayerCompositor %p computeCompositingPolicy - under memory pressure %d, memory policy %d, compositing policy %d", this, MemoryPressureHandler::singleton().isUnderMemoryPressure(), static_cast<int>(memoryPolicy), static_cast<int>(m_compositingPolicy));
395
}
396
365
bool RenderLayerCompositor::canRender3DTransforms() const
397
bool RenderLayerCompositor::canRender3DTransforms() const
366
{
398
{
367
    return hasAcceleratedCompositing() && (m_compositingTriggers & ChromeClient::ThreeDTransformTrigger);
399
    return hasAcceleratedCompositing() && (m_compositingTriggers & ChromeClient::ThreeDTransformTrigger);
Lines 732-738 bool RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec4
732
764
733
        auto& frame = m_renderView.frameView().frame();
765
        auto& frame = m_renderView.frameView().frame();
734
        bool isMainFrame = isMainFrameCompositor();
766
        bool isMainFrame = isMainFrameCompositor();
735
        LOG(Compositing, "\nUpdate %d of %s.\n", m_rootLayerUpdateCount, isMainFrame ? "main frame" : frame.tree().uniqueName().string().utf8().data());
767
        LOG_WITH_STREAM(Compositing, stream << "\nUpdate " << m_rootLayerUpdateCount << " of " << (isMainFrame ? "main frame" : frame.tree().uniqueName().string().utf8().data()) << " - compositing policy is " << m_compositingPolicy);
736
    }
768
    }
737
#endif
769
#endif
738
770
Lines 2370-2376 bool RenderLayerCompositor::requiresCompositingForTransform(RenderLayerModelObje a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec5
2370
2402
2371
    // Note that we ask the renderer if it has a transform, because the style may have transforms,
2403
    // Note that we ask the renderer if it has a transform, because the style may have transforms,
2372
    // but the renderer may be an inline that doesn't suppport them.
2404
    // but the renderer may be an inline that doesn't suppport them.
2373
    return renderer.hasTransform() && renderer.style().transform().has3DOperation();
2405
    if (!renderer.hasTransform())
2406
        return false;
2407
    
2408
    switch (m_compositingPolicy) {
2409
    case CompositingPolicy::Normal:
2410
        return renderer.style().transform().has3DOperation();
2411
    case CompositingPolicy::Conservative:
2412
        return !renderer.style().transform().isRepresentableIn2D();
2413
    }
2414
    return false;
2374
}
2415
}
2375
2416
2376
bool RenderLayerCompositor::requiresCompositingForBackfaceVisibility(RenderLayerModelObject& renderer) const
2417
bool RenderLayerCompositor::requiresCompositingForBackfaceVisibility(RenderLayerModelObject& renderer) const
Lines 2396-2410 bool RenderLayerCompositor::requiresCompositingForVideo(RenderLayerModelObject& a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec6
2396
{
2437
{
2397
    if (!(m_compositingTriggers & ChromeClient::VideoTrigger))
2438
    if (!(m_compositingTriggers & ChromeClient::VideoTrigger))
2398
        return false;
2439
        return false;
2440
2399
#if ENABLE(VIDEO)
2441
#if ENABLE(VIDEO)
2400
    if (is<RenderVideo>(renderer)) {
2442
    if (!is<RenderVideo>(renderer))
2401
        auto& video = downcast<RenderVideo>(renderer);
2443
        return false;
2402
        return (video.requiresImmediateCompositing() || video.shouldDisplayVideo()) && canAccelerateVideoRendering(video);
2444
2403
    }
2445
    auto& video = downcast<RenderVideo>(renderer);
2446
    return (video.requiresImmediateCompositing() || video.shouldDisplayVideo()) && canAccelerateVideoRendering(video);
2404
#else
2447
#else
2405
    UNUSED_PARAM(renderer);
2448
    UNUSED_PARAM(renderer);
2406
#endif
2407
    return false;
2449
    return false;
2450
#endif
2408
}
2451
}
2409
2452
2410
bool RenderLayerCompositor::requiresCompositingForCanvas(RenderLayerModelObject& renderer) const
2453
bool RenderLayerCompositor::requiresCompositingForCanvas(RenderLayerModelObject& renderer) const
Lines 2412-2428 bool RenderLayerCompositor::requiresCompositingForCanvas(RenderLayerModelObject& a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec7
2412
    if (!(m_compositingTriggers & ChromeClient::CanvasTrigger))
2455
    if (!(m_compositingTriggers & ChromeClient::CanvasTrigger))
2413
        return false;
2456
        return false;
2414
2457
2415
    if (renderer.isCanvas()) {
2458
    if (!renderer.isCanvas())
2416
#if USE(COMPOSITING_FOR_SMALL_CANVASES)
2459
        return false;
2417
        bool isCanvasLargeEnoughToForceCompositing = true;
2460
2418
#else
2461
    bool isCanvasLargeEnoughToForceCompositing = true;
2419
        auto* canvas = downcast<HTMLCanvasElement>(renderer.element());
2462
#if !USE(COMPOSITING_FOR_SMALL_CANVASES)
2420
        auto canvasArea = canvas->size().area<RecordOverflow>();
2463
    auto* canvas = downcast<HTMLCanvasElement>(renderer.element());
2421
        bool isCanvasLargeEnoughToForceCompositing = !canvasArea.hasOverflowed() && canvasArea.unsafeGet() >= canvasAreaThresholdRequiringCompositing;
2464
    auto canvasArea = canvas->size().area<RecordOverflow>();
2465
    isCanvasLargeEnoughToForceCompositing = !canvasArea.hasOverflowed() && canvasArea.unsafeGet() >= canvasAreaThresholdRequiringCompositing;
2422
#endif
2466
#endif
2423
        CanvasCompositingStrategy compositingStrategy = canvasCompositingStrategy(renderer);
2467
2424
        return compositingStrategy == CanvasAsLayerContents || (compositingStrategy == CanvasPaintedToLayer && isCanvasLargeEnoughToForceCompositing);
2468
    CanvasCompositingStrategy compositingStrategy = canvasCompositingStrategy(renderer);
2425
    }
2469
    if (compositingStrategy == CanvasAsLayerContents)
2470
        return true;
2471
2472
    if (m_compositingPolicy == CompositingPolicy::Normal)
2473
        return compositingStrategy == CanvasPaintedToLayer && isCanvasLargeEnoughToForceCompositing;
2426
2474
2427
    return false;
2475
    return false;
2428
}
2476
}
Lines 2432-2439 bool RenderLayerCompositor::requiresCompositingForPlugin(RenderLayerModelObject& a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec8
2432
    if (!(m_compositingTriggers & ChromeClient::PluginTrigger))
2480
    if (!(m_compositingTriggers & ChromeClient::PluginTrigger))
2433
        return false;
2481
        return false;
2434
2482
2435
    bool composite = is<RenderEmbeddedObject>(renderer) && downcast<RenderEmbeddedObject>(renderer).allowsAcceleratedCompositing();
2483
    bool isCompositedPlugin = is<RenderEmbeddedObject>(renderer) && downcast<RenderEmbeddedObject>(renderer).allowsAcceleratedCompositing();
2436
    if (!composite)
2484
    if (!isCompositedPlugin)
2437
        return false;
2485
        return false;
2438
2486
2439
    m_reevaluateCompositingAfterLayout = true;
2487
    m_reevaluateCompositingAfterLayout = true;
Lines 2565-2570 bool RenderLayerCompositor::requiresCompositingForWillChange(RenderLayerModelObj a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec9
2565
    if (!renderer.style().willChange() || !renderer.style().willChange()->canTriggerCompositing())
2613
    if (!renderer.style().willChange() || !renderer.style().willChange()->canTriggerCompositing())
2566
        return false;
2614
        return false;
2567
2615
2616
    if (m_compositingPolicy == CompositingPolicy::Conservative)
2617
        return false;
2618
2568
    if (is<RenderBox>(renderer))
2619
    if (is<RenderBox>(renderer))
2569
        return true;
2620
        return true;
2570
2621
Lines 2807-2814 bool RenderLayerCompositor::needsFixedRootBackgroundLayer(const RenderLayer& lay a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec10
2807
    if (m_renderView.settings().fixedBackgroundsPaintRelativeToDocument())
2858
    if (m_renderView.settings().fixedBackgroundsPaintRelativeToDocument())
2808
        return false;
2859
        return false;
2809
2860
2810
    LOG(Compositing, "RenderLayerCompositor %p needsFixedRootBackgroundLayer returning %d", this, supportsFixedRootBackgroundCompositing() && m_renderView.rootBackgroundIsEntirelyFixed());
2811
2812
    return supportsFixedRootBackgroundCompositing() && m_renderView.rootBackgroundIsEntirelyFixed();
2861
    return supportsFixedRootBackgroundCompositing() && m_renderView.rootBackgroundIsEntirelyFixed();
2813
}
2862
}
2814
2863
Lines 4091-4094 TextStream& operator<<(TextStream& ts, CompositingUpdateType updateType) a/Source/WebCore/rendering/RenderLayerCompositor.cpp_sec11
4091
    return ts;
4140
    return ts;
4092
}
4141
}
4093
4142
4143
TextStream& operator<<(TextStream& ts, CompositingPolicy compositingPolicy)
4144
{
4145
    switch (compositingPolicy) {
4146
    case CompositingPolicy::Normal: ts << "normal"; break;
4147
    case CompositingPolicy::Conservative: ts << "conservative"; break;
4148
    }
4149
    return ts;
4150
}
4151
4094
} // namespace WebCore
4152
} // namespace WebCore
- a/Source/WebCore/rendering/RenderLayerCompositor.h +7 lines
Lines 333-338 private: a/Source/WebCore/rendering/RenderLayerCompositor.h_sec1
333
    struct CompositingState;
333
    struct CompositingState;
334
    struct OverlapExtent;
334
    struct OverlapExtent;
335
335
336
    void setCompositingPolicy(CompositingPolicy);
337
    void compositingPolicyChanged();
338
    void computeCompositingPolicy();
339
    
336
    // GraphicsLayerClient implementation
340
    // GraphicsLayerClient implementation
337
    void notifyFlushRequired(const GraphicsLayer*) override;
341
    void notifyFlushRequired(const GraphicsLayer*) override;
338
    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior) override;
342
    void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const FloatRect&, GraphicsLayerPaintBehavior) override;
Lines 490-495 private: a/Source/WebCore/rendering/RenderLayerCompositor.h_sec2
490
494
491
    ChromeClient::CompositingTriggerFlags m_compositingTriggers { static_cast<ChromeClient::CompositingTriggerFlags>(ChromeClient::AllTriggers) };
495
    ChromeClient::CompositingTriggerFlags m_compositingTriggers { static_cast<ChromeClient::CompositingTriggerFlags>(ChromeClient::AllTriggers) };
492
    bool m_hasAcceleratedCompositing { true };
496
    bool m_hasAcceleratedCompositing { true };
497
    
498
    CompositingPolicy m_compositingPolicy { CompositingPolicy::Normal };
493
499
494
    bool m_showDebugBorders { false };
500
    bool m_showDebugBorders { false };
495
    bool m_showRepaintCounter { false };
501
    bool m_showRepaintCounter { false };
Lines 572-576 private: a/Source/WebCore/rendering/RenderLayerCompositor.h_sec3
572
void paintScrollbar(Scrollbar*, GraphicsContext&, const IntRect& clip);
578
void paintScrollbar(Scrollbar*, GraphicsContext&, const IntRect& clip);
573
579
574
WTF::TextStream& operator<<(WTF::TextStream&, CompositingUpdateType);
580
WTF::TextStream& operator<<(WTF::TextStream&, CompositingUpdateType);
581
WTF::TextStream& operator<<(WTF::TextStream&, CompositingPolicy);
575
582
576
} // namespace WebCore
583
} // namespace WebCore
- a/Source/WebCore/testing/Internals.cpp +43 lines
Lines 3001-3006 ExceptionOr<unsigned> Internals::compositingUpdateCount() a/Source/WebCore/testing/Internals.cpp_sec1
3001
    return document->renderView()->compositor().compositingUpdateCount();
3001
    return document->renderView()->compositor().compositingUpdateCount();
3002
}
3002
}
3003
3003
3004
ExceptionOr<void> Internals::setCompositingPolicyOverride(std::optional<CompositingPolicy> policyOverride)
3005
{
3006
    Document* document = contextDocument();
3007
    if (!document)
3008
        return Exception { InvalidAccessError };
3009
3010
    if (!policyOverride) {
3011
        document->page()->setCompositingPolicyOverride(std::nullopt);
3012
        return { };
3013
    }
3014
3015
    switch (policyOverride.value()) {
3016
    case Internals::CompositingPolicy::Normal:
3017
        document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Normal);
3018
        break;
3019
    case Internals::CompositingPolicy::Conservative:
3020
        document->page()->setCompositingPolicyOverride(WebCore::CompositingPolicy::Conservative);
3021
        break;
3022
    }
3023
    
3024
    return { };
3025
}
3026
3027
ExceptionOr<std::optional<Internals::CompositingPolicy>> Internals::compositingPolicyOverride() const
3028
{
3029
    Document* document = contextDocument();
3030
    if (!document)
3031
        return Exception { InvalidAccessError };
3032
3033
    auto policyOverride = document->page()->compositingPolicyOverride();
3034
    if (!policyOverride)
3035
        return { std::nullopt };
3036
3037
    switch (policyOverride.value()) {
3038
    case WebCore::CompositingPolicy::Normal:
3039
        return { Internals::CompositingPolicy::Normal };
3040
    case WebCore::CompositingPolicy::Conservative:
3041
        return { Internals::CompositingPolicy::Conservative };
3042
    }
3043
3044
    return { Internals::CompositingPolicy::Normal };
3045
}
3046
3004
ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node)
3047
ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node)
3005
{
3048
{
3006
    Document* document;
3049
    Document* document;
- a/Source/WebCore/testing/Internals.h +4 lines
Lines 440-445 public: a/Source/WebCore/testing/Internals.h_sec1
440
    ExceptionOr<void> startTrackingCompositingUpdates();
440
    ExceptionOr<void> startTrackingCompositingUpdates();
441
    ExceptionOr<unsigned> compositingUpdateCount();
441
    ExceptionOr<unsigned> compositingUpdateCount();
442
442
443
    enum CompositingPolicy { Normal, Conservative };
444
    ExceptionOr<void> setCompositingPolicyOverride(std::optional<CompositingPolicy>);
445
    ExceptionOr<std::optional<CompositingPolicy>> compositingPolicyOverride() const;
446
443
    ExceptionOr<void> updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node*);
447
    ExceptionOr<void> updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node*);
444
    unsigned layoutCount() const;
448
    unsigned layoutCount() const;
445
449
- a/Source/WebCore/testing/Internals.idl +7 lines
Lines 81-86 enum EventThrottlingBehavior { a/Source/WebCore/testing/Internals.idl_sec1
81
    "unresponsive"
81
    "unresponsive"
82
};
82
};
83
83
84
enum CompositingPolicy {
85
    "normal",
86
    "conservative"
87
};
88
84
[Conditional=VIDEO] enum PlaybackControlsPurpose {
89
[Conditional=VIDEO] enum PlaybackControlsPurpose {
85
    "ControlsManager",
90
    "ControlsManager",
86
    "NowPlaying"
91
    "NowPlaying"
Lines 433-438 enum EventThrottlingBehavior { a/Source/WebCore/testing/Internals.idl_sec2
433
    [MayThrowException] void startTrackingCompositingUpdates();
438
    [MayThrowException] void startTrackingCompositingUpdates();
434
    [MayThrowException] unsigned long compositingUpdateCount();
439
    [MayThrowException] unsigned long compositingUpdateCount();
435
440
441
    attribute CompositingPolicy? compositingPolicyOverride;
442
436
    // |node| should be Document, HTMLIFrameElement, or unspecified.
443
    // |node| should be Document, HTMLIFrameElement, or unspecified.
437
    // If |node| is an HTMLIFrameElement, it assumes node.contentDocument is
444
    // If |node| is an HTMLIFrameElement, it assumes node.contentDocument is
438
    // specified without security checks. Unspecified or null means this document.
445
    // specified without security checks. Unspecified or null means this document.
- a/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp +19 lines
Lines 63-68 a/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp_sec1
63
#include <WebCore/Page.h>
63
#include <WebCore/Page.h>
64
#include <WebCore/PageOverlay.h>
64
#include <WebCore/PageOverlay.h>
65
#include <WebCore/PageOverlayController.h>
65
#include <WebCore/PageOverlayController.h>
66
#include <WebCore/RenderLayerCompositor.h>
66
#include <WebCore/SecurityOriginData.h>
67
#include <WebCore/SecurityOriginData.h>
67
#include <WebCore/URL.h>
68
#include <WebCore/URL.h>
68
#include <WebCore/WheelEventTestTrigger.h>
69
#include <WebCore/WheelEventTestTrigger.h>
Lines 713-715 void WKBundlePageSetEventThrottlingBehaviorOverride(WKBundlePageRef page, WKEven a/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePage.cpp_sec2
713
714
714
    toImpl(page)->corePage()->setEventThrottlingBehaviorOverride(behaviorValue);
715
    toImpl(page)->corePage()->setEventThrottlingBehaviorOverride(behaviorValue);
715
}
716
}
717
718
void WKBundlePageSetCompositingPolicyOverride(WKBundlePageRef page, WKCompositingPolicy* policy)
719
{
720
    std::optional<WebCore::CompositingPolicy> policyValue;
721
    if (policy) {
722
        switch (*policy) {
723
        case kWKCompositingPolicyNormal:
724
            policyValue = WebCore::CompositingPolicy::Normal;
725
            break;
726
        case kWKCompositingPolicyConservative:
727
            policyValue = WebCore::CompositingPolicy::Conservative;
728
            break;
729
        }
730
    }
731
732
    toImpl(page)->corePage()->setCompositingPolicyOverride(policyValue);
733
}
734
- a/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h +10 lines
Lines 120-125 typedef uint32_t WKEventThrottlingBehavior; a/Source/WebKit/WebProcess/InjectedBundle/API/c/WKBundlePagePrivate.h_sec1
120
// Passing null in the second parameter clears the override.
120
// Passing null in the second parameter clears the override.
121
WK_EXPORT void WKBundlePageSetEventThrottlingBehaviorOverride(WKBundlePageRef, WKEventThrottlingBehavior*);
121
WK_EXPORT void WKBundlePageSetEventThrottlingBehaviorOverride(WKBundlePageRef, WKEventThrottlingBehavior*);
122
122
123
enum {
124
    kWKCompositingPolicyNormal = 0,
125
    kWKCompositingPolicyConservative
126
};
127
128
typedef uint32_t WKCompositingPolicy;
129
130
// Passing null in the second parameter clears the override.
131
WK_EXPORT void WKBundlePageSetCompositingPolicyOverride(WKBundlePageRef, WKCompositingPolicy*);
132
123
#if TARGET_OS_IPHONE
133
#if TARGET_OS_IPHONE
124
WK_EXPORT void WKBundlePageSetUseTestingViewportConfiguration(WKBundlePageRef, bool);
134
WK_EXPORT void WKBundlePageSetUseTestingViewportConfiguration(WKBundlePageRef, bool);
125
#endif
135
#endif
- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +4 lines
Lines 426-431 void InjectedBundlePage::prepare() a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp_sec1
426
    // Force consistent "responsive" behavior for WebPage::eventThrottlingDelay() for testing. Tests can override via internals.
426
    // Force consistent "responsive" behavior for WebPage::eventThrottlingDelay() for testing. Tests can override via internals.
427
    WKEventThrottlingBehavior behavior = kWKEventThrottlingBehaviorResponsive;
427
    WKEventThrottlingBehavior behavior = kWKEventThrottlingBehaviorResponsive;
428
    WKBundlePageSetEventThrottlingBehaviorOverride(m_page, &behavior);
428
    WKBundlePageSetEventThrottlingBehaviorOverride(m_page, &behavior);
429
    
430
    // Force consistent compositing behavior, even if the test runner is under memory pressure. Tests can override via internals.
431
    WKCompositingPolicy policy = kWKCompositingPolicyNormal;
432
    WKBundlePageSetCompositingPolicyOverride(m_page, &policy);
429
}
433
}
430
434
431
void InjectedBundlePage::resetAfterTest()
435
void InjectedBundlePage::resetAfterTest()
- a/LayoutTests/compositing/layer-creation/compositing-policy-expected.txt +28 lines
Line 0 a/LayoutTests/compositing/layer-creation/compositing-policy-expected.txt_sec1
1
transform: translate3d(10px, 1px, 1px)
2
Has backing under low memory.
3
transform: translateZ(0)
4
translateZ(0): No backing under low memory.
5
transform: translate3d(10px, 1px, 0)
6
No backing under low memory.
7
will-change: transform
8
No backing under low memory.
9
 (GraphicsLayer
10
  (anchor 0.00 0.00)
11
  (bounds 800.00 1018.00)
12
  (children 1
13
    (GraphicsLayer
14
      (bounds 800.00 1018.00)
15
      (contentsOpaque 1)
16
      (children 1
17
        (GraphicsLayer
18
          (position 18.00 10.00)
19
          (bounds 308.00 108.00)
20
          (contentsOpaque 1)
21
          (drawsContent 1)
22
          (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])
23
        )
24
      )
25
    )
26
  )
27
)
28
- a/LayoutTests/compositing/layer-creation/compositing-policy.html +66 lines
Line 0 a/LayoutTests/compositing/layer-creation/compositing-policy.html_sec1
1
<!DOCTYPE html>
2
3
<html>
4
<head>
5
    <style>
6
        body {
7
            overflow:hidden; /* prevent scrollbars and document height from affecting test output */
8
            height: 1000px;
9
        }
10
        .box {
11
            margin: 10px;
12
            height: 100px;
13
            width: 300px;
14
            padding: 4px;
15
            background-color: silver;
16
        }
17
    </style>
18
    <script>
19
        if (window.testRunner)
20
            testRunner.dumpAsText();
21
22
        if (window.internals)
23
            internals.compositingPolicyOverride = 'conservative';
24
25
        function dumpLayers()
26
        {
27
            let canvas = document.getElementsByTagName('canvas')[0];
28
            var ctx = canvas.getContext('2d');
29
            ctx.fillStyle = 'white';
30
            ctx.fillRect(0, 0, canvas.width, canvas.height);
31
            if (window.testRunner)
32
                document.getElementById('layers').innerText = window.internals.layerTreeAsText(document);
33
        }
34
35
        window.addEventListener('load', dumpLayers, false);
36
    </script>
37
</head>
38
<body>
39
40
<div class="box" style="transform: translate3d(10px, 1px, 1px)">
41
    <pre>transform: translate3d(10px, 1px, 1px)</pre>
42
    Has backing under low memory.
43
</div>
44
45
<div class="box" style="transform: translateZ(0)">
46
    <pre>transform: translateZ(0)</pre>
47
    translateZ(0): No backing under low memory.
48
</div>
49
50
<div class="box" style="transform: translate3d(10px, 1px, 0)">
51
    <pre>transform: translate3d(10px, 1px, 0)</pre>
52
    No backing under low memory.
53
</div>
54
55
<div class="box" style="will-change: transform">
56
    <pre>will-change: transform</pre>
57
    No backing under low memory.
58
</div>
59
60
<canvas class="box" style="box-shadow: 0 0 10px black">
61
</canvas>
62
63
<pre id="layers"></pre>
64
65
</body>
66
</html>

Return to Bug 187866