Backed out changeset b0724a9e58bf (bug 1278341) for crashes in mozilla::layers::TextureClientPool::ReturnUnlockedClients

--HG--
extra : rebase_source : 0d2eedce1ee93725b3f77f64e15d7d74321bffbd
This commit is contained in:
Carsten "Tomcat" Book 2016-07-19 10:17:19 +02:00
parent b1fa1b86ff
commit 730118cb62
4 changed files with 121 additions and 98 deletions

View File

@ -19,25 +19,30 @@
namespace mozilla {
namespace layers {
static void
ShrinkCallback(nsITimer *aTimer, void *aClosure)
{
static_cast<TextureClientPool*>(aClosure)->ShrinkToMinimumSize();
}
TextureClientPool::TextureClientPool(LayersBackend aLayersBackend,
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
TextureFlags aFlags,
uint32_t aInitialPoolSize,
uint32_t aPoolIncrementSize,
uint32_t aMaxTextureClients,
uint32_t aShrinkTimeoutMsec,
TextureForwarder* aAllocator)
: mBackend(aLayersBackend)
, mFormat(aFormat)
, mSize(aSize)
, mFlags(aFlags)
, mInitialPoolSize(aInitialPoolSize)
, mPoolIncrementSize(aPoolIncrementSize)
, mMaxTextureClients(aMaxTextureClients)
, mShrinkTimeoutMsec(aShrinkTimeoutMsec)
, mOutstandingClients(0)
, mSurfaceAllocator(aAllocator)
{
TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n",
this, mInitialPoolSize);
TCP_LOG("TexturePool %p created with max size %u and timeout %u\n",
this, mMaxTextureClients, aShrinkTimeoutMsec);
mTimer = do_CreateInstance("@mozilla.org/timer;1");
if (aFormat == gfx::SurfaceFormat::UNKNOWN) {
gfxWarning() << "Creating texture pool for SurfaceFormat::UNKNOWN format";
@ -87,65 +92,45 @@ TextureClientPool::GetTextureClient()
{
// Try to fetch a client from the pool
RefPtr<TextureClient> textureClient;
// We initially allocate mInitialPoolSize for our pool. If we run
// out of TextureClients, we allocate additional TextureClients to try and keep around
// mPoolIncrementSize
if (!mTextureClients.size()) {
size_t size = mOutstandingClients ? mPoolIncrementSize : mInitialPoolSize;
AllocateTextureClients(size);
if (mTextureClients.size()) {
mOutstandingClients++;
textureClient = mTextureClients.top();
mTextureClients.pop();
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this);
MOZ_ASSERT(ok);
#endif
TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n",
this, textureClient.get(), mTextureClients.size(), mOutstandingClients);
return textureClient.forget();
}
if (!mTextureClients.size()) {
// All our allocations failed, return nullptr
return nullptr;
// We're increasing the number of outstanding TextureClients without reusing a
// client, we may need to free a deferred-return TextureClient.
ShrinkToMaximumSize();
// No unused clients in the pool, create one
if (gfxPrefs::ForceShmemTiles()) {
// gfx::BackendType::NONE means use the content backend
textureClient = TextureClient::CreateForRawBufferAccess(mSurfaceAllocator,
mFormat, mSize, gfx::BackendType::NONE,
mFlags, ALLOC_DEFAULT);
} else {
textureClient = TextureClient::CreateForDrawing(mSurfaceAllocator,
mFormat, mSize, mBackend, BackendSelector::Content, mFlags);
}
mOutstandingClients++;
textureClient = mTextureClients.top();
mTextureClients.pop();
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
if (textureClient) {
textureClient->mPoolTracker = this;
}
DebugOnly<bool> ok = TestClientPool("fetch", textureClient, this);
MOZ_ASSERT(ok);
#endif
TCP_LOG("TexturePool %p giving %p from pool; size %u outstanding %u\n",
TCP_LOG("TexturePool %p giving new %p; size %u outstanding %u\n",
this, textureClient.get(), mTextureClients.size(), mOutstandingClients);
return textureClient.forget();
}
void
TextureClientPool::AllocateTextureClients(size_t aSize)
{
TCP_LOG("TexturePool %p allocating %u clients, outstanding %u\n",
this, aSize, mOutstandingClients);
RefPtr<TextureClient> newClient;
while (mTextureClients.size() < aSize) {
if (gfxPrefs::ForceShmemTiles()) {
// gfx::BackendType::NONE means use the content backend
newClient =
TextureClient::CreateForRawBufferAccess(mSurfaceAllocator,
mFormat, mSize,
gfx::BackendType::NONE,
mFlags, ALLOC_DEFAULT);
} else {
newClient =
TextureClient::CreateForDrawing(mSurfaceAllocator,
mFormat, mSize,
mBackend,
BackendSelector::Content,
mFlags);
}
if (newClient) {
mTextureClients.push(newClient.forget());
}
}
}
void
TextureClientPool::ReturnTextureClient(TextureClient *aClient)
{
@ -165,6 +150,14 @@ TextureClientPool::ReturnTextureClient(TextureClient *aClient)
// Shrink down if we're beyond our maximum size
ShrinkToMaximumSize();
// Kick off the pool shrinking timer if there are still more unused texture
// clients than our desired minimum cache size.
if (mTextureClients.size() > sMinCacheSize) {
TCP_LOG("TexturePool %p scheduling a shrink-to-min-size\n", this);
mTimer->InitWithFuncCallback(ShrinkCallback, this, mShrinkTimeoutMsec,
nsITimer::TYPE_ONE_SHOT);
}
}
void
@ -187,54 +180,80 @@ TextureClientPool::ReturnTextureClientDeferred(TextureClient* aClient)
void
TextureClientPool::ShrinkToMaximumSize()
{
uint32_t totalClientsOutstanding = mTextureClients.size() + mOutstandingClients;
TCP_LOG("TexturePool %p shrinking to max size %u; total outstanding %u\n",
this, mMaxTextureClients, totalClientsOutstanding);
// We're over our desired maximum size, immediately shrink down to the
// maximum.
//
// maximum, or zero if we have too many outstanding texture clients.
// We cull from the deferred TextureClients first, as we can't reuse those
// until they get returned.
uint32_t totalUnusedTextureClients = mTextureClients.size() + mTextureClientsDeferred.size();
// If we have > mInitialPoolSize outstanding, then we want to keep around
// mPoolIncrementSize at a maximum. If we have fewer than mInitialPoolSize
// outstanding, then keep around the entire initial pool size.
uint32_t targetUnusedClients;
if (mOutstandingClients > mInitialPoolSize) {
targetUnusedClients = mPoolIncrementSize;
} else {
targetUnusedClients = mInitialPoolSize;
}
TCP_LOG("TexturePool %p shrinking to maximum unused size %u; total outstanding %u\n",
this, targetUnusedClients, mOutstandingClients);
while (totalUnusedTextureClients > targetUnusedClients) {
while (totalClientsOutstanding > mMaxTextureClients) {
if (mTextureClientsDeferred.size()) {
MOZ_ASSERT(mOutstandingClients > 0);
mOutstandingClients--;
TCP_LOG("TexturePool %p dropped deferred client %p; %u remaining\n",
this, mTextureClientsDeferred.front().get(),
mTextureClientsDeferred.size() - 1);
mTextureClientsDeferred.pop_front();
} else {
if (!mTextureClients.size()) {
// Getting here means we're over our desired number of TextureClients
// with none in the pool. This can happen during shutdown, or for
// pathological cases, or it could mean that mMaxTextureClients needs
// adjusting for whatever device we're running on.
TCP_LOG("TexturePool %p encountering pathological case!\n", this);
break;
}
TCP_LOG("TexturePool %p dropped non-deferred client %p; %u remaining\n",
this, mTextureClients.top().get(), mTextureClients.size() - 1);
mTextureClients.pop();
}
totalUnusedTextureClients--;
totalClientsOutstanding--;
}
}
void
TextureClientPool::ShrinkToMinimumSize()
{
ReturnUnlockedClients();
while (!mTextureClientsDeferred.empty()) {
MOZ_ASSERT(mOutstandingClients > 0);
mOutstandingClients--;
TCP_LOG("TexturePool %p releasing deferred client %p\n",
this, mTextureClientsDeferred.front().get());
mTextureClientsDeferred.pop_front();
}
TCP_LOG("TexturePool %p shrinking to minimum size %u\n", this, sMinCacheSize);
while (mTextureClients.size() > sMinCacheSize) {
TCP_LOG("TexturePool %p popped %p; shrunk to %u\n",
this, mTextureClients.top().get(), mTextureClients.size() - 1);
mTextureClients.pop();
}
}
void
TextureClientPool::ReturnDeferredClients()
{
TCP_LOG("TexturePool %p returning %u deferred clients to pool\n",
this, mTextureClientsDeferred.size());
if (mTextureClientsDeferred.empty()) {
return;
}
TCP_LOG("TexturePool %p returning %u deferred clients to pool\n",
this, mTextureClientsDeferred.size());
ReturnUnlockedClients();
ShrinkToMaximumSize();
// Kick off the pool shrinking timer if there are still more unused texture
// clients than our desired minimum cache size.
if (mTextureClients.size() > sMinCacheSize) {
TCP_LOG("TexturePool %p kicking off shrink-to-min timer\n", this);
mTimer->InitWithFuncCallback(ShrinkCallback, this, mShrinkTimeoutMsec,
nsITimer::TYPE_ONE_SHOT);
}
}
void
@ -285,7 +304,7 @@ TextureClientPool::Clear()
void TextureClientPool::Destroy()
{
Clear();
mInitialPoolSize = 0;
mMaxTextureClients = 0;
}
} // namespace layers

View File

@ -48,8 +48,8 @@ public:
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
TextureFlags aFlags,
uint32_t aInitialPoolSize,
uint32_t aPoolIncrementSize,
uint32_t aMaxTextureClients,
uint32_t aShrinkTimeoutMsec,
TextureForwarder* aAllocator);
/**
@ -75,18 +75,24 @@ public:
*/
void ReturnTextureClientDeferred(TextureClient *aClient) override;
/**
* Attempt to shrink the pool so that there are no more than
* mMaxTextureClients clients outstanding.
*/
void ShrinkToMaximumSize();
/**
* Attempt to shrink the pool so that there are no more than sMinCacheSize
* unused clients.
*/
void ShrinkToMinimumSize();
/**
* Return any clients to the pool that were previously returned in
* ReturnTextureClientDeferred.
*/
void ReturnDeferredClients();
/**
* Attempt to shrink the pool so that there are no more than
* mInitialPoolSize outstanding.
*/
void ShrinkToMaximumSize();
/**
* Report that a client retrieved via GetTextureClient() has become
* unusable, so that it will no longer be tracked.
@ -111,11 +117,9 @@ public:
private:
void ReturnUnlockedClients();
/// We maintain a number of unused texture clients for immediate return from
/// GetTextureClient(). This will normally be called if there are no
/// TextureClients available in the pool, which ideally should only ever
/// be at startup.
void AllocateTextureClients(size_t aSize);
// The minimum size of the pool (the number of tiles that will be kept after
// shrinking).
static const uint32_t sMinCacheSize = 0;
/// Backend passed to the TextureClient for buffer creation.
LayersBackend mBackend;
@ -129,13 +133,13 @@ private:
/// Flags passed to the TextureClient for buffer creation.
const TextureFlags mFlags;
// The initial number of unused texture clients to seed the pool with
// on construction
uint32_t mInitialPoolSize;
// The maximum number of texture clients managed by this pool that we want
// to remain active.
uint32_t mMaxTextureClients;
// How many unused texture clients to try and keep around if we go over
// the initial allocation
uint32_t mPoolIncrementSize;
// The time in milliseconds before the pool will be shrunk to the minimum
// size after returning a client.
uint32_t mShrinkTimeoutMsec;
/// This is a total number of clients in the wild and in the stack of
/// deferred clients (see below). So, the total number of clients in

View File

@ -954,8 +954,8 @@ CompositorBridgeChild::GetTexturePool(LayersBackend aBackend,
IntSize(gfxPlatform::GetPlatform()->GetTileWidth(),
gfxPlatform::GetPlatform()->GetTileHeight()),
aFlags,
gfxPrefs::LayersTileInitialPoolSize(),
gfxPrefs::LayersTilePoolIncrementSize(),
gfxPrefs::LayersTileMaxPoolSize(),
gfxPrefs::LayersTileShrinkPoolTimeout(),
this));
return mTexturePools.LastElement();
@ -965,7 +965,7 @@ void
CompositorBridgeChild::HandleMemoryPressure()
{
for (size_t i = 0; i < mTexturePools.Length(); i++) {
mTexturePools[i]->Clear();
mTexturePools[i]->ShrinkToMinimumSize();
}
}

View File

@ -485,8 +485,8 @@ private:
// they are often the same size as the screen, especially for width.
DECL_GFX_PREF(Once, "layers.tile-width", LayersTileWidth, int32_t, 256);
DECL_GFX_PREF(Once, "layers.tile-height", LayersTileHeight, int32_t, 256);
DECL_GFX_PREF(Once, "layers.tile-initial-pool-size", LayersTileInitialPoolSize, uint32_t, (uint32_t)50);
DECL_GFX_PREF(Once, "layers.tile-pool-increment-size", LayersTilePoolIncrementSize, uint32_t, (uint32_t)10);
DECL_GFX_PREF(Once, "layers.tile-max-pool-size", LayersTileMaxPoolSize, uint32_t, (uint32_t)50);
DECL_GFX_PREF(Once, "layers.tile-shrink-pool-timeout", LayersTileShrinkPoolTimeout, uint32_t, (uint32_t)1000);
DECL_GFX_PREF(Once, "layers.tiles.adjust", LayersTilesAdjust, bool, true);
DECL_GFX_PREF(Once, "layers.tiles.edge-padding", TileEdgePaddingEnabled, bool, true);
DECL_GFX_PREF(Live, "layers.tiles.fade-in.enabled", LayerTileFadeInEnabled, bool, false);