michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "TextureClientPool.h" michael@0: #include "CompositableClient.h" michael@0: #include "mozilla/layers/ISurfaceAllocator.h" michael@0: michael@0: #include "gfxPrefs.h" michael@0: michael@0: #include "nsComponentManagerUtils.h" michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: static void michael@0: ShrinkCallback(nsITimer *aTimer, void *aClosure) michael@0: { michael@0: static_cast(aClosure)->ShrinkToMinimumSize(); michael@0: } michael@0: michael@0: TextureClientPool::TextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize, michael@0: ISurfaceAllocator *aAllocator) michael@0: : mFormat(aFormat) michael@0: , mSize(aSize) michael@0: , mOutstandingClients(0) michael@0: , mSurfaceAllocator(aAllocator) michael@0: { michael@0: mTimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: } michael@0: michael@0: TextureClientPool::~TextureClientPool() michael@0: { michael@0: mTimer->Cancel(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: TextureClientPool::GetTextureClient() michael@0: { michael@0: mOutstandingClients++; michael@0: michael@0: // Try to fetch a client from the pool michael@0: RefPtr textureClient; michael@0: if (mTextureClients.size()) { michael@0: textureClient = mTextureClients.top(); michael@0: textureClient->WaitReleaseFence(); michael@0: mTextureClients.pop(); michael@0: return textureClient; michael@0: } michael@0: michael@0: // We're increasing the number of outstanding TextureClients without reusing a michael@0: // client, we may need to free a deferred-return TextureClient. michael@0: ShrinkToMaximumSize(); michael@0: michael@0: // No unused clients in the pool, create one michael@0: if (gfxPrefs::ForceShmemTiles()) { michael@0: // gfx::BackendType::NONE means use the content backend michael@0: textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator, michael@0: mFormat, TEXTURE_IMMEDIATE_UPLOAD, gfx::BackendType::NONE); michael@0: } else { michael@0: textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator, michael@0: mFormat, TEXTURE_IMMEDIATE_UPLOAD, gfx::BackendType::NONE, mSize); michael@0: } michael@0: textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT); michael@0: michael@0: return textureClient; michael@0: } michael@0: michael@0: void michael@0: TextureClientPool::ReturnTextureClient(TextureClient *aClient) michael@0: { michael@0: if (!aClient) { michael@0: return; michael@0: } michael@0: MOZ_ASSERT(mOutstandingClients); michael@0: mOutstandingClients--; michael@0: michael@0: // Add the client to the pool and shrink down if we're beyond our maximum size michael@0: mTextureClients.push(aClient); michael@0: ShrinkToMaximumSize(); michael@0: michael@0: // Kick off the pool shrinking timer if there are still more unused texture michael@0: // clients than our desired minimum cache size. michael@0: if (mTextureClients.size() > sMinCacheSize) { michael@0: mTimer->InitWithFuncCallback(ShrinkCallback, this, sShrinkTimeout, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextureClientPool::ReturnTextureClientDeferred(TextureClient *aClient) michael@0: { michael@0: mTextureClientsDeferred.push(aClient); michael@0: ShrinkToMaximumSize(); michael@0: } michael@0: michael@0: void michael@0: TextureClientPool::ShrinkToMaximumSize() michael@0: { michael@0: uint32_t totalClientsOutstanding = mTextureClients.size() + mOutstandingClients; michael@0: michael@0: // We're over our desired maximum size, immediately shrink down to the michael@0: // maximum, or zero if we have too many outstanding texture clients. michael@0: // We cull from the deferred TextureClients first, as we can't reuse those michael@0: // until they get returned. michael@0: while (totalClientsOutstanding > sMaxTextureClients) { michael@0: if (mTextureClientsDeferred.size()) { michael@0: mOutstandingClients--; michael@0: mTextureClientsDeferred.pop(); michael@0: } else { michael@0: if (!mTextureClients.size()) { michael@0: // Getting here means we're over our desired number of TextureClients michael@0: // with none in the pool. This can happen for pathological cases, or michael@0: // it could mean that sMaxTextureClients needs adjusting for whatever michael@0: // device we're running on. michael@0: break; michael@0: } michael@0: mTextureClients.pop(); michael@0: } michael@0: totalClientsOutstanding--; michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextureClientPool::ShrinkToMinimumSize() michael@0: { michael@0: while (mTextureClients.size() > sMinCacheSize) { michael@0: mTextureClients.pop(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextureClientPool::ReturnDeferredClients() michael@0: { michael@0: while (!mTextureClientsDeferred.empty()) { michael@0: ReturnTextureClient(mTextureClientsDeferred.top()); michael@0: mTextureClientsDeferred.pop(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: TextureClientPool::Clear() michael@0: { michael@0: while (!mTextureClients.empty()) { michael@0: mTextureClients.pop(); michael@0: } michael@0: while (!mTextureClientsDeferred.empty()) { michael@0: mOutstandingClients--; michael@0: mTextureClientsDeferred.pop(); michael@0: } michael@0: } michael@0: michael@0: } michael@0: }