Bug 1200595 - Consolidate the TextureClient's destruction logic. r=mattwoodrow

This commit is contained in:
Nicolas Silva 2015-11-20 14:25:03 +01:00
parent c12c0c1984
commit 8278de119c
23 changed files with 317 additions and 390 deletions

View File

@ -279,7 +279,6 @@ SharedSurface_Gralloc::WaitForBufferOwnership()
bool
SharedSurface_Gralloc::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
{
mTextureClient->MarkShared();
return mTextureClient->ToSurfaceDescriptor(*out_descriptor);
}

View File

@ -149,7 +149,7 @@ AsyncCanvasRenderer::CopyFromTextureClient(TextureClient* aTextureClient)
{
MutexAutoLock lock(mMutex);
TextureClientAutoLock texLock(aTextureClient, layers::OpenMode::OPEN_READ);
if (texLock.Succeeded()) {
if (!texLock.Succeeded()) {
return;
}

View File

@ -51,19 +51,21 @@ enum class TextureFlags : uint32_t {
// deallocation.
// The default behaviour is to deallocate on the host side.
DEALLOCATE_CLIENT = 1 << 6,
DEALLOCATE_SYNC = 1 << 6, // XXX - make it a separate flag.
DEALLOCATE_MAIN_THREAD = 1 << 8,
// After being shared ith the compositor side, an immutable texture is never
// modified, it can only be read. It is safe to not Lock/Unlock immutable
// textures.
IMMUTABLE = 1 << 7,
IMMUTABLE = 1 << 9,
// The contents of the texture must be uploaded or copied immediately
// during the transaction, because the producer may want to write
// to it again.
IMMEDIATE_UPLOAD = 1 << 8,
IMMEDIATE_UPLOAD = 1 << 10,
// The texture is part of a component-alpha pair
COMPONENT_ALPHA = 1 << 9,
COMPONENT_ALPHA = 1 << 11,
// OR union of all valid bits
ALL_BITS = (1 << 10) - 1,
ALL_BITS = (1 << 12) - 1,
// the default flags
DEFAULT = NO_FLAGS
};

View File

@ -21,17 +21,6 @@ using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
already_AddRefed<TextureClient>
CreateX11TextureClient(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureFlags aFlags, ISurfaceAllocator* aAllocator)
{
TextureData* data = X11TextureData::Create(aSize, aFormat, aFlags, aAllocator);
if (!data) {
return nullptr;
}
return MakeAndAddRef<TextureClient>(data, aFlags, aAllocator);
}
X11TextureData::X11TextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
bool aClientDeallocation, bool aIsCrossProcess,
gfxXlibSurface* aSurface)

View File

@ -56,10 +56,6 @@ protected:
bool mIsCrossProcess;
};
already_AddRefed<TextureClient>
CreateX11TextureClient(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureFlags aFlags, ISurfaceAllocator* aAllocator);
} // namespace layers
} // namespace mozilla

View File

@ -67,17 +67,17 @@ using namespace mozilla::ipc;
using namespace mozilla::gl;
using namespace mozilla::gfx;
struct ReleaseKeepAlive : public nsRunnable
struct TextureDeallocParams
{
NS_IMETHOD Run()
{
mKeep = nullptr;
return NS_OK;
}
UniquePtr<KeepAlive> mKeep;
TextureData* data;
RefPtr<TextureChild> actor;
RefPtr<ISurfaceAllocator> allocator;
bool clientDeallocation;
bool syncDeallocation;
};
void DeallocateTextureClient(TextureDeallocParams params);
/**
* TextureChild is the content-side incarnation of the PTexture IPDL actor.
*
@ -93,11 +93,8 @@ class TextureChild final : public ChildActor<PTextureChild>
{
~TextureChild()
{
if (mKeep && mMainThreadOnly && !NS_IsMainThread()) {
RefPtr<ReleaseKeepAlive> release = new ReleaseKeepAlive();
release->mKeep = Move(mKeep);
NS_DispatchToMainThread(release);
}
// We should have deallocated mTextureData in ActorDestroy
MOZ_ASSERT(!mTextureData);
}
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(TextureChild)
@ -106,13 +103,14 @@ public:
: mForwarder(nullptr)
, mMonitor("TextureChild")
, mTextureClient(nullptr)
, mTextureData(nullptr)
, mDestroyed(false)
, mMainThreadOnly(false)
, mIPCOpen(false)
{
}
, mOwnsTextureData(false)
{}
bool Recv__delete__() override;
bool Recv__delete__() override { return true; }
bool RecvCompositorRecycle() override
{
@ -168,41 +166,191 @@ private:
// Monitor protecting mTextureClient.
Monitor mMonitor;
TextureClient* mTextureClient;
UniquePtr<KeepAlive> mKeep;
TextureData* mTextureData;
Atomic<bool> mDestroyed;
bool mMainThreadOnly;
bool mIPCOpen;
bool mOwnsTextureData;
friend class TextureClient;
friend void DeallocateTextureClient(TextureDeallocParams params);
};
bool
TextureChild::Recv__delete__()
static void DestroyTextureData(TextureData* aTextureData, ISurfaceAllocator* aAllocator,
bool aDeallocate, bool aMainThreadOnly)
{
return true;
MOZ_ASSERT(aTextureData);
if (!aTextureData) {
return;
}
if (aMainThreadOnly && !NS_IsMainThread()) {
RefPtr<ISurfaceAllocator> allocatorRef = aAllocator;
NS_DispatchToMainThread(NS_NewRunnableFunction([aTextureData, allocatorRef, aDeallocate]() -> void {
DestroyTextureData(aTextureData, allocatorRef, aDeallocate, true);
}));
return;
}
if (aDeallocate) {
aTextureData->Deallocate(aAllocator);
} else {
aTextureData->Forget(aAllocator);
}
delete aTextureData;
}
void
TextureChild::ActorDestroy(ActorDestroyReason why)
{
if (mTextureClient) {
mTextureClient->mActor = nullptr;
mTextureClient->mAllocator = nullptr;
}
mWaitForRecycle = nullptr;
mKeep = nullptr;
if (mTextureData) {
DestroyTextureData(mTextureData, GetAllocator(), mOwnsTextureData, mMainThreadOnly);
mTextureData = nullptr;
}
}
void DeallocateTextureClientSyncProxy(TextureDeallocParams params,
ReentrantMonitor* aBarrier, bool* aDone)
{
DeallocateTextureClient(params);
ReentrantMonitorAutoEnter autoMon(*aBarrier);
*aDone = true;
aBarrier->NotifyAll();
}
/// The logic for synchronizing a TextureClient's deallocation goes here.
///
/// This funciton takes care of dispatching work to the right thread using
/// a synchronous proxy if needed, and handles client/host deallocation.
void
DeallocateTextureClient(TextureDeallocParams params)
{
TextureChild* actor = params.actor;
MessageLoop* ipdlMsgLoop = nullptr;
if (params.allocator) {
ipdlMsgLoop = params.allocator->GetMessageLoop();
if (!ipdlMsgLoop) {
// An allocator with no message loop means we are too late in the shutdown
// sequence.
gfxCriticalError() << "Texture deallocated too late during shutdown";
return;
}
}
// First make sure that the work is happening on the IPDL thread.
if (ipdlMsgLoop && MessageLoop::current() != ipdlMsgLoop) {
if (params.syncDeallocation) {
bool done = false;
ReentrantMonitor barrier("DeallocateTextureClient");
ReentrantMonitorAutoEnter autoMon(barrier);
ipdlMsgLoop->PostTask(FROM_HERE,
NewRunnableFunction(DeallocateTextureClientSyncProxy,
params, &barrier, &done));
while (!done) {
barrier.Wait();
}
} else {
ipdlMsgLoop->PostTask(FROM_HERE,
NewRunnableFunction(DeallocateTextureClient, params));
}
// The work has been forwarded to the IPDL thread, we are done.
return;
}
// Below this line, we are either in the IPDL thread or ther is no IPDL
// thread anymore.
if (!ipdlMsgLoop) {
// If we don't have a message loop we can't know for sure that we are in
// the IPDL thread and use the ISurfaceAllocator.
// This should ideally not happen outside of gtest, but some shutdown raciness
// could put us in this situation.
params.allocator = nullptr;
}
if (!actor) {
// We don't have an IPDL actor, probably because we destroyed the TextureClient
// before sharing it with the compositor. It means the data cannot be owned by
// the TextureHost since we never created the TextureHost.
DestroyTextureData(params.data, params.allocator,
true, // client-side deallocation
false); // main-thread deallocation
return;
}
if (!actor->IPCOpen()) {
// The actor is already deallocated which probably means there was a shutdown
// race causing this function to be called concurrently which is bad!
gfxCriticalError() << "Racy texture deallocation";
return;
}
if (params.syncDeallocation) {
MOZ_PERFORMANCE_WARNING("gfx",
"TextureClient/Host pair requires synchronous deallocation");
actor->DestroySynchronously();
DestroyTextureData(params.data, params.allocator, params.clientDeallocation,
actor->mMainThreadOnly);
} else {
actor->mTextureData = params.data;
actor->mOwnsTextureData = params.clientDeallocation;
actor->Destroy();
// DestroyTextureData will be called by TextureChild::ActorDestroy
}
}
void TextureClient::Destroy(bool aForceSync)
{
MOZ_ASSERT(!IsLocked());
RefPtr<TextureChild> actor = mActor;
mActor = nullptr;
if (actor && !actor->mDestroyed.compareExchange(false, true)) {
actor = nullptr;
}
TextureData* data = mData;
if (!mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
mData = nullptr;
}
if (data || actor) {
TextureDeallocParams params;
params.actor = actor;
params.allocator = mAllocator;
params.clientDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT);
if (mWorkaroundAnnoyingSharedSurfaceLifetimeIssues) {
params.data = nullptr;
} else {
params.data = data;
}
// At the moment we always deallocate synchronously when deallocating on the
// client side, but having asynchronous deallocate in some of the cases will
// be a worthwhile optimization.
params.syncDeallocation = !!(mFlags & TextureFlags::DEALLOCATE_CLIENT) || aForceSync;
DeallocateTextureClient(params);
}
}
bool
TextureClient::Lock(OpenMode aMode)
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
MOZ_ASSERT(!mIsLocked);
if (mIsLocked) {
return mOpenMode == aMode;
}
if (mRemoveFromCompositableWaiter) {
mRemoveFromCompositableWaiter->WaitComplete();
mRemoveFromCompositableWaiter = nullptr;
}
mIsLocked = mData->Lock(aMode, mReleaseFenceHandle.IsValid() ? &mReleaseFenceHandle : nullptr);
mOpenMode = aMode;
@ -212,7 +360,7 @@ TextureClient::Lock(OpenMode aMode)
void
TextureClient::Unlock()
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mIsLocked);
if (!mIsLocked) {
return;
@ -241,44 +389,33 @@ TextureClient::Unlock()
bool
TextureClient::HasInternalBuffer() const
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
return mData->HasInternalBuffer();
}
gfx::IntSize
TextureClient::GetSize() const
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
return mData->GetSize();
}
gfx::SurfaceFormat
TextureClient::GetFormat() const
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
return mData->GetFormat();
}
TextureClient::~TextureClient()
{
if (ShouldDeallocateInDestructor()) {
mData->Deallocate(mAllocator);
} else {
mData->Forget(mAllocator);
}
delete mData;
}
void
TextureClient::FinalizeOnIPDLThread()
{
mData->FinalizeOnIPDLThread(this);
Destroy(false);
}
void
TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mIsLocked);
MOZ_ASSERT(aSurface);
@ -308,7 +445,7 @@ TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface)
already_AddRefed<TextureClient>
TextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
TextureData* data = mData->CreateSimilar(mAllocator, aFlags, aAllocFlags);
if (!data) {
return nullptr;
@ -320,7 +457,7 @@ TextureClient::CreateSimilar(TextureFlags aFlags, TextureAllocationFlags aAllocF
gfx::DrawTarget*
TextureClient::BorrowDrawTarget()
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mIsLocked);
// TODO- We can't really assert that at the moment because there is code that Borrows
// the DrawTarget, just to get a snapshot, which is legit in term of OpenMode
@ -348,7 +485,7 @@ TextureClient::BorrowDrawTarget()
bool
TextureClient::BorrowMappedData(MappedTextureData& aMap)
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
// TODO - SharedRGBImage just accesses the buffer without properly locking
// the texture. It's bad.
@ -363,14 +500,14 @@ TextureClient::BorrowMappedData(MappedTextureData& aMap)
bool
TextureClient::BorrowMappedYCbCrData(MappedYCbCrTextureData& aMap)
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
return mData->BorrowMappedYCbCrData(aMap);
}
bool
TextureClient::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
{
MOZ_ASSERT(mValid);
MOZ_ASSERT(IsValid());
return mData->Serialize(aOutDescriptor);
}
@ -382,10 +519,12 @@ TextureClient::WaitForBufferOwnership(bool aWaitReleaseFence)
mRemoveFromCompositableWaiter = nullptr;
}
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21
if (aWaitReleaseFence && mReleaseFenceHandle.IsValid()) {
mData->WaitForFence(&mReleaseFenceHandle);
mReleaseFenceHandle = FenceHandle();
}
#endif
}
// static
@ -409,12 +548,20 @@ TextureClient::DestroyIPDLActor(PTextureChild* actor)
TextureClient*
TextureClient::AsTextureClient(PTextureChild* actor)
{
return actor ? static_cast<TextureChild*>(actor)->mTextureClient : nullptr;
if (!actor) {
return nullptr;
}
TextureChild* tc = static_cast<TextureChild*>(actor);
if (tc->mDestroyed) {
return nullptr;
}
return tc->mTextureClient;
}
bool
TextureClient::IsSharedWithCompositor() const {
return mShared && mActor && mActor->IPCOpen();
return mActor && mActor->IPCOpen();
}
void
@ -423,7 +570,7 @@ TextureClient::AddFlags(TextureFlags aFlags)
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags |= aFlags;
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -434,7 +581,7 @@ TextureClient::RemoveFlags(TextureFlags aFlags)
MOZ_ASSERT(!IsSharedWithCompositor() ||
((GetFlags() & TextureFlags::RECYCLE) && !IsAddedToCompositableClient()));
mFlags &= ~aFlags;
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -447,7 +594,7 @@ TextureClient::RecycleTexture(TextureFlags aFlags)
mAddedToCompositableClient = false;
if (mFlags != aFlags) {
mFlags = aFlags;
if (mValid && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
if (IsValid() && mActor && !mActor->mDestroyed && mActor->IPCOpen()) {
mActor->SendRecycleTexture(mFlags);
}
}
@ -503,7 +650,7 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
MOZ_ASSERT(mActor);
mActor->mForwarder = aForwarder;
mActor->mTextureClient = this;
mShared = true;
mActor->mMainThreadOnly = !!(mFlags & TextureFlags::DEALLOCATE_MAIN_THREAD);
return mActor->IPCOpen();
}
@ -548,7 +695,7 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
LayersBackend parentBackend = aAllocator->GetCompositorBackendType();
gfx::BackendType moz2DBackend = BackendTypeForBackendSelector(parentBackend, aSelector);
RefPtr<TextureClient> texture;
TextureData* data = nullptr;
#if defined(XP_WIN)
int32_t maxTextureSize = aAllocator->GetMaxTextureSize();
@ -561,33 +708,23 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize)
{
texture = CreateDXGITextureClient(aSize, aFormat, aTextureFlags, aAllocFlags, aAllocator);
if (texture) {
return texture.forget();
}
data = DXGITextureData::Create(aSize, aFormat, aAllocFlags);
}
if (parentBackend == LayersBackend::LAYERS_D3D9 &&
moz2DBackend == gfx::BackendType::CAIRO &&
aAllocator->IsSameProcess() &&
aSize.width <= maxTextureSize &&
aSize.height <= maxTextureSize &&
NS_IsMainThread()) {
if (gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
TextureData* data = D3D9TextureData::Create(aSize, aFormat, aAllocFlags);
if (data) {
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
}
}
NS_IsMainThread() &&
gfxWindowsPlatform::GetPlatform()->GetD3D9Device()) {
data = D3D9TextureData::Create(aSize, aFormat, aAllocFlags);
}
if (!texture && aFormat == SurfaceFormat::B8G8R8X8 &&
if (!data && aFormat == SurfaceFormat::B8G8R8X8 &&
aAllocator->IsSameProcess() &&
moz2DBackend == gfx::BackendType::CAIRO &&
NS_IsMainThread()) {
TextureData* data = DIBTextureData::Create(aSize, aFormat, aAllocator);
if (data) {
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
}
data = DIBTextureData::Create(aSize, aFormat, aAllocator);
}
#endif
@ -595,37 +732,34 @@ TextureClient::CreateForDrawing(CompositableForwarder* aAllocator,
gfxSurfaceType type =
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
if (parentBackend == LayersBackend::LAYERS_BASIC &&
if (!data && parentBackend == LayersBackend::LAYERS_BASIC &&
moz2DBackend == gfx::BackendType::CAIRO &&
type == gfxSurfaceType::Xlib)
{
texture = CreateX11TextureClient(aSize, aFormat, aTextureFlags, aAllocator);
if (texture) {
return texture.forget();
}
data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
}
#ifdef GL_PROVIDER_GLX
if (parentBackend == LayersBackend::LAYERS_OPENGL &&
if (!data && parentBackend == LayersBackend::LAYERS_OPENGL &&
type == gfxSurfaceType::Xlib &&
aFormat != SurfaceFormat::A8 &&
gl::sGLXLibrary.UseTextureFromPixmap())
{
texture = CreateX11TextureClient(aSize, aFormat, aTextureFlags, aAllocator);
if (texture) {
return texture.forget();
}
data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
}
#endif
#endif
#ifdef MOZ_WIDGET_GONK
texture = CreateGrallocTextureClientForDrawing(aSize, aFormat, moz2DBackend,
aTextureFlags, aAllocator);
if (texture) {
return texture.forget();
if (!data) {
data = GrallocTextureData::CreateForDrawing(aSize, aFormat, moz2DBackend,
aAllocator);
}
#endif
if (data) {
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
}
// Can't do any better than a buffer texture client.
return TextureClient::CreateForRawBufferAccess(aAllocator, aFormat, aSize,
moz2DBackend, aTextureFlags, aAllocFlags);
@ -645,6 +779,10 @@ TextureClient::CreateForRawBufferAccess(ISurfaceAllocator* aAllocator,
return nullptr;
}
if (aAllocFlags & ALLOC_DISALLOW_BUFFERTEXTURECLIENT) {
return nullptr;
}
if (!gfx::Factory::AllowedSurfaceSize(aSize)) {
return nullptr;
}
@ -717,39 +855,13 @@ TextureClient::TextureClient(TextureData* aData, TextureFlags aFlags, ISurfaceAl
, mExpectedDtRefs(0)
#endif
, mIsLocked(false)
, mShared(false)
, mValid(true)
, mAddedToCompositableClient(false)
, mWorkaroundAnnoyingSharedSurfaceLifetimeIssues(false)
#ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL
, mPoolTracker(nullptr)
#endif
{}
void
TextureClient::KeepUntilFullDeallocation(UniquePtr<KeepAlive> aKeep, bool aMainThreadOnly)
{
MOZ_ASSERT(mActor);
MOZ_ASSERT(!mActor->mKeep);
mActor->mKeep = Move(aKeep);
mActor->mMainThreadOnly = aMainThreadOnly;
}
void TextureClient::ForceRemove(bool sync)
{
if (mActor && mActor->mDestroyed) {
mActor = nullptr;
}
if (mValid && mActor) {
FinalizeOnIPDLThread();
if (mActor->CanSend()) {
if (sync || GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
mActor->DestroySynchronously();
} else {
mActor->Destroy();
}
}
}
MarkInvalid();
mFlags |= mData->GetTextureFlags();
}
bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
@ -782,45 +894,6 @@ bool TextureClient::CopyToTextureClient(TextureClient* aTarget,
return true;
}
void
TextureClient::Finalize()
{
MOZ_ASSERT(!IsLocked());
// Always make a temporary strong reference to the actor before we use it,
// in case TextureChild::ActorDestroy might null mActor concurrently.
RefPtr<TextureChild> actor = mActor;
if (actor) {
if (actor->mDestroyed) {
actor = nullptr;
return;
}
// The actor has a raw pointer to us, actor->mTextureClient.
// Null it before RemoveTexture calls to avoid invalid actor->mTextureClient
// when calling TextureChild::ActorDestroy()
actor->SetTextureClient(nullptr);
// `actor->mWaitForRecycle` may not be null, as we may be being called from setting
// this RefPtr to null! Clearing it here will double-Release() it.
// this will call ForceRemove in the right thread, using a sync proxy if needed
if (actor->GetForwarder()) {
actor->GetForwarder()->RemoveTexture(this);
}
}
}
bool
TextureClient::ShouldDeallocateInDestructor() const
{
// If we're meant to be deallocated by the host,
// but we haven't been shared yet or
// TextureFlags::DEALLOCATE_CLIENT is set, then we should
// deallocate on the client instead.
return !mShared || (GetFlags() & TextureFlags::DEALLOCATE_CLIENT);
}
void
TextureClient::SetRemoveFromCompositableWaiter(AsyncTransactionWaiter* aWaiter) {
mRemoveFromCompositableWaiter = aWaiter;

View File

@ -214,8 +214,7 @@ public:
virtual void SyncWithObject(SyncObject* aFence) {};
/// Needed until the destruction sequence of TextureClient is revamped.
virtual void FinalizeOnIPDLThread(TextureClient*) {}
virtual TextureFlags GetTextureFlags() const { return TextureFlags::NO_FLAGS; }
};
/**
@ -383,7 +382,7 @@ public:
* to be used appropriately since the latter are also there to map/numap data.
*/
bool HasSynchronization() const { return false; }
/**
* Indicates whether the TextureClient implementation is backed by an
* in-memory buffer. The consequence of this is that locking the
@ -448,13 +447,11 @@ public:
bool IsSharedWithCompositor() const;
bool ShouldDeallocateInDestructor() const;
/**
* If this method returns false users of TextureClient are not allowed
* to access the shared data.
*/
bool IsValid() const { return mValid; }
bool IsValid() const { return !!mData; }
/**
* Called when TextureClient is added to CompositableClient.
@ -467,16 +464,6 @@ public:
*/
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.
* It's a temporary hack to ensure that DXGI textures don't get destroyed
* between serialization and deserialization.
*
* This must not be called off the texture's IPDL thread.
*/
void KeepUntilFullDeallocation(UniquePtr<KeepAlive> aKeep, bool aMainThreadOnly = false);
/**
* Create and init the TextureChild/Parent IPDL actor pair.
*
@ -501,7 +488,7 @@ public:
* If sync is true, the destruction will be synchronous regardless of the
* texture's flags (bad for performance, use with care).
*/
void ForceRemove(bool sync = false);
void Destroy(bool sync = false);
virtual void SetReleaseFenceHandle(const FenceHandle& aReleaseFenceHandle)
{
@ -532,6 +519,9 @@ public:
/**
* This function waits until the buffer is no longer being used.
*
* XXX - Ideally we shouldn't need this method because Lock the right
* thing already.
*/
virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true);
@ -554,8 +544,6 @@ public:
void SyncWithObject(SyncObject* aFence) { mData->SyncWithObject(aFence); }
void MarkShared() { mShared = true; }
ISurfaceAllocator* GetAllocator() { return mAllocator; }
TextureClientRecycleAllocator* GetRecycleAllocator() { return mRecycleAllocator; }
@ -575,23 +563,11 @@ private:
* Here goes the shut-down code that uses virtual methods.
* Must only be called by Release().
*/
B2G_ACL_EXPORT void Finalize();
/**
* Called once during the destruction of the texture on the IPDL thread, if
* the texture is shared on the compositor (otherwise it is not called at all).
*/
void FinalizeOnIPDLThread();
B2G_ACL_EXPORT void Finalize() {}
friend class AtomicRefCountedWithFinalize<TextureClient>;
friend class gl::SharedSurface_Gralloc;
protected:
/**
* An invalid TextureClient cannot provide access to its shared data
* anymore. This usually means it will soon be destroyed.
*/
void MarkInvalid() { mValid = false; }
/**
* Should only be called *once* per texture, in TextureClient::InitIPDLActor.
* Some texture implementations rely on the fact that the descriptor will be
@ -620,9 +596,8 @@ protected:
DebugOnly<uint32_t> mExpectedDtRefs;
bool mIsLocked;
bool mShared;
bool mValid;
bool mAddedToCompositableClient;
bool mWorkaroundAnnoyingSharedSurfaceLifetimeIssues;
RefPtr<TextureReadbackSink> mReadbackSink;

View File

@ -52,7 +52,9 @@ SharedSurfaceTextureClient::SharedSurfaceTextureClient(SharedSurfaceTextureData*
TextureFlags aFlags,
ISurfaceAllocator* aAllocator)
: TextureClient(aData, aFlags, aAllocator)
{}
{
mWorkaroundAnnoyingSharedSurfaceLifetimeIssues = true;
}
already_AddRefed<SharedSurfaceTextureClient>
SharedSurfaceTextureClient::Create(UniquePtr<gl::SharedSurface> surf, gl::SurfaceFactory* factory,
@ -127,5 +129,29 @@ SharedSurfaceTextureClient::GetAcquireFenceHandle() const
return TextureClient::GetAcquireFenceHandle();
}
SharedSurfaceTextureClient::~SharedSurfaceTextureClient()
{
// XXX - Things break when using the proper destruction handshake with
// SharedSurfaceTextureData because the TextureData outlives its gl
// context. Having a strong reference to the gl context creates a cycle.
// This needs to be fixed in a better way, though, because deleting
// the TextureData here can race with the compositor and cause flashing.
TextureData* data = mData;
mData = nullptr;
Destroy();
if (data) {
// Destroy mData right away without doing the proper deallocation handshake,
// because SharedSurface depends on things that may not outlive the texture's
// destructor so we can't wait until we know the compositor isn't using the
// texture anymore.
// It goes without saying that this is really bad and we should fix the bugs
// that block doing the right thing such as bug 1224199 sooner rather than
// later.
delete data;
}
}
} // namespace layers
} // namespace mozilla

View File

@ -66,6 +66,8 @@ public:
TextureFlags aFlags,
ISurfaceAllocator* aAllocator);
~SharedSurfaceTextureClient();
static already_AddRefed<SharedSurfaceTextureClient>
Create(UniquePtr<gl::SharedSurface> surf, gl::SurfaceFactory* factory,
ISurfaceAllocator* aAllocator, TextureFlags aFlags);

View File

@ -433,19 +433,6 @@ DXGITextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationF
}
}
already_AddRefed<TextureClient>
CreateDXGITextureClient(IntSize aSize, SurfaceFormat aFormat,
TextureFlags aTextureFlags, TextureAllocationFlags aAllocFlags,
ISurfaceAllocator* aAllocator)
{
TextureData* data = DXGITextureData::Create(aSize, aFormat, aAllocFlags);
if (!data) {
return nullptr;
}
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);
}
DXGITextureData*
D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat, TextureAllocationFlags aFlags,
ID3D11Device* aDevice)
@ -654,26 +641,6 @@ DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor)
return true;
}
class YCbCrKeepAliveD3D11 : public KeepAlive
{
public:
YCbCrKeepAliveD3D11(RefPtr<IUnknown> aTextures[3])
{
mTextures[0] = aTextures[0];
mTextures[1] = aTextures[1];
mTextures[2] = aTextures[2];
}
protected:
RefPtr<IUnknown> mTextures[3];
};
void
DXGIYCbCrTextureData::FinalizeOnIPDLThread(TextureClient* aWrapper)
{
aWrapper->KeepUntilFullDeallocation(MakeUnique<YCbCrKeepAliveD3D11>(mHoldRefs));
}
void
DXGIYCbCrTextureData::Deallocate(ISurfaceAllocator*)
{
@ -812,18 +779,6 @@ D3D10TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface)
return true;
}
void
D3D11TextureData::FinalizeOnIPDLThread(TextureClient* aWrapper)
{
aWrapper->KeepUntilFullDeallocation(MakeUnique<TKeepAlive<ID3D11Texture2D>>(mTexture));
}
void
D3D10TextureData::FinalizeOnIPDLThread(TextureClient* aWrapper)
{
aWrapper->KeepUntilFullDeallocation(MakeUnique<TKeepAlive<ID3D10Texture2D>>(mTexture));
}
DXGITextureHostD3D11::DXGITextureHostD3D11(TextureFlags aFlags,
const SurfaceDescriptorD3D10& aDescriptor)
: TextureHost(aFlags)

View File

@ -55,11 +55,6 @@ protected:
bool mHasSynchronization;
};
already_AddRefed<TextureClient>
CreateDXGITextureClient(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureFlags atextureFlags, TextureAllocationFlags aFlags,
ISurfaceAllocator* aAllocator);
class D3D11TextureData : public DXGITextureData
{
public:
@ -95,8 +90,6 @@ protected:
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
bool aNeedsClear, bool aNeedsClearWhite);
virtual void FinalizeOnIPDLThread(TextureClient* aWrapper) override;
virtual void GetDXGIResource(IDXGIResource** aOutResource) override;
RefPtr<ID3D11Texture2D> mTexture;
@ -141,8 +134,6 @@ protected:
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
bool aNeedsClear, bool aNeedsClearWhite);
virtual void FinalizeOnIPDLThread(TextureClient*) override;
virtual void GetDXGIResource(IDXGIResource** aOutResource) override;
RefPtr<ID3D10Texture2D> mTexture;
@ -201,9 +192,12 @@ public:
virtual bool UpdateFromSurface(gfx::SourceSurface*) override { return false; }
protected:
virtual void FinalizeOnIPDLThread(TextureClient*) override;
virtual TextureFlags GetTextureFlags() const override
{
return TextureFlags::DEALLOCATE_MAIN_THREAD;
}
protected:
RefPtr<IUnknown> mHoldRefs[3];
HANDLE mHandles[3];
gfx::IntSize mSize;
@ -421,9 +415,9 @@ class SyncObjectD3D11 : public SyncObject
{
public:
SyncObjectD3D11(SyncHandle aSyncHandle);
virtual void FinalizeFrame();
virtual SyncType GetSyncType() { return SyncType::D3D11; }
virtual void FinalizeFrame();
void RegisterTexture(ID3D11Texture2D* aTexture);
void RegisterTexture(ID3D10Texture2D* aTexture);

View File

@ -487,14 +487,6 @@ D3D9TextureData::CreateSimilar(ISurfaceAllocator*, TextureFlags aFlags, TextureA
return D3D9TextureData::Create(mSize, mFormat, aAllocFlags);
}
void
D3D9TextureData::FinalizeOnIPDLThread(TextureClient* aWrapper)
{
if (mTexture) {
aWrapper->KeepUntilFullDeallocation(MakeUnique<TKeepAlive<IDirect3DTexture9>>(mTexture));
}
}
bool
D3D9TextureData::Lock(OpenMode aMode, FenceHandle*)
{

View File

@ -209,8 +209,6 @@ public:
virtual void Deallocate(ISurfaceAllocator* aAllocator) {}
protected:
virtual void FinalizeOnIPDLThread(TextureClient* aWrapper) override;
D3D9TextureData(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
IDirect3DTexture9* aTexture);

View File

@ -107,12 +107,6 @@ public:
CompositableClient* aCompositable,
TextureClient* aTexture) {}
/**
* Tell the compositor side to delete the TextureHost corresponding to the
* TextureClient passed in parameter.
*/
virtual void RemoveTexture(TextureClient* aTexture) = 0;
/**
* Holds a reference to a TextureClient until after the next
* compositor transaction, and then drops it.

View File

@ -198,7 +198,7 @@ static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone)
for (int i = textures.Length() - 1; i >= 0; --i) {
RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
if (client) {
client->ForceRemove();
client->Destroy();
}
}
sImageBridgeChildSingleton->SendWillStop();
@ -766,7 +766,7 @@ bool InImageBridgeChildThread()
MessageLoop * ImageBridgeChild::GetMessageLoop() const
{
return sImageBridgeChildThread->message_loop();
return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr;
}
void ImageBridgeChild::ConnectAsync(ImageBridgeParent* aParent)
@ -1130,38 +1130,6 @@ ImageBridgeChild::RemoveTextureFromCompositableAsync(AsyncTransactionTracker* aA
aAsyncTransactionTracker);
}
static void RemoveTextureSync(TextureClient* aTexture, ReentrantMonitor* aBarrier, bool* aDone)
{
aTexture->ForceRemove();
ReentrantMonitorAutoEnter autoMon(*aBarrier);
*aDone = true;
aBarrier->NotifyAll();
}
void ImageBridgeChild::RemoveTexture(TextureClient* aTexture)
{
if (InImageBridgeChildThread()) {
MOZ_ASSERT(!mShuttingDown);
aTexture->ForceRemove();
return;
}
ReentrantMonitor barrier("RemoveTexture Lock");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&RemoveTextureSync, aTexture, &barrier, &done));
// should stop the thread until the ImageClient has been created on
// the other thread
while (!done) {
barrier.Wait();
}
}
bool ImageBridgeChild::IsSameProcess() const
{
return OtherPid() == base::GetCurrentProcId();

View File

@ -259,8 +259,6 @@ public:
CompositableClient* aCompositable,
TextureClient* aTexture) override;
virtual void RemoveTexture(TextureClient* aTexture) override;
virtual void UseTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) override
{

View File

@ -40,7 +40,7 @@ LayerTransactionChild::Destroy()
for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) {
TextureClient* texture = TextureClient::AsTextureClient(iter.Get()->GetKey());
if (texture) {
texture->ForceRemove();
texture->Destroy();
}
}

View File

@ -470,38 +470,6 @@ ShadowLayerForwarder::InWorkerThread()
return MessageLoop::current() && (GetMessageLoop()->id() == MessageLoop::current()->id());
}
static void RemoveTextureWorker(TextureClient* aTexture, ReentrantMonitor* aBarrier, bool* aDone)
{
aTexture->ForceRemove();
ReentrantMonitorAutoEnter autoMon(*aBarrier);
*aDone = true;
aBarrier->NotifyAll();
}
void
ShadowLayerForwarder::RemoveTexture(TextureClient* aTexture)
{
MOZ_ASSERT(aTexture);
if (InWorkerThread()) {
aTexture->ForceRemove();
return;
}
ReentrantMonitor barrier("ShadowLayerForwarder::RemoveTexture Lock");
ReentrantMonitorAutoEnter autoMon(barrier);
bool done = false;
GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&RemoveTextureWorker, aTexture, &barrier, &done));
// Wait until the TextureClient has been ForceRemoved on the worker thread
while (!done) {
barrier.Wait();
}
}
void
ShadowLayerForwarder::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>&
aConfigurations)

View File

@ -221,8 +221,6 @@ public:
CompositableClient* aCompositable,
TextureClient* aTexture) override;
virtual void RemoveTexture(TextureClient* aTexture) override;
/**
* Communicate to the compositor that aRegion in the texture identified by aLayer
* and aIdentifier has been updated to aThebesBuffer.

View File

@ -118,7 +118,11 @@ GrallocTextureData::~GrallocTextureData()
void
GrallocTextureData::Deallocate(ISurfaceAllocator* aAllocator)
{
aAllocator->DeallocGrallocBuffer(&mGrallocHandle);
MOZ_ASSERT(aAllocator);
if (aAllocator) {
aAllocator->DeallocGrallocBuffer(&mGrallocHandle);
}
mGrallocHandle = null_t();
mGraphicBuffer = nullptr;
}
@ -126,7 +130,11 @@ GrallocTextureData::Deallocate(ISurfaceAllocator* aAllocator)
void
GrallocTextureData::Forget(ISurfaceAllocator* aAllocator)
{
aAllocator->DropGrallocBuffer(&mGrallocHandle);
MOZ_ASSERT(aAllocator);
if (aAllocator) {
aAllocator->DropGrallocBuffer(&mGrallocHandle);
}
mGrallocHandle = null_t();
mGraphicBuffer = nullptr;
}
@ -142,7 +150,7 @@ void
GrallocTextureData::WaitForFence(FenceHandle* aFence)
{
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 21 && ANDROID_VERSION >= 17
if (aFence->IsValid()) {
if (aFence && aFence->IsValid()) {
RefPtr<FenceHandle::FdObj> fdObj = aFence->GetAndResetFdObj();
android::sp<Fence> fence = new Fence(fdObj->GetAndResetFd());
#if ANDROID_VERSION == 17
@ -161,8 +169,6 @@ GrallocTextureData::Lock(OpenMode aMode, FenceHandle* aReleaseFence)
{
MOZ_ASSERT(!mMappedBuffer);
WaitForFence(aReleaseFence);
uint32_t usage = 0;
if (aMode & OpenMode::OPEN_READ) {
usage |= GRALLOC_USAGE_SW_READ_OFTEN;
@ -170,20 +176,30 @@ GrallocTextureData::Lock(OpenMode aMode, FenceHandle* aReleaseFence)
if (aMode & OpenMode::OPEN_WRITE) {
usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
}
void** mappedBufferPtr = reinterpret_cast<void**>(&mMappedBuffer);
int32_t rv = 0;
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
RefPtr<FenceHandle::FdObj> fdObj = aReleaseFence->GetAndResetFdObj();
int32_t rv = mGraphicBuffer->lockAsync(usage,
reinterpret_cast<void**>(&mMappedBuffer),
fdObj->GetAndResetFd());
if (aReleaseFence) {
RefPtr<FenceHandle::FdObj> fdObj = aReleaseFence->GetAndResetFdObj();
rv = mGraphicBuffer->lockAsync(usage, mappedBufferPtr,
fdObj->GetAndResetFd());
} else {
rv = mGraphicBuffer->lock(usage, mappedBufferPtr);
}
#else
int32_t rv = mGraphicBuffer->lock(usage,
reinterpret_cast<void**>(&mMappedBuffer));
// older versions of android don't have lockAsync
WaitForFence(aReleaseFence);
rv = mGraphicBuffer->lock(usage, mappedBufferPtr);
#endif
if (rv) {
mMappedBuffer = nullptr;
NS_WARNING("Couldn't lock graphic buffer");
return false;
}
return true;
}
@ -271,6 +287,9 @@ GrallocTextureData::Create(gfx::IntSize aSize, AndroidFormat aAndroidFormat,
gfx::BackendType aMoz2dBackend, uint32_t aUsage,
ISurfaceAllocator* aAllocator)
{
if (!aAllocator) {
return nullptr;
}
int32_t maxSize = aAllocator->GetMaxTextureSize();
if (aSize.width > maxSize || aSize.height > maxSize) {
return nullptr;
@ -346,23 +365,16 @@ GrallocTextureData::CreateForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFor
return data;
}
already_AddRefed<TextureClient>
CreateGrallocTextureClientForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
gfx::BackendType aMoz2dBackend,
TextureFlags aFlags,
ISurfaceAllocator* aAllocator)
TextureFlags
GrallocTextureData::GetTextureFlags() const
{
TextureData* data = GrallocTextureData::CreateForDrawing(aSize, aFormat, aMoz2dBackend,
aAllocator);
if (!data) {
return nullptr;
if (IsGrallocRBSwapped(mFormat)) {
return TextureFlags::RB_SWAPPED;
}
if (IsGrallocRBSwapped(aFormat)) {
aFlags |= TextureFlags::RB_SWAPPED;
}
return MakeAndAddRef<TextureClient>(data, aFlags, aAllocator);
return TextureFlags::NO_FLAGS;
}
// static
GrallocTextureData*
GrallocTextureData::CreateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbCrSize,

View File

@ -107,6 +107,8 @@ public:
~GrallocTextureData();
virtual TextureFlags GetTextureFlags() const override;
protected:
GrallocTextureData(MaybeMagicGrallocBufferHandle aGrallocHandle,
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
@ -128,10 +130,6 @@ protected:
gfx::SurfaceFormat SurfaceFormatForPixelFormat(android::PixelFormat aFormat);
already_AddRefed<TextureClient> CreateGrallocTextureClientForDrawing(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
gfx::BackendType aMoz2dBackend, TextureFlags aFlags,
ISurfaceAllocator* aAllocator);
} // namespace layers
} // namespace mozilla

View File

@ -18,14 +18,6 @@ MacIOSurfaceTextureData::MacIOSurfaceTextureData(MacIOSurface* aSurface)
MacIOSurfaceTextureData::~MacIOSurfaceTextureData()
{}
void
MacIOSurfaceTextureData::FinalizeOnIPDLThread(TextureClient* aWrapper)
{
if (mSurface) {
aWrapper->KeepUntilFullDeallocation(MakeUnique<TKeepAlive<MacIOSurface>>(mSurface));
}
}
// static
MacIOSurfaceTextureData*
MacIOSurfaceTextureData::Create(MacIOSurface* aSurface)

View File

@ -42,8 +42,6 @@ public:
protected:
explicit MacIOSurfaceTextureData(MacIOSurface* aSurface);
virtual void FinalizeOnIPDLThread(TextureClient* aWrapper) override;
RefPtr<MacIOSurface> mSurface;
};