summaryrefslogtreecommitdiffstats
path: root/cc/layer_tree_host.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cc/layer_tree_host.cc')
-rw-r--r--cc/layer_tree_host.cc861
1 files changed, 861 insertions, 0 deletions
diff --git a/cc/layer_tree_host.cc b/cc/layer_tree_host.cc
new file mode 100644
index 0000000..d75a3d3
--- /dev/null
+++ b/cc/layer_tree_host.cc
@@ -0,0 +1,861 @@
+// Copyright 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+
+#include "CCLayerTreeHost.h"
+
+#include "CCFontAtlas.h"
+#include "CCGraphicsContext.h"
+#include "CCHeadsUpDisplayLayerImpl.h"
+#include "CCLayerAnimationController.h"
+#include "CCLayerIterator.h"
+#include "CCLayerTreeHostClient.h"
+#include "CCLayerTreeHostCommon.h"
+#include "CCLayerTreeHostImpl.h"
+#include "CCOcclusionTracker.h"
+#include "CCOverdrawMetrics.h"
+#include "CCSettings.h"
+#include "CCSingleThreadProxy.h"
+#include "CCThreadProxy.h"
+#include "HeadsUpDisplayLayerChromium.h"
+#include "LayerChromium.h"
+#include "Region.h"
+#include "TraceEvent.h"
+#include "TreeSynchronizer.h"
+
+using namespace std;
+using WebKit::WebTransformationMatrix;
+
+namespace {
+static int numLayerTreeInstances;
+}
+
+namespace cc {
+
+bool CCLayerTreeHost::s_needsFilterContext = false;
+
+CCLayerTreeSettings::CCLayerTreeSettings()
+ : acceleratePainting(false)
+ , showFPSCounter(false)
+ , showPlatformLayerTree(false)
+ , showPaintRects(false)
+ , showPropertyChangedRects(false)
+ , showSurfaceDamageRects(false)
+ , showScreenSpaceRects(false)
+ , showReplicaScreenSpaceRects(false)
+ , showOccludingRects(false)
+ , renderVSyncEnabled(true)
+ , refreshRate(0)
+ , maxPartialTextureUpdates(std::numeric_limits<size_t>::max())
+ , defaultTileSize(IntSize(256, 256))
+ , maxUntiledLayerSize(IntSize(512, 512))
+ , minimumOcclusionTrackingSize(IntSize(160, 160))
+{
+}
+
+CCLayerTreeSettings::~CCLayerTreeSettings()
+{
+}
+
+RendererCapabilities::RendererCapabilities()
+ : bestTextureFormat(0)
+ , contextHasCachedFrontBuffer(false)
+ , usingPartialSwap(false)
+ , usingAcceleratedPainting(false)
+ , usingSetVisibility(false)
+ , usingSwapCompleteCallback(false)
+ , usingGpuMemoryManager(false)
+ , usingDiscardFramebuffer(false)
+ , usingEglImage(false)
+ , maxTextureSize(0)
+{
+}
+
+RendererCapabilities::~RendererCapabilities()
+{
+}
+
+bool CCLayerTreeHost::anyLayerTreeHostInstanceExists()
+{
+ return numLayerTreeInstances > 0;
+}
+
+scoped_ptr<CCLayerTreeHost> CCLayerTreeHost::create(CCLayerTreeHostClient* client, const CCLayerTreeSettings& settings)
+{
+ scoped_ptr<CCLayerTreeHost> layerTreeHost(new CCLayerTreeHost(client, settings));
+ if (!layerTreeHost->initialize())
+ return scoped_ptr<CCLayerTreeHost>();
+ return layerTreeHost.Pass();
+}
+
+CCLayerTreeHost::CCLayerTreeHost(CCLayerTreeHostClient* client, const CCLayerTreeSettings& settings)
+ : m_animating(false)
+ , m_needsAnimateLayers(false)
+ , m_client(client)
+ , m_commitNumber(0)
+ , m_renderingStats()
+ , m_rendererInitialized(false)
+ , m_contextLost(false)
+ , m_numTimesRecreateShouldFail(0)
+ , m_numFailedRecreateAttempts(0)
+ , m_settings(settings)
+ , m_deviceScaleFactor(1)
+ , m_visible(true)
+ , m_pageScaleFactor(1)
+ , m_minPageScaleFactor(1)
+ , m_maxPageScaleFactor(1)
+ , m_triggerIdleUpdates(true)
+ , m_backgroundColor(SK_ColorWHITE)
+ , m_hasTransparentBackground(false)
+ , m_partialTextureUpdateRequests(0)
+{
+ ASSERT(CCProxy::isMainThread());
+ numLayerTreeInstances++;
+}
+
+bool CCLayerTreeHost::initialize()
+{
+ TRACE_EVENT0("cc", "CCLayerTreeHost::initialize");
+
+ if (CCProxy::hasImplThread())
+ m_proxy = CCThreadProxy::create(this);
+ else
+ m_proxy = CCSingleThreadProxy::create(this);
+ m_proxy->start();
+
+ return m_proxy->initializeContext();
+}
+
+CCLayerTreeHost::~CCLayerTreeHost()
+{
+ if (m_rootLayer)
+ m_rootLayer->setLayerTreeHost(0);
+ ASSERT(CCProxy::isMainThread());
+ TRACE_EVENT0("cc", "CCLayerTreeHost::~CCLayerTreeHost");
+ ASSERT(m_proxy.get());
+ m_proxy->stop();
+ m_proxy.reset();
+ numLayerTreeInstances--;
+ RateLimiterMap::iterator it = m_rateLimiters.begin();
+ if (it != m_rateLimiters.end())
+ it->second->stop();
+}
+
+void CCLayerTreeHost::setSurfaceReady()
+{
+ m_proxy->setSurfaceReady();
+}
+
+void CCLayerTreeHost::initializeRenderer()
+{
+ TRACE_EVENT0("cc", "CCLayerTreeHost::initializeRenderer");
+ if (!m_proxy->initializeRenderer()) {
+ // Uh oh, better tell the client that we can't do anything with this context.
+ m_client->didRecreateOutputSurface(false);
+ return;
+ }
+
+ // Update m_settings based on capabilities that we got back from the renderer.
+ m_settings.acceleratePainting = m_proxy->rendererCapabilities().usingAcceleratedPainting;
+
+ // Update m_settings based on partial update capability.
+ m_settings.maxPartialTextureUpdates = min(m_settings.maxPartialTextureUpdates, m_proxy->maxPartialTextureUpdates());
+
+ m_contentsTextureManager = CCPrioritizedTextureManager::create(0, m_proxy->rendererCapabilities().maxTextureSize, CCRenderer::ContentPool);
+ m_surfaceMemoryPlaceholder = m_contentsTextureManager->createTexture(IntSize(), GraphicsContext3D::RGBA);
+
+ m_rendererInitialized = true;
+
+ m_settings.defaultTileSize = IntSize(min(m_settings.defaultTileSize.width(), m_proxy->rendererCapabilities().maxTextureSize),
+ min(m_settings.defaultTileSize.height(), m_proxy->rendererCapabilities().maxTextureSize));
+ m_settings.maxUntiledLayerSize = IntSize(min(m_settings.maxUntiledLayerSize.width(), m_proxy->rendererCapabilities().maxTextureSize),
+ min(m_settings.maxUntiledLayerSize.height(), m_proxy->rendererCapabilities().maxTextureSize));
+}
+
+CCLayerTreeHost::RecreateResult CCLayerTreeHost::recreateContext()
+{
+ TRACE_EVENT0("cc", "CCLayerTreeHost::recreateContext");
+ ASSERT(m_contextLost);
+
+ bool recreated = false;
+ if (!m_numTimesRecreateShouldFail)
+ recreated = m_proxy->recreateContext();
+ else
+ m_numTimesRecreateShouldFail--;
+
+ if (recreated) {
+ m_client->didRecreateOutputSurface(true);
+ m_contextLost = false;
+ return RecreateSucceeded;
+ }
+
+ // Tolerate a certain number of recreation failures to work around races
+ // in the context-lost machinery.
+ m_numFailedRecreateAttempts++;
+ if (m_numFailedRecreateAttempts < 5) {
+ // FIXME: The single thread does not self-schedule context
+ // recreation. So force another recreation attempt to happen by requesting
+ // another commit.
+ if (!CCProxy::hasImplThread())
+ setNeedsCommit();
+ return RecreateFailedButTryAgain;
+ }
+
+ // We have tried too many times to recreate the context. Tell the host to fall
+ // back to software rendering.
+ m_client->didRecreateOutputSurface(false);
+ return RecreateFailedAndGaveUp;
+}
+
+void CCLayerTreeHost::deleteContentsTexturesOnImplThread(CCResourceProvider* resourceProvider)
+{
+ ASSERT(CCProxy::isImplThread());
+ if (m_rendererInitialized)
+ m_contentsTextureManager->clearAllMemory(resourceProvider);
+}
+
+void CCLayerTreeHost::acquireLayerTextures()
+{
+ ASSERT(CCProxy::isMainThread());
+ m_proxy->acquireLayerTextures();
+}
+
+void CCLayerTreeHost::updateAnimations(double monotonicFrameBeginTime)
+{
+ m_animating = true;
+ m_client->animate(monotonicFrameBeginTime);
+ animateLayers(monotonicFrameBeginTime);
+ m_animating = false;
+
+ m_renderingStats.numAnimationFrames++;
+}
+
+void CCLayerTreeHost::layout()
+{
+ m_client->layout();
+}
+
+void CCLayerTreeHost::beginCommitOnImplThread(CCLayerTreeHostImpl* hostImpl)
+{
+ ASSERT(CCProxy::isImplThread());
+ TRACE_EVENT0("cc", "CCLayerTreeHost::commitTo");
+
+ m_contentsTextureManager->reduceMemory(hostImpl->resourceProvider());
+}
+
+// This function commits the CCLayerTreeHost to an impl tree. When modifying
+// this function, keep in mind that the function *runs* on the impl thread! Any
+// code that is logically a main thread operation, e.g. deletion of a LayerChromium,
+// should be delayed until the CCLayerTreeHost::commitComplete, which will run
+// after the commit, but on the main thread.
+void CCLayerTreeHost::finishCommitOnImplThread(CCLayerTreeHostImpl* hostImpl)
+{
+ ASSERT(CCProxy::isImplThread());
+
+ hostImpl->setRootLayer(TreeSynchronizer::synchronizeTrees(rootLayer(), hostImpl->detachLayerTree(), hostImpl));
+
+ if (m_rootLayer && m_hudLayer)
+ hostImpl->setHudLayer(static_cast<CCHeadsUpDisplayLayerImpl*>(CCLayerTreeHostCommon::findLayerInSubtree(hostImpl->rootLayer(), m_hudLayer->id())));
+ else
+ hostImpl->setHudLayer(0);
+
+ // We may have added an animation during the tree sync. This will cause both layer tree hosts
+ // to visit their controllers.
+ if (rootLayer() && m_needsAnimateLayers)
+ hostImpl->setNeedsAnimateLayers();
+
+ hostImpl->setSourceFrameNumber(commitNumber());
+ hostImpl->setViewportSize(layoutViewportSize(), deviceViewportSize());
+ hostImpl->setDeviceScaleFactor(deviceScaleFactor());
+ hostImpl->setPageScaleFactorAndLimits(m_pageScaleFactor, m_minPageScaleFactor, m_maxPageScaleFactor);
+ hostImpl->setBackgroundColor(m_backgroundColor);
+ hostImpl->setHasTransparentBackground(m_hasTransparentBackground);
+
+ m_commitNumber++;
+}
+
+void CCLayerTreeHost::setFontAtlas(scoped_ptr<CCFontAtlas> fontAtlas)
+{
+ m_fontAtlas = fontAtlas.Pass();
+ setNeedsCommit();
+}
+
+void CCLayerTreeHost::willCommit()
+{
+ m_client->willCommit();
+ if (m_rootLayer && m_settings.showDebugInfo()) {
+ if (!m_hudLayer)
+ m_hudLayer = HeadsUpDisplayLayerChromium::create();
+
+ if (m_fontAtlas.get())
+ m_hudLayer->setFontAtlas(m_fontAtlas.Pass());
+
+ if (!m_hudLayer->parent())
+ m_rootLayer->addChild(m_hudLayer);
+ }
+}
+
+void CCLayerTreeHost::commitComplete()
+{
+ m_deleteTextureAfterCommitList.clear();
+ m_client->didCommit();
+}
+
+scoped_ptr<CCGraphicsContext> CCLayerTreeHost::createContext()
+{
+ return m_client->createOutputSurface();
+}
+
+scoped_ptr<CCInputHandler> CCLayerTreeHost::createInputHandler()
+{
+ return m_client->createInputHandler();
+}
+
+scoped_ptr<CCLayerTreeHostImpl> CCLayerTreeHost::createLayerTreeHostImpl(CCLayerTreeHostImplClient* client)
+{
+ return CCLayerTreeHostImpl::create(m_settings, client);
+}
+
+void CCLayerTreeHost::didLoseContext()
+{
+ TRACE_EVENT0("cc", "CCLayerTreeHost::didLoseContext");
+ ASSERT(CCProxy::isMainThread());
+ m_contextLost = true;
+ m_numFailedRecreateAttempts = 0;
+ setNeedsCommit();
+}
+
+bool CCLayerTreeHost::compositeAndReadback(void *pixels, const IntRect& rect)
+{
+ m_triggerIdleUpdates = false;
+ bool ret = m_proxy->compositeAndReadback(pixels, rect);
+ m_triggerIdleUpdates = true;
+ return ret;
+}
+
+void CCLayerTreeHost::finishAllRendering()
+{
+ if (!m_rendererInitialized)
+ return;
+ m_proxy->finishAllRendering();
+}
+
+void CCLayerTreeHost::renderingStats(CCRenderingStats* stats) const
+{
+ *stats = m_renderingStats;
+ m_proxy->renderingStats(stats);
+}
+
+const RendererCapabilities& CCLayerTreeHost::rendererCapabilities() const
+{
+ return m_proxy->rendererCapabilities();
+}
+
+void CCLayerTreeHost::setNeedsAnimate()
+{
+ ASSERT(CCProxy::hasImplThread());
+ m_proxy->setNeedsAnimate();
+}
+
+void CCLayerTreeHost::setNeedsCommit()
+{
+ m_proxy->setNeedsCommit();
+}
+
+void CCLayerTreeHost::setNeedsRedraw()
+{
+ m_proxy->setNeedsRedraw();
+ if (!CCThreadProxy::implThread())
+ m_client->scheduleComposite();
+}
+
+bool CCLayerTreeHost::commitRequested() const
+{
+ return m_proxy->commitRequested();
+}
+
+void CCLayerTreeHost::setAnimationEvents(scoped_ptr<CCAnimationEventsVector> events, double wallClockTime)
+{
+ ASSERT(CCThreadProxy::isMainThread());
+ setAnimationEventsRecursive(*events.get(), m_rootLayer.get(), wallClockTime);
+}
+
+void CCLayerTreeHost::didAddAnimation()
+{
+ m_needsAnimateLayers = true;
+ m_proxy->didAddAnimation();
+}
+
+void CCLayerTreeHost::setRootLayer(scoped_refptr<LayerChromium> rootLayer)
+{
+ if (m_rootLayer == rootLayer)
+ return;
+
+ if (m_rootLayer)
+ m_rootLayer->setLayerTreeHost(0);
+ m_rootLayer = rootLayer;
+ if (m_rootLayer)
+ m_rootLayer->setLayerTreeHost(this);
+
+ if (m_hudLayer)
+ m_hudLayer->removeFromParent();
+
+ setNeedsCommit();
+}
+
+void CCLayerTreeHost::setViewportSize(const IntSize& layoutViewportSize, const IntSize& deviceViewportSize)
+{
+ if (layoutViewportSize == m_layoutViewportSize && deviceViewportSize == m_deviceViewportSize)
+ return;
+
+ m_layoutViewportSize = layoutViewportSize;
+ m_deviceViewportSize = deviceViewportSize;
+
+ setNeedsCommit();
+}
+
+void CCLayerTreeHost::setPageScaleFactorAndLimits(float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor)
+{
+ if (pageScaleFactor == m_pageScaleFactor && minPageScaleFactor == m_minPageScaleFactor && maxPageScaleFactor == m_maxPageScaleFactor)
+ return;
+
+ m_pageScaleFactor = pageScaleFactor;
+ m_minPageScaleFactor = minPageScaleFactor;
+ m_maxPageScaleFactor = maxPageScaleFactor;
+ setNeedsCommit();
+}
+
+void CCLayerTreeHost::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+ m_visible = visible;
+ m_proxy->setVisible(visible);
+}
+
+void CCLayerTreeHost::reduceContentsTexturesMemoryOnImplThread(size_t limitBytes, CCResourceProvider* resourceProvider)
+{
+ ASSERT(CCProxy::isImplThread());
+ ASSERT(m_contentsTextureManager.get());
+ m_contentsTextureManager->reduceMemoryOnImplThread(limitBytes, resourceProvider);
+}
+
+bool CCLayerTreeHost::evictedContentsTexturesBackingsExist() const
+{
+ ASSERT(CCProxy::isImplThread());
+ ASSERT(m_contentsTextureManager.get());
+ return m_contentsTextureManager->evictedBackingsExist();
+}
+
+void CCLayerTreeHost::getEvictedContentTexturesBackings(CCPrioritizedTextureManager::BackingVector& evictedBackings)
+{
+ ASSERT(CCProxy::isImplThread());
+ evictedBackings.clear();
+ if (m_rendererInitialized)
+ m_contentsTextureManager->getEvictedBackings(evictedBackings);
+}
+
+void CCLayerTreeHost::unlinkEvictedContentTexturesBackings(const CCPrioritizedTextureManager::BackingVector& evictedBackings)
+{
+ ASSERT(CCProxy::isMainThread());
+ ASSERT(m_contentsTextureManager.get());
+ m_contentsTextureManager->unlinkEvictedBackings(evictedBackings);
+}
+
+bool CCLayerTreeHost::deleteEvictedContentTexturesBackings()
+{
+ ASSERT(CCProxy::isImplThread() && CCProxy::isMainThreadBlocked());
+ ASSERT(m_contentsTextureManager.get());
+ return m_contentsTextureManager->deleteEvictedBackings();
+}
+
+void CCLayerTreeHost::startPageScaleAnimation(const IntSize& targetPosition, bool useAnchor, float scale, double durationSec)
+{
+ m_proxy->startPageScaleAnimation(targetPosition, useAnchor, scale, durationSec);
+}
+
+void CCLayerTreeHost::loseContext(int numTimes)
+{
+ TRACE_EVENT1("cc", "CCLayerTreeHost::loseCompositorContext", "numTimes", numTimes);
+ m_numTimesRecreateShouldFail = numTimes - 1;
+ m_proxy->loseContext();
+}
+
+CCPrioritizedTextureManager* CCLayerTreeHost::contentsTextureManager() const
+{
+ return m_contentsTextureManager.get();
+}
+
+void CCLayerTreeHost::composite()
+{
+ ASSERT(!CCThreadProxy::implThread());
+ static_cast<CCSingleThreadProxy*>(m_proxy.get())->compositeImmediately();
+}
+
+void CCLayerTreeHost::scheduleComposite()
+{
+ m_client->scheduleComposite();
+}
+
+bool CCLayerTreeHost::initializeRendererIfNeeded()
+{
+ if (!m_rendererInitialized) {
+ initializeRenderer();
+ // If we couldn't initialize, then bail since we're returning to software mode.
+ if (!m_rendererInitialized)
+ return false;
+ }
+ if (m_contextLost) {
+ if (recreateContext() != RecreateSucceeded)
+ return false;
+ }
+ return true;
+}
+
+void CCLayerTreeHost::updateLayers(CCTextureUpdateQueue& queue, size_t memoryAllocationLimitBytes)
+{
+ ASSERT(m_rendererInitialized);
+ ASSERT(memoryAllocationLimitBytes);
+
+ if (!rootLayer())
+ return;
+
+ if (layoutViewportSize().isEmpty())
+ return;
+
+ m_contentsTextureManager->setMaxMemoryLimitBytes(memoryAllocationLimitBytes);
+
+ updateLayers(rootLayer(), queue);
+}
+
+static void setScale(LayerChromium* layer, float deviceScaleFactor, float pageScaleFactor)
+{
+ if (layer->boundsContainPageScale())
+ layer->setContentsScale(deviceScaleFactor);
+ else
+ layer->setContentsScale(deviceScaleFactor * pageScaleFactor);
+}
+
+static LayerChromium* findFirstScrollableLayer(LayerChromium* layer)
+{
+ if (!layer)
+ return 0;
+
+ if (layer->scrollable())
+ return layer;
+
+ for (size_t i = 0; i < layer->children().size(); ++i) {
+ LayerChromium* found = findFirstScrollableLayer(layer->children()[i].get());
+ if (found)
+ return found;
+ }
+
+ return 0;
+}
+
+static void updateLayerScale(LayerChromium* layer, float deviceScaleFactor, float pageScaleFactor)
+{
+ setScale(layer, deviceScaleFactor, pageScaleFactor);
+
+ LayerChromium* maskLayer = layer->maskLayer();
+ if (maskLayer)
+ setScale(maskLayer, deviceScaleFactor, pageScaleFactor);
+
+ LayerChromium* replicaMaskLayer = layer->replicaLayer() ? layer->replicaLayer()->maskLayer() : 0;
+ if (replicaMaskLayer)
+ setScale(replicaMaskLayer, deviceScaleFactor, pageScaleFactor);
+
+ const std::vector<scoped_refptr<LayerChromium> >& children = layer->children();
+ for (unsigned int i = 0; i < children.size(); ++i)
+ updateLayerScale(children[i].get(), deviceScaleFactor, pageScaleFactor);
+}
+
+void CCLayerTreeHost::updateLayers(LayerChromium* rootLayer, CCTextureUpdateQueue& queue)
+{
+ TRACE_EVENT0("cc", "CCLayerTreeHost::updateLayers");
+
+ updateLayerScale(rootLayer, m_deviceScaleFactor, m_pageScaleFactor);
+
+ LayerList updateList;
+
+ {
+ if (CCSettings::pageScalePinchZoomEnabled()) {
+ LayerChromium* rootScroll = findFirstScrollableLayer(rootLayer);
+ if (rootScroll)
+ rootScroll->setImplTransform(m_implTransform);
+ }
+
+ TRACE_EVENT0("cc", "CCLayerTreeHost::updateLayers::calcDrawEtc");
+ CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, deviceViewportSize(), m_deviceScaleFactor, rendererCapabilities().maxTextureSize, updateList);
+ }
+
+ // Reset partial texture update requests.
+ m_partialTextureUpdateRequests = 0;
+
+ bool needMoreUpdates = paintLayerContents(updateList, queue);
+ if (m_triggerIdleUpdates && needMoreUpdates)
+ setNeedsCommit();
+
+ for (size_t i = 0; i < updateList.size(); ++i)
+ updateList[i]->clearRenderSurface();
+}
+
+void CCLayerTreeHost::setPrioritiesForSurfaces(size_t surfaceMemoryBytes)
+{
+ // Surfaces have a place holder for their memory since they are managed
+ // independantly but should still be tracked and reduce other memory usage.
+ m_surfaceMemoryPlaceholder->setTextureManager(m_contentsTextureManager.get());
+ m_surfaceMemoryPlaceholder->setRequestPriority(CCPriorityCalculator::renderSurfacePriority());
+ m_surfaceMemoryPlaceholder->setToSelfManagedMemoryPlaceholder(surfaceMemoryBytes);
+}
+
+void CCLayerTreeHost::setPrioritiesForLayers(const LayerList& updateList)
+{
+ // Use BackToFront since it's cheap and this isn't order-dependent.
+ typedef CCLayerIterator<LayerChromium, LayerList, RenderSurfaceChromium, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
+
+ CCPriorityCalculator calculator;
+ CCLayerIteratorType end = CCLayerIteratorType::end(&updateList);
+ for (CCLayerIteratorType it = CCLayerIteratorType::begin(&updateList); it != end; ++it) {
+ if (it.representsItself())
+ it->setTexturePriorities(calculator);
+ else if (it.representsTargetRenderSurface()) {
+ if (it->maskLayer())
+ it->maskLayer()->setTexturePriorities(calculator);
+ if (it->replicaLayer() && it->replicaLayer()->maskLayer())
+ it->replicaLayer()->maskLayer()->setTexturePriorities(calculator);
+ }
+ }
+}
+
+void CCLayerTreeHost::prioritizeTextures(const LayerList& renderSurfaceLayerList, CCOverdrawMetrics& metrics)
+{
+ m_contentsTextureManager->clearPriorities();
+
+ size_t memoryForRenderSurfacesMetric = calculateMemoryForRenderSurfaces(renderSurfaceLayerList);
+
+ setPrioritiesForLayers(renderSurfaceLayerList);
+ setPrioritiesForSurfaces(memoryForRenderSurfacesMetric);
+
+ metrics.didUseContentsTextureMemoryBytes(m_contentsTextureManager->memoryAboveCutoffBytes());
+ metrics.didUseRenderSurfaceTextureMemoryBytes(memoryForRenderSurfacesMetric);
+
+ m_contentsTextureManager->prioritizeTextures();
+}
+
+size_t CCLayerTreeHost::calculateMemoryForRenderSurfaces(const LayerList& updateList)
+{
+ size_t readbackBytes = 0;
+ size_t maxBackgroundTextureBytes = 0;
+ size_t contentsTextureBytes = 0;
+
+ // Start iteration at 1 to skip the root surface as it does not have a texture cost.
+ for (size_t i = 1; i < updateList.size(); ++i) {
+ LayerChromium* renderSurfaceLayer = updateList[i].get();
+ RenderSurfaceChromium* renderSurface = renderSurfaceLayer->renderSurface();
+
+ size_t bytes = CCTexture::memorySizeBytes(renderSurface->contentRect().size(), GraphicsContext3D::RGBA);
+ contentsTextureBytes += bytes;
+
+ if (renderSurfaceLayer->backgroundFilters().isEmpty())
+ continue;
+
+ if (bytes > maxBackgroundTextureBytes)
+ maxBackgroundTextureBytes = bytes;
+ if (!readbackBytes)
+ readbackBytes = CCTexture::memorySizeBytes(m_deviceViewportSize, GraphicsContext3D::RGBA);
+ }
+ return readbackBytes + maxBackgroundTextureBytes + contentsTextureBytes;
+}
+
+bool CCLayerTreeHost::paintMasksForRenderSurface(LayerChromium* renderSurfaceLayer, CCTextureUpdateQueue& queue)
+{
+ // Note: Masks and replicas only exist for layers that own render surfaces. If we reach this point
+ // in code, we already know that at least something will be drawn into this render surface, so the
+ // mask and replica should be painted.
+
+ bool needMoreUpdates = false;
+ LayerChromium* maskLayer = renderSurfaceLayer->maskLayer();
+ if (maskLayer) {
+ maskLayer->update(queue, 0, m_renderingStats);
+ needMoreUpdates |= maskLayer->needMoreUpdates();
+ }
+
+ LayerChromium* replicaMaskLayer = renderSurfaceLayer->replicaLayer() ? renderSurfaceLayer->replicaLayer()->maskLayer() : 0;
+ if (replicaMaskLayer) {
+ replicaMaskLayer->update(queue, 0, m_renderingStats);
+ needMoreUpdates |= replicaMaskLayer->needMoreUpdates();
+ }
+ return needMoreUpdates;
+}
+
+bool CCLayerTreeHost::paintLayerContents(const LayerList& renderSurfaceLayerList, CCTextureUpdateQueue& queue)
+{
+ // Use FrontToBack to allow for testing occlusion and performing culling during the tree walk.
+ typedef CCLayerIterator<LayerChromium, LayerList, RenderSurfaceChromium, CCLayerIteratorActions::FrontToBack> CCLayerIteratorType;
+
+ bool needMoreUpdates = false;
+ bool recordMetricsForFrame = true; // FIXME: In the future, disable this when about:tracing is off.
+ CCOcclusionTracker occlusionTracker(m_rootLayer->renderSurface()->contentRect(), recordMetricsForFrame);
+ occlusionTracker.setMinimumTrackingSize(m_settings.minimumOcclusionTrackingSize);
+
+ prioritizeTextures(renderSurfaceLayerList, occlusionTracker.overdrawMetrics());
+
+ CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
+ for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
+ occlusionTracker.enterLayer(it);
+
+ if (it.representsTargetRenderSurface()) {
+ ASSERT(it->renderSurface()->drawOpacity() || it->renderSurface()->drawOpacityIsAnimating());
+ needMoreUpdates |= paintMasksForRenderSurface(*it, queue);
+ } else if (it.representsItself()) {
+ ASSERT(!it->bounds().isEmpty());
+ it->update(queue, &occlusionTracker, m_renderingStats);
+ needMoreUpdates |= it->needMoreUpdates();
+ }
+
+ occlusionTracker.leaveLayer(it);
+ }
+
+ occlusionTracker.overdrawMetrics().recordMetrics(this);
+
+ return needMoreUpdates;
+}
+
+void CCLayerTreeHost::applyScrollAndScale(const CCScrollAndScaleSet& info)
+{
+ if (!m_rootLayer)
+ return;
+
+ LayerChromium* rootScrollLayer = findFirstScrollableLayer(m_rootLayer.get());
+ IntSize rootScrollDelta;
+
+ for (size_t i = 0; i < info.scrolls.size(); ++i) {
+ LayerChromium* layer = CCLayerTreeHostCommon::findLayerInSubtree(m_rootLayer.get(), info.scrolls[i].layerId);
+ if (!layer)
+ continue;
+ if (layer == rootScrollLayer)
+ rootScrollDelta += info.scrolls[i].scrollDelta;
+ else
+ layer->setScrollPosition(layer->scrollPosition() + info.scrolls[i].scrollDelta);
+ }
+ if (!rootScrollDelta.isZero() || info.pageScaleDelta != 1)
+ m_client->applyScrollAndScale(rootScrollDelta, info.pageScaleDelta);
+}
+
+void CCLayerTreeHost::setImplTransform(const WebKit::WebTransformationMatrix& transform)
+{
+ m_implTransform = transform;
+}
+
+void CCLayerTreeHost::startRateLimiter(WebKit::WebGraphicsContext3D* context)
+{
+ if (m_animating)
+ return;
+
+ ASSERT(context);
+ RateLimiterMap::iterator it = m_rateLimiters.find(context);
+ if (it != m_rateLimiters.end())
+ it->second->start();
+ else {
+ scoped_refptr<RateLimiter> rateLimiter = RateLimiter::create(context, this);
+ m_rateLimiters[context] = rateLimiter;
+ rateLimiter->start();
+ }
+}
+
+void CCLayerTreeHost::stopRateLimiter(WebKit::WebGraphicsContext3D* context)
+{
+ RateLimiterMap::iterator it = m_rateLimiters.find(context);
+ if (it != m_rateLimiters.end()) {
+ it->second->stop();
+ m_rateLimiters.erase(it);
+ }
+}
+
+void CCLayerTreeHost::rateLimit()
+{
+ // Force a no-op command on the compositor context, so that any ratelimiting commands will wait for the compositing
+ // context, and therefore for the SwapBuffers.
+ m_proxy->forceSerializeOnSwapBuffers();
+}
+
+bool CCLayerTreeHost::bufferedUpdates()
+{
+ return m_settings.maxPartialTextureUpdates != numeric_limits<size_t>::max();
+}
+
+bool CCLayerTreeHost::requestPartialTextureUpdate()
+{
+ if (m_partialTextureUpdateRequests >= m_settings.maxPartialTextureUpdates)
+ return false;
+
+ m_partialTextureUpdateRequests++;
+ return true;
+}
+
+void CCLayerTreeHost::deleteTextureAfterCommit(scoped_ptr<CCPrioritizedTexture> texture)
+{
+ m_deleteTextureAfterCommitList.append(texture.Pass());
+}
+
+void CCLayerTreeHost::setDeviceScaleFactor(float deviceScaleFactor)
+{
+ if (deviceScaleFactor == m_deviceScaleFactor)
+ return;
+ m_deviceScaleFactor = deviceScaleFactor;
+
+ setNeedsCommit();
+}
+
+void CCLayerTreeHost::animateLayers(double monotonicTime)
+{
+ if (!CCSettings::acceleratedAnimationEnabled() || !m_needsAnimateLayers)
+ return;
+
+ TRACE_EVENT0("cc", "CCLayerTreeHostImpl::animateLayers");
+ m_needsAnimateLayers = animateLayersRecursive(m_rootLayer.get(), monotonicTime);
+}
+
+bool CCLayerTreeHost::animateLayersRecursive(LayerChromium* current, double monotonicTime)
+{
+ if (!current)
+ return false;
+
+ bool subtreeNeedsAnimateLayers = false;
+ CCLayerAnimationController* currentController = current->layerAnimationController();
+ currentController->animate(monotonicTime, 0);
+
+ // If the current controller still has an active animation, we must continue animating layers.
+ if (currentController->hasActiveAnimation())
+ subtreeNeedsAnimateLayers = true;
+
+ for (size_t i = 0; i < current->children().size(); ++i) {
+ if (animateLayersRecursive(current->children()[i].get(), monotonicTime))
+ subtreeNeedsAnimateLayers = true;
+ }
+
+ return subtreeNeedsAnimateLayers;
+}
+
+void CCLayerTreeHost::setAnimationEventsRecursive(const CCAnimationEventsVector& events, LayerChromium* layer, double wallClockTime)
+{
+ if (!layer)
+ return;
+
+ for (size_t eventIndex = 0; eventIndex < events.size(); ++eventIndex) {
+ if (layer->id() == events[eventIndex].layerId) {
+ if (events[eventIndex].type == CCAnimationEvent::Started)
+ layer->notifyAnimationStarted(events[eventIndex], wallClockTime);
+ else
+ layer->notifyAnimationFinished(wallClockTime);
+ }
+ }
+
+ for (size_t childIndex = 0; childIndex < layer->children().size(); ++childIndex)
+ setAnimationEventsRecursive(events, layer->children()[childIndex].get(), wallClockTime);
+}
+
+} // namespace cc