Title: [147797] trunk/Source/WebCore
Revision
147797
Author
[email protected]
Date
2013-04-05 14:19:56 -0700 (Fri, 05 Apr 2013)

Log Message

Throttle compositing layer flushes during page loading
https://bugs.webkit.org/show_bug.cgi?id=113786

Reviewed by Simon Fraser.
        
Page content can change rapidly during page loading triggering excessive layer flushes and repainting. We should avoid this unnecessary work.
        
This patch reduces layer flushes (and painting) during loading by 50-70% on many popular pages.

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadProgressingStatusChanged):        
* loader/FrameLoader.h:
* loader/ProgressTracker.cpp:
(WebCore::ProgressTracker::ProgressTracker):
(WebCore::ProgressTracker::reset):
(WebCore::ProgressTracker::progressStarted):
(WebCore::ProgressTracker::finalProgressComplete):
(WebCore::ProgressTracker::isLoadProgressing):
(WebCore::ProgressTracker::progressHeartbeatTimerFired):
* loader/ProgressTracker.h:
        
    Track if the document load is progressing. This is done with a heartbeat timer that checks every 100ms if we have received more than 1k of data.
    If four heartbeats pass without progress then we consider the load stalled.

* page/FrameView.cpp:
(WebCore::FrameView::resetDeferredRepaintDelay):
        
    Disable throttling temporary on user interaction so the page stays as responsive as possible even during loading.

(WebCore::FrameView::updateLayerFlushThrottling):
        
    Enable throttling when the load is progressing, disable otherwise.

* page/FrameView.h:
* platform/graphics/GraphicsLayer.h:
(WebCore::GraphicsLayer::canThrottleLayerFlush):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::platformCALayerDidCreateTiles):
(WebCore::GraphicsLayerCA::canThrottleLayerFlush):
        
    Don't throttle if new tiles have been added by the tile controller. They may have stale content and need to be flushed immediately.

(WebCore::GraphicsLayerCA::noteLayerPropertyChanged):
        
    Set the new TilesAdded change flag.

* platform/graphics/ca/GraphicsLayerCA.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::notifyFlushRequired):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::RenderLayerCompositor):
(WebCore::RenderLayerCompositor::notifyFlushRequired):
(WebCore::RenderLayerCompositor::scheduleLayerFlushNow):
        
    Factor the actual flush scheduling to private function.

(WebCore::RenderLayerCompositor::scheduleLayerFlush):
        
    Mark the compositor for flush and return without flushing if the flushes are currently being throttled.

(WebCore::RenderLayerCompositor::flushPendingLayerChanges):
        
    After a flush, start the throtting timer (currently 0.5s) coalescing the subsequent flushes.

(WebCore::RenderLayerCompositor::didChangeVisibleRect):
        
    Do immediately flush if needed.

(WebCore::RenderLayerCompositor::setLayerFlushThrottlingEnabled):
        
    Flush immediately if disabled.

(WebCore::RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction):
(WebCore::RenderLayerCompositor::isThrottlingLayerFlushes):
(WebCore::RenderLayerCompositor::startLayerFlushTimerIfNeeded):
(WebCore::RenderLayerCompositor::layerFlushTimerFired):
        
    Flush when the timer fires timer.

* rendering/RenderLayerCompositor.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (147796 => 147797)


--- trunk/Source/WebCore/ChangeLog	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/ChangeLog	2013-04-05 21:19:56 UTC (rev 147797)
@@ -1,3 +1,86 @@
+2013-04-05  Antti Koivisto  <[email protected]>
+
+        Throttle compositing layer flushes during page loading
+        https://bugs.webkit.org/show_bug.cgi?id=113786
+
+        Reviewed by Simon Fraser.
+        
+        Page content can change rapidly during page loading triggering excessive layer flushes and repainting. We should avoid this unnecessary work.
+        
+        This patch reduces layer flushes (and painting) during loading by 50-70% on many popular pages.
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::loadProgressingStatusChanged):        
+        * loader/FrameLoader.h:
+        * loader/ProgressTracker.cpp:
+        (WebCore::ProgressTracker::ProgressTracker):
+        (WebCore::ProgressTracker::reset):
+        (WebCore::ProgressTracker::progressStarted):
+        (WebCore::ProgressTracker::finalProgressComplete):
+        (WebCore::ProgressTracker::isLoadProgressing):
+        (WebCore::ProgressTracker::progressHeartbeatTimerFired):
+        * loader/ProgressTracker.h:
+        
+            Track if the document load is progressing. This is done with a heartbeat timer that checks every 100ms if we have received more than 1k of data.
+            If four heartbeats pass without progress then we consider the load stalled.
+
+        * page/FrameView.cpp:
+        (WebCore::FrameView::resetDeferredRepaintDelay):
+        
+            Disable throttling temporary on user interaction so the page stays as responsive as possible even during loading.
+
+        (WebCore::FrameView::updateLayerFlushThrottling):
+        
+            Enable throttling when the load is progressing, disable otherwise.
+
+        * page/FrameView.h:
+        * platform/graphics/GraphicsLayer.h:
+        (WebCore::GraphicsLayer::canThrottleLayerFlush):
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::platformCALayerDidCreateTiles):
+        (WebCore::GraphicsLayerCA::canThrottleLayerFlush):
+        
+            Don't throttle if new tiles have been added by the tile controller. They may have stale content and need to be flushed immediately.
+
+        (WebCore::GraphicsLayerCA::noteLayerPropertyChanged):
+        
+            Set the new TilesAdded change flag.
+
+        * platform/graphics/ca/GraphicsLayerCA.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::notifyFlushRequired):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::RenderLayerCompositor):
+        (WebCore::RenderLayerCompositor::notifyFlushRequired):
+        (WebCore::RenderLayerCompositor::scheduleLayerFlushNow):
+        
+            Factor the actual flush scheduling to private function.
+
+        (WebCore::RenderLayerCompositor::scheduleLayerFlush):
+        
+            Mark the compositor for flush and return without flushing if the flushes are currently being throttled.
+
+        (WebCore::RenderLayerCompositor::flushPendingLayerChanges):
+        
+            After a flush, start the throtting timer (currently 0.5s) coalescing the subsequent flushes.
+
+        (WebCore::RenderLayerCompositor::didChangeVisibleRect):
+        
+            Do immediately flush if needed.
+
+        (WebCore::RenderLayerCompositor::setLayerFlushThrottlingEnabled):
+        
+            Flush immediately if disabled.
+
+        (WebCore::RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction):
+        (WebCore::RenderLayerCompositor::isThrottlingLayerFlushes):
+        (WebCore::RenderLayerCompositor::startLayerFlushTimerIfNeeded):
+        (WebCore::RenderLayerCompositor::layerFlushTimerFired):
+        
+            Flush when the timer fires timer.
+
+        * rendering/RenderLayerCompositor.h:
+
 2013-04-05  Benjamin Poulain  <[email protected]>
 
         Clean the chromium bits of WebCore's WebDatabase

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (147796 => 147797)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2013-04-05 21:19:56 UTC (rev 147797)
@@ -3316,6 +3316,12 @@
     return m_networkingContext.get();
 }
 
+void FrameLoader::loadProgressingStatusChanged()
+{
+    bool isLoadProgressing = m_frame->page()->progress()->isLoadProgressing();
+    m_frame->page()->mainFrame()->view()->updateLayerFlushThrottling(isLoadProgressing);
+}
+
 void FrameLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
     MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);

Modified: trunk/Source/WebCore/loader/FrameLoader.h (147796 => 147797)


--- trunk/Source/WebCore/loader/FrameLoader.h	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/loader/FrameLoader.h	2013-04-05 21:19:56 UTC (rev 147797)
@@ -281,6 +281,8 @@
 
     NetworkingContext* networkingContext() const;
 
+    void loadProgressingStatusChanged();
+
     const KURL& previousURL() const { return m_previousURL; }
 
     void reportMemoryUsage(MemoryObjectInfo*) const;

Modified: trunk/Source/WebCore/loader/ProgressTracker.cpp (147796 => 147797)


--- trunk/Source/WebCore/loader/ProgressTracker.cpp	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/loader/ProgressTracker.cpp	2013-04-05 21:19:56 UTC (rev 147797)
@@ -51,6 +51,13 @@
 
 static const int progressItemDefaultEstimatedLength = 1024 * 16;
 
+// Check if the load is progressing this often.
+static const double progressHeartbeatInterval = 0.1;
+// How many heartbeats must pass without progress before deciding the load is currently stalled.
+static const unsigned loadStalledHeartbeatCount = 4;
+// How many bytes are required between heartbeats to consider it progress.
+static const unsigned minumumBytesPerHeartbeatForProgress = 1024;
+
 struct ProgressItem {
     WTF_MAKE_NONCOPYABLE(ProgressItem); WTF_MAKE_FAST_ALLOCATED;
 public:
@@ -74,6 +81,9 @@
     , m_finalProgressChangedSent(false)
     , m_progressValue(0)
     , m_numProgressTrackedFrames(0)
+    , m_progressHeartbeatTimer(this, &ProgressTracker::progressHeartbeatTimerFired)
+    , m_heartbeatsWithNoProgress(0)
+    , m_totalBytesReceivedBeforePreviousHeartbeat(0)
 {
 }
 
@@ -103,6 +113,10 @@
     m_finalProgressChangedSent = false;
     m_numProgressTrackedFrames = 0;
     m_originatingProgressFrame = 0;
+
+    m_heartbeatsWithNoProgress = 0;
+    m_totalBytesReceivedBeforePreviousHeartbeat = 0;
+    m_progressHeartbeatTimer.stop();
 }
 
 void ProgressTracker::progressStarted(Frame* frame)
@@ -115,7 +129,10 @@
         reset();
         m_progressValue = initialProgressValue;
         m_originatingProgressFrame = frame;
-    
+
+        m_progressHeartbeatTimer.startRepeating(progressHeartbeatInterval);
+        m_originatingProgressFrame->loader()->loadProgressingStatusChanged();
+
         m_originatingProgressFrame->loader()->client()->postProgressStartedNotification();
     }
     m_numProgressTrackedFrames++;
@@ -157,6 +174,8 @@
 
     frame->loader()->client()->setMainFrameDocumentReady(true);
     frame->loader()->client()->postProgressFinishedNotification();
+    frame->loader()->loadProgressingStatusChanged();
+
     InspectorInstrumentation::frameStoppedLoading(frame.get());
 }
 
@@ -264,5 +283,24 @@
     return ++s_uniqueIdentifier;
 }
 
+bool ProgressTracker::isLoadProgressing() const
+{
+    return m_progressValue && m_progressValue < finalProgressValue && m_heartbeatsWithNoProgress < loadStalledHeartbeatCount;
+}
 
+void ProgressTracker::progressHeartbeatTimerFired(Timer<ProgressTracker>*)
+{
+    if (m_totalBytesReceived < m_totalBytesReceivedBeforePreviousHeartbeat + minumumBytesPerHeartbeatForProgress)
+        ++m_heartbeatsWithNoProgress;
+    else
+        m_heartbeatsWithNoProgress = 0;
+
+    m_totalBytesReceivedBeforePreviousHeartbeat = m_totalBytesReceived;
+
+    m_originatingProgressFrame->loader()->loadProgressingStatusChanged();
+
+    if (m_progressValue >= finalProgressValue)
+        m_progressHeartbeatTimer.stop();
 }
+
+}

Modified: trunk/Source/WebCore/loader/ProgressTracker.h (147796 => 147797)


--- trunk/Source/WebCore/loader/ProgressTracker.h	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/loader/ProgressTracker.h	2013-04-05 21:19:56 UTC (rev 147797)
@@ -26,6 +26,7 @@
 #ifndef ProgressTracker_h
 #define ProgressTracker_h
 
+#include "Timer.h"
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
 #include <wtf/Noncopyable.h>
@@ -58,11 +59,15 @@
     long long totalPageAndResourceBytesToLoad() const { return m_totalPageAndResourceBytesToLoad; }
     long long totalBytesReceived() const { return m_totalBytesReceived; }
 
+    bool isLoadProgressing() const;
+
 private:
     ProgressTracker();
 
     void reset();
     void finalProgressComplete();
+
+    void progressHeartbeatTimerFired(Timer<ProgressTracker>*);
     
     static unsigned long s_uniqueIdentifier;
     
@@ -78,6 +83,10 @@
     
     int m_numProgressTrackedFrames;
     HashMap<unsigned long, OwnPtr<ProgressItem> > m_progressItems;
+
+    Timer<ProgressTracker> m_progressHeartbeatTimer;
+    unsigned m_heartbeatsWithNoProgress;
+    long long m_totalBytesReceivedBeforePreviousHeartbeat;
 };
     
 }

Modified: trunk/Source/WebCore/page/FrameView.cpp (147796 => 147797)


--- trunk/Source/WebCore/page/FrameView.cpp	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/page/FrameView.cpp	2013-04-05 21:19:56 UTC (rev 147797)
@@ -2258,6 +2258,10 @@
         if (!m_deferringRepaints)
             doDeferredRepaints();
     }
+#if USE(ACCELERATED_COMPOSITING)
+    if (RenderView* view = renderView())
+        view->compositor()->disableLayerFlushThrottlingTemporarilyForInteraction();
+#endif
 }
 
 double FrameView::adjustedDeferredRepaintDelay() const
@@ -2285,6 +2289,16 @@
     m_disableRepaints--;
 }
 
+void FrameView::updateLayerFlushThrottling(bool isLoadProgressing)
+{
+#if USE(ACCELERATED_COMPOSITING)
+    if (RenderView* view = renderView())
+        view->compositor()->setLayerFlushThrottlingEnabled(isLoadProgressing);
+#else
+    UNUSED_PARAM(isLoadProgressing);
+#endif
+}
+
 void FrameView::layoutTimerFired(Timer<FrameView>*)
 {
 #ifdef INSTRUMENT_LAYOUT_SCHEDULING

Modified: trunk/Source/WebCore/page/FrameView.h (147796 => 147797)


--- trunk/Source/WebCore/page/FrameView.h	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/page/FrameView.h	2013-04-05 21:19:56 UTC (rev 147797)
@@ -236,6 +236,8 @@
     void startDeferredRepaintTimer(double delay);
     void resetDeferredRepaintDelay();
 
+    void updateLayerFlushThrottling(bool isLoadProgressing);
+
     void beginDisableRepaints();
     void endDisableRepaints();
     bool repaintsDisabled() { return m_disableRepaints > 0; }

Modified: trunk/Source/WebCore/platform/graphics/GraphicsLayer.h (147796 => 147797)


--- trunk/Source/WebCore/platform/graphics/GraphicsLayer.h	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/platform/graphics/GraphicsLayer.h	2013-04-05 21:19:56 UTC (rev 147797)
@@ -437,6 +437,8 @@
 
     void updateDebugIndicators();
 
+    virtual bool canThrottleLayerFlush() const { return false; }
+
     virtual void reportMemoryUsage(MemoryObjectInfo*) const;
 
 protected:

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


--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2013-04-05 21:19:56 UTC (rev 147797)
@@ -1110,9 +1110,7 @@
     for (size_t i = 0; i < dirtyRects.size(); ++i)
         setNeedsDisplayInRect(dirtyRects[i]);
 
-    // Ensure that the layout is up to date before any individual tiles are painted by telling the client
-    // that it needs to flush its layer state, which will end up scheduling the layer flusher.
-    client()->notifyFlushRequired(this);
+    noteLayerPropertyChanged(TilesAdded);
 }
 
 float GraphicsLayerCA::platformCALayerDeviceScaleFactor()
@@ -3052,12 +3050,22 @@
     propagateLayerChangeToReplicas();
 }
 
+bool GraphicsLayerCA::canThrottleLayerFlush() const
+{
+    // Tile layers are currently plain CA layers, attached directly by TileController. They require immediate flush as they may contain garbage.
+    return !(m_uncommittedChanges & TilesAdded);
+}
+
 void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
 {
-    if (!m_uncommittedChanges && m_client)
-        m_client->notifyFlushRequired(this);
+    bool hadUncommittedChanges = !!m_uncommittedChanges;
+    bool oldCanThrottleLayerFlush = canThrottleLayerFlush();
 
     m_uncommittedChanges |= flags;
+
+    bool needsFlush = !hadUncommittedChanges || oldCanThrottleLayerFlush != canThrottleLayerFlush();
+    if (needsFlush && m_client)
+        m_client->notifyFlushRequired(this);
 }
 
 double GraphicsLayerCA::backingStoreMemoryEstimate() const

Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h (147796 => 147797)


--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h	2013-04-05 21:19:56 UTC (rev 147797)
@@ -254,6 +254,8 @@
 
     bool recursiveVisibleRectChangeRequiresFlush(const TransformState&) const;
 
+    virtual bool canThrottleLayerFlush() const;
+
     // Used to track the path down the tree for replica layers.
     struct ReplicaState {
         static const size_t maxReplicaDepth = 16;
@@ -397,7 +399,8 @@
         ContentsVisibilityChanged = 1 << 25,
         VisibleRectChanged = 1 << 26,
         FiltersChanged = 1 << 27,
-        DebugIndicatorsChanged = 1 << 28
+        TilesAdded = 1 < 28,
+        DebugIndicatorsChanged = 1 << 29
     };
     typedef unsigned LayerChangeFlags;
     void noteLayerPropertyChanged(LayerChangeFlags flags);

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (147796 => 147797)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2013-04-05 21:19:56 UTC (rev 147797)
@@ -2148,10 +2148,11 @@
     renderer()->animation()->notifyAnimationStarted(renderer(), time);
 }
 
-void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer*)
+void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer)
 {
-    if (!renderer()->documentBeingDestroyed())
-        compositor()->scheduleLayerFlush();
+    if (renderer()->documentBeingDestroyed())
+        return;
+    compositor()->scheduleLayerFlush(layer->canThrottleLayerFlush());
 }
 
 void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer)

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (147796 => 147797)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2013-04-05 21:19:56 UTC (rev 147797)
@@ -84,10 +84,12 @@
 #define WTF_USE_COMPOSITING_FOR_SMALL_CANVASES 1
 #endif
 
+namespace WebCore {
+
 static const int canvasAreaThresholdRequiringCompositing = 50 * 100;
+// During page loading delay layer flushes up to this many seconds to allow them coalesce, reducing workload.
+static const double throttledLayerFlushDelay = .5;
 
-namespace WebCore {
-
 using namespace HTMLNames;
 
 class RenderLayerCompositor::OverlapMap {
@@ -211,6 +213,10 @@
     , m_isTrackingRepaints(false)
     , m_layersWithTiledBackingCount(0)
     , m_rootLayerAttachment(RootLayerUnattached)
+    , m_layerFlushTimer(this, &RenderLayerCompositor::layerFlushTimerFired)
+    , m_layerFlushThrottlingEnabled(false)
+    , m_layerFlushThrottlingTemporarilyDisabledForInteraction(false)
+    , m_hasPendingLayerFlush(false)
 #if !LOG_DISABLED
     , m_rootLayerUpdateCount(0)
     , m_obligateCompositedLayerCount(0)
@@ -317,12 +323,27 @@
     position = -scrollPosition;
 }
 
-void RenderLayerCompositor::scheduleLayerFlush()
+void RenderLayerCompositor::notifyFlushRequired(const GraphicsLayer* layer)
 {
+    scheduleLayerFlush(layer->canThrottleLayerFlush());
+}
+
+void RenderLayerCompositor::scheduleLayerFlushNow()
+{
+    m_hasPendingLayerFlush = false;
     if (Page* page = this->page())
         page->chrome()->client()->scheduleCompositingLayerFlush();
 }
 
+void RenderLayerCompositor::scheduleLayerFlush(bool canThrottle)
+{
+    if (canThrottle && isThrottlingLayerFlushes()) {
+        m_hasPendingLayerFlush = true;
+        return;
+    }
+    scheduleLayerFlushNow();
+}
+
 void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
 {
     // FrameView::flushCompositingStateIncludingSubframes() flushes each subframe,
@@ -361,6 +382,7 @@
         
         m_viewportConstrainedLayersNeedingUpdate.clear();
     }
+    startLayerFlushTimerIfNeeded();
 }
 
 void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer, const GraphicsLayer* graphicsLayer)
@@ -384,8 +406,9 @@
         return;
 
     IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect();
-    if (rootLayer->visibleRectChangeRequiresFlush(visibleRect))
-        scheduleLayerFlush();
+    if (!rootLayer->visibleRectChangeRequiresFlush(visibleRect))
+        return;
+    scheduleLayerFlushNow();
 }
 
 void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*)
@@ -3124,6 +3147,51 @@
     return 0;
 }
 
+void RenderLayerCompositor::setLayerFlushThrottlingEnabled(bool enabled)
+{
+    m_layerFlushThrottlingEnabled = enabled;
+    if (m_layerFlushThrottlingEnabled)
+        return;
+    m_layerFlushTimer.stop();
+    if (!m_hasPendingLayerFlush)
+        return;
+    scheduleLayerFlushNow();
+}
+
+void RenderLayerCompositor::disableLayerFlushThrottlingTemporarilyForInteraction()
+{
+    if (m_layerFlushThrottlingTemporarilyDisabledForInteraction)
+        return;
+    m_layerFlushThrottlingTemporarilyDisabledForInteraction = true;
+}
+
+bool RenderLayerCompositor::isThrottlingLayerFlushes() const
+{
+    if (!m_layerFlushThrottlingEnabled)
+        return false;
+    if (!m_layerFlushTimer.isActive())
+        return false;
+    if (m_layerFlushThrottlingTemporarilyDisabledForInteraction)
+        return false;
+    return true;
+}
+
+void RenderLayerCompositor::startLayerFlushTimerIfNeeded()
+{
+    m_layerFlushThrottlingTemporarilyDisabledForInteraction = false;
+    m_layerFlushTimer.stop();
+    if (!m_layerFlushThrottlingEnabled)
+        return;
+    m_layerFlushTimer.startOneShot(throttledLayerFlushDelay);
+}
+
+void RenderLayerCompositor::layerFlushTimerFired(Timer<RenderLayerCompositor>*)
+{
+    if (!m_hasPendingLayerFlush)
+        return;
+    scheduleLayerFlushNow();
+}
+
 void RenderLayerCompositor::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
 {
     MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Rendering);

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.h (147796 => 147797)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.h	2013-04-05 20:52:10 UTC (rev 147796)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.h	2013-04-05 21:19:56 UTC (rev 147797)
@@ -126,7 +126,7 @@
     
     // GraphicsLayers buffer state, which gets pushed to the underlying platform layers
     // at specific times.
-    void scheduleLayerFlush();
+    void scheduleLayerFlush(bool canThrottle);
     void flushPendingLayerChanges(bool isFlushRoot = true);
     
     // flushPendingLayerChanges() flushes the entire GraphicsLayer tree, which can cross frame boundaries.
@@ -277,13 +277,16 @@
     bool hasNonMainLayersWithTiledBacking() const { return m_layersWithTiledBackingCount; }
 
     CompositingReasons reasonsForCompositing(const RenderLayer*) const;
-    
+
+    void setLayerFlushThrottlingEnabled(bool);
+    void disableLayerFlushThrottlingTemporarilyForInteraction();
+
 private:
     class OverlapMap;
 
     // GraphicsLayerClient implementation
     virtual void notifyAnimationStarted(const GraphicsLayer*, double) OVERRIDE { }
-    virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE { scheduleLayerFlush(); }
+    virtual void notifyFlushRequired(const GraphicsLayer*) OVERRIDE;
     virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect&) OVERRIDE;
 
     virtual bool isTrackingRepaints() const OVERRIDE;
@@ -380,6 +383,11 @@
     bool requiresContentShadowLayer() const;
 #endif
 
+    void scheduleLayerFlushNow();
+    bool isThrottlingLayerFlushes() const;
+    void startLayerFlushTimerIfNeeded();
+    void layerFlushTimerFired(Timer<RenderLayerCompositor>*);
+
 #if !LOG_DISABLED
     const char* logReasonsForCompositing(const RenderLayer*);
     void logLayerInfo(const RenderLayer*, int depth);
@@ -441,6 +449,11 @@
 
     OwnPtr<GraphicsLayerUpdater> m_layerUpdater; // Updates tiled layer visible area periodically while animations are running.
 
+    Timer<RenderLayerCompositor> m_layerFlushTimer;
+    bool m_layerFlushThrottlingEnabled;
+    bool m_layerFlushThrottlingTemporarilyDisabledForInteraction;
+    bool m_hasPendingLayerFlush;
+
 #if !LOG_DISABLED
     int m_rootLayerUpdateCount;
     int m_obligateCompositedLayerCount; // count of layer that have to be composited.
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to