Bug 1091777 - Add TextureClient recycling to CairoImag r=nical

This commit is contained in:
Sotaro Ikeda 2014-11-13 07:53:49 -08:00
parent f12bdba2f9
commit 4a33624da4
13 changed files with 455 additions and 17 deletions

View File

@ -496,11 +496,33 @@ CairoImage::GetTextureClient(CompositableClient *aClient)
return nullptr;
}
// gfx::BackendType::NONE means default to content backend
textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
surface->GetSize(),
gfx::BackendType::NONE,
TextureFlags::DEFAULT);
// XXX windows' TextureClients do not hold ISurfaceAllocator,
// recycler does not work on windows.
#ifndef XP_WIN
// XXX only gonk ensure when TextureClient is recycled,
// TextureHost is not used by CompositableHost.
#ifdef MOZ_WIDGET_GONK
RefPtr<TextureClientRecycleAllocator> recycler =
aClient->GetTextureClientRecycler();
if (recycler) {
textureClient =
recycler->CreateOrRecycleForDrawing(surface->GetFormat(),
surface->GetSize(),
gfx::BackendType::NONE,
aClient->GetTextureFlags());
}
#endif
#endif
if (!textureClient) {
// gfx::BackendType::NONE means default to content backend
textureClient = aClient->CreateTextureClientForDrawing(surface->GetFormat(),
surface->GetSize(),
gfx::BackendType::NONE,
TextureFlags::DEFAULT);
}
if (!textureClient) {
return nullptr;
}

View File

@ -811,7 +811,7 @@ public:
virtual ISharedImage* AsSharedImage() { return this; }
virtual uint8_t* GetBuffer() { return nullptr; }
virtual TextureClient* GetTextureClient(CompositableClient* aClient);
virtual TextureClient* GetTextureClient(CompositableClient* aClient) MOZ_OVERRIDE;
gfx::IntSize GetSize() { return mSize; }

View File

@ -219,6 +219,7 @@ CompositableClient::AddTextureClient(TextureClient* aClient)
if(!aClient || !aClient->IsAllocated()) {
return false;
}
aClient->SetAddedToCompositableClient();
return aClient->InitIPDLActor(mForwarder);
}
@ -227,11 +228,35 @@ CompositableClient::OnTransaction()
{
}
void
CompositableClient::ClearCachedResources()
{
if (mTextureClientRecycler) {
mTextureClientRecycler = nullptr;
}
}
void
CompositableClient::RemoveTexture(TextureClient* aTexture)
{
mForwarder->RemoveTextureFromCompositable(this, aTexture);
}
TextureClientRecycleAllocator*
CompositableClient::GetTextureClientRecycler()
{
if (mTextureClientRecycler) {
return mTextureClientRecycler;
}
if (!mForwarder) {
return nullptr;
}
mTextureClientRecycler =
new layers::TextureClientRecycleAllocator(mForwarder);
return mTextureClientRecycler;
}
} // namespace layers
} // namespace mozilla

View File

@ -16,6 +16,7 @@
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/LayersTypes.h" // for LayersBackend
#include "mozilla/layers/TextureClient.h" // for TextureClient
#include "mozilla/layers/TextureClientRecycleAllocator.h" // for TextureClientRecycleAllocator
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
namespace mozilla {
@ -194,7 +195,7 @@ public:
* Clear any resources that are not immediately necessary. This may be called
* in low-memory conditions.
*/
virtual void ClearCachedResources() {}
virtual void ClearCachedResources();
/**
* Should be called when deataching a TextureClient from a Compositable, because
@ -229,12 +230,15 @@ public:
TextureFlags GetTextureFlags() const { return mTextureFlags; }
TextureClientRecycleAllocator* GetTextureClientRecycler();
protected:
CompositableChild* mCompositableChild;
CompositableForwarder* mForwarder;
// Some layers may want to enforce some flags to all their textures
// (like disallowing tiling)
TextureFlags mTextureFlags;
RefPtr<TextureClientRecycleAllocator> mTextureClientRecycler;
friend class CompositableChild;
};

View File

@ -176,12 +176,57 @@ TextureClient::AsTextureClient(PTextureChild* actor)
return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr;
}
void
TextureClient::AddFlags(TextureFlags aFlags)
{
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags |= aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
void
TextureClient::RemoveFlags(TextureFlags aFlags)
{
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags &= ~aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
void
TextureClient::RecycleTexture(TextureFlags aFlags)
{
MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
MOZ_ASSERT(!HasRecycleCallback());
mAddedToCompositableClient = false;
if (mFlags != aFlags) {
mFlags = aFlags;
if (mValid && mActor && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
}
void
TextureClient::WaitForCompositorRecycle()
{
mActor->WaitForCompositorRecycle();
}
void
TextureClient::SetAddedToCompositableClient()
{
if (!mAddedToCompositableClient) {
mAddedToCompositableClient = true;
}
}
bool
TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
{
@ -429,6 +474,7 @@ TextureClient::TextureClient(TextureFlags aFlags)
: mFlags(aFlags)
, mShared(false)
, mValid(true)
, mAddedToCompositableClient(false)
{}
TextureClient::~TextureClient()

View File

@ -301,17 +301,11 @@ public:
return (mFlags & aFlags) == aFlags;
}
void AddFlags(TextureFlags aFlags)
{
MOZ_ASSERT(!IsSharedWithCompositor());
mFlags |= aFlags;
}
void AddFlags(TextureFlags aFlags);
void RemoveFlags(TextureFlags aFlags)
{
MOZ_ASSERT(!IsSharedWithCompositor());
mFlags &= ~aFlags;
}
void RemoveFlags(TextureFlags aFlags);
void RecycleTexture(TextureFlags aFlags);
/**
* valid only for TextureFlags::RECYCLE TextureClient.
@ -341,6 +335,17 @@ public:
*/
bool IsValid() const { return mValid; }
/**
* Called when TextureClient is added to CompositableClient.
*/
void SetAddedToCompositableClient();
/**
* If this method retuns false, TextureClient is already added to CompositableClient,
* since its creation or recycling.
*/
bool IsAddedToCompositableClient() const { return mAddedToCompositableClient; }
/**
* kee the passed object alive until the IPDL actor is destroyed. This can
* help avoid race conditions in some cases.
@ -461,6 +466,7 @@ protected:
gl::GfxTextureWasteTracker mWasteTracker;
bool mShared;
bool mValid;
bool mAddedToCompositableClient;
RefPtr<TextureReadbackSink> mReadbackSink;

View File

@ -0,0 +1,257 @@
/* -*- 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 <map>
#include <stack>
#include "gfxPlatform.h"
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/Mutex.h"
#include "TextureClientRecycleAllocator.h"
namespace mozilla {
namespace layers {
class TextureClientRecycleAllocatorImp : public ISurfaceAllocator
{
~TextureClientRecycleAllocatorImp();
public:
explicit TextureClientRecycleAllocatorImp(ISurfaceAllocator* aAllocator);
// Creates and allocates a TextureClient.
TemporaryRef<TextureClient>
CreateOrRecycleForDrawing(gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
gfx::BackendType aMoz2dBackend,
TextureFlags aTextureFlags,
TextureAllocationFlags flags);
void Destroy();
void RecycleCallbackImp(TextureClient* aClient);
static void RecycleCallback(TextureClient* aClient, void* aClosure);
// ISurfaceAllocator
virtual LayersBackend GetCompositorBackendType() const MOZ_OVERRIDE
{
return mSurfaceAllocator->GetCompositorBackendType();
}
virtual bool AllocShmem(size_t aSize,
mozilla::ipc::SharedMemory::SharedMemoryType aType,
mozilla::ipc::Shmem* aShmem) MOZ_OVERRIDE
{
return mSurfaceAllocator->AllocShmem(aSize, aType, aShmem);
}
virtual bool AllocUnsafeShmem(size_t aSize,
mozilla::ipc::SharedMemory::SharedMemoryType aType,
mozilla::ipc::Shmem* aShmem) MOZ_OVERRIDE
{
return mSurfaceAllocator->AllocUnsafeShmem(aSize, aType, aShmem);
}
virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) MOZ_OVERRIDE
{
mSurfaceAllocator->DeallocShmem(aShmem);
}
virtual bool IsSameProcess() const MOZ_OVERRIDE
{
return mSurfaceAllocator->IsSameProcess();
}
protected:
// ISurfaceAllocator
virtual bool IsOnCompositorSide() const MOZ_OVERRIDE
{
return false;
}
private:
static const uint32_t kMaxPooledSized = 2;
// Used to keep TextureClient's reference count stable as not to disrupt recycling.
class TextureClientHolder
{
~TextureClientHolder() {}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureClientHolder)
explicit TextureClientHolder(TextureClient* aClient)
: mTextureClient(aClient)
{}
TextureClient* GetTextureClient()
{
return mTextureClient;
}
void ClearTextureClient() { mTextureClient = nullptr; }
protected:
RefPtr<TextureClient> mTextureClient;
};
bool mDestroyed;
uint32_t mMaxPooledSize;
RefPtr<ISurfaceAllocator> mSurfaceAllocator;
std::map<TextureClient*, RefPtr<TextureClientHolder> > mInUseClients;
// On b2g gonk, std::queue might be a better choice.
// On ICS, fence wait happens implicitly before drawing.
// Since JB, fence wait happens explicitly when fetching a client from the pool.
// stack is good from Graphics cache usage point of view.
std::stack<RefPtr<TextureClientHolder> > mPooledClients;
Mutex mLock;
};
TextureClientRecycleAllocatorImp::TextureClientRecycleAllocatorImp(ISurfaceAllocator *aAllocator)
: mDestroyed(false)
, mMaxPooledSize(kMaxPooledSized)
, mSurfaceAllocator(aAllocator)
, mLock("TextureClientRecycleAllocatorImp.mLock")
{
}
TextureClientRecycleAllocatorImp::~TextureClientRecycleAllocatorImp()
{
MOZ_ASSERT(mDestroyed);
MOZ_ASSERT(mPooledClients.empty());
MOZ_ASSERT(mInUseClients.empty());
}
TemporaryRef<TextureClient>
TextureClientRecycleAllocatorImp::CreateOrRecycleForDrawing(
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
gfx::BackendType aMoz2DBackend,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags)
{
// TextureAllocationFlags is actually used only by ContentClient.
// This class does not handle ConteClient's TextureClient allocation.
MOZ_ASSERT(aAllocFlags == TextureAllocationFlags::ALLOC_DEFAULT);
MOZ_ASSERT(!(aTextureFlags & TextureFlags::RECYCLE));
aTextureFlags = aTextureFlags | TextureFlags::RECYCLE; // Set recycle flag
RefPtr<TextureClientHolder> textureHolder;
if (aMoz2DBackend == gfx::BackendType::NONE) {
aMoz2DBackend = gfxPlatform::GetPlatform()->GetContentBackend();
}
{
MutexAutoLock lock(mLock);
if (mDestroyed) {
return nullptr;
} else if (!mPooledClients.empty()) {
textureHolder = mPooledClients.top();
mPooledClients.pop();
// If a pooled TextureClient is not compatible, release it.
if (textureHolder->GetTextureClient()->GetFormat() != aFormat ||
textureHolder->GetTextureClient()->GetSize() != aSize)
{
TextureClientReleaseTask* task = new TextureClientReleaseTask(textureHolder->GetTextureClient());
textureHolder->ClearTextureClient();
textureHolder = nullptr;
// Release TextureClient.
mSurfaceAllocator->GetMessageLoop()->PostTask(FROM_HERE, task);
} else {
textureHolder->GetTextureClient()->RecycleTexture(aTextureFlags);
}
}
}
if (!textureHolder) {
// Allocate new TextureClient
RefPtr<TextureClient> texture;
texture = TextureClient::CreateForDrawing(this, aFormat, aSize, aMoz2DBackend,
aTextureFlags, aAllocFlags);
if (!texture) {
return nullptr;
}
textureHolder = new TextureClientHolder(texture);
}
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(mInUseClients.find(textureHolder->GetTextureClient()) == mInUseClients.end());
// Register TextureClient
mInUseClients[textureHolder->GetTextureClient()] = textureHolder;
}
textureHolder->GetTextureClient()->SetRecycleCallback(TextureClientRecycleAllocatorImp::RecycleCallback, this);
return textureHolder->GetTextureClient();
}
void
TextureClientRecycleAllocatorImp::Destroy()
{
MutexAutoLock lock(mLock);
if (mDestroyed) {
return;
}
mDestroyed = true;
while (!mPooledClients.empty()) {
mPooledClients.pop();
}
}
void
TextureClientRecycleAllocatorImp::RecycleCallbackImp(TextureClient* aClient)
{
RefPtr<TextureClientHolder> textureHolder;
aClient->ClearRecycleCallback();
{
MutexAutoLock lock(mLock);
if (mInUseClients.find(aClient) != mInUseClients.end()) {
textureHolder = mInUseClients[aClient]; // Keep reference count of TextureClientHolder within lock.
if (!mDestroyed && mPooledClients.size() < mMaxPooledSize) {
mPooledClients.push(textureHolder);
}
mInUseClients.erase(aClient);
}
}
}
/* static */ void
TextureClientRecycleAllocatorImp::RecycleCallback(TextureClient* aClient, void* aClosure)
{
TextureClientRecycleAllocatorImp* recycleAllocator = static_cast<TextureClientRecycleAllocatorImp*>(aClosure);
recycleAllocator->RecycleCallbackImp(aClient);
}
TextureClientRecycleAllocator::TextureClientRecycleAllocator(ISurfaceAllocator *aAllocator)
{
mAllocator = new TextureClientRecycleAllocatorImp(aAllocator);
}
TextureClientRecycleAllocator::~TextureClientRecycleAllocator()
{
mAllocator->Destroy();
mAllocator = nullptr;
}
TemporaryRef<TextureClient>
TextureClientRecycleAllocator::CreateOrRecycleForDrawing(
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
gfx::BackendType aMoz2DBackend,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags)
{
return mAllocator->CreateOrRecycleForDrawing(aFormat,
aSize,
aMoz2DBackend,
aTextureFlags,
aAllocFlags);
}
}
}

View File

@ -0,0 +1,49 @@
/* -*- 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/. */
#ifndef MOZILLA_GFX_TEXTURECLIENT_RECYCLE_ALLOCATOR_H
#define MOZILLA_GFX_TEXTURECLIENT_RECYCLE_ALLOCATOR_H
#include "mozilla/gfx/Types.h"
#include "mozilla/RefPtr.h"
#include "TextureClient.h"
namespace mozilla {
namespace layers {
class ISurfaceAllocator;
class TextureClientRecycleAllocatorImp;
/**
* TextureClientRecycleAllocator provides TextureClients allocation and
* recycling capabilities. It expects allocations of same sizes and
* attributres. If a recycled TextureClient is different from
* requested one, the recycled one is dropped and new TextureClient is allocated.
*/
class TextureClientRecycleAllocator
{
~TextureClientRecycleAllocator();
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureClientRecycleAllocator)
explicit TextureClientRecycleAllocator(ISurfaceAllocator* aAllocator);
// Creates and allocates a TextureClient.
TemporaryRef<TextureClient>
CreateOrRecycleForDrawing(gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
gfx::BackendType aMoz2dBackend,
TextureFlags aTextureFlags,
TextureAllocationFlags flags = ALLOC_DEFAULT);
private:
RefPtr<TextureClientRecycleAllocatorImp> mAllocator;
};
}
}
#endif /* MOZILLA_GFX_TEXTURECLIENT_RECYCLE_ALLOCATOR_H */

View File

@ -106,6 +106,7 @@ TiledContentClient::TiledContentClient(ClientTiledPaintedLayer* aPaintedLayer,
void
TiledContentClient::ClearCachedResources()
{
CompositableClient::ClearCachedResources();
mTiledBuffer.DiscardBuffers();
mLowPrecisionTiledBuffer.DiscardBuffers();
}

View File

@ -85,6 +85,8 @@ public:
virtual bool RecvRemoveTexture() MOZ_OVERRIDE;
virtual bool RecvRecycleTexture(const TextureFlags& aTextureFlags) MOZ_OVERRIDE;
TextureHost* GetTextureHost() { return mTextureHost; }
void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
@ -301,6 +303,15 @@ void TextureHost::Finalize()
}
}
void
TextureHost::RecycleTexture(TextureFlags aFlags)
{
MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
MOZ_ASSERT(aFlags & TextureFlags::RECYCLE);
MOZ_ASSERT(!HasRecycleCallback());
mFlags = aFlags;
}
void
TextureHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{
@ -793,6 +804,16 @@ TextureParent::ClearTextureHost()
mTextureHost = nullptr;
}
bool
TextureParent::RecvRecycleTexture(const TextureFlags& aTextureFlags)
{
if (!mTextureHost) {
return true;
}
mTextureHost->RecycleTexture(aTextureFlags);
return true;
}
////////////////////////////////////////////////////////////////////////////////
static RefPtr<TextureSource>

View File

@ -506,6 +506,8 @@ public:
virtual TextureHostOGL* AsHostOGL() { return nullptr; }
protected:
void RecycleTexture(TextureFlags aFlags);
PTextureParent* mActor;
TextureFlags mFlags;

View File

@ -11,6 +11,7 @@ include protocol PImageBridge;
include "mozilla/GfxMessageUtils.h";
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
namespace mozilla {
namespace layers {
@ -39,6 +40,8 @@ parent:
* Asynchronously tell the Compositor side to remove the texture.
*/
async RemoveTexture();
async RecycleTexture(TextureFlags aTextureFlags);
};
} // layers

View File

@ -125,6 +125,7 @@ EXPORTS.mozilla.layers += [
'client/ImageClient.h',
'client/TextureClient.h',
'client/TextureClientPool.h',
'client/TextureClientRecycleAllocator.h',
'client/TiledContentClient.h',
'composite/AsyncCompositionManager.h',
'composite/CanvasLayerComposite.h',
@ -268,6 +269,7 @@ UNIFIED_SOURCES += [
'client/ImageClient.cpp',
'client/TextureClient.cpp',
'client/TextureClientPool.cpp',
'client/TextureClientRecycleAllocator.cpp',
'client/TiledContentClient.cpp',
'composite/AsyncCompositionManager.cpp',
'composite/CanvasLayerComposite.cpp',