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 "ImageBridgeChild.h" michael@0: #include // for vector michael@0: #include "CompositorParent.h" // for CompositorParent michael@0: #include "ImageBridgeParent.h" // for ImageBridgeParent michael@0: #include "ImageContainer.h" // for ImageContainer michael@0: #include "Layers.h" // for Layer, etc michael@0: #include "ShadowLayers.h" // for ShadowLayerForwarder michael@0: #include "base/message_loop.h" // for MessageLoop michael@0: #include "base/platform_thread.h" // for PlatformThread michael@0: #include "base/process.h" // for ProcessHandle michael@0: #include "base/process_util.h" // for OpenProcessHandle michael@0: #include "base/task.h" // for NewRunnableFunction, etc michael@0: #include "base/thread.h" // for Thread michael@0: #include "base/tracked.h" // for FROM_HERE michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock michael@0: #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc michael@0: #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc michael@0: #include "mozilla/ipc/Transport.h" // for Transport michael@0: #include "mozilla/gfx/Point.h" // for IntSize michael@0: #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc michael@0: #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator michael@0: #include "mozilla/layers/ImageClient.h" // for ImageClient michael@0: #include "mozilla/layers/LayersMessages.h" // for CompositableOperation michael@0: #include "mozilla/layers/PCompositableChild.h" // for PCompositableChild michael@0: #include "mozilla/layers/TextureClient.h" // for TextureClient michael@0: #include "mozilla/mozalloc.h" // for operator new, etc michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc michael@0: #include "nsTArray.h" // for nsAutoTArray, nsTArray, etc michael@0: #include "nsTArrayForwardDeclare.h" // for AutoInfallibleTArray michael@0: #include "nsThreadUtils.h" // for NS_IsMainThread michael@0: #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop michael@0: #include "mozilla/StaticPtr.h" // for StaticRefPtr michael@0: #include "mozilla/layers/TextureClient.h" michael@0: michael@0: struct nsIntRect; michael@0: michael@0: using namespace base; michael@0: using namespace mozilla::ipc; michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace ipc { michael@0: class Shmem; michael@0: } michael@0: michael@0: namespace layers { michael@0: michael@0: class PGrallocBufferChild; michael@0: typedef std::vector OpVector; michael@0: michael@0: struct CompositableTransaction michael@0: { michael@0: CompositableTransaction() michael@0: : mSwapRequired(false) michael@0: , mFinished(true) michael@0: {} michael@0: ~CompositableTransaction() michael@0: { michael@0: End(); michael@0: } michael@0: bool Finished() const michael@0: { michael@0: return mFinished; michael@0: } michael@0: void Begin() michael@0: { michael@0: MOZ_ASSERT(mFinished); michael@0: mFinished = false; michael@0: } michael@0: void End() michael@0: { michael@0: mFinished = true; michael@0: mSwapRequired = false; michael@0: mOperations.clear(); michael@0: } michael@0: bool IsEmpty() const michael@0: { michael@0: return mOperations.empty(); michael@0: } michael@0: void AddNoSwapEdit(const CompositableOperation& op) michael@0: { michael@0: NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?"); michael@0: mOperations.push_back(op); michael@0: } michael@0: void AddEdit(const CompositableOperation& op) michael@0: { michael@0: AddNoSwapEdit(op); michael@0: mSwapRequired = true; michael@0: } michael@0: michael@0: OpVector mOperations; michael@0: bool mSwapRequired; michael@0: bool mFinished; michael@0: }; michael@0: michael@0: struct AutoEndTransaction { michael@0: AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {} michael@0: ~AutoEndTransaction() { mTxn->End(); } michael@0: CompositableTransaction* mTxn; michael@0: }; michael@0: michael@0: void michael@0: ImageBridgeChild::UseTexture(CompositableClient* aCompositable, michael@0: TextureClient* aTexture) michael@0: { michael@0: MOZ_ASSERT(aCompositable); michael@0: MOZ_ASSERT(aTexture); michael@0: MOZ_ASSERT(aCompositable->GetIPDLActor()); michael@0: MOZ_ASSERT(aTexture->GetIPDLActor()); michael@0: mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(), michael@0: nullptr, aTexture->GetIPDLActor())); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable, michael@0: TextureClient* aTextureOnBlack, michael@0: TextureClient* aTextureOnWhite) michael@0: { michael@0: MOZ_ASSERT(aCompositable); michael@0: MOZ_ASSERT(aTextureOnWhite); michael@0: MOZ_ASSERT(aTextureOnBlack); michael@0: MOZ_ASSERT(aCompositable->GetIPDLActor()); michael@0: MOZ_ASSERT(aTextureOnWhite->GetIPDLActor()); michael@0: MOZ_ASSERT(aTextureOnBlack->GetIPDLActor()); michael@0: MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize()); michael@0: mTxn->AddNoSwapEdit(OpUseComponentAlphaTextures(nullptr, aCompositable->GetIPDLActor(), michael@0: nullptr, aTextureOnBlack->GetIPDLActor(), michael@0: nullptr, aTextureOnWhite->GetIPDLActor())); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::UpdatedTexture(CompositableClient* aCompositable, michael@0: TextureClient* aTexture, michael@0: nsIntRegion* aRegion) michael@0: { michael@0: MOZ_ASSERT(aCompositable); michael@0: MOZ_ASSERT(aTexture); michael@0: MOZ_ASSERT(aCompositable->GetIPDLActor()); michael@0: MOZ_ASSERT(aTexture->GetIPDLActor()); michael@0: MaybeRegion region = aRegion ? MaybeRegion(*aRegion) michael@0: : MaybeRegion(null_t()); michael@0: mTxn->AddNoSwapEdit(OpUpdateTexture(nullptr, aCompositable->GetIPDLActor(), michael@0: nullptr, aTexture->GetIPDLActor(), michael@0: region)); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::UpdatePictureRect(CompositableClient* aCompositable, michael@0: const nsIntRect& aRect) michael@0: { michael@0: MOZ_ASSERT(aCompositable); michael@0: MOZ_ASSERT(aCompositable->GetIPDLActor()); michael@0: mTxn->AddNoSwapEdit(OpUpdatePictureRect(nullptr, aCompositable->GetIPDLActor(), aRect)); michael@0: } michael@0: michael@0: // Singleton michael@0: static StaticRefPtr sImageBridgeChildSingleton; michael@0: static StaticRefPtr sImageBridgeParentSingleton; michael@0: static Thread *sImageBridgeChildThread = nullptr; michael@0: michael@0: void ReleaseImageBridgeParentSingleton() { michael@0: sImageBridgeParentSingleton = nullptr; michael@0: } michael@0: michael@0: // dispatched function michael@0: static void ImageBridgeShutdownStep1(ReentrantMonitor *aBarrier, bool *aDone) michael@0: { michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: michael@0: NS_ABORT_IF_FALSE(InImageBridgeChildThread(), michael@0: "Should be in ImageBridgeChild thread."); michael@0: if (sImageBridgeChildSingleton) { michael@0: // Force all managed protocols to shut themselves down cleanly michael@0: InfallibleTArray compositables; michael@0: sImageBridgeChildSingleton->ManagedPCompositableChild(compositables); michael@0: for (int i = compositables.Length() - 1; i >= 0; --i) { michael@0: CompositableClient::FromIPDLActor(compositables[i])->Destroy(); michael@0: } michael@0: InfallibleTArray textures; michael@0: sImageBridgeChildSingleton->ManagedPTextureChild(textures); michael@0: for (int i = textures.Length() - 1; i >= 0; --i) { michael@0: TextureClient::AsTextureClient(textures[i])->ForceRemove(); michael@0: } michael@0: sImageBridgeChildSingleton->SendWillStop(); michael@0: sImageBridgeChildSingleton->MarkShutDown(); michael@0: // From now on, no message can be sent through the image bridge from the michael@0: // client side except the final Stop message. michael@0: } michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: // dispatched function michael@0: static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone) michael@0: { michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: michael@0: NS_ABORT_IF_FALSE(InImageBridgeChildThread(), michael@0: "Should be in ImageBridgeChild thread."); michael@0: michael@0: sImageBridgeChildSingleton->SendStop(); michael@0: michael@0: sImageBridgeChildSingleton = nullptr; michael@0: michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: // dispatched function michael@0: static void CreateImageClientSync(RefPtr* result, michael@0: ReentrantMonitor* barrier, michael@0: CompositableType aType, michael@0: bool *aDone) michael@0: { michael@0: ReentrantMonitorAutoEnter autoMon(*barrier); michael@0: *result = sImageBridgeChildSingleton->CreateImageClientNow(aType); michael@0: *aDone = true; michael@0: barrier->NotifyAll(); michael@0: } michael@0: michael@0: michael@0: struct GrallocParam { michael@0: IntSize size; michael@0: uint32_t format; michael@0: uint32_t usage; michael@0: MaybeMagicGrallocBufferHandle* handle; michael@0: PGrallocBufferChild** child; michael@0: michael@0: GrallocParam(const IntSize& aSize, michael@0: const uint32_t& aFormat, michael@0: const uint32_t& aUsage, michael@0: MaybeMagicGrallocBufferHandle* aHandle, michael@0: PGrallocBufferChild** aChild) michael@0: : size(aSize) michael@0: , format(aFormat) michael@0: , usage(aUsage) michael@0: , handle(aHandle) michael@0: , child(aChild) michael@0: {} michael@0: }; michael@0: michael@0: // dispatched function michael@0: static void AllocGrallocBufferSync(const GrallocParam& aParam, michael@0: Monitor* aBarrier, michael@0: bool* aDone) michael@0: { michael@0: MonitorAutoLock autoMon(*aBarrier); michael@0: michael@0: sImageBridgeChildSingleton->AllocGrallocBufferNow(aParam.size, michael@0: aParam.format, michael@0: aParam.usage, michael@0: aParam.handle, michael@0: aParam.child); michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: // dispatched function michael@0: static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * parent) michael@0: { michael@0: MessageLoop *parentMsgLoop = parent->GetMessageLoop(); michael@0: ipc::MessageChannel *parentChannel = parent->GetIPCChannel(); michael@0: child->Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide); michael@0: } michael@0: michael@0: ImageBridgeChild::ImageBridgeChild() michael@0: : mShuttingDown(false) michael@0: { michael@0: mTxn = new CompositableTransaction(); michael@0: } michael@0: ImageBridgeChild::~ImageBridgeChild() michael@0: { michael@0: delete mTxn; michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::MarkShutDown() michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: mShuttingDown = true; michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::Connect(CompositableClient* aCompositable) michael@0: { michael@0: MOZ_ASSERT(aCompositable); michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: uint64_t id = 0; michael@0: PCompositableChild* child = michael@0: SendPCompositableConstructor(aCompositable->GetTextureInfo(), &id); michael@0: MOZ_ASSERT(child); michael@0: aCompositable->InitIPDLActor(child, id); michael@0: } michael@0: michael@0: PCompositableChild* michael@0: ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo, uint64_t* aID) michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: return CompositableClient::CreateIPDLActor(); michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor) michael@0: { michael@0: return CompositableClient::DestroyIPDLActor(aActor); michael@0: } michael@0: michael@0: michael@0: Thread* ImageBridgeChild::GetThread() const michael@0: { michael@0: return sImageBridgeChildThread; michael@0: } michael@0: michael@0: ImageBridgeChild* ImageBridgeChild::GetSingleton() michael@0: { michael@0: return sImageBridgeChildSingleton; michael@0: } michael@0: michael@0: bool ImageBridgeChild::IsCreated() michael@0: { michael@0: return GetSingleton() != nullptr; michael@0: } michael@0: michael@0: void ImageBridgeChild::StartUp() michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); michael@0: ImageBridgeChild::StartUpOnThread(new Thread("ImageBridgeChild")); michael@0: } michael@0: michael@0: #ifdef MOZ_NUWA_PROCESS michael@0: #include "ipc/Nuwa.h" michael@0: #endif michael@0: michael@0: static void michael@0: ConnectImageBridgeInChildProcess(Transport* aTransport, michael@0: ProcessHandle aOtherProcess) michael@0: { michael@0: // Bind the IPC channel to the image bridge thread. michael@0: sImageBridgeChildSingleton->Open(aTransport, aOtherProcess, michael@0: XRE_GetIOMessageLoop(), michael@0: ipc::ChildSide); michael@0: #ifdef MOZ_NUWA_PROCESS michael@0: if (IsNuwaProcess()) { michael@0: sImageBridgeChildThread michael@0: ->message_loop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(NuwaMarkCurrentThread, michael@0: (void (*)(void *))nullptr, michael@0: (void *)nullptr)); michael@0: } michael@0: #endif michael@0: } michael@0: michael@0: static void ReleaseImageClientNow(ImageClient* aClient) michael@0: { michael@0: MOZ_ASSERT(InImageBridgeChildThread()); michael@0: aClient->Release(); michael@0: } michael@0: michael@0: // static michael@0: void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient) michael@0: { michael@0: if (!IsCreated()) { michael@0: // CompositableClient::Release should normally happen in the ImageBridgeChild michael@0: // thread because it usually generate some IPDL messages. michael@0: // However, if we take this branch it means that the ImageBridgeChild michael@0: // has already shut down, along with the CompositableChild, which means no michael@0: // message will be sent and it is safe to run this code from any thread. michael@0: MOZ_ASSERT(aClient->GetIPDLActor() == nullptr); michael@0: aClient->Release(); michael@0: return; michael@0: } michael@0: michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(&ReleaseImageClientNow, aClient)); michael@0: } michael@0: michael@0: static void ReleaseTextureClientNow(TextureClient* aClient) michael@0: { michael@0: MOZ_ASSERT(InImageBridgeChildThread()); michael@0: aClient->Release(); michael@0: } michael@0: michael@0: // static michael@0: void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient) michael@0: { michael@0: if (!IsCreated()) { michael@0: // TextureClient::Release should normally happen in the ImageBridgeChild michael@0: // thread because it usually generate some IPDL messages. michael@0: // However, if we take this branch it means that the ImageBridgeChild michael@0: // has already shut down, along with the TextureChild, which means no michael@0: // message will be sent and it is safe to run this code from any thread. michael@0: MOZ_ASSERT(aClient->GetIPDLActor() == nullptr); michael@0: aClient->Release(); michael@0: return; michael@0: } michael@0: michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(&ReleaseTextureClientNow, aClient)); michael@0: } michael@0: michael@0: static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContainer) michael@0: { michael@0: MOZ_ASSERT(aClient); michael@0: MOZ_ASSERT(aContainer); michael@0: sImageBridgeChildSingleton->BeginTransaction(); michael@0: aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE); michael@0: aClient->OnTransaction(); michael@0: sImageBridgeChildSingleton->EndTransaction(); michael@0: } michael@0: michael@0: //static michael@0: void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, michael@0: ImageContainer* aContainer) michael@0: { michael@0: if (!IsCreated()) { michael@0: return; michael@0: } michael@0: michael@0: if (InImageBridgeChildThread()) { michael@0: UpdateImageClientNow(aClient, aContainer); michael@0: return; michael@0: } michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction< michael@0: void (*)(ImageClient*, ImageContainer*), michael@0: ImageClient*, michael@0: nsRefPtr >(&UpdateImageClientNow, aClient, aContainer)); michael@0: } michael@0: michael@0: static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront, ReentrantMonitor* aBarrier, bool* aDone) michael@0: { michael@0: ImageBridgeChild::FlushAllImagesNow(aClient, aContainer, aExceptFront); michael@0: michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: //static michael@0: void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront) michael@0: { michael@0: if (!IsCreated()) { michael@0: return; michael@0: } michael@0: michael@0: MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); michael@0: michael@0: if (InImageBridgeChildThread()) { michael@0: FlushAllImagesNow(aClient, aContainer, aExceptFront); michael@0: return; michael@0: } michael@0: michael@0: ReentrantMonitor barrier("CreateImageClient Lock"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: bool done = false; michael@0: michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(&FlushAllImagesSync, aClient, aContainer, aExceptFront, &barrier, &done)); michael@0: michael@0: // should stop the thread until the ImageClient has been created on michael@0: // the other thread michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: } michael@0: michael@0: //static michael@0: void ImageBridgeChild::FlushAllImagesNow(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront) michael@0: { michael@0: MOZ_ASSERT(aClient); michael@0: sImageBridgeChildSingleton->BeginTransaction(); michael@0: if (aContainer && !aExceptFront) { michael@0: aContainer->ClearCurrentImage(); michael@0: } michael@0: aClient->FlushAllImages(aExceptFront); michael@0: aClient->OnTransaction(); michael@0: sImageBridgeChildSingleton->EndTransaction(); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::BeginTransaction() michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?"); michael@0: mTxn->Begin(); michael@0: } michael@0: michael@0: class MOZ_STACK_CLASS AutoRemoveTextures michael@0: { michael@0: public: michael@0: AutoRemoveTextures(ImageBridgeChild* aImageBridge) michael@0: : mImageBridge(aImageBridge) {} michael@0: michael@0: ~AutoRemoveTextures() michael@0: { michael@0: mImageBridge->RemoveTexturesIfNecessary(); michael@0: } michael@0: private: michael@0: ImageBridgeChild* mImageBridge; michael@0: }; michael@0: michael@0: void michael@0: ImageBridgeChild::EndTransaction() michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?"); michael@0: michael@0: AutoEndTransaction _(mTxn); michael@0: AutoRemoveTextures autoRemoveTextures(this); michael@0: michael@0: if (mTxn->IsEmpty()) { michael@0: return; michael@0: } michael@0: michael@0: AutoInfallibleTArray cset; michael@0: cset.SetCapacity(mTxn->mOperations.size()); michael@0: if (!mTxn->mOperations.empty()) { michael@0: cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size()); michael@0: } michael@0: ShadowLayerForwarder::PlatformSyncBeforeUpdate(); michael@0: michael@0: AutoInfallibleTArray replies; michael@0: michael@0: if (mTxn->mSwapRequired) { michael@0: if (!SendUpdate(cset, &replies)) { michael@0: NS_WARNING("could not send async texture transaction"); michael@0: return; michael@0: } michael@0: } else { michael@0: // If we don't require a swap we can call SendUpdateNoSwap which michael@0: // assumes that aReplies is empty (DEBUG assertion) michael@0: if (!SendUpdateNoSwap(cset)) { michael@0: NS_WARNING("could not send async texture transaction (no swap)"); michael@0: return; michael@0: } michael@0: } michael@0: for (nsTArray::size_type i = 0; i < replies.Length(); ++i) { michael@0: const EditReply& reply = replies[i]; michael@0: switch (reply.type()) { michael@0: case EditReply::TOpTextureSwap: { michael@0: const OpTextureSwap& ots = reply.get_OpTextureSwap(); michael@0: michael@0: CompositableClient* compositable = michael@0: CompositableClient::FromIPDLActor(ots.compositableChild()); michael@0: michael@0: MOZ_ASSERT(compositable); michael@0: michael@0: compositable->SetDescriptorFromReply(ots.textureId(), ots.image()); michael@0: break; michael@0: } michael@0: case EditReply::TReturnReleaseFence: { michael@0: const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence(); michael@0: FenceHandle fence = rep.fence(); michael@0: PTextureChild* child = rep.textureChild(); michael@0: michael@0: if (!fence.IsValid() || !child) { michael@0: break; michael@0: } michael@0: RefPtr texture = TextureClient::AsTextureClient(child); michael@0: if (texture) { michael@0: texture->SetReleaseFenceHandle(fence); michael@0: } michael@0: break; michael@0: } michael@0: default: michael@0: NS_RUNTIMEABORT("not reached"); michael@0: } michael@0: } michael@0: } michael@0: michael@0: michael@0: PImageBridgeChild* michael@0: ImageBridgeChild::StartUpInChildProcess(Transport* aTransport, michael@0: ProcessId aOtherProcess) michael@0: { michael@0: NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!"); michael@0: michael@0: ProcessHandle processHandle; michael@0: if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: sImageBridgeChildThread = new Thread("ImageBridgeChild"); michael@0: if (!sImageBridgeChildThread->Start()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: sImageBridgeChildSingleton = new ImageBridgeChild(); michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(ConnectImageBridgeInChildProcess, michael@0: aTransport, processHandle)); michael@0: michael@0: return sImageBridgeChildSingleton; michael@0: } michael@0: michael@0: void ImageBridgeChild::ShutDown() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); michael@0: if (ImageBridgeChild::IsCreated()) { michael@0: MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); michael@0: michael@0: { michael@0: ReentrantMonitor barrier("ImageBridge ShutdownStep1 lock"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: michael@0: bool done = false; michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(&ImageBridgeShutdownStep1, &barrier, &done)); michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: } michael@0: michael@0: { michael@0: ReentrantMonitor barrier("ImageBridge ShutdownStep2 lock"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: michael@0: bool done = false; michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(&ImageBridgeShutdownStep2, &barrier, &done)); michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: } michael@0: michael@0: delete sImageBridgeChildThread; michael@0: sImageBridgeChildThread = nullptr; michael@0: } michael@0: } michael@0: michael@0: bool ImageBridgeChild::StartUpOnThread(Thread* aThread) michael@0: { michael@0: NS_ABORT_IF_FALSE(aThread, "ImageBridge needs a thread."); michael@0: if (sImageBridgeChildSingleton == nullptr) { michael@0: sImageBridgeChildThread = aThread; michael@0: if (!aThread->IsRunning()) { michael@0: aThread->Start(); michael@0: } michael@0: sImageBridgeChildSingleton = new ImageBridgeChild(); michael@0: sImageBridgeParentSingleton = new ImageBridgeParent( michael@0: CompositorParent::CompositorLoop(), nullptr); michael@0: sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton); michael@0: return true; michael@0: } else { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool InImageBridgeChildThread() michael@0: { michael@0: return sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId(); michael@0: } michael@0: michael@0: MessageLoop * ImageBridgeChild::GetMessageLoop() const michael@0: { michael@0: return sImageBridgeChildThread->message_loop(); michael@0: } michael@0: michael@0: void ImageBridgeChild::ConnectAsync(ImageBridgeParent* aParent) michael@0: { michael@0: GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&ConnectImageBridge, michael@0: this, aParent)); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier) michael@0: { michael@0: if (sImageBridgeChildSingleton) { michael@0: sImageBridgeChildSingleton->IdentifyTextureHost(aIdentifier); michael@0: } michael@0: } michael@0: michael@0: TemporaryRef michael@0: ImageBridgeChild::CreateImageClient(CompositableType aType) michael@0: { michael@0: if (InImageBridgeChildThread()) { michael@0: return CreateImageClientNow(aType); michael@0: } michael@0: ReentrantMonitor barrier("CreateImageClient Lock"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: bool done = false; michael@0: michael@0: RefPtr result = nullptr; michael@0: GetMessageLoop()->PostTask(FROM_HERE, NewRunnableFunction(&CreateImageClientSync, michael@0: &result, &barrier, aType, &done)); michael@0: // should stop the thread until the ImageClient has been created on michael@0: // the other thread michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: return result.forget(); michael@0: } michael@0: michael@0: TemporaryRef michael@0: ImageBridgeChild::CreateImageClientNow(CompositableType aType) michael@0: { michael@0: MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); michael@0: RefPtr client michael@0: = ImageClient::CreateImageClient(aType, this, 0); michael@0: MOZ_ASSERT(client, "failed to create ImageClient"); michael@0: if (client) { michael@0: client->Connect(); michael@0: } michael@0: return client.forget(); michael@0: } michael@0: michael@0: PGrallocBufferChild* michael@0: ImageBridgeChild::AllocPGrallocBufferChild(const IntSize&, const uint32_t&, const uint32_t&, michael@0: MaybeMagicGrallocBufferHandle*) michael@0: { michael@0: #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC michael@0: return GrallocBufferActor::Create(); michael@0: #else michael@0: NS_RUNTIMEABORT("No gralloc buffers for you"); michael@0: return nullptr; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeChild::DeallocPGrallocBufferChild(PGrallocBufferChild* actor) michael@0: { michael@0: #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC michael@0: delete actor; michael@0: return true; michael@0: #else michael@0: NS_RUNTIMEABORT("Um, how did we get here?"); michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeChild::AllocUnsafeShmem(size_t aSize, michael@0: ipc::SharedMemory::SharedMemoryType aType, michael@0: ipc::Shmem* aShmem) michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: if (InImageBridgeChildThread()) { michael@0: return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem); michael@0: } else { michael@0: return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe michael@0: } michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeChild::AllocShmem(size_t aSize, michael@0: ipc::SharedMemory::SharedMemoryType aType, michael@0: ipc::Shmem* aShmem) michael@0: { michael@0: if (InImageBridgeChildThread()) { michael@0: return PImageBridgeChild::AllocShmem(aSize, aType, aShmem); michael@0: } else { michael@0: return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe michael@0: } michael@0: } michael@0: michael@0: // NewRunnableFunction accepts a limited number of parameters so we need a michael@0: // struct here michael@0: struct AllocShmemParams { michael@0: RefPtr mAllocator; michael@0: size_t mSize; michael@0: ipc::SharedMemory::SharedMemoryType mType; michael@0: ipc::Shmem* mShmem; michael@0: bool mUnsafe; michael@0: bool mSuccess; michael@0: }; michael@0: michael@0: static void ProxyAllocShmemNow(AllocShmemParams* aParams, michael@0: ReentrantMonitor* aBarrier, michael@0: bool* aDone) michael@0: { michael@0: MOZ_ASSERT(aParams); michael@0: MOZ_ASSERT(aDone); michael@0: MOZ_ASSERT(aBarrier); michael@0: michael@0: if (aParams->mUnsafe) { michael@0: aParams->mSuccess = aParams->mAllocator->AllocUnsafeShmem(aParams->mSize, michael@0: aParams->mType, michael@0: aParams->mShmem); michael@0: } else { michael@0: aParams->mSuccess = aParams->mAllocator->AllocShmem(aParams->mSize, michael@0: aParams->mType, michael@0: aParams->mShmem); michael@0: } michael@0: michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize, michael@0: SharedMemory::SharedMemoryType aType, michael@0: ipc::Shmem* aShmem, michael@0: bool aUnsafe) michael@0: { michael@0: ReentrantMonitor barrier("AllocatorProxy alloc"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: michael@0: AllocShmemParams params = { michael@0: this, aSize, aType, aShmem, aUnsafe, true michael@0: }; michael@0: bool done = false; michael@0: michael@0: GetMessageLoop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(&ProxyAllocShmemNow, michael@0: ¶ms, michael@0: &barrier, michael@0: &done)); michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: return params.mSuccess; michael@0: } michael@0: michael@0: static void ProxyDeallocShmemNow(ISurfaceAllocator* aAllocator, michael@0: ipc::Shmem* aShmem, michael@0: ReentrantMonitor* aBarrier, michael@0: bool* aDone) michael@0: { michael@0: MOZ_ASSERT(aShmem); michael@0: MOZ_ASSERT(aDone); michael@0: MOZ_ASSERT(aBarrier); michael@0: michael@0: aAllocator->DeallocShmem(*aShmem); michael@0: michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem) michael@0: { michael@0: if (InImageBridgeChildThread()) { michael@0: PImageBridgeChild::DeallocShmem(aShmem); michael@0: } else { michael@0: ReentrantMonitor barrier("AllocatorProxy Dealloc"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: michael@0: bool done = false; michael@0: GetMessageLoop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(&ProxyDeallocShmemNow, michael@0: this, michael@0: &aShmem, michael@0: &barrier, michael@0: &done)); michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: PGrallocBufferChild* michael@0: ImageBridgeChild::AllocGrallocBuffer(const IntSize& aSize, michael@0: uint32_t aFormat, michael@0: uint32_t aUsage, michael@0: MaybeMagicGrallocBufferHandle* aHandle) michael@0: { michael@0: if (InImageBridgeChildThread()) { michael@0: PGrallocBufferChild* child = nullptr; michael@0: ImageBridgeChild::AllocGrallocBufferNow(aSize, aFormat, aUsage, aHandle, &child); michael@0: return child; michael@0: } michael@0: michael@0: Monitor barrier("AllocGrallocBuffer Lock"); michael@0: MonitorAutoLock autoMon(barrier); michael@0: bool done = false; michael@0: PGrallocBufferChild* child = nullptr; michael@0: michael@0: GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(&AllocGrallocBufferSync, michael@0: GrallocParam(aSize, aFormat, aUsage, aHandle, &child), &barrier, &done)); michael@0: michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: michael@0: return child; michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::AllocGrallocBufferNow(const gfx::IntSize& aSize, michael@0: uint32_t aFormat, uint32_t aUsage, michael@0: MaybeMagicGrallocBufferHandle* aHandle, michael@0: PGrallocBufferChild** aChild) michael@0: { michael@0: #ifdef MOZ_WIDGET_GONK michael@0: *aChild = SendPGrallocBufferConstructor(aSize, michael@0: aFormat, michael@0: aUsage, michael@0: aHandle); michael@0: #else michael@0: NS_RUNTIMEABORT("not implemented"); michael@0: aChild = nullptr; michael@0: #endif michael@0: } michael@0: michael@0: static void ProxyDeallocGrallocBufferNow(ISurfaceAllocator* aAllocator, michael@0: PGrallocBufferChild* aChild, michael@0: ReentrantMonitor* aBarrier, michael@0: bool* aDone) michael@0: { michael@0: MOZ_ASSERT(aChild); michael@0: MOZ_ASSERT(aDone); michael@0: MOZ_ASSERT(aBarrier); michael@0: michael@0: #ifdef MOZ_WIDGET_GONK michael@0: PGrallocBufferChild::Send__delete__(aChild); michael@0: #else michael@0: NS_RUNTIMEABORT("not implemented"); michael@0: #endif michael@0: michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::DeallocGrallocBuffer(PGrallocBufferChild* aChild) michael@0: { michael@0: MOZ_ASSERT(aChild); michael@0: if (InImageBridgeChildThread()) { michael@0: #ifdef MOZ_WIDGET_GONK michael@0: PGrallocBufferChild::Send__delete__(aChild); michael@0: #else michael@0: NS_RUNTIMEABORT("not implemented"); michael@0: #endif michael@0: } else { michael@0: ReentrantMonitor barrier("AllocatorProxy Dealloc"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: michael@0: bool done = false; michael@0: GetMessageLoop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(&ProxyDeallocGrallocBufferNow, michael@0: this, michael@0: aChild, michael@0: &barrier, michael@0: &done)); michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: PTextureChild* michael@0: ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&, michael@0: const TextureFlags&) michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: return TextureClient::CreateIPDLActor(); michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor) michael@0: { michael@0: return TextureClient::DestroyIPDLActor(actor); michael@0: } michael@0: michael@0: PTextureChild* michael@0: ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, michael@0: TextureFlags aFlags) michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: return SendPTextureConstructor(aSharedData, aFlags); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable, michael@0: TextureClient* aTexture) michael@0: { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: if (aTexture->GetFlags() & TEXTURE_DEALLOCATE_CLIENT) { michael@0: mTxn->AddEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), michael@0: nullptr, aTexture->GetIPDLActor())); michael@0: } else { michael@0: mTxn->AddNoSwapEdit(OpRemoveTexture(nullptr, aCompositable->GetIPDLActor(), michael@0: nullptr, aTexture->GetIPDLActor())); michael@0: } michael@0: // Hold texture until transaction complete. michael@0: HoldUntilTransaction(aTexture); michael@0: } michael@0: michael@0: static void RemoveTextureSync(TextureClient* aTexture, ReentrantMonitor* aBarrier, bool* aDone) michael@0: { michael@0: aTexture->ForceRemove(); michael@0: michael@0: ReentrantMonitorAutoEnter autoMon(*aBarrier); michael@0: *aDone = true; michael@0: aBarrier->NotifyAll(); michael@0: } michael@0: michael@0: void ImageBridgeChild::RemoveTexture(TextureClient* aTexture) michael@0: { michael@0: if (InImageBridgeChildThread()) { michael@0: MOZ_ASSERT(!mShuttingDown); michael@0: aTexture->ForceRemove(); michael@0: return; michael@0: } michael@0: michael@0: ReentrantMonitor barrier("RemoveTexture Lock"); michael@0: ReentrantMonitorAutoEnter autoMon(barrier); michael@0: bool done = false; michael@0: michael@0: sImageBridgeChildSingleton->GetMessageLoop()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableFunction(&RemoveTextureSync, aTexture, &barrier, &done)); michael@0: michael@0: // should stop the thread until the ImageClient has been created on michael@0: // the other thread michael@0: while (!done) { michael@0: barrier.Wait(); michael@0: } michael@0: } michael@0: michael@0: bool ImageBridgeChild::IsSameProcess() const michael@0: { michael@0: return OtherProcess() == ipc::kInvalidProcessHandle; michael@0: } michael@0: michael@0: } // layers michael@0: } // mozilla