diff options
author | ccameron@chromium.org <ccameron@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-22 22:50:28 +0000 |
---|---|---|
committer | ccameron@chromium.org <ccameron@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-22 22:50:28 +0000 |
commit | a0a008420151bf3f117f294250e35641af25f213 (patch) | |
tree | 7cd0378a4d4b0570d1654a695b97c0957568aff6 /cc | |
parent | 6c12c50736a7f2cce5d8776c9d64b85e3435aec6 (diff) | |
download | chromium_src-a0a008420151bf3f117f294250e35641af25f213.zip chromium_src-a0a008420151bf3f117f294250e35641af25f213.tar.gz chromium_src-a0a008420151bf3f117f294250e35641af25f213.tar.bz2 |
Conditionalize memory allocation limit based on visibility
Replace the single value with a ManagedMemoryPolicy structure
which has the limit in bytes when visible and when not visible,
and also has a priority cutoff when visible and when not visible.
In CCRendererClient, separate the methods for specifying and
enforcing a memory policy. This is so that one may decrease the
consumption of a renderer that has grown over time, without
disallowing growth in the future.
BUG=134750
Review URL: https://chromiumcodereview.appspot.com/11196038
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163420 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc')
-rw-r--r-- | cc/cc.gyp | 2 | ||||
-rw-r--r-- | cc/delegated_renderer_layer_impl_unittest.cc | 2 | ||||
-rw-r--r-- | cc/gl_renderer.cc | 2 | ||||
-rw-r--r-- | cc/gl_renderer_unittest.cc | 3 | ||||
-rw-r--r-- | cc/layer_tree_host_impl.cc | 24 | ||||
-rw-r--r-- | cc/layer_tree_host_impl.h | 10 | ||||
-rw-r--r-- | cc/layer_tree_host_impl_unittest.cc | 25 | ||||
-rw-r--r-- | cc/layer_tree_host_unittest.cc | 6 | ||||
-rw-r--r-- | cc/managed_memory_policy.cc | 45 | ||||
-rw-r--r-- | cc/managed_memory_policy.h | 29 | ||||
-rw-r--r-- | cc/prioritized_texture_manager.cc | 48 | ||||
-rw-r--r-- | cc/prioritized_texture_manager.h | 22 | ||||
-rw-r--r-- | cc/prioritized_texture_unittest.cc | 69 | ||||
-rw-r--r-- | cc/priority_calculator.cc | 40 | ||||
-rw-r--r-- | cc/priority_calculator.h | 10 | ||||
-rw-r--r-- | cc/renderer.h | 4 | ||||
-rw-r--r-- | cc/single_thread_proxy.cc | 4 | ||||
-rw-r--r-- | cc/single_thread_proxy.h | 2 | ||||
-rw-r--r-- | cc/software_renderer_unittest.cc | 3 | ||||
-rw-r--r-- | cc/thread_proxy.cc | 4 | ||||
-rw-r--r-- | cc/thread_proxy.h | 2 |
21 files changed, 289 insertions, 67 deletions
@@ -73,6 +73,8 @@ 'CCLayerTreeHostCommon.h', 'layer_tree_host_impl.cc', 'layer_tree_host_impl.h', + 'managed_memory_policy.cc', + 'managed_memory_policy.h', 'math_util.cc', 'math_util.h', 'occlusion_tracker.cc', diff --git a/cc/delegated_renderer_layer_impl_unittest.cc b/cc/delegated_renderer_layer_impl_unittest.cc index 2ebc763..7e37259 100644 --- a/cc/delegated_renderer_layer_impl_unittest.cc +++ b/cc/delegated_renderer_layer_impl_unittest.cc @@ -51,7 +51,7 @@ public: virtual void setNeedsRedrawOnImplThread() OVERRIDE { } virtual void setNeedsCommitOnImplThread() OVERRIDE { } virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { } - virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes) OVERRIDE { return true; } + virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) OVERRIDE { return true; } protected: scoped_ptr<CCGraphicsContext> createContext() diff --git a/cc/gl_renderer.cc b/cc/gl_renderer.cc index 51d46f5..908aedf 100644 --- a/cc/gl_renderer.cc +++ b/cc/gl_renderer.cc @@ -1075,7 +1075,7 @@ void CCRendererGL::onMemoryAllocationChangedOnImplThread(WebKit::WebGraphicsMemo // bytes. This will happen when the memory manager thinks that the renderer // is not visible (which the renderer knows better). if (allocation.gpuResourceSizeInBytes) - m_client->setMemoryAllocationLimitBytes(allocation.gpuResourceSizeInBytes); + m_client->setManagedMemoryPolicy(ManagedMemoryPolicy(allocation.gpuResourceSizeInBytes)); enforceMemoryPolicy(); } diff --git a/cc/gl_renderer_unittest.cc b/cc/gl_renderer_unittest.cc index 33bf8c7..5505278 100644 --- a/cc/gl_renderer_unittest.cc +++ b/cc/gl_renderer_unittest.cc @@ -74,7 +74,8 @@ public: virtual void didLoseContext() OVERRIDE { } virtual void onSwapBuffersComplete() OVERRIDE { } virtual void setFullRootLayerDamage() OVERRIDE { m_setFullRootLayerDamageCount++; } - virtual void setMemoryAllocationLimitBytes(size_t bytes) OVERRIDE { m_memoryAllocationLimitBytes = bytes; } + virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { m_memoryAllocationLimitBytes = policy.bytesLimitWhenVisible; } + virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { } // Methods added for test. int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount; } diff --git a/cc/layer_tree_host_impl.cc b/cc/layer_tree_host_impl.cc index d762b0c..aa1b9db 100644 --- a/cc/layer_tree_host_impl.cc +++ b/cc/layer_tree_host_impl.cc @@ -223,7 +223,10 @@ CCLayerTreeHostImpl::CCLayerTreeHostImpl(const CCLayerTreeSettings& settings, CC , m_deviceScaleFactor(1) , m_visible(true) , m_contentsTexturesPurged(false) - , m_memoryAllocationLimitBytes(CCPrioritizedTextureManager::defaultMemoryAllocationLimit()) + , m_managedMemoryPolicy(CCPrioritizedTextureManager::defaultMemoryAllocationLimit(), + CCPriorityCalculator::allowEverythingCutoff(), + 0, + CCPriorityCalculator::allowNothingCutoff()) , m_backgroundColor(0) , m_hasTransparentBackground(false) , m_needsAnimateLayers(false) @@ -634,9 +637,11 @@ bool CCLayerTreeHostImpl::prepareToDraw(FrameData& frame) return true; } -void CCLayerTreeHostImpl::reduceContentsTextureMemoryOnImplThread(size_t limitBytes) +void CCLayerTreeHostImpl::enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) { - bool evictedResources = m_client->reduceContentsTextureMemoryOnImplThread(limitBytes); + bool evictedResources = m_client->reduceContentsTextureMemoryOnImplThread( + m_visible ? policy.bytesLimitWhenVisible : policy.bytesLimitWhenNotVisible, + m_visible ? policy.priorityCutoffWhenVisible : policy.priorityCutoffWhenNotVisible); if (evictedResources) { setContentsTexturesPurged(); m_client->setNeedsCommitOnImplThread(); @@ -644,13 +649,14 @@ void CCLayerTreeHostImpl::reduceContentsTextureMemoryOnImplThread(size_t limitBy } } -void CCLayerTreeHostImpl::setMemoryAllocationLimitBytes(size_t bytes) +void CCLayerTreeHostImpl::setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) { - DCHECK(bytes); - if (m_memoryAllocationLimitBytes == bytes) + if (m_managedMemoryPolicy == policy) return; - m_memoryAllocationLimitBytes = bytes; - reduceContentsTextureMemoryOnImplThread(m_visible ? m_memoryAllocationLimitBytes : 0); + m_managedMemoryPolicy = policy; + enforceManagedMemoryPolicy(m_managedMemoryPolicy); + // We always need to commit after changing the memory policy because the new + // limit can result in more or less content having texture allocated for it. m_client->setNeedsCommitOnImplThread(); } @@ -817,7 +823,7 @@ void CCLayerTreeHostImpl::setVisible(bool visible) return; m_visible = visible; didVisibilityChange(this, m_visible); - reduceContentsTextureMemoryOnImplThread(m_visible ? m_memoryAllocationLimitBytes : 0); + enforceManagedMemoryPolicy(m_managedMemoryPolicy); if (!m_renderer) return; diff --git a/cc/layer_tree_host_impl.h b/cc/layer_tree_host_impl.h index bcdc355..076dedf 100644 --- a/cc/layer_tree_host_impl.h +++ b/cc/layer_tree_host_impl.h @@ -42,7 +42,7 @@ public: virtual void setNeedsCommitOnImplThread() = 0; virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimationEventsVector>, double wallClockTime) = 0; // Returns true if resources were deleted by this call. - virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes) = 0; + virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) = 0; }; // CCPinchZoomViewport models the bounds and offset of the viewport that is used during a pinch-zoom operation. @@ -150,7 +150,8 @@ public: virtual void didLoseContext() OVERRIDE; virtual void onSwapBuffersComplete() OVERRIDE; virtual void setFullRootLayerDamage() OVERRIDE; - virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE; + virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE; + virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE; // WebCompositorOutputSurfaceClient implementation. virtual void onVSyncParametersChanged(double monotonicTimebase, double intervalInSeconds) OVERRIDE; @@ -194,8 +195,7 @@ public: bool contentsTexturesPurged() const { return m_contentsTexturesPurged; } void setContentsTexturesPurged(); void resetContentsTexturesPurged(); - size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; } - void reduceContentsTextureMemoryOnImplThread(size_t limitBytes); + size_t memoryAllocationLimitBytes() const { return m_managedMemoryPolicy.bytesLimitWhenVisible; } void setViewportSize(const IntSize& layoutViewportSize, const IntSize& deviceViewportSize); const IntSize& layoutViewportSize() const { return m_layoutViewportSize; } @@ -319,7 +319,7 @@ private: float m_deviceScaleFactor; bool m_visible; bool m_contentsTexturesPurged; - size_t m_memoryAllocationLimitBytes; + ManagedMemoryPolicy m_managedMemoryPolicy; SkColor m_backgroundColor; bool m_hasTransparentBackground; diff --git a/cc/layer_tree_host_impl_unittest.cc b/cc/layer_tree_host_impl_unittest.cc index 5029de2..f8e7385 100644 --- a/cc/layer_tree_host_impl_unittest.cc +++ b/cc/layer_tree_host_impl_unittest.cc @@ -87,7 +87,7 @@ public: virtual void setNeedsRedrawOnImplThread() OVERRIDE { m_didRequestRedraw = true; } virtual void setNeedsCommitOnImplThread() OVERRIDE { m_didRequestCommit = true; } virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE { } - virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes) OVERRIDE { return m_reduceMemoryResult; } + virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) OVERRIDE { return m_reduceMemoryResult; } void setReduceMemoryResult(bool reduceMemoryResult) { m_reduceMemoryResult = reduceMemoryResult; } @@ -236,16 +236,16 @@ TEST_P(CCLayerTreeHostImplTest, notifyIfCanDrawChanged) // Toggle contents textures purged without causing any evictions, // and make sure that it does not change canDraw. setReduceMemoryResult(false); - m_hostImpl->setMemoryAllocationLimitBytes( - m_hostImpl->memoryAllocationLimitBytes() - 1); + m_hostImpl->setManagedMemoryPolicy(ManagedMemoryPolicy( + m_hostImpl->memoryAllocationLimitBytes() - 1)); EXPECT_TRUE(m_hostImpl->canDraw()); EXPECT_FALSE(m_onCanDrawStateChangedCalled); m_onCanDrawStateChangedCalled = false; // Toggle contents textures purged to make sure it toggles canDraw. setReduceMemoryResult(true); - m_hostImpl->setMemoryAllocationLimitBytes( - m_hostImpl->memoryAllocationLimitBytes() - 1); + m_hostImpl->setManagedMemoryPolicy(ManagedMemoryPolicy( + m_hostImpl->memoryAllocationLimitBytes() - 1)); EXPECT_FALSE(m_hostImpl->canDraw()); EXPECT_TRUE(m_onCanDrawStateChangedCalled); m_onCanDrawStateChangedCalled = false; @@ -4030,23 +4030,23 @@ TEST_P(CCLayerTreeHostImplTest, releaseContentsTextureShouldTriggerCommit) // evicted, we need to re-commit because the new value may result in us // drawing something different than before. setReduceMemoryResult(false); - m_hostImpl->setMemoryAllocationLimitBytes( - m_hostImpl->memoryAllocationLimitBytes() - 1); + m_hostImpl->setManagedMemoryPolicy(ManagedMemoryPolicy( + m_hostImpl->memoryAllocationLimitBytes() - 1)); EXPECT_TRUE(m_didRequestCommit); m_didRequestCommit = false; // Especially if changing the memory limit caused evictions, we need // to re-commit. setReduceMemoryResult(true); - m_hostImpl->setMemoryAllocationLimitBytes( - m_hostImpl->memoryAllocationLimitBytes() - 1); + m_hostImpl->setManagedMemoryPolicy(ManagedMemoryPolicy( + m_hostImpl->memoryAllocationLimitBytes() - 1)); EXPECT_TRUE(m_didRequestCommit); m_didRequestCommit = false; // But if we set it to the same value that it was before, we shouldn't // re-commit. - m_hostImpl->setMemoryAllocationLimitBytes( - m_hostImpl->memoryAllocationLimitBytes()); + m_hostImpl->setManagedMemoryPolicy(ManagedMemoryPolicy( + m_hostImpl->memoryAllocationLimitBytes())); EXPECT_FALSE(m_didRequestCommit); } @@ -4077,7 +4077,8 @@ public: virtual void didLoseContext() OVERRIDE { } virtual void onSwapBuffersComplete() OVERRIDE { } virtual void setFullRootLayerDamage() OVERRIDE { } - virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE { } + virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { } + virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { } protected: CCTestRenderer(CCResourceProvider* resourceProvider) : CCRendererGL(this, resourceProvider) { } diff --git a/cc/layer_tree_host_unittest.cc b/cc/layer_tree_host_unittest.cc index 1de5332..da27070 100644 --- a/cc/layer_tree_host_unittest.cc +++ b/cc/layer_tree_host_unittest.cc @@ -2566,7 +2566,7 @@ public: // Reduce the memory limit to only fit the root layer and one render surface. This // prevents any contents drawing into surfaces from being allocated. - hostImpl->setMemoryAllocationLimitBytes(100 * 100 * 4 * 2); + hostImpl->setManagedMemoryPolicy(ManagedMemoryPolicy(100 * 100 * 4 * 2)); break; case 1: EXPECT_FALSE(renderer->haveCachedResourcesForRenderPassId(surface1RenderPassId)); @@ -2716,7 +2716,7 @@ public: virtual void run() OVERRIDE { DCHECK(m_test->m_implForEvictTextures); - m_test->m_implForEvictTextures->reduceContentsTextureMemoryOnImplThread(0); + m_test->m_implForEvictTextures->enforceManagedMemoryPolicy(ManagedMemoryPolicy(0)); } private: @@ -2875,7 +2875,7 @@ public: void evictTexturesOnImplThread() { DCHECK(m_implForEvictTextures); - m_implForEvictTextures->reduceContentsTextureMemoryOnImplThread(0); + m_implForEvictTextures->enforceManagedMemoryPolicy(ManagedMemoryPolicy(0)); } // Commit 1: Just commit and draw normally, then at the end, set ourselves diff --git a/cc/managed_memory_policy.cc b/cc/managed_memory_policy.cc new file mode 100644 index 0000000..29f1170 --- /dev/null +++ b/cc/managed_memory_policy.cc @@ -0,0 +1,45 @@ +// 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 "managed_memory_policy.h" + +#include "priority_calculator.h" + +namespace cc { + +ManagedMemoryPolicy::ManagedMemoryPolicy(size_t bytesLimitWhenVisible) + : bytesLimitWhenVisible(bytesLimitWhenVisible) + , priorityCutoffWhenVisible(CCPriorityCalculator::allowEverythingCutoff()) + , bytesLimitWhenNotVisible(0) + , priorityCutoffWhenNotVisible(CCPriorityCalculator::allowNothingCutoff()) +{ +} + +ManagedMemoryPolicy::ManagedMemoryPolicy(size_t bytesLimitWhenVisible, + int priorityCutoffWhenVisible, + size_t bytesLimitWhenNotVisible, + int priorityCutoffWhenNotVisible) + : bytesLimitWhenVisible(bytesLimitWhenVisible) + , priorityCutoffWhenVisible(priorityCutoffWhenVisible) + , bytesLimitWhenNotVisible(bytesLimitWhenNotVisible) + , priorityCutoffWhenNotVisible(priorityCutoffWhenNotVisible) +{ +} + +bool ManagedMemoryPolicy::operator==(const ManagedMemoryPolicy& other) const +{ + return bytesLimitWhenVisible == other.bytesLimitWhenVisible && + priorityCutoffWhenVisible == other.priorityCutoffWhenVisible && + bytesLimitWhenNotVisible == other.bytesLimitWhenNotVisible && + priorityCutoffWhenNotVisible == other.priorityCutoffWhenNotVisible; +} + +bool ManagedMemoryPolicy::operator!=(const ManagedMemoryPolicy& other) const +{ + return !(*this == other); +} + +} // namespace cc diff --git a/cc/managed_memory_policy.h b/cc/managed_memory_policy.h new file mode 100644 index 0000000..eba13c3 --- /dev/null +++ b/cc/managed_memory_policy.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef managed_memory_policy_h +#define managed_memory_policy_h + +#include "base/basictypes.h" + +namespace cc { + +struct ManagedMemoryPolicy { + ManagedMemoryPolicy(size_t bytesLimitWhenVisible); + ManagedMemoryPolicy(size_t bytesLimitWhenVisible, + int priorityCutoffWhenVisible, + size_t bytesLimitWhenNotVisible, + int priorityCutoffWhenNotVisible); + bool operator==(const ManagedMemoryPolicy&) const; + bool operator!=(const ManagedMemoryPolicy&) const; + + size_t bytesLimitWhenVisible; + int priorityCutoffWhenVisible; + size_t bytesLimitWhenNotVisible; + int priorityCutoffWhenNotVisible; +}; + +} // namespace cc + +#endif diff --git a/cc/prioritized_texture_manager.cc b/cc/prioritized_texture_manager.cc index 1b18be2..900a1da 100644 --- a/cc/prioritized_texture_manager.cc +++ b/cc/prioritized_texture_manager.cc @@ -19,6 +19,7 @@ namespace cc { CCPrioritizedTextureManager::CCPrioritizedTextureManager(size_t maxMemoryLimitBytes, int, int pool) : m_maxMemoryLimitBytes(maxMemoryLimitBytes) + , m_externalPriorityCutoff(CCPriorityCalculator::allowEverythingCutoff()) , m_memoryUseBytes(0) , m_memoryAboveCutoffBytes(0) , m_memoryAvailableBytes(0) @@ -56,13 +57,11 @@ void CCPrioritizedTextureManager::prioritizeTextures() sortedTextures.push_back(*it); std::sort(sortedTextures.begin(), sortedTextures.end(), compareTextures); + // Compute a priority cutoff based on memory pressure m_memoryAvailableBytes = m_maxMemoryLimitBytes; - m_priorityCutoff = CCPriorityCalculator::lowestPriority(); + m_priorityCutoff = m_externalPriorityCutoff; size_t memoryBytes = 0; for (TextureVector::iterator it = sortedTextures.begin(); it != sortedTextures.end(); ++it) { - if ((*it)->requestPriority() == CCPriorityCalculator::lowestPriority()) - break; - if ((*it)->isSelfManaged()) { // Account for self-managed memory immediately by reducing the memory // available (since it never gets acquired). @@ -83,6 +82,16 @@ void CCPrioritizedTextureManager::prioritizeTextures() } } + // Disallow any textures with priority below the external cutoff to have backings. + size_t memoryLinkedTexturesBytes = 0; + for (TextureVector::iterator it = sortedTextures.begin(); it != sortedTextures.end(); ++it) { + CCPrioritizedTexture* texture = (*it); + if (!CCPriorityCalculator::priorityIsHigher(texture->requestPriority(), m_externalPriorityCutoff) && + texture->haveBackingTexture()) + texture->unlink(); + } + DCHECK(memoryLinkedTexturesBytes <= m_memoryAvailableBytes); + // Only allow textures if they are higher than the cutoff. All textures // of the same priority are accepted or rejected together, rather than // being partially allowed randomly. @@ -155,9 +164,14 @@ bool CCPrioritizedTextureManager::requestLate(CCPrioritizedTexture* texture) if (texture->isAbovePriorityCutoff()) return true; + // Allow textures that have priority equal to the cutoff, but not strictly lower. if (CCPriorityCalculator::priorityIsLower(texture->requestPriority(), m_priorityCutoff)) return false; + // Disallow textures that do not have a priority strictly higher than the external cutoff. + if (!CCPriorityCalculator::priorityIsHigher(texture->requestPriority(), m_externalPriorityCutoff)) + return false; + size_t newMemoryBytes = m_memoryAboveCutoffBytes + texture->bytes(); if (newMemoryBytes > m_memoryAvailableBytes) return false; @@ -191,7 +205,7 @@ void CCPrioritizedTextureManager::acquireBackingTextureIfNeeded(CCPrioritizedTex // Otherwise reduce memory and just allocate a new backing texures. if (!backing) { - evictBackingsToReduceMemory(m_memoryAvailableBytes - texture->bytes(), RespectManagerPriorityCutoff, resourceProvider); + evictBackingsToReduceMemory(m_memoryAvailableBytes - texture->bytes(), CCPriorityCalculator::allowEverythingCutoff(), EvictOnlyRecyclable, resourceProvider); backing = createBacking(texture->size(), texture->format(), resourceProvider); } @@ -207,19 +221,21 @@ void CCPrioritizedTextureManager::acquireBackingTextureIfNeeded(CCPrioritizedTex backing->updatePriority(); } -bool CCPrioritizedTextureManager::evictBackingsToReduceMemory(size_t limitBytes, EvictionPriorityPolicy evictionPolicy, CCResourceProvider* resourceProvider) +bool CCPrioritizedTextureManager::evictBackingsToReduceMemory(size_t limitBytes, int priorityCutoff, EvictionPolicy evictionPolicy, CCResourceProvider* resourceProvider) { DCHECK(CCProxy::isImplThread()); - if (memoryUseBytes() <= limitBytes) + if (memoryUseBytes() <= limitBytes && CCPriorityCalculator::allowEverythingCutoff() == priorityCutoff) return false; // Destroy backings until we are below the limit, // or until all backings remaining are above the cutoff. - while (memoryUseBytes() > limitBytes && m_backings.size() > 0) { + while (m_backings.size() > 0) { CCPrioritizedTexture::Backing* backing = m_backings.front(); - if (evictionPolicy == RespectManagerPriorityCutoff) - if (backing->wasAbovePriorityCutoffAtLastPriorityUpdate()) - break; + if (memoryUseBytes() <= limitBytes && + CCPriorityCalculator::priorityIsHigher(backing->requestPriorityAtLastPriorityUpdate(), priorityCutoff)) + break; + if (evictionPolicy == EvictOnlyRecyclable && !backing->canBeRecycled()) + break; evictFirstBackingResource(resourceProvider); } return true; @@ -229,7 +245,7 @@ void CCPrioritizedTextureManager::reduceMemory(CCResourceProvider* resourceProvi { DCHECK(CCProxy::isImplThread() && CCProxy::isMainThreadBlocked()); - evictBackingsToReduceMemory(m_memoryAvailableBytes, RespectManagerPriorityCutoff, resourceProvider); + evictBackingsToReduceMemory(m_memoryAvailableBytes, CCPriorityCalculator::allowEverythingCutoff(), EvictOnlyRecyclable, resourceProvider); DCHECK(memoryUseBytes() <= maxMemoryLimitBytes()); // We currently collect backings from deleted textures for later recycling. @@ -245,7 +261,7 @@ void CCPrioritizedTextureManager::reduceMemory(CCResourceProvider* resourceProvi } size_t tenPercentOfMemory = m_memoryAvailableBytes / 10; if (wastedMemory > tenPercentOfMemory) - evictBackingsToReduceMemory(memoryUseBytes() - (wastedMemory - tenPercentOfMemory), RespectManagerPriorityCutoff, resourceProvider); + evictBackingsToReduceMemory(memoryUseBytes() - (wastedMemory - tenPercentOfMemory), CCPriorityCalculator::allowEverythingCutoff(), EvictOnlyRecyclable, resourceProvider); // Unlink all evicted backings for (BackingList::const_iterator it = m_evictedBackings.begin(); it != m_evictedBackings.end(); ++it) { @@ -261,10 +277,10 @@ void CCPrioritizedTextureManager::clearAllMemory(CCResourceProvider* resourcePro { DCHECK(CCProxy::isImplThread() && CCProxy::isMainThreadBlocked()); DCHECK(resourceProvider); - evictBackingsToReduceMemory(0, DoNotRespectManagerPriorityCutoff, resourceProvider); + evictBackingsToReduceMemory(0, CCPriorityCalculator::allowEverythingCutoff(), EvictAnything, resourceProvider); } -bool CCPrioritizedTextureManager::reduceMemoryOnImplThread(size_t limitBytes, CCResourceProvider* resourceProvider) +bool CCPrioritizedTextureManager::reduceMemoryOnImplThread(size_t limitBytes, int priorityCutoff, CCResourceProvider* resourceProvider) { DCHECK(CCProxy::isImplThread()); DCHECK(resourceProvider); @@ -272,7 +288,7 @@ bool CCPrioritizedTextureManager::reduceMemoryOnImplThread(size_t limitBytes, CC // the list are not sorted by priority. Sort them before doing the eviction. if (m_backingsTailNotSorted) sortBackings(); - return evictBackingsToReduceMemory(limitBytes, DoNotRespectManagerPriorityCutoff, resourceProvider); + return evictBackingsToReduceMemory(limitBytes, priorityCutoff, EvictAnything, resourceProvider); } void CCPrioritizedTextureManager::getEvictedBackings(BackingList& evictedBackings) diff --git a/cc/prioritized_texture_manager.h b/cc/prioritized_texture_manager.h index 439fe81..cbf3c49 100644 --- a/cc/prioritized_texture_manager.h +++ b/cc/prioritized_texture_manager.h @@ -65,13 +65,17 @@ public: void setMaxMemoryLimitBytes(size_t bytes) { m_maxMemoryLimitBytes = bytes; } size_t maxMemoryLimitBytes() const { return m_maxMemoryLimitBytes; } + // Sepecify a external priority cutoff. Only textures that have a strictly higher priority + // than this cutoff will be allowed. + void setExternalPriorityCutoff(int priorityCutoff) { m_externalPriorityCutoff = priorityCutoff; } + void prioritizeTextures(); void clearPriorities(); // Delete contents textures' backing resources until they use only bytesLimit bytes. This may // be called on the impl thread while the main thread is running. Returns true if resources are // indeed evicted as a result of this call. - bool reduceMemoryOnImplThread(size_t limitBytes, CCResourceProvider*); + bool reduceMemoryOnImplThread(size_t limitBytes, int priorityCutoff, CCResourceProvider*); // Returns true if there exist any textures that are linked to backings that have had their // resources evicted. Only when we commit a tree that has no textures linked to evicted backings // may we allow drawing. @@ -103,9 +107,9 @@ public: private: friend class CCPrioritizedTextureTest; - enum EvictionPriorityPolicy { - RespectManagerPriorityCutoff, - DoNotRespectManagerPriorityCutoff, + enum EvictionPolicy { + EvictOnlyRecyclable, + EvictAnything, }; // Compare textures. Highest priority first. @@ -136,7 +140,7 @@ private: CCPrioritizedTextureManager(size_t maxMemoryLimitBytes, int maxTextureSize, int pool); - bool evictBackingsToReduceMemory(size_t limitBytes, EvictionPriorityPolicy, CCResourceProvider*); + bool evictBackingsToReduceMemory(size_t limitBytes, int priorityCutoff, EvictionPolicy, CCResourceProvider*); CCPrioritizedTexture::Backing* createBacking(IntSize, GLenum format, CCResourceProvider*); void evictFirstBackingResource(CCResourceProvider*); void deleteUnlinkedEvictedBackings(); @@ -145,7 +149,13 @@ private: void assertInvariants(); size_t m_maxMemoryLimitBytes; - unsigned m_priorityCutoff; + // The priority cutoff based on memory pressure. This is not a strict + // cutoff -- requestLate allows textures with priority equal to this + // cutoff to be allowed. + int m_priorityCutoff; + // The priority cutoff based on external memory policy. This is a strict + // cutoff -- no textures with priority equal to this cutoff will be allowed. + int m_externalPriorityCutoff; size_t m_memoryUseBytes; size_t m_memoryAboveCutoffBytes; size_t m_memoryAvailableBytes; diff --git a/cc/prioritized_texture_unittest.cc b/cc/prioritized_texture_unittest.cc index ccad1cc..69796cb 100644 --- a/cc/prioritized_texture_unittest.cc +++ b/cc/prioritized_texture_unittest.cc @@ -196,6 +196,71 @@ TEST_F(CCPrioritizedTextureTest, changeMemoryLimits) textureManager->clearAllMemory(resourceProvider()); } +TEST_F(CCPrioritizedTextureTest, changePriorityCutoff) +{ + const size_t maxTextures = 8; + scoped_ptr<CCPrioritizedTextureManager> textureManager = createManager(maxTextures); + scoped_ptr<CCPrioritizedTexture> textures[maxTextures]; + + for (size_t i = 0; i < maxTextures; ++i) + textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat); + for (size_t i = 0; i < maxTextures; ++i) + textures[i]->setRequestPriority(100 + i); + + // Set the cutoff to drop two textures. Try to requestLate on all textures, and + // make sure that requestLate doesn't work on a texture with equal priority to + // the cutoff. + textureManager->setMaxMemoryLimitBytes(texturesMemorySize(8)); + textureManager->setExternalPriorityCutoff(106); + prioritizeTexturesAndBackings(textureManager.get()); + for (size_t i = 0; i < maxTextures; ++i) + EXPECT_EQ(validateTexture(textures[i], true), i < 6); + { + DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked; + textureManager->reduceMemory(resourceProvider()); + } + EXPECT_EQ(texturesMemorySize(6), textureManager->memoryAboveCutoffBytes()); + EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes()); + + // Set the cutoff to drop two more textures. + textureManager->setExternalPriorityCutoff(104); + prioritizeTexturesAndBackings(textureManager.get()); + for (size_t i = 0; i < maxTextures; ++i) + EXPECT_EQ(validateTexture(textures[i], false), i < 4); + { + DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked; + textureManager->reduceMemory(resourceProvider()); + } + EXPECT_EQ(texturesMemorySize(4), textureManager->memoryAboveCutoffBytes()); + + // Do a one-time eviction for one more texture based on priority cutoff + CCPrioritizedTextureManager::BackingList evictedBackings; + { + DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked; + textureManager->reduceMemoryOnImplThread(texturesMemorySize(8), 104, resourceProvider()); + textureManager->getEvictedBackings(evictedBackings); + EXPECT_EQ(0, evictedBackings.size()); + textureManager->reduceMemoryOnImplThread(texturesMemorySize(8), 103, resourceProvider()); + textureManager->getEvictedBackings(evictedBackings); + EXPECT_EQ(1, evictedBackings.size()); + } + textureManager->unlinkEvictedBackings(evictedBackings); + EXPECT_EQ(texturesMemorySize(3), textureManager->memoryUseBytes()); + + // Re-allocate the the texture after the one-time drop. + prioritizeTexturesAndBackings(textureManager.get()); + for (size_t i = 0; i < maxTextures; ++i) + EXPECT_EQ(validateTexture(textures[i], false), i < 4); + { + DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked; + textureManager->reduceMemory(resourceProvider()); + } + EXPECT_EQ(texturesMemorySize(4), textureManager->memoryAboveCutoffBytes()); + + DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked; + textureManager->clearAllMemory(resourceProvider()); +} + TEST_F(CCPrioritizedTextureTest, textureManagerPartialUpdateTextures) { const size_t maxTextures = 4; @@ -567,11 +632,11 @@ TEST_F(CCPrioritizedTextureTest, clearUploadsToEvictedResources) EXPECT_EQ(4, queue.fullUploadSize()); textureManager->reduceMemoryOnImplThread( - texturesMemorySize(1), resourceProvider()); + texturesMemorySize(1), CCPriorityCalculator::allowEverythingCutoff(), resourceProvider()); queue.clearUploadsToEvictedResources(); EXPECT_EQ(1, queue.fullUploadSize()); - textureManager->reduceMemoryOnImplThread(0, resourceProvider()); + textureManager->reduceMemoryOnImplThread(0, CCPriorityCalculator::allowEverythingCutoff(), resourceProvider()); queue.clearUploadsToEvictedResources(); EXPECT_EQ(0, queue.fullUploadSize()); diff --git a/cc/priority_calculator.cc b/cc/priority_calculator.cc index 0d527e0..9818716 100644 --- a/cc/priority_calculator.cc +++ b/cc/priority_calculator.cc @@ -10,12 +10,18 @@ using namespace std; namespace cc { +static const int nothingPriorityCutoff = -3; + +static const int mostHighPriority = -2; + static const int uiDrawsToRootSurfacePriority = -1; static const int visibleDrawsToRootSurfacePriority = 0; static const int renderSurfacesPriority = 1; static const int uiDoesNotDrawToRootSurfacePriority = 2; static const int visibleDoesNotDrawToRootSurfacePriority = 3; +static const int visibleOnlyPriorityCutoff = 4; + // The lower digits are how far from being visible the texture is, // in pixels. static const int notVisibleBasePriority = 1000000; @@ -28,6 +34,10 @@ static const int smallAnimatedLayerPriority = notVisibleBasePriority + 512; static const int lingeringBasePriority = 2000000; static const int lingeringLimitPriority = 2900000; +static const int mostLowPriority = 3000000; + +static const int everythingPriorityCutoff = 3000001; + // static int CCPriorityCalculator::uiPriority(bool drawsToRootSurface) { @@ -81,4 +91,34 @@ int CCPriorityCalculator::smallAnimatedLayerMinPriority() return smallAnimatedLayerPriority; } +// static +int CCPriorityCalculator::highestPriority() +{ + return mostHighPriority; +} + +// static +int CCPriorityCalculator::lowestPriority() +{ + return mostLowPriority; +} + +// static +int CCPriorityCalculator::allowNothingCutoff() +{ + return nothingPriorityCutoff; +} + +// static +int CCPriorityCalculator::allowVisibleOnlyCutoff() +{ + return visibleOnlyPriorityCutoff; +} + +// static +int CCPriorityCalculator::allowEverythingCutoff() +{ + return everythingPriorityCutoff; +} + } // cc diff --git a/cc/priority_calculator.h b/cc/priority_calculator.h index 2d0f5ba..cab581b 100644 --- a/cc/priority_calculator.h +++ b/cc/priority_calculator.h @@ -19,11 +19,15 @@ public: static int priorityFromDistance(const IntRect& visibleRect, const IntRect& textureRect, bool drawsToRootSurface); static int smallAnimatedLayerMinPriority(); - static inline int highestPriority() { return std::numeric_limits<int>::min(); } - static inline int lowestPriority() { return std::numeric_limits<int>::max(); } + static int highestPriority(); + static int lowestPriority(); static inline bool priorityIsLower(int a, int b) { return a > b; } static inline bool priorityIsHigher(int a, int b) { return a < b; } - static inline bool maxPriority(int a, int b) { return priorityIsHigher(a, b) ? a : b; } + static inline int maxPriority(int a, int b) { return priorityIsHigher(a, b) ? a : b; } + + static int allowNothingCutoff(); + static int allowVisibleOnlyCutoff(); + static int allowEverythingCutoff(); }; } diff --git a/cc/renderer.h b/cc/renderer.h index 6ac38e2..a1cb51d 100644 --- a/cc/renderer.h +++ b/cc/renderer.h @@ -6,6 +6,7 @@ #define CCRenderer_h #include "CCLayerTreeHost.h" +#include "managed_memory_policy.h" #include "FloatQuad.h" #include "base/basictypes.h" #include "cc/render_pass.h" @@ -21,7 +22,8 @@ public: virtual void didLoseContext() = 0; virtual void onSwapBuffersComplete() = 0; virtual void setFullRootLayerDamage() = 0; - virtual void setMemoryAllocationLimitBytes(size_t) = 0; + virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) = 0; + virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) = 0; protected: virtual ~CCRendererClient() { } }; diff --git a/cc/single_thread_proxy.cc b/cc/single_thread_proxy.cc index af9232f..d43606b 100644 --- a/cc/single_thread_proxy.cc +++ b/cc/single_thread_proxy.cc @@ -277,13 +277,13 @@ void CCSingleThreadProxy::postAnimationEventsToMainThreadOnImplThread(scoped_ptr m_layerTreeHost->setAnimationEvents(events.Pass(), wallClockTime); } -bool CCSingleThreadProxy::reduceContentsTextureMemoryOnImplThread(size_t limitBytes) +bool CCSingleThreadProxy::reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) { DCHECK(isImplThread()); if (!m_layerTreeHost->contentsTextureManager()) return false; - return m_layerTreeHost->contentsTextureManager()->reduceMemoryOnImplThread(limitBytes, m_layerTreeHostImpl->resourceProvider()); + return m_layerTreeHost->contentsTextureManager()->reduceMemoryOnImplThread(limitBytes, priorityCutoff, m_layerTreeHostImpl->resourceProvider()); } // Called by the legacy scheduling path (e.g. where render_widget does the scheduling) diff --git a/cc/single_thread_proxy.h b/cc/single_thread_proxy.h index 67c7faa..8c7661a 100644 --- a/cc/single_thread_proxy.h +++ b/cc/single_thread_proxy.h @@ -53,7 +53,7 @@ public: virtual void setNeedsRedrawOnImplThread() OVERRIDE; virtual void setNeedsCommitOnImplThread() OVERRIDE; virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE; - virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes) OVERRIDE; + virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) OVERRIDE; // Called by the legacy path where RenderWidget does the scheduling. void compositeImmediately(); diff --git a/cc/software_renderer_unittest.cc b/cc/software_renderer_unittest.cc index fa45efe..8601e3f 100644 --- a/cc/software_renderer_unittest.cc +++ b/cc/software_renderer_unittest.cc @@ -48,7 +48,8 @@ public: virtual void didLoseContext() OVERRIDE { } virtual void onSwapBuffersComplete() OVERRIDE { } virtual void setFullRootLayerDamage() OVERRIDE { } - virtual void setMemoryAllocationLimitBytes(size_t) OVERRIDE { } + virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { }; + virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy) OVERRIDE { }; protected: DebugScopedSetImplThread m_alwaysImplThread; diff --git a/cc/thread_proxy.cc b/cc/thread_proxy.cc index c4caa4d..54a11b3 100644 --- a/cc/thread_proxy.cc +++ b/cc/thread_proxy.cc @@ -348,14 +348,14 @@ void CCThreadProxy::postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAni m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::setAnimationEvents, events.release(), wallClockTime)); } -bool CCThreadProxy::reduceContentsTextureMemoryOnImplThread(size_t limitBytes) +bool CCThreadProxy::reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) { DCHECK(isImplThread()); if (!m_layerTreeHost->contentsTextureManager()) return false; - if (!m_layerTreeHost->contentsTextureManager()->reduceMemoryOnImplThread(limitBytes, m_layerTreeHostImpl->resourceProvider())) + if (!m_layerTreeHost->contentsTextureManager()->reduceMemoryOnImplThread(limitBytes, priorityCutoff, m_layerTreeHostImpl->resourceProvider())) return false; // The texture upload queue may reference textures that were just purged, clear diff --git a/cc/thread_proxy.h b/cc/thread_proxy.h index c6c3a16..29b2549 100644 --- a/cc/thread_proxy.h +++ b/cc/thread_proxy.h @@ -61,7 +61,7 @@ public: virtual void setNeedsRedrawOnImplThread() OVERRIDE; virtual void setNeedsCommitOnImplThread() OVERRIDE; virtual void postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAnimationEventsVector>, double wallClockTime) OVERRIDE; - virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes) OVERRIDE; + virtual bool reduceContentsTextureMemoryOnImplThread(size_t limitBytes, int priorityCutoff) OVERRIDE; // CCSchedulerClient implementation virtual void scheduledActionBeginFrame() OVERRIDE; |