Files
palemoon27/gfx/layers/client/TextureClientRecycleAllocator.cpp
T
roytam1 3b276a5398 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1077651 Measure frame uniformity by synthesizing native events. r=kats,mrbkap (95a796145)
- Bug 1154231 - Part 2. Reclaim cached resources when memory-pressure occurs. r=mattwoodrow (cff6ac1f9)
- fix build (15112d396)
- Bug 1155649 - XFlush at the end of frames when OMTC is enabled on Linux. r=jrmuizel (8bc22dd42)
- Bug 1158120 - Edit include and comments that contained gfxIntSize and nsIntSize. r=nical (fc25c0c96)
- Bug 1167235 - Part 1: Add code exposing a PersistentBufferProvider. r=nical (8340f8ede)
- Bug 1134251 - Disable broken B2G Desktop tests on Mulet. r=jmaher, r=jgilbert (db4d4253c)
- Bug 1134271 - Skip conformance/canvas/buffer-offscreen-test.html on Android; r=jgilbert (2fe8d8623)
- Bug 1124996 - Remove expected fail on OSX 10.10. r=jgilbert (388438a7e)
- Bug 1145492 - Update FramebufferTexture2D to allow binding mipmaps. r=jgilbert (5e4c6bf95)
- Bug 1158089 - Remove LAYERS_D3D10 enum value since it's unused. r=Bas (720d3b3b4)
- Bug 1156058 - Null pointer check. r=jgilbert (f9b9c6ca6)
- Bug 1131463 - Report AtomicRefCounterWithFinalize doing the wrong thing with AddRef and Release in release build as well. r=sotaro (7c009766e)
- Bug 1142071 - Re-add WaitForBufferOwnership() r=jgilbert (0753bcd25)
- partial revert of patch not found... (4ed1e76f1)
- Bug 1143979 - Use RAII local instead of useless temporary. - r=kamidphish (d8a50143f)
- Bug 1017865 - Refactor attach/detach for FB attachments. - r=kamidphish (9c7e41065)
- Bug 1144906 - Add accel E10S backend for WebGL compositing. - r=jrmuizel,mattwoodrow,nical,sotaro (559ab767f)
- Bug 1167235 - Part 2: Add support for the basic buffer provider to CanvasLayer. r=nical (4ac399c16)
- Bug 1155252 - Add a pref to control the maximum canvas 2d size and set it to 0x7ff. r=jrmuizel (7ae6cde3f)
- Bug 1167235 - Part 3: Switch CanvasRenderingContext2D to use the new BufferProvider API. r=nical (f678c14ab)
- Bug 1192159: Do not forget about the transform when not using an active target. r=jrmuizel (a4bd28a75)
- Bug 1167235 - Part 4: Remove DrawTarget as a possible means of initializing Canvas layers. r=nical (dbd153cfb)
- Bug 1167235 - Part 5: Make CanvasLayerComposite ImageHost type agnostic. r=nical (df15bd85d)
- Bug 1167235 - Part 6: Fix up HasInternalBuffer return value on TextureHostDirectUpload. r=nical (437cd1680)
- Bug 1091851 - Fix a race condition in Sqlite.jsm shutdown. r=mak (8b6ac8848)
2020-12-09 23:03:57 +08:00

272 lines
8.6 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 <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);
void SetMaxPoolSize(uint32_t aMax)
{
if (aMax > 0) {
mMaxPooledSize = aMax;
}
}
// Creates and allocates a TextureClient.
already_AddRefed<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 override
{
return mSurfaceAllocator->GetCompositorBackendType();
}
virtual bool AllocShmem(size_t aSize,
mozilla::ipc::SharedMemory::SharedMemoryType aType,
mozilla::ipc::Shmem* aShmem) override
{
return mSurfaceAllocator->AllocShmem(aSize, aType, aShmem);
}
virtual bool AllocUnsafeShmem(size_t aSize,
mozilla::ipc::SharedMemory::SharedMemoryType aType,
mozilla::ipc::Shmem* aShmem) override
{
return mSurfaceAllocator->AllocUnsafeShmem(aSize, aType, aShmem);
}
virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override
{
mSurfaceAllocator->DeallocShmem(aShmem);
}
virtual bool IsSameProcess() const override
{
return mSurfaceAllocator->IsSameProcess();
}
protected:
// ISurfaceAllocator
virtual bool IsOnCompositorSide() const 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());
}
already_AddRefed<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 ||
aAllocFlags == TextureAllocationFlags::ALLOC_DISALLOW_BUFFERTEXTURECLIENT);
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);
RefPtr<TextureClient> client(textureHolder->GetTextureClient());
return client.forget();
}
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)
{
MOZ_ASSERT(aClient && !aClient->IsDead());
TextureClientRecycleAllocatorImp* recycleAllocator = static_cast<TextureClientRecycleAllocatorImp*>(aClosure);
recycleAllocator->RecycleCallbackImp(aClient);
}
TextureClientRecycleAllocator::TextureClientRecycleAllocator(ISurfaceAllocator *aAllocator)
{
mAllocator = new TextureClientRecycleAllocatorImp(aAllocator);
}
TextureClientRecycleAllocator::~TextureClientRecycleAllocator()
{
mAllocator->Destroy();
mAllocator = nullptr;
}
void
TextureClientRecycleAllocator::SetMaxPoolSize(uint32_t aMax)
{
mAllocator->SetMaxPoolSize(aMax);
}
already_AddRefed<TextureClient>
TextureClientRecycleAllocator::CreateOrRecycleForDrawing(
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
gfx::BackendType aMoz2DBackend,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags)
{
return mAllocator->CreateOrRecycleForDrawing(aFormat,
aSize,
aMoz2DBackend,
aTextureFlags,
aAllocFlags);
}
} // namespace layers
} // namespace mozilla