summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc/ImageBridgeChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/ipc/ImageBridgeChild.cpp')
-rw-r--r--gfx/layers/ipc/ImageBridgeChild.cpp1239
1 files changed, 1239 insertions, 0 deletions
diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp
new file mode 100644
index 000000000..0466a1031
--- /dev/null
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -0,0 +1,1239 @@
+/* -*- 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 "ImageBridgeChild.h"
+#include <vector> // for vector
+#include "ImageBridgeParent.h" // for ImageBridgeParent
+#include "ImageContainer.h" // for ImageContainer
+#include "Layers.h" // for Layer, etc
+#include "ShadowLayers.h" // for ShadowLayerForwarder
+#include "base/message_loop.h" // for MessageLoop
+#include "base/platform_thread.h" // for PlatformThread
+#include "base/process.h" // for ProcessId
+#include "base/task.h" // for NewRunnableFunction, etc
+#include "base/thread.h" // for Thread
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/Monitor.h" // for Monitor, MonitorAutoLock
+#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
+#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
+#include "mozilla/ipc/Transport.h" // for Transport
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/layers/AsyncCanvasRenderer.h"
+#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager
+#include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild
+#include "mozilla/layers/CompositableChild.h"
+#include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
+#include "mozilla/layers/ImageClient.h" // for ImageClient
+#include "mozilla/layers/ImageContainerChild.h"
+#include "mozilla/layers/LayersMessages.h" // for CompositableOperation
+#include "mozilla/layers/PCompositableChild.h" // for PCompositableChild
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/mozalloc.h" // for operator new, etc
+#include "mtransport/runnable_utils.h"
+#include "nsContentUtils.h"
+#include "nsISupportsImpl.h" // for ImageContainer::AddRef, etc
+#include "nsTArray.h" // for AutoTArray, nsTArray, etc
+#include "nsTArrayForwardDeclare.h" // for AutoTArray
+#include "nsThreadUtils.h" // for NS_IsMainThread
+#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
+#include "mozilla/StaticMutex.h"
+#include "mozilla/StaticPtr.h" // for StaticRefPtr
+#include "mozilla/layers/TextureClient.h"
+#include "SynchronousTask.h"
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+using base::Thread;
+using base::ProcessId;
+using namespace mozilla::ipc;
+using namespace mozilla::gfx;
+using namespace mozilla::media;
+
+typedef std::vector<CompositableOperation> OpVector;
+typedef nsTArray<OpDestroy> OpDestroyVector;
+
+namespace {
+class ImageBridgeThread : public Thread {
+public:
+
+ ImageBridgeThread() : Thread("ImageBridgeChild") {
+ }
+
+protected:
+
+ MOZ_IS_CLASS_INIT
+ void Init() {
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ mPseudoStackHack = mozilla_get_pseudo_stack();
+#endif
+ }
+
+ void CleanUp() {
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ mPseudoStackHack = nullptr;
+#endif
+ }
+
+private:
+
+#ifdef MOZ_ENABLE_PROFILER_SPS
+ // This is needed to avoid a spurious leak report. There's no other
+ // use for it. See bug 1239504 and bug 1215265.
+ MOZ_INIT_OUTSIDE_CTOR PseudoStack* mPseudoStackHack;
+#endif
+};
+}
+
+struct CompositableTransaction
+{
+ CompositableTransaction()
+ : mSwapRequired(false)
+ , mFinished(true)
+ {}
+ ~CompositableTransaction()
+ {
+ End();
+ }
+ bool Finished() const
+ {
+ return mFinished;
+ }
+ void Begin()
+ {
+ MOZ_ASSERT(mFinished);
+ mFinished = false;
+ }
+ void End()
+ {
+ mFinished = true;
+ mSwapRequired = false;
+ mOperations.clear();
+ mDestroyedActors.Clear();
+ }
+ bool IsEmpty() const
+ {
+ return mOperations.empty() && mDestroyedActors.IsEmpty();
+ }
+ void AddNoSwapEdit(const CompositableOperation& op)
+ {
+ MOZ_ASSERT(!Finished(), "forgot BeginTransaction?");
+ mOperations.push_back(op);
+ }
+ void AddEdit(const CompositableOperation& op)
+ {
+ AddNoSwapEdit(op);
+ MarkSyncTransaction();
+ }
+ void MarkSyncTransaction()
+ {
+ mSwapRequired = true;
+ }
+
+ OpVector mOperations;
+ OpDestroyVector mDestroyedActors;
+ bool mSwapRequired;
+ bool mFinished;
+};
+
+struct AutoEndTransaction {
+ explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
+ ~AutoEndTransaction() { mTxn->End(); }
+ CompositableTransaction* mTxn;
+};
+
+void
+ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures)
+{
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(aCompositable->GetIPDLActor());
+ MOZ_ASSERT(aCompositable->IsConnected());
+
+ AutoTArray<TimedTexture,4> textures;
+
+ for (auto& t : aTextures) {
+ MOZ_ASSERT(t.mTextureClient);
+ MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
+
+ if (!t.mTextureClient->IsSharedWithCompositor()) {
+ return;
+ }
+
+ ReadLockDescriptor readLock;
+ t.mTextureClient->SerializeReadLock(readLock);
+
+ textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
+ readLock,
+ t.mTimeStamp, t.mPictureRect,
+ t.mFrameID, t.mProducerID));
+
+ // Wait end of usage on host side if TextureFlags::RECYCLE is set or GrallocTextureData case
+ HoldUntilCompositableRefReleasedIfNecessary(t.mTextureClient);
+ }
+ mTxn->AddNoSwapEdit(CompositableOperation(nullptr, aCompositable->GetIPDLActor(),
+ OpUseTexture(textures)));
+}
+
+void
+ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
+ TextureClient* aTextureOnBlack,
+ TextureClient* aTextureOnWhite)
+{
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(aTextureOnWhite);
+ MOZ_ASSERT(aTextureOnBlack);
+ MOZ_ASSERT(aCompositable->IsConnected());
+ MOZ_ASSERT(aTextureOnWhite->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnBlack->GetIPDLActor());
+ MOZ_ASSERT(aTextureOnBlack->GetSize() == aTextureOnWhite->GetSize());
+
+ ReadLockDescriptor readLockW;
+ ReadLockDescriptor readLockB;
+ aTextureOnBlack->SerializeReadLock(readLockB);
+ aTextureOnWhite->SerializeReadLock(readLockW);
+
+ HoldUntilCompositableRefReleasedIfNecessary(aTextureOnBlack);
+ HoldUntilCompositableRefReleasedIfNecessary(aTextureOnWhite);
+
+ mTxn->AddNoSwapEdit(
+ CompositableOperation(
+ nullptr,
+ aCompositable->GetIPDLActor(),
+ OpUseComponentAlphaTextures(
+ nullptr, aTextureOnBlack->GetIPDLActor(),
+ nullptr, aTextureOnWhite->GetIPDLActor(),
+ readLockB, readLockW
+ )
+ )
+ );
+}
+
+void
+ImageBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient)
+{
+ // Wait ReleaseCompositableRef only when TextureFlags::RECYCLE is set on ImageBridge.
+ if (!aClient ||
+ !(aClient->GetFlags() & TextureFlags::RECYCLE)) {
+ return;
+ }
+ aClient->SetLastFwdTransactionId(GetFwdTransactionId());
+ mTexturesWaitingRecycled.Put(aClient->GetSerial(), aClient);
+}
+
+void
+ImageBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId)
+{
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ if (aFwdTransactionId < client->GetLastFwdTransactionId()) {
+ // Released on host side, but client already requested newer use texture.
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+void
+ImageBridgeChild::CancelWaitForRecycle(uint64_t aTextureId)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+
+ RefPtr<TextureClient> client = mTexturesWaitingRecycled.Get(aTextureId);
+ if (!client) {
+ return;
+ }
+ mTexturesWaitingRecycled.Remove(aTextureId);
+}
+
+// Singleton
+static StaticMutex sImageBridgeSingletonLock;
+static StaticRefPtr<ImageBridgeChild> sImageBridgeChildSingleton;
+static Thread *sImageBridgeChildThread = nullptr;
+
+// dispatched function
+void
+ImageBridgeChild::ShutdownStep1(SynchronousTask* aTask)
+{
+ AutoCompleteTask complete(aTask);
+
+ MOZ_ASSERT(InImageBridgeChildThread(),
+ "Should be in ImageBridgeChild thread.");
+
+ MediaSystemResourceManager::Shutdown();
+
+ // Force all managed protocols to shut themselves down cleanly
+ InfallibleTArray<PCompositableChild*> compositables;
+ ManagedPCompositableChild(compositables);
+ for (int i = compositables.Length() - 1; i >= 0; --i) {
+ auto compositable = CompositableClient::FromIPDLActor(compositables[i]);
+ if (compositable) {
+ compositable->Destroy();
+ }
+ }
+ InfallibleTArray<PTextureChild*> textures;
+ ManagedPTextureChild(textures);
+ for (int i = textures.Length() - 1; i >= 0; --i) {
+ RefPtr<TextureClient> client = TextureClient::AsTextureClient(textures[i]);
+ if (client) {
+ client->Destroy();
+ }
+ }
+
+ if (mCanSend) {
+ SendWillClose();
+ }
+ MarkShutDown();
+
+ // From now on, no message can be sent through the image bridge from the
+ // client side except the final Stop message.
+}
+
+// dispatched function
+void
+ImageBridgeChild::ShutdownStep2(SynchronousTask* aTask)
+{
+ AutoCompleteTask complete(aTask);
+
+ MOZ_ASSERT(InImageBridgeChildThread(),
+ "Should be in ImageBridgeChild thread.");
+
+ if (!mCalledClose) {
+ Close();
+ mCalledClose = true;
+ }
+}
+
+void
+ImageBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+ mCanSend = false;
+ mCalledClose = true;
+}
+
+void
+ImageBridgeChild::DeallocPImageBridgeChild()
+{
+ this->Release();
+}
+
+void
+ImageBridgeChild::CreateImageClientSync(SynchronousTask* aTask,
+ RefPtr<ImageClient>* result,
+ CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild)
+{
+ AutoCompleteTask complete(aTask);
+ *result = CreateImageClientNow(aType, aImageContainer, aContainerChild);
+}
+
+// dispatched function
+void
+ImageBridgeChild::CreateCanvasClientSync(SynchronousTask* aTask,
+ CanvasClient::CanvasClientType aType,
+ TextureFlags aFlags,
+ RefPtr<CanvasClient>* const outResult)
+{
+ AutoCompleteTask complete(aTask);
+ *outResult = CreateCanvasClientNow(aType, aFlags);
+}
+
+ImageBridgeChild::ImageBridgeChild()
+ : mCanSend(false)
+ , mCalledClose(false)
+ , mFwdTransactionId(0)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ mTxn = new CompositableTransaction();
+}
+
+ImageBridgeChild::~ImageBridgeChild()
+{
+ delete mTxn;
+}
+
+void
+ImageBridgeChild::MarkShutDown()
+{
+ mTexturesWaitingRecycled.Clear();
+
+ mCanSend = false;
+}
+
+void
+ImageBridgeChild::Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer)
+{
+ MOZ_ASSERT(aCompositable);
+ MOZ_ASSERT(InImageBridgeChildThread());
+ MOZ_ASSERT(CanSend());
+
+ uint64_t id = 0;
+
+ PImageContainerChild* imageContainerChild = nullptr;
+ if (aImageContainer)
+ imageContainerChild = aImageContainer->GetPImageContainerChild();
+
+ PCompositableChild* child =
+ SendPCompositableConstructor(aCompositable->GetTextureInfo(),
+ imageContainerChild, &id);
+ if (!child) {
+ return;
+ }
+ aCompositable->InitIPDLActor(child, id);
+}
+
+PCompositableChild*
+ImageBridgeChild::AllocPCompositableChild(const TextureInfo& aInfo,
+ PImageContainerChild* aChild, uint64_t* aID)
+{
+ MOZ_ASSERT(CanSend());
+ return AsyncCompositableChild::CreateActor();
+}
+
+bool
+ImageBridgeChild::DeallocPCompositableChild(PCompositableChild* aActor)
+{
+ AsyncCompositableChild::DestroyActor(aActor);
+ return true;
+}
+
+
+Thread* ImageBridgeChild::GetThread() const
+{
+ return sImageBridgeChildThread;
+}
+
+/* static */ RefPtr<ImageBridgeChild>
+ImageBridgeChild::GetSingleton()
+{
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ return sImageBridgeChildSingleton;
+}
+
+void
+ImageBridgeChild::ReleaseImageContainer(RefPtr<ImageContainerChild> aChild)
+{
+ if (!aChild) {
+ return;
+ }
+
+ if (!InImageBridgeChildThread()) {
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ReleaseImageContainer,
+ aChild);
+ GetMessageLoop()->PostTask(runnable.forget());
+ return;
+ }
+
+ aChild->SendAsyncDelete();
+}
+
+void
+ImageBridgeChild::ReleaseTextureClientNow(TextureClient* aClient)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+ RELEASE_MANUALLY(aClient);
+}
+
+/* static */ void
+ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
+{
+ if (!aClient) {
+ return;
+ }
+
+ RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
+ if (!imageBridge) {
+ // TextureClient::Release should normally happen in the ImageBridgeChild
+ // thread because it usually generate some IPDL messages.
+ // However, if we take this branch it means that the ImageBridgeChild
+ // has already shut down, along with the TextureChild, which means no
+ // message will be sent and it is safe to run this code from any thread.
+ MOZ_ASSERT(aClient->GetIPDLActor() == nullptr);
+ RELEASE_MANUALLY(aClient);
+ return;
+ }
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ imageBridge,
+ &ImageBridgeChild::ReleaseTextureClientNow,
+ aClient);
+ imageBridge->GetMessageLoop()->PostTask(runnable.forget());
+}
+
+void
+ImageBridgeChild::UpdateImageClient(RefPtr<ImageClient> aClient, RefPtr<ImageContainer> aContainer)
+{
+ if (!aClient || !aContainer) {
+ return;
+ }
+
+ if (!InImageBridgeChildThread()) {
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::UpdateImageClient,
+ aClient,
+ aContainer);
+ GetMessageLoop()->PostTask(runnable.forget());
+ return;
+ }
+
+ if (!CanSend()) {
+ return;
+ }
+
+ // If the client has become disconnected before this event was dispatched,
+ // early return now.
+ if (!aClient->IsConnected()) {
+ return;
+ }
+
+ BeginTransaction();
+ aClient->UpdateImage(aContainer, Layer::CONTENT_OPAQUE);
+ EndTransaction();
+}
+
+void
+ImageBridgeChild::UpdateAsyncCanvasRendererSync(SynchronousTask* aTask, AsyncCanvasRenderer* aWrapper)
+{
+ AutoCompleteTask complete(aTask);
+
+ UpdateAsyncCanvasRendererNow(aWrapper);
+}
+
+void
+ImageBridgeChild::UpdateAsyncCanvasRenderer(AsyncCanvasRenderer* aWrapper)
+{
+ aWrapper->GetCanvasClient()->UpdateAsync(aWrapper);
+
+ if (InImageBridgeChildThread()) {
+ UpdateAsyncCanvasRendererNow(aWrapper);
+ return;
+ }
+
+ SynchronousTask task("UpdateAsyncCanvasRenderer Lock");
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::UpdateAsyncCanvasRendererSync,
+ &task,
+ aWrapper);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+}
+
+void
+ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrapper)
+{
+ MOZ_ASSERT(aWrapper);
+
+ if (!CanSend()) {
+ return;
+ }
+
+ BeginTransaction();
+ aWrapper->GetCanvasClient()->Updated();
+ EndTransaction();
+}
+
+void
+ImageBridgeChild::FlushAllImagesSync(SynchronousTask* aTask,
+ ImageClient* aClient,
+ ImageContainer* aContainer)
+{
+ AutoCompleteTask complete(aTask);
+
+ if (!CanSend()) {
+ return;
+ }
+
+ MOZ_ASSERT(aClient);
+ BeginTransaction();
+ if (aContainer) {
+ aContainer->ClearImagesFromImageBridge();
+ }
+ aClient->FlushAllImages();
+ EndTransaction();
+}
+
+void
+ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer)
+{
+ MOZ_ASSERT(aClient);
+ MOZ_ASSERT(!InImageBridgeChildThread());
+
+ if (InImageBridgeChildThread()) {
+ NS_ERROR("ImageBridgeChild::FlushAllImages() is called on ImageBridge thread.");
+ return;
+ }
+
+ SynchronousTask task("FlushAllImages Lock");
+
+ // RefPtrs on arguments are not needed since this dispatches synchronously.
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::FlushAllImagesSync,
+ &task,
+ aClient,
+ aContainer);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+}
+
+void
+ImageBridgeChild::BeginTransaction()
+{
+ MOZ_ASSERT(CanSend());
+ MOZ_ASSERT(mTxn->Finished(), "uncommitted txn?");
+ UpdateFwdTransactionId();
+ mTxn->Begin();
+}
+
+void
+ImageBridgeChild::EndTransaction()
+{
+ MOZ_ASSERT(CanSend());
+ MOZ_ASSERT(!mTxn->Finished(), "forgot BeginTransaction?");
+
+ AutoEndTransaction _(mTxn);
+
+ if (mTxn->IsEmpty()) {
+ return;
+ }
+
+ AutoTArray<CompositableOperation, 10> cset;
+ cset.SetCapacity(mTxn->mOperations.size());
+ if (!mTxn->mOperations.empty()) {
+ cset.AppendElements(&mTxn->mOperations.front(), mTxn->mOperations.size());
+ }
+
+ if (!IsSameProcess()) {
+ ShadowLayerForwarder::PlatformSyncBeforeUpdate();
+ }
+
+ AutoTArray<EditReply, 10> replies;
+
+ if (mTxn->mSwapRequired) {
+ if (!SendUpdate(cset, mTxn->mDestroyedActors, GetFwdTransactionId(), &replies)) {
+ NS_WARNING("could not send async texture transaction");
+ return;
+ }
+ } else {
+ // If we don't require a swap we can call SendUpdateNoSwap which
+ // assumes that aReplies is empty (DEBUG assertion)
+ if (!SendUpdateNoSwap(cset, mTxn->mDestroyedActors, GetFwdTransactionId())) {
+ NS_WARNING("could not send async texture transaction (no swap)");
+ return;
+ }
+ }
+ for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
+ NS_RUNTIMEABORT("not reached");
+ }
+}
+
+void
+ImageBridgeChild::SendImageBridgeThreadId()
+{
+}
+
+bool
+ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ gfxPlatform::GetPlatform();
+
+ if (!sImageBridgeChildThread) {
+ sImageBridgeChildThread = new ImageBridgeThread();
+ if (!sImageBridgeChildThread->Start()) {
+ return false;
+ }
+ }
+
+ RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
+
+ RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
+ child,
+ &ImageBridgeChild::Bind,
+ Move(aEndpoint));
+ child->GetMessageLoop()->PostTask(runnable.forget());
+
+ // Assign this after so other threads can't post messages before we connect to IPDL.
+ {
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = child;
+ }
+
+ return true;
+}
+
+bool
+ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Note that at this point, ActorDestroy may not have been called yet,
+ // meaning mCanSend is still true. In this case we will try to send a
+ // synchronous WillClose message to the parent, and will certainly get a
+ // false result and a MsgDropped processing error. This is okay.
+ ShutdownSingleton();
+
+ return InitForContent(Move(aEndpoint));
+}
+
+void
+ImageBridgeChild::Bind(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ if (!aEndpoint.Bind(this)) {
+ return;
+ }
+
+ // This reference is dropped in DeallocPImageBridgeChild.
+ this->AddRef();
+
+ mCanSend = true;
+ SendImageBridgeThreadId();
+}
+
+void
+ImageBridgeChild::BindSameProcess(RefPtr<ImageBridgeParent> aParent)
+{
+ MessageLoop *parentMsgLoop = aParent->GetMessageLoop();
+ ipc::MessageChannel *parentChannel = aParent->GetIPCChannel();
+ Open(parentChannel, parentMsgLoop, mozilla::ipc::ChildSide);
+
+ // This reference is dropped in DeallocPImageBridgeChild.
+ this->AddRef();
+
+ mCanSend = true;
+ SendImageBridgeThreadId();
+}
+
+/* static */ void
+ImageBridgeChild::ShutDown()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ ShutdownSingleton();
+
+ delete sImageBridgeChildThread;
+ sImageBridgeChildThread = nullptr;
+}
+
+/* static */ void
+ImageBridgeChild::ShutdownSingleton()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
+ child->WillShutdown();
+
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = nullptr;
+ }
+}
+
+void
+ImageBridgeChild::WillShutdown()
+{
+ {
+ SynchronousTask task("ImageBridge ShutdownStep1 lock");
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ShutdownStep1,
+ &task);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+ }
+
+ {
+ SynchronousTask task("ImageBridge ShutdownStep2 lock");
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ShutdownStep2,
+ &task);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+ }
+}
+
+void
+ImageBridgeChild::InitSameProcess()
+{
+ NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
+
+ MOZ_ASSERT(!sImageBridgeChildSingleton);
+ MOZ_ASSERT(!sImageBridgeChildThread);
+
+ sImageBridgeChildThread = new ImageBridgeThread();
+ if (!sImageBridgeChildThread->IsRunning()) {
+ sImageBridgeChildThread->Start();
+ }
+
+ RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
+ RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ child,
+ &ImageBridgeChild::BindSameProcess,
+ parent);
+ child->GetMessageLoop()->PostTask(runnable.forget());
+
+ // Assign this after so other threads can't post messages before we connect to IPDL.
+ {
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = child;
+ }
+}
+
+/* static */ void
+ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ MOZ_ASSERT(!sImageBridgeChildSingleton);
+ MOZ_ASSERT(!sImageBridgeChildThread);
+
+ sImageBridgeChildThread = new ImageBridgeThread();
+ if (!sImageBridgeChildThread->IsRunning()) {
+ sImageBridgeChildThread->Start();
+ }
+
+ RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
+
+ MessageLoop* loop = child->GetMessageLoop();
+ loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
+ child, &ImageBridgeChild::Bind, Move(aEndpoint)));
+
+ // Assign this after so other threads can't post messages before we connect to IPDL.
+ {
+ StaticMutexAutoLock lock(sImageBridgeSingletonLock);
+ sImageBridgeChildSingleton = child;
+ }
+}
+
+bool InImageBridgeChildThread()
+{
+ return sImageBridgeChildThread &&
+ sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
+}
+
+MessageLoop * ImageBridgeChild::GetMessageLoop() const
+{
+ return sImageBridgeChildThread ? sImageBridgeChildThread->message_loop() : nullptr;
+}
+
+/* static */ void
+ImageBridgeChild::IdentifyCompositorTextureHost(const TextureFactoryIdentifier& aIdentifier)
+{
+ if (RefPtr<ImageBridgeChild> child = GetSingleton()) {
+ child->IdentifyTextureHost(aIdentifier);
+ }
+}
+
+RefPtr<ImageClient>
+ImageBridgeChild::CreateImageClient(CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild)
+{
+ if (InImageBridgeChildThread()) {
+ return CreateImageClientNow(aType, aImageContainer, aContainerChild);
+ }
+
+ SynchronousTask task("CreateImageClient Lock");
+
+ RefPtr<ImageClient> result = nullptr;
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::CreateImageClientSync,
+ &task,
+ &result,
+ aType,
+ aImageContainer,
+ aContainerChild);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return result;
+}
+
+RefPtr<ImageClient>
+ImageBridgeChild::CreateImageClientNow(CompositableType aType,
+ ImageContainer* aImageContainer,
+ ImageContainerChild* aContainerChild)
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+ if (!CanSend()) {
+ return nullptr;
+ }
+
+ if (aImageContainer) {
+ aContainerChild->RegisterWithIPDL();
+ if (!SendPImageContainerConstructor(aContainerChild)) {
+ return nullptr;
+ }
+ }
+
+ RefPtr<ImageClient> client = ImageClient::CreateImageClient(aType, this, TextureFlags::NO_FLAGS);
+ MOZ_ASSERT(client, "failed to create ImageClient");
+ if (client) {
+ client->Connect(aImageContainer);
+ }
+ return client;
+}
+
+already_AddRefed<CanvasClient>
+ImageBridgeChild::CreateCanvasClient(CanvasClient::CanvasClientType aType,
+ TextureFlags aFlag)
+{
+ if (InImageBridgeChildThread()) {
+ return CreateCanvasClientNow(aType, aFlag);
+ }
+
+ SynchronousTask task("CreateCanvasClient Lock");
+
+ // RefPtrs on arguments are not needed since this dispatches synchronously.
+ RefPtr<CanvasClient> result = nullptr;
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::CreateCanvasClientSync,
+ &task,
+ aType,
+ aFlag,
+ &result);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return result.forget();
+}
+
+already_AddRefed<CanvasClient>
+ImageBridgeChild::CreateCanvasClientNow(CanvasClient::CanvasClientType aType,
+ TextureFlags aFlag)
+{
+ RefPtr<CanvasClient> client
+ = CanvasClient::CreateCanvasClient(aType, this, aFlag);
+ MOZ_ASSERT(client, "failed to create CanvasClient");
+ if (client) {
+ client->Connect();
+ }
+ return client.forget();
+}
+
+bool
+ImageBridgeChild::AllocUnsafeShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (!InImageBridgeChildThread()) {
+ return DispatchAllocShmemInternal(aSize, aType, aShmem, true); // true: unsafe
+ }
+
+ if (!CanSend()) {
+ return false;
+ }
+ return PImageBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem);
+}
+
+bool
+ImageBridgeChild::AllocShmem(size_t aSize,
+ ipc::SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem)
+{
+ if (!InImageBridgeChildThread()) {
+ return DispatchAllocShmemInternal(aSize, aType, aShmem, false); // false: unsafe
+ }
+
+ if (!CanSend()) {
+ return false;
+ }
+ return PImageBridgeChild::AllocShmem(aSize, aType, aShmem);
+}
+
+// NewRunnableFunction accepts a limited number of parameters so we need a
+// struct here
+struct AllocShmemParams {
+ size_t mSize;
+ ipc::SharedMemory::SharedMemoryType mType;
+ ipc::Shmem* mShmem;
+ bool mUnsafe;
+ bool mSuccess;
+};
+
+void
+ImageBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, AllocShmemParams* aParams)
+{
+ AutoCompleteTask complete(aTask);
+
+ if (!CanSend()) {
+ return;
+ }
+
+ bool ok = false;
+ if (aParams->mUnsafe) {
+ ok = AllocUnsafeShmem(aParams->mSize, aParams->mType, aParams->mShmem);
+ } else {
+ ok = AllocShmem(aParams->mSize, aParams->mType, aParams->mShmem);
+ }
+ aParams->mSuccess = ok;
+}
+
+bool
+ImageBridgeChild::DispatchAllocShmemInternal(size_t aSize,
+ SharedMemory::SharedMemoryType aType,
+ ipc::Shmem* aShmem,
+ bool aUnsafe)
+{
+ SynchronousTask task("AllocatorProxy alloc");
+
+ AllocShmemParams params = {
+ aSize, aType, aShmem, aUnsafe, false
+ };
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ProxyAllocShmemNow,
+ &task,
+ &params);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+
+ return params.mSuccess;
+}
+
+void
+ImageBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
+ ipc::Shmem* aShmem,
+ bool* aResult)
+{
+ AutoCompleteTask complete(aTask);
+
+ if (!CanSend()) {
+ return;
+ }
+ *aResult = DeallocShmem(*aShmem);
+}
+
+bool
+ImageBridgeChild::DeallocShmem(ipc::Shmem& aShmem)
+{
+ if (InImageBridgeChildThread()) {
+ if (!CanSend()) {
+ return false;
+ }
+ return PImageBridgeChild::DeallocShmem(aShmem);
+ }
+
+ SynchronousTask task("AllocatorProxy Dealloc");
+ bool result = false;
+
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::ProxyDeallocShmemNow,
+ &task,
+ &aShmem,
+ &result);
+ GetMessageLoop()->PostTask(runnable.forget());
+
+ task.Wait();
+ return result;
+}
+
+PTextureChild*
+ImageBridgeChild::AllocPTextureChild(const SurfaceDescriptor&,
+ const LayersBackend&,
+ const TextureFlags&,
+ const uint64_t& aSerial)
+{
+ MOZ_ASSERT(CanSend());
+ return TextureClient::CreateIPDLActor();
+}
+
+bool
+ImageBridgeChild::DeallocPTextureChild(PTextureChild* actor)
+{
+ return TextureClient::DestroyIPDLActor(actor);
+}
+
+PMediaSystemResourceManagerChild*
+ImageBridgeChild::AllocPMediaSystemResourceManagerChild()
+{
+ MOZ_ASSERT(CanSend());
+ return new mozilla::media::MediaSystemResourceManagerChild();
+}
+
+bool
+ImageBridgeChild::DeallocPMediaSystemResourceManagerChild(PMediaSystemResourceManagerChild* aActor)
+{
+ MOZ_ASSERT(aActor);
+ delete static_cast<mozilla::media::MediaSystemResourceManagerChild*>(aActor);
+ return true;
+}
+
+PImageContainerChild*
+ImageBridgeChild::AllocPImageContainerChild()
+{
+ // we always use the "power-user" ctor
+ NS_RUNTIMEABORT("not reached");
+ return nullptr;
+}
+
+bool
+ImageBridgeChild::DeallocPImageContainerChild(PImageContainerChild* actor)
+{
+ static_cast<ImageContainerChild*>(actor)->UnregisterFromIPDL();
+ return true;
+}
+
+bool
+ImageBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages)
+{
+ for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) {
+ const AsyncParentMessageData& message = aMessages[i];
+
+ switch (message.type()) {
+ case AsyncParentMessageData::TOpNotifyNotUsed: {
+ const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed();
+ NotifyNotUsed(op.TextureId(), op.fwdTransactionId());
+ break;
+ }
+ default:
+ NS_ERROR("unknown AsyncParentMessageData type");
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+ImageBridgeChild::RecvDidComposite(InfallibleTArray<ImageCompositeNotification>&& aNotifications)
+{
+ for (auto& n : aNotifications) {
+ ImageContainerChild* child =
+ static_cast<ImageContainerChild*>(n.imageContainerChild());
+ if (child) {
+ child->NotifyComposite(n);
+ }
+ }
+ return true;
+}
+
+PTextureChild*
+ImageBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData,
+ LayersBackend aLayersBackend,
+ TextureFlags aFlags,
+ uint64_t aSerial)
+{
+ MOZ_ASSERT(CanSend());
+ return SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, aSerial);
+}
+
+static bool
+IBCAddOpDestroy(CompositableTransaction* aTxn, const OpDestroy& op, bool synchronously)
+{
+ if (aTxn->Finished()) {
+ return false;
+ }
+
+ aTxn->mDestroyedActors.AppendElement(op);
+
+ if (synchronously) {
+ aTxn->MarkSyncTransaction();
+ }
+
+ return true;
+}
+
+bool
+ImageBridgeChild::DestroyInTransaction(PTextureChild* aTexture, bool synchronously)
+{
+ return IBCAddOpDestroy(mTxn, OpDestroy(aTexture), synchronously);
+}
+
+bool
+ImageBridgeChild::DestroyInTransaction(PCompositableChild* aCompositable, bool synchronously)
+{
+ return IBCAddOpDestroy(mTxn, OpDestroy(aCompositable), synchronously);
+}
+
+
+void
+ImageBridgeChild::RemoveTextureFromCompositable(CompositableClient* aCompositable,
+ TextureClient* aTexture)
+{
+ MOZ_ASSERT(CanSend());
+ MOZ_ASSERT(aTexture);
+ MOZ_ASSERT(aTexture->IsSharedWithCompositor());
+ MOZ_ASSERT(aCompositable->IsConnected());
+ if (!aTexture || !aTexture->IsSharedWithCompositor() || !aCompositable->IsConnected()) {
+ return;
+ }
+
+ CompositableOperation op(
+ nullptr, aCompositable->GetIPDLActor(),
+ OpRemoveTexture(nullptr, aTexture->GetIPDLActor()));
+
+ if (aTexture->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
+ mTxn->AddEdit(op);
+ } else {
+ mTxn->AddNoSwapEdit(op);
+ }
+}
+
+bool ImageBridgeChild::IsSameProcess() const
+{
+ return OtherPid() == base::GetCurrentProcId();
+}
+
+void
+ImageBridgeChild::Destroy(CompositableChild* aCompositable)
+{
+ if (!InImageBridgeChildThread()) {
+ RefPtr<Runnable> runnable = WrapRunnable(
+ RefPtr<ImageBridgeChild>(this),
+ &ImageBridgeChild::Destroy,
+ RefPtr<CompositableChild>(aCompositable));
+ GetMessageLoop()->PostTask(runnable.forget());
+ return;
+ }
+ CompositableForwarder::Destroy(aCompositable);
+}
+
+bool
+ImageBridgeChild::CanSend() const
+{
+ MOZ_ASSERT(InImageBridgeChildThread());
+ return mCanSend;
+}
+
+void
+ImageBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
+{
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
+}
+
+} // namespace layers
+} // namespace mozilla