diff options
Diffstat (limited to 'cc/layer_tree_host.cc')
-rw-r--r-- | cc/layer_tree_host.cc | 861 |
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 |