gecko-dev/gfx/layers/client/TextureClientPool.cpp

156 lines
4.3 KiB
C++

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TextureClientPool.h"
#include "CompositableClient.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "gfxPrefs.h"
#include "nsComponentManagerUtils.h"
namespace mozilla {
namespace layers {
static void
ShrinkCallback(nsITimer *aTimer, void *aClosure)
{
static_cast<TextureClientPool*>(aClosure)->ShrinkToMinimumSize();
}
TextureClientPool::TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
ISurfaceAllocator *aAllocator)
: mFormat(aFormat)
, mSize(aSize)
, mOutstandingClients(0)
, mSurfaceAllocator(aAllocator)
{
mTimer = do_CreateInstance("@mozilla.org/timer;1");
}
TextureClientPool::~TextureClientPool()
{
mTimer->Cancel();
}
TemporaryRef<TextureClient>
TextureClientPool::GetTextureClient()
{
mOutstandingClients++;
// Try to fetch a client from the pool
RefPtr<TextureClient> textureClient;
if (mTextureClients.size()) {
textureClient = mTextureClients.top();
textureClient->WaitForBufferOwnership();
mTextureClients.pop();
return textureClient;
}
// 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::CreateBufferTextureClient(mSurfaceAllocator,
mFormat, TextureFlags::IMMEDIATE_UPLOAD, gfx::BackendType::NONE);
} else {
textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator,
mFormat, TextureFlags::IMMEDIATE_UPLOAD, gfx::BackendType::NONE, mSize);
}
textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT);
return textureClient;
}
void
TextureClientPool::ReturnTextureClient(TextureClient *aClient)
{
if (!aClient) {
return;
}
MOZ_ASSERT(mOutstandingClients);
mOutstandingClients--;
// Add the client to the pool and shrink down if we're beyond our maximum size
mTextureClients.push(aClient);
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) {
mTimer->InitWithFuncCallback(ShrinkCallback, this, sShrinkTimeout,
nsITimer::TYPE_ONE_SHOT);
}
}
void
TextureClientPool::ReturnTextureClientDeferred(TextureClient *aClient)
{
mTextureClientsDeferred.push(aClient);
ShrinkToMaximumSize();
}
void
TextureClientPool::ShrinkToMaximumSize()
{
uint32_t totalClientsOutstanding = mTextureClients.size() + mOutstandingClients;
// We're over our desired maximum size, immediately shrink down to the
// 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.
while (totalClientsOutstanding > sMaxTextureClients) {
if (mTextureClientsDeferred.size()) {
mOutstandingClients--;
mTextureClientsDeferred.pop();
} else {
if (!mTextureClients.size()) {
// Getting here means we're over our desired number of TextureClients
// with none in the pool. This can happen for pathological cases, or
// it could mean that sMaxTextureClients needs adjusting for whatever
// device we're running on.
break;
}
mTextureClients.pop();
}
totalClientsOutstanding--;
}
}
void
TextureClientPool::ShrinkToMinimumSize()
{
while (mTextureClients.size() > sMinCacheSize) {
mTextureClients.pop();
}
}
void
TextureClientPool::ReturnDeferredClients()
{
while (!mTextureClientsDeferred.empty()) {
ReturnTextureClient(mTextureClientsDeferred.top());
mTextureClientsDeferred.pop();
}
}
void
TextureClientPool::Clear()
{
while (!mTextureClients.empty()) {
mTextureClients.pop();
}
while (!mTextureClientsDeferred.empty()) {
mOutstandingClients--;
mTextureClientsDeferred.pop();
}
}
}
}