blob: 9c37395e6f4a055c4cd7ed9d93cb48e9f45c4331 [file] [log] [blame]
// Copyright 2012 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 "cc/prioritized_texture.h"
#include "cc/prioritized_texture_manager.h"
#include "cc/single_thread_proxy.h" // For DebugScopedSetImplThread
#include "cc/test/fake_graphics_context.h"
#include "cc/test/tiled_layer_test_common.h"
#include "cc/texture.h"
#include "testing/gtest/include/gtest/gtest.h"
using namespace cc;
using namespace WebKitTests;
namespace cc {
class PrioritizedTextureTest : public testing::Test {
public:
PrioritizedTextureTest()
: m_textureSize(256, 256)
, m_textureFormat(GL_RGBA)
, m_context(WebKit::createFakeGraphicsContext())
{
DebugScopedSetImplThread implThread;
m_resourceProvider = ResourceProvider::create(m_context.get());
}
virtual ~PrioritizedTextureTest()
{
DebugScopedSetImplThread implThread;
m_resourceProvider.reset();
}
size_t texturesMemorySize(size_t textureCount)
{
return Texture::memorySizeBytes(m_textureSize, m_textureFormat) * textureCount;
}
scoped_ptr<PrioritizedTextureManager> createManager(size_t maxTextures)
{
return PrioritizedTextureManager::create(texturesMemorySize(maxTextures), 1024, 0);
}
bool validateTexture(scoped_ptr<PrioritizedTexture>& texture, bool requestLate)
{
textureManagerAssertInvariants(texture->textureManager());
if (requestLate)
texture->requestLate();
textureManagerAssertInvariants(texture->textureManager());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
bool success = texture->canAcquireBackingTexture();
if (success)
texture->acquireBackingTexture(resourceProvider());
return success;
}
void prioritizeTexturesAndBackings(PrioritizedTextureManager* textureManager)
{
textureManager->prioritizeTextures();
textureManagerUpdateBackingsPriorities(textureManager);
}
void textureManagerUpdateBackingsPriorities(PrioritizedTextureManager* textureManager)
{
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->pushTexturePrioritiesToBackings();
}
ResourceProvider* resourceProvider()
{
return m_resourceProvider.get();
}
void textureManagerAssertInvariants(PrioritizedTextureManager* textureManager)
{
#ifndef NDEBUG
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->assertInvariants();
#endif
}
bool textureBackingIsAbovePriorityCutoff(PrioritizedTexture* texture)
{
return texture->m_backing->wasAbovePriorityCutoffAtLastPriorityUpdate();
}
protected:
const IntSize m_textureSize;
const GLenum m_textureFormat;
scoped_ptr<GraphicsContext> m_context;
scoped_ptr<ResourceProvider> m_resourceProvider;
};
}
namespace {
TEST_F(PrioritizedTextureTest, requestTextureExceedingMaxLimit)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
// Create textures for double our memory limit.
scoped_ptr<PrioritizedTexture> textures[maxTextures*2];
for (size_t i = 0; i < maxTextures*2; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// Set decreasing priorities
for (size_t i = 0; i < maxTextures*2; ++i)
textures[i]->setRequestPriority(100 + i);
// Only lower half should be available.
prioritizeTexturesAndBackings(textureManager.get());
EXPECT_TRUE(validateTexture(textures[0], false));
EXPECT_TRUE(validateTexture(textures[7], false));
EXPECT_FALSE(validateTexture(textures[8], false));
EXPECT_FALSE(validateTexture(textures[15], false));
// Set increasing priorities
for (size_t i = 0; i < maxTextures*2; ++i)
textures[i]->setRequestPriority(100 - i);
// Only upper half should be available.
prioritizeTexturesAndBackings(textureManager.get());
EXPECT_FALSE(validateTexture(textures[0], false));
EXPECT_FALSE(validateTexture(textures[7], false));
EXPECT_TRUE(validateTexture(textures[8], false));
EXPECT_TRUE(validateTexture(textures[15], false));
EXPECT_EQ(texturesMemorySize(maxTextures), textureManager->memoryAboveCutoffBytes());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, changeMemoryLimits)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
scoped_ptr<PrioritizedTexture> 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 max limit to 8 textures
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(8));
prioritizeTexturesAndBackings(textureManager.get());
for (size_t i = 0; i < maxTextures; ++i)
validateTexture(textures[i], false);
{
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->reduceMemory(resourceProvider());
}
EXPECT_EQ(texturesMemorySize(8), textureManager->memoryAboveCutoffBytes());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
// Set max limit to 5 textures
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(5));
prioritizeTexturesAndBackings(textureManager.get());
for (size_t i = 0; i < maxTextures; ++i)
EXPECT_EQ(validateTexture(textures[i], false), i < 5);
{
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->reduceMemory(resourceProvider());
}
EXPECT_EQ(texturesMemorySize(5), textureManager->memoryAboveCutoffBytes());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
// Set max limit to 4 textures
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(4));
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());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, changePriorityCutoff)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
scoped_ptr<PrioritizedTexture> 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
PrioritizedTextureManager::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(PrioritizedTextureTest, textureManagerPartialUpdateTextures)
{
const size_t maxTextures = 4;
const size_t numTextures = 4;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
scoped_ptr<PrioritizedTexture> textures[numTextures];
scoped_ptr<PrioritizedTexture> moreTextures[numTextures];
for (size_t i = 0; i < numTextures; ++i) {
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
moreTextures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
}
for (size_t i = 0; i < numTextures; ++i)
textures[i]->setRequestPriority(200 + i);
prioritizeTexturesAndBackings(textureManager.get());
// Allocate textures which are currently high priority.
EXPECT_TRUE(validateTexture(textures[0], false));
EXPECT_TRUE(validateTexture(textures[1], false));
EXPECT_TRUE(validateTexture(textures[2], false));
EXPECT_TRUE(validateTexture(textures[3], false));
EXPECT_TRUE(textures[0]->haveBackingTexture());
EXPECT_TRUE(textures[1]->haveBackingTexture());
EXPECT_TRUE(textures[2]->haveBackingTexture());
EXPECT_TRUE(textures[3]->haveBackingTexture());
for (size_t i = 0; i < numTextures; ++i)
moreTextures[i]->setRequestPriority(100 + i);
prioritizeTexturesAndBackings(textureManager.get());
// Textures are now below cutoff.
EXPECT_FALSE(validateTexture(textures[0], false));
EXPECT_FALSE(validateTexture(textures[1], false));
EXPECT_FALSE(validateTexture(textures[2], false));
EXPECT_FALSE(validateTexture(textures[3], false));
// But they are still valid to use.
EXPECT_TRUE(textures[0]->haveBackingTexture());
EXPECT_TRUE(textures[1]->haveBackingTexture());
EXPECT_TRUE(textures[2]->haveBackingTexture());
EXPECT_TRUE(textures[3]->haveBackingTexture());
// Higher priority textures are finally needed.
EXPECT_TRUE(validateTexture(moreTextures[0], false));
EXPECT_TRUE(validateTexture(moreTextures[1], false));
EXPECT_TRUE(validateTexture(moreTextures[2], false));
EXPECT_TRUE(validateTexture(moreTextures[3], false));
// Lower priority have been fully evicted.
EXPECT_FALSE(textures[0]->haveBackingTexture());
EXPECT_FALSE(textures[1]->haveBackingTexture());
EXPECT_FALSE(textures[2]->haveBackingTexture());
EXPECT_FALSE(textures[3]->haveBackingTexture());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, textureManagerPrioritiesAreEqual)
{
const size_t maxTextures = 16;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// All 16 textures have the same priority except 2 higher priority.
for (size_t i = 0; i < maxTextures; ++i)
textures[i]->setRequestPriority(100);
textures[0]->setRequestPriority(99);
textures[1]->setRequestPriority(99);
// Set max limit to 8 textures
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(8));
prioritizeTexturesAndBackings(textureManager.get());
// The two high priority textures should be available, others should not.
for (size_t i = 0; i < 2; ++i)
EXPECT_TRUE(validateTexture(textures[i], false));
for (size_t i = 2; i < maxTextures; ++i)
EXPECT_FALSE(validateTexture(textures[i], false));
EXPECT_EQ(texturesMemorySize(2), textureManager->memoryAboveCutoffBytes());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
// Manually reserving textures should only succeed on the higher priority textures,
// and on remaining textures up to the memory limit.
for (size_t i = 0; i < 8; i++)
EXPECT_TRUE(validateTexture(textures[i], true));
for (size_t i = 9; i < maxTextures; i++)
EXPECT_FALSE(validateTexture(textures[i], true));
EXPECT_EQ(texturesMemorySize(8), textureManager->memoryAboveCutoffBytes());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, textureManagerDestroyedFirst)
{
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(1);
scoped_ptr<PrioritizedTexture> texture = textureManager->createTexture(m_textureSize, m_textureFormat);
// Texture is initially invalid, but it will become available.
EXPECT_FALSE(texture->haveBackingTexture());
texture->setRequestPriority(100);
prioritizeTexturesAndBackings(textureManager.get());
EXPECT_TRUE(validateTexture(texture, false));
EXPECT_TRUE(texture->canAcquireBackingTexture());
EXPECT_TRUE(texture->haveBackingTexture());
{
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
textureManager.reset();
EXPECT_FALSE(texture->canAcquireBackingTexture());
EXPECT_FALSE(texture->haveBackingTexture());
}
TEST_F(PrioritizedTextureTest, textureMovedToNewManager)
{
scoped_ptr<PrioritizedTextureManager> textureManagerOne = createManager(1);
scoped_ptr<PrioritizedTextureManager> textureManagerTwo = createManager(1);
scoped_ptr<PrioritizedTexture> texture = textureManagerOne->createTexture(m_textureSize, m_textureFormat);
// Texture is initially invalid, but it will become available.
EXPECT_FALSE(texture->haveBackingTexture());
texture->setRequestPriority(100);
prioritizeTexturesAndBackings(textureManagerOne.get());
EXPECT_TRUE(validateTexture(texture, false));
EXPECT_TRUE(texture->canAcquireBackingTexture());
EXPECT_TRUE(texture->haveBackingTexture());
texture->setTextureManager(0);
{
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManagerOne->clearAllMemory(resourceProvider());
}
textureManagerOne.reset();
EXPECT_FALSE(texture->canAcquireBackingTexture());
EXPECT_FALSE(texture->haveBackingTexture());
texture->setTextureManager(textureManagerTwo.get());
prioritizeTexturesAndBackings(textureManagerTwo.get());
EXPECT_TRUE(validateTexture(texture, false));
EXPECT_TRUE(texture->canAcquireBackingTexture());
EXPECT_TRUE(texture->haveBackingTexture());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManagerTwo->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, renderSurfacesReduceMemoryAvailableOutsideRootSurface)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
// Half of the memory is taken by surfaces (with high priority place-holder)
scoped_ptr<PrioritizedTexture> renderSurfacePlaceHolder = textureManager->createTexture(m_textureSize, m_textureFormat);
renderSurfacePlaceHolder->setToSelfManagedMemoryPlaceholder(texturesMemorySize(4));
renderSurfacePlaceHolder->setRequestPriority(PriorityCalculator::renderSurfacePriority());
// Create textures to fill our memory limit.
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// Set decreasing non-visible priorities outside root surface.
for (size_t i = 0; i < maxTextures; ++i)
textures[i]->setRequestPriority(100 + i);
// Only lower half should be available.
prioritizeTexturesAndBackings(textureManager.get());
EXPECT_TRUE(validateTexture(textures[0], false));
EXPECT_TRUE(validateTexture(textures[3], false));
EXPECT_FALSE(validateTexture(textures[4], false));
EXPECT_FALSE(validateTexture(textures[7], false));
// Set increasing non-visible priorities outside root surface.
for (size_t i = 0; i < maxTextures; ++i)
textures[i]->setRequestPriority(100 - i);
// Only upper half should be available.
prioritizeTexturesAndBackings(textureManager.get());
EXPECT_FALSE(validateTexture(textures[0], false));
EXPECT_FALSE(validateTexture(textures[3], false));
EXPECT_TRUE(validateTexture(textures[4], false));
EXPECT_TRUE(validateTexture(textures[7], false));
EXPECT_EQ(texturesMemorySize(4), textureManager->memoryAboveCutoffBytes());
EXPECT_EQ(texturesMemorySize(4), textureManager->memoryForSelfManagedTextures());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, renderSurfacesReduceMemoryAvailableForRequestLate)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
// Half of the memory is taken by surfaces (with high priority place-holder)
scoped_ptr<PrioritizedTexture> renderSurfacePlaceHolder = textureManager->createTexture(m_textureSize, m_textureFormat);
renderSurfacePlaceHolder->setToSelfManagedMemoryPlaceholder(texturesMemorySize(4));
renderSurfacePlaceHolder->setRequestPriority(PriorityCalculator::renderSurfacePriority());
// Create textures to fill our memory limit.
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// Set equal priorities.
for (size_t i = 0; i < maxTextures; ++i)
textures[i]->setRequestPriority(100);
// The first four to be requested late will be available.
prioritizeTexturesAndBackings(textureManager.get());
for (unsigned i = 0; i < maxTextures; ++i)
EXPECT_FALSE(validateTexture(textures[i], false));
for (unsigned i = 0; i < maxTextures; i += 2)
EXPECT_TRUE(validateTexture(textures[i], true));
for (unsigned i = 1; i < maxTextures; i += 2)
EXPECT_FALSE(validateTexture(textures[i], true));
EXPECT_EQ(texturesMemorySize(4), textureManager->memoryAboveCutoffBytes());
EXPECT_EQ(texturesMemorySize(4), textureManager->memoryForSelfManagedTextures());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, whenRenderSurfaceNotAvailableTexturesAlsoNotAvailable)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
// Half of the memory is taken by surfaces (with high priority place-holder)
scoped_ptr<PrioritizedTexture> renderSurfacePlaceHolder = textureManager->createTexture(m_textureSize, m_textureFormat);
renderSurfacePlaceHolder->setToSelfManagedMemoryPlaceholder(texturesMemorySize(4));
renderSurfacePlaceHolder->setRequestPriority(PriorityCalculator::renderSurfacePriority());
// Create textures to fill our memory limit.
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// Set 6 visible textures in the root surface, and 2 in a child surface.
for (size_t i = 0; i < 6; ++i)
textures[i]->setRequestPriority(PriorityCalculator::visiblePriority(true));
for (size_t i = 6; i < 8; ++i)
textures[i]->setRequestPriority(PriorityCalculator::visiblePriority(false));
prioritizeTexturesAndBackings(textureManager.get());
// Unable to requestLate textures in the child surface.
EXPECT_FALSE(validateTexture(textures[6], true));
EXPECT_FALSE(validateTexture(textures[7], true));
// Root surface textures are valid.
for (size_t i = 0; i < 6; ++i)
EXPECT_TRUE(validateTexture(textures[i], false));
EXPECT_EQ(texturesMemorySize(6), textureManager->memoryAboveCutoffBytes());
EXPECT_EQ(texturesMemorySize(2), textureManager->memoryForSelfManagedTextures());
EXPECT_LE(textureManager->memoryUseBytes(), textureManager->memoryAboveCutoffBytes());
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, requestLateBackingsSorting)
{
const size_t maxTextures = 8;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(maxTextures));
// Create textures to fill our memory limit.
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// Set equal priorities, and allocate backings for all textures.
for (size_t i = 0; i < maxTextures; ++i)
textures[i]->setRequestPriority(100);
prioritizeTexturesAndBackings(textureManager.get());
for (unsigned i = 0; i < maxTextures; ++i)
EXPECT_TRUE(validateTexture(textures[i], false));
// Drop the memory limit and prioritize (none will be above the threshold,
// but they still have backings because reduceMemory hasn't been called).
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(maxTextures / 2));
prioritizeTexturesAndBackings(textureManager.get());
// Push half of them back over the limit.
for (size_t i = 0; i < maxTextures; i += 2)
EXPECT_TRUE(textures[i]->requestLate());
// Push the priorities to the backings array and sort the backings array
textureManagerUpdateBackingsPriorities(textureManager.get());
// Assert that the backings list be sorted with the below-limit backings
// before the above-limit backings.
textureManagerAssertInvariants(textureManager.get());
// Make sure that we have backings for all of the textures.
for (size_t i = 0; i < maxTextures; ++i)
EXPECT_TRUE(textures[i]->haveBackingTexture());
// Make sure that only the requestLate textures are above the priority cutoff
for (size_t i = 0; i < maxTextures; i += 2)
EXPECT_TRUE(textureBackingIsAbovePriorityCutoff(textures[i].get()));
for (size_t i = 1; i < maxTextures; i += 2)
EXPECT_FALSE(textureBackingIsAbovePriorityCutoff(textures[i].get()));
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
TEST_F(PrioritizedTextureTest, clearUploadsToEvictedResources)
{
const size_t maxTextures = 4;
scoped_ptr<PrioritizedTextureManager> textureManager =
createManager(maxTextures);
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(maxTextures));
// Create textures to fill our memory limit.
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
// Set equal priorities, and allocate backings for all textures.
for (size_t i = 0; i < maxTextures; ++i)
textures[i]->setRequestPriority(100);
prioritizeTexturesAndBackings(textureManager.get());
for (unsigned i = 0; i < maxTextures; ++i)
EXPECT_TRUE(validateTexture(textures[i], false));
ResourceUpdateQueue queue;
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
for (size_t i = 0; i < maxTextures; ++i) {
const ResourceUpdate upload = ResourceUpdate::Create(
textures[i].get(), NULL, gfx::Rect(), gfx::Rect(), gfx::Vector2d());
queue.appendFullUpload(upload);
}
// Make sure that we have backings for all of the textures.
for (size_t i = 0; i < maxTextures; ++i)
EXPECT_TRUE(textures[i]->haveBackingTexture());
queue.clearUploadsToEvictedResources();
EXPECT_EQ(4, queue.fullUploadSize());
textureManager->reduceMemoryOnImplThread(
texturesMemorySize(1), PriorityCalculator::allowEverythingCutoff(), resourceProvider());
queue.clearUploadsToEvictedResources();
EXPECT_EQ(1, queue.fullUploadSize());
textureManager->reduceMemoryOnImplThread(0, PriorityCalculator::allowEverythingCutoff(), resourceProvider());
queue.clearUploadsToEvictedResources();
EXPECT_EQ(0, queue.fullUploadSize());
}
TEST_F(PrioritizedTextureTest, usageStatistics)
{
const size_t maxTextures = 5;
scoped_ptr<PrioritizedTextureManager> textureManager = createManager(maxTextures);
scoped_ptr<PrioritizedTexture> textures[maxTextures];
for (size_t i = 0; i < maxTextures; ++i)
textures[i] = textureManager->createTexture(m_textureSize, m_textureFormat);
textures[0]->setRequestPriority(PriorityCalculator::allowVisibleOnlyCutoff() - 1);
textures[1]->setRequestPriority(PriorityCalculator::allowVisibleOnlyCutoff());
textures[2]->setRequestPriority(PriorityCalculator::allowVisibleAndNearbyCutoff() - 1);
textures[3]->setRequestPriority(PriorityCalculator::allowVisibleAndNearbyCutoff());
textures[4]->setRequestPriority(PriorityCalculator::allowVisibleAndNearbyCutoff() + 1);
// Set max limit to 2 textures.
textureManager->setMaxMemoryLimitBytes(texturesMemorySize(2));
prioritizeTexturesAndBackings(textureManager.get());
// The first two textures should be available, others should not.
for (size_t i = 0; i < 2; ++i)
EXPECT_TRUE(validateTexture(textures[i], false));
for (size_t i = 2; i < maxTextures; ++i)
EXPECT_FALSE(validateTexture(textures[i], false));
// Validate the statistics.
{
DebugScopedSetImplThread implThread;
EXPECT_EQ(texturesMemorySize(2), textureManager->memoryUseBytes());
EXPECT_EQ(texturesMemorySize(1), textureManager->memoryVisibleBytes());
EXPECT_EQ(texturesMemorySize(3), textureManager->memoryVisibleAndNearbyBytes());
}
// Re-prioritize the textures, but do not push the values to backings.
textures[0]->setRequestPriority(PriorityCalculator::allowVisibleOnlyCutoff() - 1);
textures[1]->setRequestPriority(PriorityCalculator::allowVisibleOnlyCutoff() - 1);
textures[2]->setRequestPriority(PriorityCalculator::allowVisibleOnlyCutoff() - 1);
textures[3]->setRequestPriority(PriorityCalculator::allowVisibleAndNearbyCutoff() - 1);
textures[4]->setRequestPriority(PriorityCalculator::allowVisibleAndNearbyCutoff());
textureManager->prioritizeTextures();
// Verify that we still see the old values.
{
DebugScopedSetImplThread implThread;
EXPECT_EQ(texturesMemorySize(2), textureManager->memoryUseBytes());
EXPECT_EQ(texturesMemorySize(1), textureManager->memoryVisibleBytes());
EXPECT_EQ(texturesMemorySize(3), textureManager->memoryVisibleAndNearbyBytes());
}
// Push priorities to backings, and verify we see the new values.
{
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->pushTexturePrioritiesToBackings();
EXPECT_EQ(texturesMemorySize(2), textureManager->memoryUseBytes());
EXPECT_EQ(texturesMemorySize(3), textureManager->memoryVisibleBytes());
EXPECT_EQ(texturesMemorySize(4), textureManager->memoryVisibleAndNearbyBytes());
}
DebugScopedSetImplThreadAndMainThreadBlocked implThreadAndMainThreadBlocked;
textureManager->clearAllMemory(resourceProvider());
}
} // namespace