Commit a6775c18 authored by antti@apple.com's avatar antti@apple.com

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:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@147797 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a4946bc1
2013-04-05 Antti Koivisto <antti@apple.com>
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 <benjamin@webkit.org> 2013-04-05 Benjamin Poulain <benjamin@webkit.org>
Clean the chromium bits of WebCore's WebDatabase Clean the chromium bits of WebCore's WebDatabase
...@@ -3316,6 +3316,12 @@ NetworkingContext* FrameLoader::networkingContext() const ...@@ -3316,6 +3316,12 @@ NetworkingContext* FrameLoader::networkingContext() const
return m_networkingContext.get(); 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 void FrameLoader::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{ {
MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader); MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Loader);
......
...@@ -281,6 +281,8 @@ public: ...@@ -281,6 +281,8 @@ public:
NetworkingContext* networkingContext() const; NetworkingContext* networkingContext() const;
void loadProgressingStatusChanged();
const KURL& previousURL() const { return m_previousURL; } const KURL& previousURL() const { return m_previousURL; }
void reportMemoryUsage(MemoryObjectInfo*) const; void reportMemoryUsage(MemoryObjectInfo*) const;
......
...@@ -51,6 +51,13 @@ static const double finalProgressValue = 0.9; // 1.0 - initialProgressValue ...@@ -51,6 +51,13 @@ static const double finalProgressValue = 0.9; // 1.0 - initialProgressValue
static const int progressItemDefaultEstimatedLength = 1024 * 16; 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 { struct ProgressItem {
WTF_MAKE_NONCOPYABLE(ProgressItem); WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(ProgressItem); WTF_MAKE_FAST_ALLOCATED;
public: public:
...@@ -74,6 +81,9 @@ ProgressTracker::ProgressTracker() ...@@ -74,6 +81,9 @@ ProgressTracker::ProgressTracker()
, m_finalProgressChangedSent(false) , m_finalProgressChangedSent(false)
, m_progressValue(0) , m_progressValue(0)
, m_numProgressTrackedFrames(0) , m_numProgressTrackedFrames(0)
, m_progressHeartbeatTimer(this, &ProgressTracker::progressHeartbeatTimerFired)
, m_heartbeatsWithNoProgress(0)
, m_totalBytesReceivedBeforePreviousHeartbeat(0)
{ {
} }
...@@ -103,6 +113,10 @@ void ProgressTracker::reset() ...@@ -103,6 +113,10 @@ void ProgressTracker::reset()
m_finalProgressChangedSent = false; m_finalProgressChangedSent = false;
m_numProgressTrackedFrames = 0; m_numProgressTrackedFrames = 0;
m_originatingProgressFrame = 0; m_originatingProgressFrame = 0;
m_heartbeatsWithNoProgress = 0;
m_totalBytesReceivedBeforePreviousHeartbeat = 0;
m_progressHeartbeatTimer.stop();
} }
void ProgressTracker::progressStarted(Frame* frame) void ProgressTracker::progressStarted(Frame* frame)
...@@ -115,7 +129,10 @@ void ProgressTracker::progressStarted(Frame* frame) ...@@ -115,7 +129,10 @@ void ProgressTracker::progressStarted(Frame* frame)
reset(); reset();
m_progressValue = initialProgressValue; m_progressValue = initialProgressValue;
m_originatingProgressFrame = frame; m_originatingProgressFrame = frame;
m_progressHeartbeatTimer.startRepeating(progressHeartbeatInterval);
m_originatingProgressFrame->loader()->loadProgressingStatusChanged();
m_originatingProgressFrame->loader()->client()->postProgressStartedNotification(); m_originatingProgressFrame->loader()->client()->postProgressStartedNotification();
} }
m_numProgressTrackedFrames++; m_numProgressTrackedFrames++;
...@@ -157,6 +174,8 @@ void ProgressTracker::finalProgressComplete() ...@@ -157,6 +174,8 @@ void ProgressTracker::finalProgressComplete()
frame->loader()->client()->setMainFrameDocumentReady(true); frame->loader()->client()->setMainFrameDocumentReady(true);
frame->loader()->client()->postProgressFinishedNotification(); frame->loader()->client()->postProgressFinishedNotification();
frame->loader()->loadProgressingStatusChanged();
InspectorInstrumentation::frameStoppedLoading(frame.get()); InspectorInstrumentation::frameStoppedLoading(frame.get());
} }
...@@ -264,5 +283,24 @@ unsigned long ProgressTracker::createUniqueIdentifier() ...@@ -264,5 +283,24 @@ unsigned long ProgressTracker::createUniqueIdentifier()
return ++s_uniqueIdentifier; 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();
}
} }
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#ifndef ProgressTracker_h #ifndef ProgressTracker_h
#define ProgressTracker_h #define ProgressTracker_h
#include "Timer.h"
#include <wtf/Forward.h> #include <wtf/Forward.h>
#include <wtf/HashMap.h> #include <wtf/HashMap.h>
#include <wtf/Noncopyable.h> #include <wtf/Noncopyable.h>
...@@ -58,11 +59,15 @@ public: ...@@ -58,11 +59,15 @@ public:
long long totalPageAndResourceBytesToLoad() const { return m_totalPageAndResourceBytesToLoad; } long long totalPageAndResourceBytesToLoad() const { return m_totalPageAndResourceBytesToLoad; }
long long totalBytesReceived() const { return m_totalBytesReceived; } long long totalBytesReceived() const { return m_totalBytesReceived; }
bool isLoadProgressing() const;
private: private:
ProgressTracker(); ProgressTracker();
void reset(); void reset();
void finalProgressComplete(); void finalProgressComplete();
void progressHeartbeatTimerFired(Timer<ProgressTracker>*);
static unsigned long s_uniqueIdentifier; static unsigned long s_uniqueIdentifier;
...@@ -78,6 +83,10 @@ private: ...@@ -78,6 +83,10 @@ private:
int m_numProgressTrackedFrames; int m_numProgressTrackedFrames;
HashMap<unsigned long, OwnPtr<ProgressItem> > m_progressItems; HashMap<unsigned long, OwnPtr<ProgressItem> > m_progressItems;
Timer<ProgressTracker> m_progressHeartbeatTimer;
unsigned m_heartbeatsWithNoProgress;
long long m_totalBytesReceivedBeforePreviousHeartbeat;
}; };
} }
......
...@@ -2258,6 +2258,10 @@ void FrameView::resetDeferredRepaintDelay() ...@@ -2258,6 +2258,10 @@ void FrameView::resetDeferredRepaintDelay()
if (!m_deferringRepaints) if (!m_deferringRepaints)
doDeferredRepaints(); doDeferredRepaints();
} }
#if USE(ACCELERATED_COMPOSITING)
if (RenderView* view = renderView())
view->compositor()->disableLayerFlushThrottlingTemporarilyForInteraction();
#endif
} }
double FrameView::adjustedDeferredRepaintDelay() const double FrameView::adjustedDeferredRepaintDelay() const
...@@ -2285,6 +2289,16 @@ void FrameView::endDisableRepaints() ...@@ -2285,6 +2289,16 @@ void FrameView::endDisableRepaints()
m_disableRepaints--; 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>*) void FrameView::layoutTimerFired(Timer<FrameView>*)
{ {
#ifdef INSTRUMENT_LAYOUT_SCHEDULING #ifdef INSTRUMENT_LAYOUT_SCHEDULING
......
...@@ -236,6 +236,8 @@ public: ...@@ -236,6 +236,8 @@ public:
void startDeferredRepaintTimer(double delay); void startDeferredRepaintTimer(double delay);
void resetDeferredRepaintDelay(); void resetDeferredRepaintDelay();
void updateLayerFlushThrottling(bool isLoadProgressing);
void beginDisableRepaints(); void beginDisableRepaints();
void endDisableRepaints(); void endDisableRepaints();
bool repaintsDisabled() { return m_disableRepaints > 0; } bool repaintsDisabled() { return m_disableRepaints > 0; }
......
...@@ -437,6 +437,8 @@ public: ...@@ -437,6 +437,8 @@ public:
void updateDebugIndicators(); void updateDebugIndicators();
virtual bool canThrottleLayerFlush() const { return false; }
virtual void reportMemoryUsage(MemoryObjectInfo*) const; virtual void reportMemoryUsage(MemoryObjectInfo*) const;
protected: protected:
......
...@@ -1110,9 +1110,7 @@ void GraphicsLayerCA::platformCALayerDidCreateTiles(const Vector<FloatRect>& dir ...@@ -1110,9 +1110,7 @@ void GraphicsLayerCA::platformCALayerDidCreateTiles(const Vector<FloatRect>& dir
for (size_t i = 0; i < dirtyRects.size(); ++i) for (size_t i = 0; i < dirtyRects.size(); ++i)
setNeedsDisplayInRect(dirtyRects[i]); setNeedsDisplayInRect(dirtyRects[i]);
// Ensure that the layout is up to date before any individual tiles are painted by telling the client noteLayerPropertyChanged(TilesAdded);
// that it needs to flush its layer state, which will end up scheduling the layer flusher.
client()->notifyFlushRequired(this);
} }
float GraphicsLayerCA::platformCALayerDeviceScaleFactor() float GraphicsLayerCA::platformCALayerDeviceScaleFactor()
...@@ -3052,12 +3050,22 @@ void GraphicsLayerCA::noteSublayersChanged() ...@@ -3052,12 +3050,22 @@ void GraphicsLayerCA::noteSublayersChanged()
propagateLayerChangeToReplicas(); 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) void GraphicsLayerCA::noteLayerPropertyChanged(LayerChangeFlags flags)
{ {
if (!m_uncommittedChanges && m_client) bool hadUncommittedChanges = !!m_uncommittedChanges;
m_client->notifyFlushRequired(this); bool oldCanThrottleLayerFlush = canThrottleLayerFlush();
m_uncommittedChanges |= flags; m_uncommittedChanges |= flags;
bool needsFlush = !hadUncommittedChanges || oldCanThrottleLayerFlush != canThrottleLayerFlush();
if (needsFlush && m_client)
m_client->notifyFlushRequired(this);
} }
double GraphicsLayerCA::backingStoreMemoryEstimate() const double GraphicsLayerCA::backingStoreMemoryEstimate() const
......
...@@ -254,6 +254,8 @@ private: ...@@ -254,6 +254,8 @@ private:
bool recursiveVisibleRectChangeRequiresFlush(const TransformState&) const; bool recursiveVisibleRectChangeRequiresFlush(const TransformState&) const;
virtual bool canThrottleLayerFlush() const;
// Used to track the path down the tree for replica layers. // Used to track the path down the tree for replica layers.
struct ReplicaState { struct ReplicaState {
static const size_t maxReplicaDepth = 16; static const size_t maxReplicaDepth = 16;
...@@ -397,7 +399,8 @@ private: ...@@ -397,7 +399,8 @@ private:
ContentsVisibilityChanged = 1 << 25, ContentsVisibilityChanged = 1 << 25,
VisibleRectChanged = 1 << 26, VisibleRectChanged = 1 << 26,
FiltersChanged = 1 << 27, FiltersChanged = 1 << 27,
DebugIndicatorsChanged = 1 << 28 TilesAdded = 1 < 28,
DebugIndicatorsChanged = 1 << 29
}; };
typedef unsigned LayerChangeFlags; typedef unsigned LayerChangeFlags;
void noteLayerPropertyChanged(LayerChangeFlags flags); void noteLayerPropertyChanged(LayerChangeFlags flags);
......
...@@ -2148,10 +2148,11 @@ void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double tim ...@@ -2148,10 +2148,11 @@ void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double tim
renderer()->animation()->notifyAnimationStarted(renderer(), time); renderer()->animation()->notifyAnimationStarted(renderer(), time);
} }
void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer*) void RenderLayerBacking::notifyFlushRequired(const GraphicsLayer* layer)
{ {
if (!renderer()->documentBeingDestroyed()) if (renderer()->documentBeingDestroyed())
compositor()->scheduleLayerFlush(); return;
compositor()->scheduleLayerFlush(layer->canThrottleLayerFlush());
} }
void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer) void RenderLayerBacking::notifyFlushBeforeDisplayRefresh(const GraphicsLayer* layer)
......
...@@ -84,10 +84,12 @@ bool WebCoreHas3DRendering = true; ...@@ -84,10 +84,12 @@ bool WebCoreHas3DRendering = true;
#define WTF_USE_COMPOSITING_FOR_SMALL_CANVASES 1 #define WTF_USE_COMPOSITING_FOR_SMALL_CANVASES 1
#endif #endif
static const int canvasAreaThresholdRequiringCompositing = 50 * 100;
namespace WebCore { 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;
using namespace HTMLNames; using namespace HTMLNames;
class RenderLayerCompositor::OverlapMap { class RenderLayerCompositor::OverlapMap {
...@@ -211,6 +213,10 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) ...@@ -211,6 +213,10 @@ RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView)
, m_isTrackingRepaints(false) , m_isTrackingRepaints(false)
, m_layersWithTiledBackingCount(0) , m_layersWithTiledBackingCount(0)
, m_rootLayerAttachment(RootLayerUnattached) , m_rootLayerAttachment(RootLayerUnattached)
, m_layerFlushTimer(this, &RenderLayerCompositor::layerFlushTimerFired)
, m_layerFlushThrottlingEnabled(false)
, m_layerFlushThrottlingTemporarilyDisabledForInteraction(false)
, m_hasPendingLayerFlush(false)
#if !LOG_DISABLED #if !LOG_DISABLED
, m_rootLayerUpdateCount(0) , m_rootLayerUpdateCount(0)
, m_obligateCompositedLayerCount(0) , m_obligateCompositedLayerCount(0)
...@@ -317,12 +323,27 @@ void RenderLayerCompositor::customPositionForVisibleRectComputation(const Graphi ...@@ -317,12 +323,27 @@ void RenderLayerCompositor::customPositionForVisibleRectComputation(const Graphi
position = -scrollPosition; 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()) if (Page* page = this->page())
page->chrome()->client()->scheduleCompositingLayerFlush(); page->chrome()->client()->scheduleCompositingLayerFlush();
} }
void RenderLayerCompositor::scheduleLayerFlush(bool canThrottle)
{
if (canThrottle && isThrottlingLayerFlushes()) {
m_hasPendingLayerFlush = true;
return;
}
scheduleLayerFlushNow();
}
void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot) void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
{ {
// FrameView::flushCompositingStateIncludingSubframes() flushes each subframe, // FrameView::flushCompositingStateIncludingSubframes() flushes each subframe,
...@@ -361,6 +382,7 @@ void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot) ...@@ -361,6 +382,7 @@ void RenderLayerCompositor::flushPendingLayerChanges(bool isFlushRoot)
m_viewportConstrainedLayersNeedingUpdate.clear(); m_viewportConstrainedLayersNeedingUpdate.clear();
} }
startLayerFlushTimerIfNeeded();
} }
void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer, const GraphicsLayer* graphicsLayer) void RenderLayerCompositor::didFlushChangesForLayer(RenderLayer* layer, const GraphicsLayer* graphicsLayer)
...@@ -384,8 +406,9 @@ void RenderLayerCompositor::didChangeVisibleRect() ...@@ -384,8 +406,9 @@ void RenderLayerCompositor::didChangeVisibleRect()
return; return;
IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect(); IntRect visibleRect = m_clipLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect();
if (rootLayer->visibleRectChangeRequiresFlush(visibleRect)) if (!rootLayer->visibleRectChangeRequiresFlush(visibleRect))
scheduleLayerFlush(); return;
scheduleLayerFlushNow();
} }
void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*) void RenderLayerCompositor::notifyFlushBeforeDisplayRefresh(const GraphicsLayer*)
...@@ -3124,6 +3147,51 @@ Page* RenderLayerCompositor::page() const ...@@ -3124,6 +3147,51 @@ Page* RenderLayerCompositor::page() const
return 0; 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 void RenderLayerCompositor::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
{ {
MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Rendering); MemoryClassInfo info(memoryObjectInfo, this, PlatformMemoryTypes::Rendering);
......
...@@ -126,7 +126,7 @@ public: ...@@ -126,7 +126,7 @@ public:
// GraphicsLayers buffer state, which gets pushed to the underlying platform layers // GraphicsLayers buffer state, which gets pushed to the underlying platform layers
// at specific times. // at specific times.
void scheduleLayerFlush(); void scheduleLayerFlush(bool canThrottle);
void flushPendingLayerChanges(bool isFlushRoot = true); void flushPendingLayerChanges(bool isFlushRoot = true);
// flushPendingLayerChanges() flushes the entire GraphicsLayer tree, which can cross frame boundaries. // flushPendingLayerChanges() flushes the entire GraphicsLayer tree, which can cross frame boundaries.
...@@ -277,13 +277,16 @@ public: ...@@ -277,13 +277,16 @@ public:
bool hasNonMainLayersWithTiledBacking() const { return m_layersWithTiledBackingCount; } bool hasNonMainLayersWithTiledBacking() const { return m_layersWithTiledBackingCount; }
CompositingReasons reasonsForCompositing(const RenderLayer*) const; CompositingReasons reasonsForCompositing(const RenderLayer*) const;
void setLayerFlushThrottlingEnabled(bool);
void disableLayerFlushThrottlingTemporarilyForInteraction();