Bug 897452 - Part 2 - PTexture deallocation logic - r=sotaro,bjacob

This commit is contained in:
Nicolas Silva 2013-12-11 13:05:11 -05:00
parent 01cd073429
commit d624f90dd5
24 changed files with 259 additions and 110 deletions

View File

@ -217,6 +217,7 @@ ImageContainer::ClearAllImages()
ImageBridgeChild::FlushAllImages(mImageClient, this, false);
return;
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
SetCurrentImageInternal(nullptr);
}

View File

@ -58,7 +58,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
if (mBuffer &&
(mBuffer->IsImmutable() || mBuffer->GetSize() != aSize)) {
RemoveTextureClient(mBuffer);
mBuffer->ForceRemove();
mBuffer = nullptr;
}

View File

@ -368,11 +368,6 @@ ClientLayerManager::ForwardTransaction()
->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReplyTextureRemoved: {
// XXX - The logic to remove textures is implemented in the next patch
// of the same bug (897452). They will land together.
break;
}
default:
NS_RUNTIMEABORT("not reached");

View File

@ -253,14 +253,6 @@ CompositableClient::AddTextureClient(TextureClient* aClient)
return aClient->InitIPDLActor(mForwarder);
}
void
CompositableClient::RemoveTextureClient(TextureClient* aClient)
{
MOZ_ASSERT(aClient);
mForwarder->RemoveTexture(aClient);
aClient->MarkInvalid();
}
void
CompositableClient::OnTransaction()
{

View File

@ -132,12 +132,6 @@ public:
*/
virtual bool AddTextureClient(TextureClient* aClient);
/**
* Tells the Compositor to delete the TextureHost corresponding to this
* TextureClient.
*/
virtual void RemoveTextureClient(TextureClient* aClient);
/**
* A hook for the Compositable to execute whatever it held off for next transaction.
*/

View File

@ -101,7 +101,7 @@ void
ImageClientSingle::FlushAllImages(bool aExceptFront)
{
if (!aExceptFront && mFrontBuffer) {
RemoveTextureClient(mFrontBuffer);
mFrontBuffer->ForceRemove();
mFrontBuffer = nullptr;
}
}
@ -110,11 +110,11 @@ void
ImageClientBuffered::FlushAllImages(bool aExceptFront)
{
if (!aExceptFront && mFrontBuffer) {
RemoveTextureClient(mFrontBuffer);
mFrontBuffer->ForceRemove();
mFrontBuffer = nullptr;
}
if (mBackBuffer) {
RemoveTextureClient(mBackBuffer);
mBackBuffer->ForceRemove();
mBackBuffer = nullptr;
}
}
@ -145,7 +145,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
}
if (mFrontBuffer) {
RemoveTextureClient(mFrontBuffer);
mFrontBuffer->ForceRemove();
}
mFrontBuffer = texture;
if (!AddTextureClient(texture)) {
@ -162,7 +162,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
}
if (mFrontBuffer && mFrontBuffer->IsImmutable()) {
RemoveTextureClient(mFrontBuffer);
mFrontBuffer->ForceRemove();
mFrontBuffer = nullptr;
}
@ -205,7 +205,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height);
if (mFrontBuffer) {
RemoveTextureClient(mFrontBuffer);
mFrontBuffer->ForceRemove();
mFrontBuffer = nullptr;
}
@ -226,7 +226,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer,
if (mFrontBuffer &&
(mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) {
RemoveTextureClient(mFrontBuffer);
mFrontBuffer->ForceRemove();
mFrontBuffer = nullptr;
}

View File

@ -39,12 +39,72 @@ using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
/**
* TextureChild is the content-side incarnation of the PTexture IPDL actor.
*
* TextureChild is used to synchronize a texture client and its corresponding
* TextureHost if needed (a TextureClient that is not shared with the compositor
* does not have a TextureChild)
*
* During the deallocation phase, a TextureChild may hold its recently destroyed
* TextureClient's data until the compositor side confirmed that it is safe to
* deallocte or recycle the it.
*/
class TextureChild : public PTextureChild
{
public:
TextureChild()
: mForwarder(nullptr)
, mTextureData(nullptr)
{
MOZ_COUNT_CTOR(TextureChild);
}
~TextureChild()
{
MOZ_COUNT_DTOR(TextureChild);
}
bool Recv__delete__() MOZ_OVERRIDE;
/**
* Only used during the deallocation phase iff we need synchronization between
* the client and host side for deallocation (that is, when the data is going
* to be deallocated or recycled on the client side).
*/
void SetTextureData(TextureClientData* aData)
{
mTextureData = aData;
}
void DeleteTextureData();
CompositableForwarder* GetForwarder() { return mForwarder; }
ISurfaceAllocator* GetAllocator() { return mForwarder; }
CompositableForwarder* mForwarder;
TextureClientData* mTextureData;
};
void
TextureChild::DeleteTextureData()
{
if (mTextureData) {
mTextureData->DeallocateSharedData(GetAllocator());
delete mTextureData;
mTextureData = nullptr;
}
}
bool
TextureChild::Recv__delete__()
{
DeleteTextureData();
return true;
}
// static
PTextureChild*
TextureClient::CreateIPDLActor()
@ -70,6 +130,7 @@ TextureClient::InitIPDLActor(CompositableForwarder* aForwarder)
}
mActor = static_cast<TextureChild*>(aForwarder->CreateEmptyTextureChild());
mActor->mForwarder = aForwarder;
mShared = true;
return mActor->SendInit(desc, GetFlags());
}
@ -122,6 +183,7 @@ public:
virtual void DeallocateSharedData(ISurfaceAllocator*)
{
delete[] mBuffer;
mBuffer = nullptr;
}
private:
@ -162,7 +224,33 @@ TextureClient::TextureClient(TextureFlags aFlags)
{}
TextureClient::~TextureClient()
{}
{
// All the destruction code that may lead to virtual method calls must
// be in Finalize() which is called just before the destructor.
}
void TextureClient::ForceRemove()
{
if (mValid && mActor) {
if (GetFlags() & TEXTURE_DEALLOCATE_CLIENT) {
mActor->SetTextureData(DropTextureData());
mActor->SendRemoveTextureSync();
mActor->DeleteTextureData();
} else {
mActor->SendRemoveTexture();
}
}
MarkInvalid();
}
void
TextureClient::Finalize()
{
if (mActor) {
// this will call ForceRemove in the right thread, using a sync proxy if needed
mActor->GetForwarder()->RemoveTexture(this);
}
}
bool
TextureClient::ShouldDeallocateInDestructor() const

View File

@ -113,14 +113,13 @@ public:
* host side, there is nothing to do.
* On the other hand, if the client data must be deallocated on the client
* side, the CompositableClient will ask the TextureClient to drop its shared
* data in the form of a TextureClientData object. The compositable will keep
* this object until it has received from the host side the confirmation that
* the compositor is not using the texture and that it is completely safe to
* deallocate the shared data.
* data in the form of a TextureClientData object. This data will be kept alive
* until the host side confirms that it is not using the data anymore and that
* it is completely safe to deallocate the shared data.
*
* See:
* - CompositableClient::RemoveTextureClient
* - CompositableClient::OnReplyTextureRemoved
* - The PTexture IPDL protocol
* - CompositableChild in TextureClient.cpp
*/
class TextureClientData {
public:
@ -297,6 +296,11 @@ public:
*/
PTextureChild* GetIPDLActor();
/**
* TODO[nical] doc!
*/
void ForceRemove();
private:
Atomic<int> mRefCount;
@ -306,10 +310,7 @@ private:
* Here goes the shut-down code that uses virtual methods.
* Must only be called by Release().
*/
void Finalize()
{
// XXX Bug 897452 - Coming soon
}
void Finalize();
protected:
void AddFlags(TextureFlags aFlags)

View File

@ -52,8 +52,8 @@ CompositableHost::UseTextureHost(TextureHost* aTexture)
if (!aTexture) {
return;
}
aTexture->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
aTexture->SetCompositor(GetCompositor());
aTexture->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
}

View File

@ -112,7 +112,7 @@ public:
* Our IPDL actor is being destroyed, get rid of any shmem resources now and
* don't worry about compositing anymore.
*/
virtual void OnActorDestroy();
virtual void OnActorDestroy() {};
// If base class overrides, it should still call the parent implementation
virtual void SetCompositor(Compositor* aCompositor);

View File

@ -42,15 +42,6 @@ ImageHost::UseTextureHost(TextureHost* aTexture)
mFrontBuffer = aTexture;
}
void
ImageHost::RemoveTextureHost(TextureHost* aTexture)
{
CompositableHost::RemoveTextureHost(aTexture);
if (mFrontBuffer && mFrontBuffer->GetID() == aTexture->GetID()) {
mFrontBuffer = nullptr;
}
}
TextureHost*
ImageHost::GetAsTextureHost()
{

View File

@ -55,8 +55,6 @@ public:
virtual void UseTextureHost(TextureHost* aTexture) MOZ_OVERRIDE;
virtual void RemoveTextureHost(TextureHost* aTexture) MOZ_OVERRIDE;
virtual TextureHost* GetAsTextureHost() MOZ_OVERRIDE;
virtual void SetPictureRect(const nsIntRect& aPictureRect) MOZ_OVERRIDE
@ -67,13 +65,6 @@ public:
virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
virtual void OnActorDestroy() MOZ_OVERRIDE
{
if (mFrontBuffer) {
mFrontBuffer->OnActorDestroy();
}
}
virtual void PrintInfo(nsACString& aTo, const char* aPrefix);
#ifdef MOZ_DUMP_PAINTING

View File

@ -39,6 +39,12 @@ public:
bool RecvInit(const SurfaceDescriptor& aSharedData,
const TextureFlags& aFlags) MOZ_OVERRIDE;
virtual bool RecvRemoveTexture() MOZ_OVERRIDE;
virtual bool RecvRemoveTextureSync() MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
TextureHost* GetTextureHost() { return mTextureHost; }
ISurfaceAllocator* mAllocator;
@ -577,6 +583,16 @@ ShmemTextureHost::DeallocateSharedData()
MOZ_ASSERT(mDeallocator,
"Shared memory would leak without a ISurfaceAllocator");
mDeallocator->DeallocShmem(*mShmem);
delete mShmem;
mShmem = nullptr;
}
}
void
ShmemTextureHost::ForgetSharedData()
{
if (mShmem) {
delete mShmem;
mShmem = nullptr;
}
}
@ -621,6 +637,12 @@ MemoryTextureHost::DeallocateSharedData()
mBuffer = nullptr;
}
void
MemoryTextureHost::ForgetSharedData()
{
mBuffer = nullptr;
}
uint8_t* MemoryTextureHost::GetBuffer()
{
return mBuffer;
@ -649,5 +671,46 @@ TextureParent::RecvInit(const SurfaceDescriptor& aSharedData,
return !!mTextureHost;
}
bool
TextureParent::RecvRemoveTexture()
{
return PTextureParent::Send__delete__(this);
}
bool
TextureParent::RecvRemoveTextureSync()
{
// we don't need to send a reply in the synchronous case since the child side
// has the guarantee that this message has been handled synchronously.
return PTextureParent::Send__delete__(this);
}
void
TextureParent::ActorDestroy(ActorDestroyReason why)
{
switch (why) {
case AncestorDeletion:
NS_WARNING("PTexture deleted after ancestor");
// fall-through to deletion path
case Deletion:
if (mTextureHost && mTextureHost->GetFlags() & !TEXTURE_DEALLOCATE_CLIENT) {
mTextureHost->DeallocateSharedData();
}
break;
case NormalShutdown:
case AbnormalShutdown:
if (mTextureHost) {
mTextureHost->OnActorDestroy();
}
break;
case FailedConstructor:
NS_RUNTIMEABORT("FailedConstructor isn't possible in PTexture");
}
mTextureHost->ForgetSharedData();
mTextureHost = nullptr;
}
} // namespace
} // namespace

View File

@ -332,6 +332,14 @@ public:
*/
virtual void DeallocateSharedData() {}
/**
* Should be overridden in order to force the TextureHost to drop all references
* to it's shared data.
*
* This is important to ensure the correctness of the deallocation protocol.
*/
virtual void ForgetSharedData() {}
/**
* An ID to differentiate TextureHosts of a given CompositableHost.
*
@ -502,6 +510,8 @@ public:
virtual void DeallocateSharedData() MOZ_OVERRIDE;
virtual void ForgetSharedData() MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
virtual const char *Name() MOZ_OVERRIDE { return "ShmemTextureHost"; }
@ -531,6 +541,8 @@ public:
virtual void DeallocateSharedData() MOZ_OVERRIDE;
virtual void ForgetSharedData() MOZ_OVERRIDE;
virtual uint8_t* GetBuffer() MOZ_OVERRIDE;
virtual const char *Name() MOZ_OVERRIDE { return "MemoryTextureHost"; }

View File

@ -163,11 +163,7 @@ public:
* Tell the compositor side to delete the TextureHost corresponding to the
* TextureClient passed in parameter.
*/
virtual void RemoveTexture(TextureClient* aTexture)
{
// XXX - this part is incomplete. The removing textures is implemented
// in a subsequent patch of the same bug (897452).
}
virtual void RemoveTexture(TextureClient* aTexture) = 0;
/**
* Tell the CompositableHost on the compositor side what texture to use for

View File

@ -233,30 +233,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
}
break;
}
case CompositableOperation::TOpRemoveTexture: {
const OpRemoveTexture& op = aEdit.get_OpRemoveTexture();
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(op.textureParent());
MOZ_ASSERT(texture);
TextureFlags flags = texture->GetFlags();
if (!(flags & TEXTURE_DEALLOCATE_CLIENT) &&
!(flags & TEXTURE_DEALLOCATE_DEFERRED)) {
texture->DeallocateSharedData();
}
// if it is not the host that deallocates the shared data, then we need
// to notfy the client side to tell when it is safe to deallocate or
// reuse it.
if (flags & TEXTURE_DEALLOCATE_CLIENT) {
replyv.push_back(ReplyTextureRemoved(op.callbackID()));
}
TextureHost::SendDeleteIPDLActor(op.textureParent());
break;
}
case CompositableOperation::TOpUpdateTexture: {
const OpUpdateTexture& op = aEdit.get_OpUpdateTexture();
CompositableHost* compositable = AsCompositable(op);
@ -268,9 +244,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
? &op.region().get_nsIntRegion()
: nullptr); // no region means invalidate the entire surface
compositable->UseTextureHost(texture);
break;
}

View File

@ -489,10 +489,6 @@ ImageBridgeChild::EndTransaction()
->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReplyTextureRemoved: {
// XXX - implemented in another patch of the same bug (897452).
break;
}
default:
NS_RUNTIMEABORT("not reached");
}
@ -916,5 +912,36 @@ ImageBridgeChild::CreateEmptyTextureChild()
return SendPTextureConstructor();
}
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()) {
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();
}
}
} // layers
} // mozilla

View File

@ -273,6 +273,8 @@ public:
virtual void UseTexture(CompositableClient* aCompositable,
TextureClient* aClient) MOZ_OVERRIDE;
virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
{

View File

@ -301,15 +301,6 @@ struct OpUpdatePictureRect {
nsIntRect picture;
};
/**
* Tells the compositor-side to remove the corresponding TextureHost and
* deallocate its data.
*/
struct OpRemoveTexture {
PTexture texture;
uint64_t callbackID;
};
/**
* Tells the compositor-side which texture to use (for example, as front buffer
* if there is several textures for double buffering)
@ -343,7 +334,6 @@ union CompositableOperation {
OpPaintTiledLayerBuffer;
OpRemoveTexture;
OpUpdateTexture;
OpUseTexture;
};
@ -387,17 +377,11 @@ struct OpTextureSwap {
SurfaceDescriptor image;
};
struct ReplyTextureRemoved {
uint64_t callbackID;
};
// Unit of a "changeset reply". This is a weird abstraction, probably
// only to be used for buffer swapping.
union EditReply {
OpContentBufferSwap;
OpTextureSwap;
ReplyTextureRemoved;
};
} // namespace

View File

@ -30,6 +30,16 @@ parent:
* Set the shared data and create the TextureHost on the parent side.
*/
async Init(SurfaceDescriptor aSharedData, uint32_t aTextureFlags);
/**
* Asynchronously tell the Compositor side to remove the texture.
*/
async RemoveTexture();
/**
* Synchronously tell the compositor side to remove the texture.
*/
sync RemoveTextureSync();
};
} // layers

View File

@ -433,6 +433,12 @@ ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
nullptr, aTexture->GetIPDLActor()));
}
void
ShadowLayerForwarder::RemoveTexture(TextureClient* aTexture)
{
aTexture->ForceRemove();
}
bool
ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies, bool* aSent)
{

View File

@ -279,6 +279,8 @@ public:
TextureIdentifier aTextureId,
SurfaceDescriptor* aDescriptor) MOZ_OVERRIDE;
virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE;
/**
* Same as above, but performs an asynchronous layer transaction
*/

View File

@ -95,6 +95,7 @@ GrallocTextureSourceOGL::GrallocTextureSourceOGL(CompositorOGL* aCompositor,
, mGraphicBuffer(aGraphicBuffer)
, mEGLImage(0)
, mFormat(aFormat)
, mNeedsReset(true)
{
MOZ_ASSERT(mGraphicBuffer.get());
}
@ -169,6 +170,14 @@ GrallocTextureSourceOGL::GetFormat() const {
void
GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData)
{
if (mCompositableBackendData != aBackendData) {
mNeedsReset = true;
}
if (!mNeedsReset) {
return;
}
mCompositableBackendData = aBackendData;
if (!mCompositor) {
@ -187,6 +196,7 @@ GrallocTextureSourceOGL::SetCompositableBackendSpecificData(CompositableBackendS
// create new EGLImage
mEGLImage = gl()->CreateEGLImageForNativeBuffer(mGraphicBuffer->getNativeBuffer());
gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
mNeedsReset = false;
}
gfx::IntSize
@ -273,6 +283,14 @@ GrallocTextureHostOGL::DeallocateSharedData()
PGrallocBufferParent::Send__delete__(mGrallocActor);
}
void
GrallocTextureHostOGL::ForgetSharedData()
{
if (mTextureSource) {
mTextureSource->ForgetBuffer();
}
}
void
GrallocTextureHostOGL::DeallocateDeviceData()
{

View File

@ -69,6 +69,7 @@ protected:
android::sp<android::GraphicBuffer> mGraphicBuffer;
EGLImage mEGLImage;
gfx::SurfaceFormat mFormat;
bool mNeedsReset;
};
class GrallocTextureHostOGL : public TextureHost
@ -91,6 +92,8 @@ public:
virtual void DeallocateSharedData() MOZ_OVERRIDE;
virtual void ForgetSharedData() MOZ_OVERRIDE;
virtual void DeallocateDeviceData() MOZ_OVERRIDE;
virtual gfx::SurfaceFormat GetFormat() const;