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 "SimpleTextureClientPool.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: #if 0 michael@0: #define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__) michael@0: #else michael@0: #define RECYCLE_LOG(...) do { } while (0) michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: using gfx::SurfaceFormat; michael@0: michael@0: /* static */ void michael@0: SimpleTextureClientPool::ShrinkCallback(nsITimer *aTimer, void *aClosure) michael@0: { michael@0: static_cast(aClosure)->ShrinkToMinimumSize(); michael@0: } michael@0: michael@0: /* static */ void michael@0: SimpleTextureClientPool::RecycleCallback(TextureClient* aClient, void* aClosure) michael@0: { michael@0: SimpleTextureClientPool* pool = michael@0: static_cast(aClosure); michael@0: michael@0: aClient->ClearRecycleCallback(); michael@0: pool->ReturnTextureClient(aClient); michael@0: } michael@0: michael@0: /* static */ void michael@0: SimpleTextureClientPool::WaitForCompositorRecycleCallback(TextureClient* aClient, void* aClosure) michael@0: { michael@0: // This will grab a reference that will be released once the compositor michael@0: // acknowledges the remote recycle. Once it is received the object michael@0: // will be fully recycled. michael@0: aClient->WaitForCompositorRecycle(); michael@0: aClient->SetRecycleCallback(SimpleTextureClientPool::RecycleCallback, aClosure); michael@0: } michael@0: michael@0: SimpleTextureClientPool::SimpleTextureClientPool(gfx::SurfaceFormat aFormat, gfx::IntSize aSize, michael@0: ISurfaceAllocator *aAllocator) michael@0: : mFormat(aFormat) michael@0: , mSize(aSize) michael@0: , mSurfaceAllocator(aAllocator) michael@0: { michael@0: mTimer = do_CreateInstance("@mozilla.org/timer;1"); michael@0: } michael@0: michael@0: TemporaryRef michael@0: SimpleTextureClientPool::GetTextureClient(bool aAutoRecycle) michael@0: { michael@0: // Try to fetch a client from the pool michael@0: RefPtr textureClient; michael@0: if (mAvailableTextureClients.size()) { michael@0: textureClient = mAvailableTextureClients.top(); michael@0: textureClient->WaitReleaseFence(); michael@0: mAvailableTextureClients.pop(); michael@0: RECYCLE_LOG("%s Skip allocate (%i left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size(), textureClient.get()); michael@0: michael@0: } else { michael@0: // No unused clients in the pool, create one michael@0: if (gfxPrefs::ForceShmemTiles()) { michael@0: textureClient = TextureClient::CreateBufferTextureClient(mSurfaceAllocator, michael@0: mFormat, TEXTURE_IMMEDIATE_UPLOAD | TEXTURE_RECYCLE, gfx::BackendType::NONE); michael@0: } else { michael@0: textureClient = TextureClient::CreateTextureClientForDrawing(mSurfaceAllocator, michael@0: mFormat, TEXTURE_FLAGS_DEFAULT | TEXTURE_RECYCLE, gfx::BackendType::NONE, mSize); michael@0: } michael@0: if (!textureClient->AllocateForSurface(mSize, ALLOC_DEFAULT)) { michael@0: NS_WARNING("TextureClient::AllocateForSurface failed!"); michael@0: } michael@0: RECYCLE_LOG("%s Must allocate (0 left), returning %p\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), textureClient.get()); michael@0: } michael@0: michael@0: if (aAutoRecycle) { michael@0: mOutstandingTextureClients.push_back(textureClient); michael@0: textureClient->SetRecycleCallback(SimpleTextureClientPool::WaitForCompositorRecycleCallback, this); michael@0: } michael@0: michael@0: return textureClient; michael@0: } michael@0: michael@0: void michael@0: SimpleTextureClientPool::ReturnTextureClient(TextureClient *aClient) michael@0: { michael@0: if (!aClient) { michael@0: return; michael@0: } michael@0: michael@0: // If we haven't hit our max cached client limit, add this one michael@0: if (mAvailableTextureClients.size() < sMaxTextureClients) { michael@0: mAvailableTextureClients.push(aClient); michael@0: RECYCLE_LOG("%s recycled %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mAvailableTextureClients.size()); michael@0: } else { michael@0: RECYCLE_LOG("%s did not recycle %p (have %d)\n", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), aClient, mAvailableTextureClients.size()); michael@0: } 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 (mAvailableTextureClients.size() > sMinCacheSize) { michael@0: mTimer->InitWithFuncCallback(SimpleTextureClientPool::ShrinkCallback, this, sShrinkTimeout, michael@0: nsITimer::TYPE_ONE_SHOT); michael@0: } michael@0: michael@0: mOutstandingTextureClients.remove(aClient); michael@0: } michael@0: michael@0: void michael@0: SimpleTextureClientPool::ShrinkToMinimumSize() michael@0: { michael@0: RECYCLE_LOG("%s ShrinkToMinimumSize, removing %d clients", (mFormat == SurfaceFormat::B8G8R8A8?"poolA":"poolX"), mAvailableTextureClients.size() > sMinCacheSize ? mAvailableTextureClients.size() - sMinCacheSize : 0); michael@0: michael@0: mTimer->Cancel(); michael@0: michael@0: while (mAvailableTextureClients.size() > sMinCacheSize) { michael@0: mAvailableTextureClients.pop(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: SimpleTextureClientPool::Clear() michael@0: { michael@0: while (!mAvailableTextureClients.empty()) { michael@0: mAvailableTextureClients.pop(); michael@0: } michael@0: } michael@0: michael@0: } michael@0: }