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.