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