| // 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; |
| } |
| |
| PassOwnPtr<CCLayerTreeHost> CCLayerTreeHost::create(CCLayerTreeHostClient* client, const CCLayerTreeSettings& settings) |
| { |
| OwnPtr<CCLayerTreeHost> layerTreeHost = adoptPtr(new CCLayerTreeHost(client, settings)); |
| if (!layerTreeHost->initialize()) |
| return nullptr; |
| return layerTreeHost.release(); |
| } |
| |
| 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); |
| m_proxy->stop(); |
| m_proxy.clear(); |
| numLayerTreeInstances--; |
| RateLimiterMap::iterator it = m_rateLimiters.begin(); |
| if (it != m_rateLimiters.end()) |
| #if WTF_NEW_HASHMAP_ITERATORS_INTERFACE |
| it->value->stop(); |
| #else |
| it->second->stop(); |
| #endif |
| } |
| |
| 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(PassOwnPtr<CCFontAtlas> fontAtlas) |
| { |
| m_fontAtlas = fontAtlas; |
| setNeedsCommit(); |
| } |
| |
| void CCLayerTreeHost::willCommit() |
| { |
| m_client->willCommit(); |
| if (m_rootLayer && m_settings.showDebugInfo()) { |
| if (!m_hudLayer) |
| m_hudLayer = HeadsUpDisplayLayerChromium::create(); |
| |
| if (m_fontAtlas) |
| m_hudLayer->setFontAtlas(m_fontAtlas.release()); |
| |
| if (!m_hudLayer->parent()) |
| m_rootLayer->addChild(m_hudLayer); |
| } |
| } |
| |
| void CCLayerTreeHost::commitComplete() |
| { |
| m_deleteTextureAfterCommitList.clear(); |
| m_client->didCommit(); |
| } |
| |
| PassOwnPtr<CCGraphicsContext> CCLayerTreeHost::createContext() |
| { |
| return m_client->createOutputSurface(); |
| } |
| |
| PassOwnPtr<CCInputHandler> CCLayerTreeHost::createInputHandler() |
| { |
| return m_client->createInputHandler(); |
| } |
| |
| PassOwnPtr<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->implSideRenderingStats(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(PassOwnPtr<CCAnimationEventsVector> events, double wallClockTime) |
| { |
| ASSERT(CCThreadProxy::isMainThread()); |
| setAnimationEventsRecursive(*events, m_rootLayer.get(), wallClockTime); |
| } |
| |
| void CCLayerTreeHost::didAddAnimation() |
| { |
| m_needsAnimateLayers = true; |
| m_proxy->didAddAnimation(); |
| } |
| |
| void CCLayerTreeHost::setRootLayer(PassRefPtr<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 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 Vector<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; |
| |
| { |
| TRACE_EVENT0("cc", "CCLayerTreeHost::updateLayers::calcDrawEtc"); |
| CCLayerTreeHostCommon::calculateDrawTransforms(rootLayer, deviceViewportSize(), m_deviceScaleFactor, rendererCapabilities().maxTextureSize, updateList); |
| CCLayerTreeHostCommon::calculateVisibleRects(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, Vector<RefPtr<LayerChromium> >, 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, Vector<RefPtr<LayerChromium> >, 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; |
| } |
| |
| 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; |
| } |
| |
| 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::startRateLimiter(WebKit::WebGraphicsContext3D* context) |
| { |
| if (m_animating) |
| return; |
| |
| ASSERT(context); |
| RateLimiterMap::iterator it = m_rateLimiters.find(context); |
| if (it != m_rateLimiters.end()) |
| #if WTF_NEW_HASHMAP_ITERATORS_INTERFACE |
| it->value->start(); |
| #else |
| it->second->start(); |
| #endif |
| else { |
| RefPtr<RateLimiter> rateLimiter = RateLimiter::create(context, this); |
| m_rateLimiters.set(context, rateLimiter); |
| rateLimiter->start(); |
| } |
| } |
| |
| void CCLayerTreeHost::stopRateLimiter(WebKit::WebGraphicsContext3D* context) |
| { |
| RateLimiterMap::iterator it = m_rateLimiters.find(context); |
| if (it != m_rateLimiters.end()) { |
| #if WTF_NEW_HASHMAP_ITERATORS_INTERFACE |
| it->value->stop(); |
| #else |
| it->second->stop(); |
| #endif |
| m_rateLimiters.remove(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(PassOwnPtr<CCPrioritizedTexture> texture) |
| { |
| m_deleteTextureAfterCommitList.append(texture); |
| } |
| |
| 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 |