Title: [287079] trunk/Source/WebCore
Revision
287079
Author
[email protected]
Date
2021-12-15 09:46:07 -0800 (Wed, 15 Dec 2021)

Log Message

Twitter scroll stutter: ensure that CA backing store is always deallocated on the main thread
https://bugs.webkit.org/show_bug.cgi?id=234328
<rdar://85892959>

Reviewed by Tim Horton.

When scrolling pages like Twitter and Facebook we observed CoreAnimation commits on the
scrolling thread taking longer than they should because CABackingStore objects were being
released in those transactions.

Work around this issue by extending the lifetime of CABackingStore objects if we detect that
they might be entrained into a scrolling tree commit, by virtue of having overlapping main
thread and scrolling thread commits.

The logic is contained in PlatformCALayerContentsDelayedReleaser, which puts layer contents
into a retaining vector when they are being cleared on the layer. They are released at the
end of a main thread commit; if we detected overlapping commits, then we release on a
dispatch to extend the lifetime slightly.

The remaining changes are plumbing to get commit willBegin/didEnd messages to PlatformCALayerContentsDelayedReleaser
for main and scrolling threads.

* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
* page/scrolling/ScrollingTree.h:
* page/scrolling/ThreadedScrollingTree.h:
* page/scrolling/mac/ScrollingCoordinatorMac.h:
* page/scrolling/mac/ScrollingCoordinatorMac.mm:
(WebCore::ScrollingCoordinatorMac::willStartPlatformRenderingUpdate):
(WebCore::ScrollingCoordinatorMac::didCompletePlatformRenderingUpdate):
* page/scrolling/mac/ScrollingTreeMac.h:
* page/scrolling/mac/ScrollingTreeMac.mm:
(ScrollingTreeMac::applyLayerPositionsInternal):
(ScrollingTreeMac::registerForPlatformRenderingUpdateCallback):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::updateContentsVisibility):
(WebCore::GraphicsLayerCA::updateDrawsContent):
* platform/graphics/ca/PlatformCALayer.cpp:
(WebCore::PlatformCALayer::clearContents):
* platform/graphics/ca/PlatformCALayer.h:
* platform/graphics/ca/cocoa/PlatformCALayerCocoa.h:
* platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
(WebCore::PlatformCALayerCocoa::setBackingStoreAttached):
(WebCore::PlatformCALayerCocoa::clearContents):
* platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.h: Added.
(WebCore::PlatformCALayerContentsDelayedReleaser::WTF_GUARDED_BY_LOCK):
* platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.mm: Added.
(WebCore::PlatformCALayerContentsDelayedReleaser::singleton):
(WebCore::PlatformCALayerContentsDelayedReleaser::takeLayerContents):
(WebCore::PlatformCALayerContentsDelayedReleaser::mainThreadCommitWillStart):
(WebCore::PlatformCALayerContentsDelayedReleaser::mainThreadCommitDidEnd):
(WebCore::PlatformCALayerContentsDelayedReleaser::scrollingThreadCommitWillStart):
(WebCore::PlatformCALayerContentsDelayedReleaser::scrollingThreadCommitDidEnd):
(WebCore::PlatformCALayerContentsDelayedReleaser::updateSawOverlappingCommit):
(WebCore::PlatformCALayerContentsDelayedReleaser::clearRetainedContents):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (287078 => 287079)


--- trunk/Source/WebCore/ChangeLog	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/ChangeLog	2021-12-15 17:46:07 UTC (rev 287079)
@@ -1,3 +1,61 @@
+2021-12-15  Simon Fraser  <[email protected]>
+
+        Twitter scroll stutter: ensure that CA backing store is always deallocated on the main thread
+        https://bugs.webkit.org/show_bug.cgi?id=234328
+        <rdar://85892959>
+
+        Reviewed by Tim Horton.
+
+        When scrolling pages like Twitter and Facebook we observed CoreAnimation commits on the
+        scrolling thread taking longer than they should because CABackingStore objects were being
+        released in those transactions.
+
+        Work around this issue by extending the lifetime of CABackingStore objects if we detect that
+        they might be entrained into a scrolling tree commit, by virtue of having overlapping main
+        thread and scrolling thread commits.
+
+        The logic is contained in PlatformCALayerContentsDelayedReleaser, which puts layer contents
+        into a retaining vector when they are being cleared on the layer. They are released at the
+        end of a main thread commit; if we detected overlapping commits, then we release on a
+        dispatch to extend the lifetime slightly.
+
+        The remaining changes are plumbing to get commit willBegin/didEnd messages to PlatformCALayerContentsDelayedReleaser
+        for main and scrolling threads.
+
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/scrolling/ScrollingTree.h:
+        * page/scrolling/ThreadedScrollingTree.h:
+        * page/scrolling/mac/ScrollingCoordinatorMac.h:
+        * page/scrolling/mac/ScrollingCoordinatorMac.mm:
+        (WebCore::ScrollingCoordinatorMac::willStartPlatformRenderingUpdate):
+        (WebCore::ScrollingCoordinatorMac::didCompletePlatformRenderingUpdate):
+        * page/scrolling/mac/ScrollingTreeMac.h:
+        * page/scrolling/mac/ScrollingTreeMac.mm:
+        (ScrollingTreeMac::applyLayerPositionsInternal):
+        (ScrollingTreeMac::registerForPlatformRenderingUpdateCallback):
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::updateContentsVisibility):
+        (WebCore::GraphicsLayerCA::updateDrawsContent):
+        * platform/graphics/ca/PlatformCALayer.cpp:
+        (WebCore::PlatformCALayer::clearContents):
+        * platform/graphics/ca/PlatformCALayer.h:
+        * platform/graphics/ca/cocoa/PlatformCALayerCocoa.h:
+        * platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm:
+        (WebCore::PlatformCALayerCocoa::setBackingStoreAttached):
+        (WebCore::PlatformCALayerCocoa::clearContents):
+        * platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.h: Added.
+        (WebCore::PlatformCALayerContentsDelayedReleaser::WTF_GUARDED_BY_LOCK):
+        * platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.mm: Added.
+        (WebCore::PlatformCALayerContentsDelayedReleaser::singleton):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::takeLayerContents):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::mainThreadCommitWillStart):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::mainThreadCommitDidEnd):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::scrollingThreadCommitWillStart):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::scrollingThreadCommitDidEnd):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::updateSawOverlappingCommit):
+        (WebCore::PlatformCALayerContentsDelayedReleaser::clearRetainedContents):
+
 2021-12-15  Chris Dumez  <[email protected]>
 
         http/tests/security/basic-auth-subresource.html and some other http auth tests are flaky

Modified: trunk/Source/WebCore/SourcesCocoa.txt (287078 => 287079)


--- trunk/Source/WebCore/SourcesCocoa.txt	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/SourcesCocoa.txt	2021-12-15 17:46:07 UTC (rev 287079)
@@ -337,6 +337,7 @@
 platform/graphics/ca/cocoa/PlatformCAAnimationCocoa.mm
 platform/graphics/ca/cocoa/PlatformCAFiltersCocoa.mm
 platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm
+platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.mm
 platform/graphics/ca/cocoa/WebSystemBackdropLayer.mm
 platform/graphics/ca/cocoa/WebTiledBackingLayer.mm
 platform/graphics/ca/cocoa/WebVideoContainerLayer.mm

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (287078 => 287079)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-12-15 17:46:07 UTC (rev 287079)
@@ -6394,6 +6394,8 @@
 		0FA0A0E523AEAA35000EEB94 /* dialog.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = dialog.css; sourceTree = "<group>"; };
 		0FA24D77162DF91900A3F4C0 /* GraphicsLayerUpdater.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsLayerUpdater.cpp; sourceTree = "<group>"; };
 		0FA24D78162DF91900A3F4C0 /* GraphicsLayerUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GraphicsLayerUpdater.h; sourceTree = "<group>"; };
+		0FA2B233276817540020C7C1 /* PlatformCALayerContentsDelayedReleaser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformCALayerContentsDelayedReleaser.h; sourceTree = "<group>"; };
+		0FA2B235276817550020C7C1 /* PlatformCALayerContentsDelayedReleaser.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformCALayerContentsDelayedReleaser.mm; sourceTree = "<group>"; };
 		0FA61B0C26F43212001AADB6 /* ScrollAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollAnimation.h; sourceTree = "<group>"; };
 		0FB0689425243B90001E8E75 /* DisplayTextBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayTextBox.cpp; sourceTree = "<group>"; };
 		0FB0689625243B90001E8E75 /* DisplayTextBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayTextBox.h; sourceTree = "<group>"; };
@@ -21671,6 +21673,8 @@
 				0F13163F16ED0CDE0035CC04 /* PlatformCAFiltersCocoa.mm */,
 				2D70BA1218074DDF0001908A /* PlatformCALayerCocoa.h */,
 				4958782012A57DDF007238AC /* PlatformCALayerCocoa.mm */,
+				0FA2B233276817540020C7C1 /* PlatformCALayerContentsDelayedReleaser.h */,
+				0FA2B235276817550020C7C1 /* PlatformCALayerContentsDelayedReleaser.mm */,
 				31DEA4541B39F4D900F77178 /* WebSystemBackdropLayer.h */,
 				31DEA4531B39F4D900F77178 /* WebSystemBackdropLayer.mm */,
 				0F580FA11496939100FB5BD8 /* WebTiledBackingLayer.h */,
@@ -33121,7 +33125,6 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				7B582DD82716F55B004B92D0 /* (null) in Headers */,
 				7CD0E2B81F80A4820016A4CE /* AbortController.h in Headers */,
 				7CD0E2BF1F80A56E0016A4CE /* AbortSignal.h in Headers */,
 				46B95195207D633400A7D2DD /* AbstractDOMWindow.h in Headers */,

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (287078 => 287079)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -245,7 +245,7 @@
 
     std::optional<FramesPerSecond> nominalFramesPerSecond();
 
-    void applyLayerPositionsInternal() WTF_REQUIRES_LOCK(m_treeLock);
+    WEBCORE_EXPORT virtual void applyLayerPositionsInternal() WTF_REQUIRES_LOCK(m_treeLock);
     void removeAllNodes() WTF_REQUIRES_LOCK(m_treeLock);
     
     virtual void hasNodeWithAnimatedScrollChanged(bool /* hasNodeWithAnimatedScroll */) { }

Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h (287078 => 287079)


--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -108,7 +108,7 @@
     void hasNodeWithAnimatedScrollChanged(bool) final;
     
     void storeScrollPositionsAtLastDisplayRefresh() WTF_REQUIRES_LOCK(m_treeLock);
-    
+
     void serviceScrollAnimations(MonotonicTime) WTF_REQUIRES_LOCK(m_treeLock);
 
     Seconds frameDuration();

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h (287078 => 287079)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -53,6 +53,7 @@
     void willStartRenderingUpdate() final;
     void didCompleteRenderingUpdate() final;
 
+    void willStartPlatformRenderingUpdate() final;
     void didCompletePlatformRenderingUpdate() final;
 
     void updateTiledScrollingIndicator();

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm (287078 => 287079)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm	2021-12-15 17:46:07 UTC (rev 287079)
@@ -33,6 +33,7 @@
 #import "FrameView.h"
 #import "Logging.h"
 #import "Page.h"
+#import "PlatformCALayerContentsDelayedReleaser.h"
 #import "PlatformWheelEvent.h"
 #import "Region.h"
 #import "ScrollingStateTree.h"
@@ -142,9 +143,15 @@
         scheduleRenderingUpdate();
 }
 
+void ScrollingCoordinatorMac::willStartPlatformRenderingUpdate()
+{
+    PlatformCALayerContentsDelayedReleaser::singleton().mainThreadCommitWillStart();
+}
+
 void ScrollingCoordinatorMac::didCompletePlatformRenderingUpdate()
 {
     downcast<ThreadedScrollingTree>(scrollingTree())->didCompletePlatformRenderingUpdate();
+    PlatformCALayerContentsDelayedReleaser::singleton().mainThreadCommitDidEnd();
 }
 
 void ScrollingCoordinatorMac::hasNodeWithAnimatedScrollChanged(bool hasAnimatingNode)

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.h (287078 => 287079)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.h	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -55,6 +55,9 @@
     void deferWheelEventTestCompletionForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) final;
     void removeWheelEventTestCompletionDeferralForReason(WheelEventTestMonitor::ScrollableAreaIdentifier, WheelEventTestMonitor::DeferReason) final;
 
+    void registerForPlatformRenderingUpdateCallback();
+    void applyLayerPositionsInternal() final WTF_REQUIRES_LOCK(m_treeLock);
+
     void lockLayersForHitTesting() final WTF_ACQUIRES_LOCK(m_layerHitTestMutex);
     void unlockLayersForHitTesting() final WTF_RELEASES_LOCK(m_layerHitTestMutex);
 

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm (287078 => 287079)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeMac.mm	2021-12-15 17:46:07 UTC (rev 287079)
@@ -28,6 +28,7 @@
 
 #import "Logging.h"
 #import "PlatformCALayer.h"
+#import "PlatformCALayerContentsDelayedReleaser.h"
 #import "ScrollingTreeFixedNode.h"
 #import "ScrollingTreeFrameHostingNode.h"
 #import "ScrollingTreeFrameScrollingNodeMac.h"
@@ -38,6 +39,7 @@
 #import "WebCoreCALayerExtras.h"
 #import "WebLayer.h"
 #import "WheelEventTestMonitor.h"
+#import <pal/spi/cocoa/QuartzCoreSPI.h>
 #import <wtf/text/TextStream.h>
 
 #if ENABLE(ASYNC_SCROLLING) && ENABLE(SCROLLING_THREAD)
@@ -240,6 +242,25 @@
     m_layerHitTestMutex.unlock();
 }
 
+void ScrollingTreeMac::applyLayerPositionsInternal()
+{
+    if (ScrollingThread::isCurrentThread())
+        registerForPlatformRenderingUpdateCallback();
+
+    ThreadedScrollingTree::applyLayerPositionsInternal();
+}
+
+void ScrollingTreeMac::registerForPlatformRenderingUpdateCallback()
+{
+    [CATransaction addCommitHandler:[] {
+        PlatformCALayerContentsDelayedReleaser::singleton().scrollingThreadCommitWillStart();
+    } forPhase:kCATransactionPhasePreLayout];
+
+    [CATransaction addCommitHandler:[] {
+        PlatformCALayerContentsDelayedReleaser::singleton().scrollingThreadCommitDidEnd();
+    } forPhase:kCATransactionPhasePostCommit];
+}
+
 void ScrollingTreeMac::setWheelEventTestMonitor(RefPtr<WheelEventTestMonitor>&& monitor)
 {
     m_wheelEventTestMonitor = WTFMove(monitor);

Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp (287078 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2021-12-15 17:46:07 UTC (rev 287079)
@@ -2351,7 +2351,7 @@
         if (m_backdropLayer)
             m_backdropLayer->setHidden(false);
     } else {
-        m_layer->setContents(nullptr);
+        m_layer->clearContents();
 
         if (m_layerClones) {
             for (auto& layer : m_layerClones->primaryLayerClones.values())
@@ -2674,7 +2674,7 @@
         m_layer->setNeedsDisplay();
         m_hasEverPainted = false;
     } else {
-        m_layer->setContents(nullptr);
+        m_layer->clearContents();
         if (m_layerClones) {
             for (auto& layer : m_layerClones->primaryLayerClones.values())
                 layer->setContents(nullptr);

Modified: trunk/Source/WebCore/platform/graphics/ca/PlatformCALayer.cpp (287078 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/PlatformCALayer.cpp	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/platform/graphics/ca/PlatformCALayer.cpp	2021-12-15 17:46:07 UTC (rev 287079)
@@ -199,6 +199,11 @@
     return *sharedPool;
 }
 
+void PlatformCALayer::clearContents()
+{
+    setContents(nullptr);
+}
+
 void PlatformCALayer::dumpAdditionalProperties(TextStream&, OptionSet<PlatformLayerTreeAsTextFlags>)
 {
 }

Modified: trunk/Source/WebCore/platform/graphics/ca/PlatformCALayer.h (287078 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/PlatformCALayer.h	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/platform/graphics/ca/PlatformCALayer.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -199,6 +199,7 @@
     virtual bool hasContents() const = 0;
     virtual CFTypeRef contents() const = 0;
     virtual void setContents(CFTypeRef) = 0;
+    virtual void clearContents();
 
 #if HAVE(IOSURFACE)
     virtual void setContents(const WebCore::IOSurface&) = 0;

Modified: trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.h (287078 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.h	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -120,6 +120,7 @@
     bool hasContents() const override;
     CFTypeRef contents() const override;
     void setContents(CFTypeRef) override;
+    void clearContents() override;
 #if HAVE(IOSURFACE)
     void setContents(const WebCore::IOSurface&) override;
     void setContents(const WTF::MachSendRight&) override;

Modified: trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm (287078 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm	2021-12-15 17:26:13 UTC (rev 287078)
+++ trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerCocoa.mm	2021-12-15 17:46:07 UTC (rev 287079)
@@ -35,6 +35,7 @@
 #import "Model.h"
 #import "PlatformCAAnimationCocoa.h"
 #import "PlatformCAFilters.h"
+#import "PlatformCALayerContentsDelayedReleaser.h"
 #import "ScrollbarThemeMac.h"
 #import "TileController.h"
 #import "TiledBacking.h"
@@ -678,7 +679,7 @@
     if (attached)
         setNeedsDisplay();
     else
-        setContents(nullptr);
+        clearContents();
 }
 
 bool PlatformCALayerCocoa::backingStoreAttached() const
@@ -784,6 +785,15 @@
     return (__bridge CFTypeRef)[m_layer contents];
 }
 
+void PlatformCALayerCocoa::clearContents()
+{
+#if PLATFORM(MAC)
+    PlatformCALayerContentsDelayedReleaser::singleton().takeLayerContents(*this);
+#else
+    setContents(nullptr);
+#endif
+}
+
 void PlatformCALayerCocoa::setContents(CFTypeRef value)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS

Added: trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.h (0 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.h	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.h	2021-12-15 17:46:07 UTC (rev 287079)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if PLATFORM(MAC)
+
+#include <wtf/Lock.h>
+#include <wtf/ThreadSafeRefCounted.h>
+
+namespace WebCore {
+
+class PlatformCALayer;
+
+// This class exists to work around rdar://85892959, where CABackingStore objects would get released on the ScrollingThread
+// during scrolling commits, which can take long enough to cause scrolling frame drops.
+class PlatformCALayerContentsDelayedReleaser : ThreadSafeRefCounted<PlatformCALayerContentsDelayedReleaser> {
+    WTF_MAKE_NONCOPYABLE(PlatformCALayerContentsDelayedReleaser);
+public:
+    static PlatformCALayerContentsDelayedReleaser& singleton();
+
+    void takeLayerContents(PlatformCALayer&);
+    
+    void mainThreadCommitWillStart();
+    void mainThreadCommitDidEnd();
+
+    void scrollingThreadCommitWillStart();
+    void scrollingThreadCommitDidEnd();
+
+private:
+    friend LazyNeverDestroyed<PlatformCALayerContentsDelayedReleaser>;
+    
+    PlatformCALayerContentsDelayedReleaser();
+
+    void updateSawOverlappingCommit() WTF_REQUIRES_LOCK(m_lock);
+    void clearRetainedContents();
+
+    Vector<RetainPtr<CFTypeRef>> m_retainedContents;
+
+    Lock m_lock;
+    unsigned m_inMainThreadCommitEntryCount WTF_GUARDED_BY_LOCK(m_lock) { 0 };
+    unsigned m_scrollingThreadCommitEntryCount WTF_GUARDED_BY_LOCK(m_lock) { 0 };
+    bool m_hadOverlappingCommit WTF_GUARDED_BY_LOCK(m_lock) { false };
+};
+
+} // namespace WebCore
+
+#endif // PLATFORM(MAC)

Added: trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.mm (0 => 287079)


--- trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.mm	                        (rev 0)
+++ trunk/Source/WebCore/platform/graphics/ca/cocoa/PlatformCALayerContentsDelayedReleaser.mm	2021-12-15 17:46:07 UTC (rev 287079)
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#import "config.h"
+#import "PlatformCALayerContentsDelayedReleaser.h"
+
+#if PLATFORM(MAC)
+
+#import "PlatformCALayer.h"
+#import <wtf/RunLoop.h>
+
+namespace WebCore {
+
+PlatformCALayerContentsDelayedReleaser& PlatformCALayerContentsDelayedReleaser::singleton()
+{
+    static LazyNeverDestroyed<PlatformCALayerContentsDelayedReleaser> delayedReleaser;
+    static std::once_flag onceFlag;
+    std::call_once(onceFlag, [] {
+        delayedReleaser.construct();
+    });
+
+    return delayedReleaser;
+}
+
+PlatformCALayerContentsDelayedReleaser::PlatformCALayerContentsDelayedReleaser() = default;
+
+void PlatformCALayerContentsDelayedReleaser::takeLayerContents(PlatformCALayer& layer)
+{
+    ASSERT(isMainThread());
+
+    auto retainedContents = RetainPtr { layer.contents() };
+    if (retainedContents)
+        m_retainedContents.append(WTFMove(retainedContents));
+    layer.setContents(nullptr);
+}
+
+void PlatformCALayerContentsDelayedReleaser::mainThreadCommitWillStart()
+{
+    Locker locker { m_lock };
+    ++m_inMainThreadCommitEntryCount;
+    updateSawOverlappingCommit();
+}
+
+void PlatformCALayerContentsDelayedReleaser::mainThreadCommitDidEnd()
+{
+    bool bothCommitsDone;
+    bool hadOverlappingCommit;
+    {
+        Locker locker { m_lock };
+        ASSERT(m_inMainThreadCommitEntryCount);
+        --m_inMainThreadCommitEntryCount;
+        bothCommitsDone = !m_scrollingThreadCommitEntryCount && !m_inMainThreadCommitEntryCount;
+        hadOverlappingCommit = m_hadOverlappingCommit;
+    }
+
+    if (bothCommitsDone) {
+        if (hadOverlappingCommit && m_retainedContents.size()) {
+            RunLoop::main().dispatch([] {
+                PlatformCALayerContentsDelayedReleaser::singleton().clearRetainedContents();
+            });
+            return;
+        }
+
+        clearRetainedContents();
+    }
+}
+
+void PlatformCALayerContentsDelayedReleaser::scrollingThreadCommitWillStart()
+{
+    ASSERT(!isMainThread());
+    Locker locker { m_lock };
+    ++m_scrollingThreadCommitEntryCount;
+    updateSawOverlappingCommit();
+}
+
+void PlatformCALayerContentsDelayedReleaser::scrollingThreadCommitDidEnd()
+{
+    ASSERT(!isMainThread());
+    Locker locker { m_lock };
+
+    ASSERT(m_scrollingThreadCommitEntryCount);
+    --m_scrollingThreadCommitEntryCount;
+    if (!m_scrollingThreadCommitEntryCount && !m_inMainThreadCommitEntryCount) {
+        if (m_hadOverlappingCommit) {
+            // m_retainedContents might be empty (it's not protected by the lock so we can't check it here),
+            // so this might be a pointless dispatch, but m_hadOverlappingCommit is rare.
+            RunLoop::main().dispatch([] {
+                PlatformCALayerContentsDelayedReleaser::singleton().clearRetainedContents();
+            });
+        }
+    }
+}
+
+void PlatformCALayerContentsDelayedReleaser::updateSawOverlappingCommit()
+{
+    m_hadOverlappingCommit |= (m_inMainThreadCommitEntryCount && m_scrollingThreadCommitEntryCount);
+}
+
+void PlatformCALayerContentsDelayedReleaser::clearRetainedContents()
+{
+    ASSERT(isMainThread());
+    m_retainedContents.clear();
+}
+
+} // namespace WebCore
+
+#endif
+
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to