michael@0: /* vim: set ts=2 sw=2 et tw=80: */ 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 "ImageBridgeParent.h" michael@0: #include // for uint64_t, uint32_t michael@0: #include "CompositableHost.h" // for CompositableParent, Create michael@0: #include "base/message_loop.h" // for MessageLoop michael@0: #include "base/process.h" // for ProcessHandle michael@0: #include "base/process_util.h" // for OpenProcessHandle michael@0: #include "base/task.h" // for CancelableTask, DeleteTask, etc michael@0: #include "base/tracked.h" // for FROM_HERE michael@0: #include "mozilla/gfx/Point.h" // for IntSize michael@0: #include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc michael@0: #include "mozilla/ipc/ProtocolUtils.h" michael@0: #include "mozilla/ipc/Transport.h" // for Transport michael@0: #include "mozilla/layers/CompositableTransactionParent.h" michael@0: #include "mozilla/layers/CompositorParent.h" // for CompositorParent michael@0: #include "mozilla/layers/LayerManagerComposite.h" michael@0: #include "mozilla/layers/LayersMessages.h" // for EditReply michael@0: #include "mozilla/layers/LayersSurfaces.h" // for PGrallocBufferParent michael@0: #include "mozilla/layers/PCompositableParent.h" michael@0: #include "mozilla/layers/PImageBridgeParent.h" michael@0: #include "mozilla/layers/Compositor.h" michael@0: #include "mozilla/mozalloc.h" // for operator new, etc michael@0: #include "nsAutoPtr.h" // for nsRefPtr michael@0: #include "nsDebug.h" // for NS_RUNTIMEABORT, etc michael@0: #include "nsISupportsImpl.h" // for ImageBridgeParent::Release, etc michael@0: #include "nsTArray.h" // for nsTArray, nsTArray_Impl michael@0: #include "nsTArrayForwardDeclare.h" // for InfallibleTArray michael@0: #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop michael@0: #include "mozilla/layers/TextureHost.h" michael@0: #include "nsThreadUtils.h" michael@0: michael@0: using namespace mozilla::ipc; michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: class PGrallocBufferParent; michael@0: michael@0: ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport) michael@0: : mMessageLoop(aLoop) michael@0: , mTransport(aTransport) michael@0: { michael@0: // creates the map only if it has not been created already, so it is safe michael@0: // with several bridges michael@0: CompositableMap::Create(); michael@0: } michael@0: michael@0: ImageBridgeParent::~ImageBridgeParent() michael@0: { michael@0: if (mTransport) { michael@0: XRE_GetIOMessageLoop()->PostTask(FROM_HERE, michael@0: new DeleteTask(mTransport)); michael@0: } michael@0: } michael@0: michael@0: LayersBackend michael@0: ImageBridgeParent::GetCompositorBackendType() const michael@0: { michael@0: return Compositor::GetBackend(); michael@0: } michael@0: michael@0: void michael@0: ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) michael@0: { michael@0: MessageLoop::current()->PostTask( michael@0: FROM_HERE, michael@0: NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy)); michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeParent::RecvUpdate(const EditArray& aEdits, EditReplyArray* aReply) michael@0: { michael@0: // If we don't actually have a compositor, then don't bother michael@0: // creating any textures. michael@0: if (Compositor::GetBackend() == LayersBackend::LAYERS_NONE) { michael@0: return true; michael@0: } michael@0: michael@0: // Clear fence handles used in previsou transaction. michael@0: ClearPrevFenceHandles(); michael@0: michael@0: EditReplyVector replyv; michael@0: for (EditArray::index_type i = 0; i < aEdits.Length(); ++i) { michael@0: if (!ReceiveCompositableUpdate(aEdits[i], replyv)) { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: aReply->SetCapacity(replyv.size()); michael@0: if (replyv.size() > 0) { michael@0: aReply->AppendElements(&replyv.front(), replyv.size()); michael@0: } michael@0: michael@0: // Ensure that any pending operations involving back and front michael@0: // buffers have completed, so that neither process stomps on the michael@0: // other's buffer contents. michael@0: LayerManagerComposite::PlatformSyncBeforeReplyUpdate(); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeParent::RecvUpdateNoSwap(const EditArray& aEdits) michael@0: { michael@0: InfallibleTArray noReplies; michael@0: bool success = RecvUpdate(aEdits, &noReplies); michael@0: NS_ABORT_IF_FALSE(noReplies.Length() == 0, "RecvUpdateNoSwap requires a sync Update to carry Edits"); michael@0: return success; michael@0: } michael@0: michael@0: static void michael@0: ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge, michael@0: Transport* aTransport, michael@0: base::ProcessHandle aOtherProcess) michael@0: { michael@0: aBridge->Open(aTransport, aOtherProcess, XRE_GetIOMessageLoop(), ipc::ParentSide); michael@0: } michael@0: michael@0: /*static*/ PImageBridgeParent* michael@0: ImageBridgeParent::Create(Transport* aTransport, ProcessId aOtherProcess) michael@0: { michael@0: base::ProcessHandle processHandle; michael@0: if (!base::OpenProcessHandle(aOtherProcess, &processHandle)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: MessageLoop* loop = CompositorParent::CompositorLoop(); michael@0: nsRefPtr bridge = new ImageBridgeParent(loop, aTransport); michael@0: bridge->mSelfRef = bridge; michael@0: loop->PostTask(FROM_HERE, michael@0: NewRunnableFunction(ConnectImageBridgeInParentProcess, michael@0: bridge.get(), aTransport, processHandle)); michael@0: return bridge.get(); michael@0: } michael@0: michael@0: bool ImageBridgeParent::RecvWillStop() michael@0: { michael@0: // If there is any texture still alive we have to force it to deallocate the michael@0: // device data (GL textures, etc.) now because shortly after SenStop() returns michael@0: // on the child side the widget will be destroyed along with it's associated michael@0: // GL context. michael@0: InfallibleTArray textures; michael@0: ManagedPTextureParent(textures); michael@0: for (unsigned int i = 0; i < textures.Length(); ++i) { michael@0: RefPtr tex = TextureHost::AsTextureHost(textures[i]); michael@0: tex->DeallocateDeviceData(); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool ImageBridgeParent::RecvStop() michael@0: { michael@0: // Nothing to do. This message just serves as synchronization between the michael@0: // child and parent threads during shutdown. michael@0: return true; michael@0: } michael@0: michael@0: static uint64_t GenImageContainerID() { michael@0: static uint64_t sNextImageID = 1; michael@0: michael@0: ++sNextImageID; michael@0: return sNextImageID; michael@0: } michael@0: michael@0: PGrallocBufferParent* michael@0: ImageBridgeParent::AllocPGrallocBufferParent(const IntSize& aSize, michael@0: const uint32_t& aFormat, michael@0: const uint32_t& aUsage, michael@0: MaybeMagicGrallocBufferHandle* aOutHandle) michael@0: { michael@0: #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC michael@0: return GrallocBufferActor::Create(aSize, aFormat, aUsage, aOutHandle); 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: ImageBridgeParent::DeallocPGrallocBufferParent(PGrallocBufferParent* 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: PCompositableParent* michael@0: ImageBridgeParent::AllocPCompositableParent(const TextureInfo& aInfo, michael@0: uint64_t* aID) michael@0: { michael@0: uint64_t id = GenImageContainerID(); michael@0: *aID = id; michael@0: return CompositableHost::CreateIPDLActor(this, aInfo, id); michael@0: } michael@0: michael@0: bool ImageBridgeParent::DeallocPCompositableParent(PCompositableParent* aActor) michael@0: { michael@0: return CompositableHost::DestroyIPDLActor(aActor); michael@0: } michael@0: michael@0: PTextureParent* michael@0: ImageBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, michael@0: const TextureFlags& aFlags) michael@0: { michael@0: return TextureHost::CreateIPDLActor(this, aSharedData, aFlags); michael@0: } michael@0: michael@0: bool michael@0: ImageBridgeParent::DeallocPTextureParent(PTextureParent* actor) michael@0: { michael@0: return TextureHost::DestroyIPDLActor(actor); michael@0: } michael@0: michael@0: MessageLoop * ImageBridgeParent::GetMessageLoop() { michael@0: return mMessageLoop; michael@0: } michael@0: michael@0: class ReleaseRunnable : public nsRunnable michael@0: { michael@0: public: michael@0: ReleaseRunnable(ImageBridgeParent* aRef) michael@0: : mRef(aRef) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHOD Run() michael@0: { michael@0: mRef->Release(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: ImageBridgeParent* mRef; michael@0: }; michael@0: michael@0: void michael@0: ImageBridgeParent::DeferredDestroy() michael@0: { michael@0: ImageBridgeParent* self; michael@0: mSelfRef.forget(&self); michael@0: michael@0: nsCOMPtr runnable = new ReleaseRunnable(self); michael@0: MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); michael@0: } michael@0: michael@0: IToplevelProtocol* michael@0: ImageBridgeParent::CloneToplevel(const InfallibleTArray& aFds, michael@0: base::ProcessHandle aPeerProcess, michael@0: mozilla::ipc::ProtocolCloneContext* aCtx) michael@0: { michael@0: for (unsigned int i = 0; i < aFds.Length(); i++) { michael@0: if (aFds[i].protocolId() == unsigned(GetProtocolId())) { michael@0: Transport* transport = OpenDescriptor(aFds[i].fd(), michael@0: Transport::MODE_SERVER); michael@0: PImageBridgeParent* bridge = Create(transport, base::GetProcId(aPeerProcess)); michael@0: bridge->CloneManagees(this, aCtx); michael@0: bridge->IToplevelProtocol::SetTransport(transport); michael@0: return bridge; michael@0: } michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: bool ImageBridgeParent::IsSameProcess() const michael@0: { michael@0: return OtherProcess() == ipc::kInvalidProcessHandle; michael@0: } michael@0: michael@0: } // layers michael@0: } // mozilla