summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc/ImageBridgeChild.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/ipc/ImageBridgeChild.h')
-rw-r--r--gfx/layers/ipc/ImageBridgeChild.h376
1 files changed, 376 insertions, 0 deletions
diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h
new file mode 100644
index 0000000000..ee8ff97299
--- /dev/null
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -0,0 +1,376 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef MOZILLA_GFX_IMAGEBRIDGECHILD_H
+#define MOZILLA_GFX_IMAGEBRIDGECHILD_H
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint32_t, uint64_t
+#include <unordered_map>
+
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/Atomics.h"
+#include "mozilla/RefPtr.h" // for already_AddRefed
+#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorTypes.h"
+#include "mozilla/layers/PImageBridgeChild.h"
+#include "mozilla/layers/TextureForwarder.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "nsRegion.h" // for nsIntRegion
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
+
+namespace mozilla {
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace layers {
+
+class ImageClient;
+class ImageContainer;
+class ImageContainerListener;
+class ImageBridgeParent;
+class CompositableClient;
+struct CompositableTransaction;
+class Image;
+class TextureClient;
+class SynchronousTask;
+
+/**
+ * Returns true if the current thread is the ImageBrdigeChild's thread.
+ *
+ * Can be called from any thread.
+ */
+bool InImageBridgeChildThread();
+
+/**
+ * The ImageBridge protocol is meant to allow ImageContainers to forward images
+ * directly to the compositor thread/process without using the main thread.
+ *
+ * ImageBridgeChild is a CompositableForwarder just like ShadowLayerForwarder.
+ * This means it also does transactions with the compositor thread/process,
+ * except that the transactions are restricted to operations on the
+ * Compositables and cannot contain messages affecting layers directly.
+ *
+ * ImageBridgeChild is also a ISurfaceAllocator. It can be used to allocate or
+ * deallocate data that is shared with the compositor. The main differerence
+ * with other ISurfaceAllocators is that some of its overriden methods can be
+ * invoked from any thread.
+ *
+ * There are three important phases in the ImageBridge protocol. These three
+ * steps can do different things depending if (A) the ImageContainer uses
+ * ImageBridge or (B) it does not use ImageBridge:
+ *
+ * - When an ImageContainer calls its method SetCurrentImage:
+ * - (A) The image is sent directly to the compositor process through the
+ * ImageBridge IPDL protocol.
+ * On the compositor side the image is stored in a global table that
+ * associates the image with an ID corresponding to the ImageContainer, and a
+ * composition is triggered.
+ * - (B) Since it does not have an ImageBridge, the image is not sent yet.
+ * instead the will be sent to the compositor during the next layer
+ * transaction (on the main thread).
+ *
+ * - During a Layer transaction:
+ * - (A) The ImageContainer uses ImageBridge. The image is already available
+ * to the compositor process because it has been sent with SetCurrentImage.
+ * Yet, the CompositableHost on the compositor side will needs the ID
+ * referring to the ImageContainer to access the Image. So during the Swap
+ * operation that happens in the transaction, we swap the container ID rather
+ * than the image data.
+ * - (B) Since the ImageContainer does not use ImageBridge, the image data is
+ * swaped.
+ *
+ * - During composition:
+ * - (A) The CompositableHost has an AsyncID, it looks up the ID in the
+ * global table to see if there is an image. If there is no image, nothing is
+ * rendered.
+ * - (B) The CompositableHost has image data rather than an ID (meaning it is
+ * not using ImageBridge), then it just composites the image data normally.
+ *
+ * This means that there might be a possibility for the ImageBridge to send the
+ * first frame before the first layer transaction that will pass the container
+ * ID to the CompositableHost happens. In this (unlikely) case the layer is not
+ * composited until the layer transaction happens. This means this scenario is
+ * not harmful.
+ *
+ * Since sending an image through imageBridge triggers compositing, the main
+ * thread is not used at all (except for the very first transaction that
+ * provides the CompositableHost with an AsyncID).
+ */
+class ImageBridgeChild final : public PImageBridgeChild,
+ public CompositableForwarder,
+ public TextureForwarder {
+ friend class ImageContainer;
+
+ typedef nsTArray<AsyncParentMessageData> AsyncParentMessageArray;
+
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageBridgeChild, override);
+
+ TextureForwarder* GetTextureForwarder() override { return this; }
+ LayersIPCActor* GetLayersIPCActor() override { return this; }
+
+ /**
+ * Creates the image bridge with a dedicated thread for ImageBridgeChild.
+ *
+ * We may want to use a specifi thread in the future. In this case, use
+ * CreateWithThread instead.
+ */
+ static void InitSameProcess(uint32_t aNamespace);
+
+ static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint,
+ uint32_t aNamespace);
+ static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
+ uint32_t aNamespace);
+ static bool ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint,
+ uint32_t aNamespace);
+
+ /**
+ * Destroys the image bridge by calling DestroyBridge, and destroys the
+ * ImageBridge's thread.
+ *
+ * If you don't want to destroy the thread, call DestroyBridge directly
+ * instead.
+ */
+ static void ShutDown();
+
+ /**
+ * returns the singleton instance.
+ *
+ * can be called from any thread.
+ */
+ static RefPtr<ImageBridgeChild> GetSingleton();
+
+ static void IdentifyCompositorTextureHost(
+ const TextureFactoryIdentifier& aIdentifier);
+
+ void BeginTransaction();
+ void EndTransaction();
+
+ /**
+ * Returns the ImageBridgeChild's thread.
+ *
+ * Can be called from any thread.
+ */
+ nsISerialEventTarget* GetThread() const override;
+
+ base::ProcessId GetParentPid() const override { return OtherPid(); }
+
+ PTextureChild* AllocPTextureChild(
+ const SurfaceDescriptor& aSharedData, ReadLockDescriptor& aReadLock,
+ const LayersBackend& aLayersBackend, const TextureFlags& aFlags,
+ const uint64_t& aSerial,
+ const wr::MaybeExternalImageId& aExternalImageId);
+
+ bool DeallocPTextureChild(PTextureChild* actor);
+
+ PMediaSystemResourceManagerChild* AllocPMediaSystemResourceManagerChild();
+ bool DeallocPMediaSystemResourceManagerChild(
+ PMediaSystemResourceManagerChild* aActor);
+
+ mozilla::ipc::IPCResult RecvParentAsyncMessages(
+ nsTArray<AsyncParentMessageData>&& aMessages);
+
+ mozilla::ipc::IPCResult RecvDidComposite(
+ nsTArray<ImageCompositeNotification>&& aNotifications);
+
+ mozilla::ipc::IPCResult RecvReportFramesDropped(
+ const CompositableHandle& aHandle, const uint32_t& aFrames);
+
+ // Create an ImageClient from any thread.
+ RefPtr<ImageClient> CreateImageClient(CompositableType aType,
+ ImageContainer* aImageContainer);
+
+ // Create an ImageClient from the ImageBridge thread.
+ RefPtr<ImageClient> CreateImageClientNow(CompositableType aType,
+ ImageContainer* aImageContainer);
+
+ void UpdateImageClient(RefPtr<ImageContainer> aContainer);
+
+ void UpdateCompositable(const RefPtr<ImageContainer> aContainer,
+ const RemoteTextureId aTextureId,
+ const RemoteTextureOwnerId aOwnerId,
+ const gfx::IntSize aSize, const TextureFlags aFlags);
+
+ /**
+ * Flush all Images sent to CompositableHost.
+ */
+ void FlushAllImages(ImageClient* aClient, ImageContainer* aContainer);
+
+ bool IPCOpen() const override { return mCanSend; }
+
+ private:
+ /**
+ * This must be called by the static function DeleteImageBridgeSync defined
+ * in ImageBridgeChild.cpp ONLY.
+ */
+ virtual ~ImageBridgeChild();
+
+ // Helpers for dispatching.
+ void CreateImageClientSync(SynchronousTask* aTask,
+ RefPtr<ImageClient>* result,
+ CompositableType aType,
+ ImageContainer* aImageContainer);
+
+ void FlushAllImagesSync(SynchronousTask* aTask, ImageClient* aClient,
+ ImageContainer* aContainer);
+
+ void ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize,
+ mozilla::ipc::Shmem* aShmem, bool aUnsafe,
+ bool* aSuccess);
+ void ProxyDeallocShmemNow(SynchronousTask* aTask, mozilla::ipc::Shmem* aShmem,
+ bool* aResult);
+
+ void UpdateTextureFactoryIdentifier(
+ const TextureFactoryIdentifier& aIdentifier);
+
+ public:
+ // CompositableForwarder
+
+ void Connect(CompositableClient* aCompositable,
+ ImageContainer* aImageContainer) override;
+
+ bool UsesImageBridge() const override { return true; }
+
+ /**
+ * See CompositableForwarder::UseTextures
+ */
+ void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) override;
+
+ void UseRemoteTexture(CompositableClient* aCompositable,
+ const RemoteTextureId aTextureId,
+ const RemoteTextureOwnerId aOwnerId,
+ const gfx::IntSize aSize,
+ const TextureFlags aFlags) override;
+
+ void EnableRemoteTexturePushCallback(CompositableClient* aCompositable,
+ const RemoteTextureOwnerId aOwnerId,
+ const gfx::IntSize aSize,
+ const TextureFlags aFlags) override;
+
+ void ReleaseCompositable(const CompositableHandle& aHandle) override;
+
+ void ForgetImageContainer(const CompositableHandle& aHandle);
+
+ /**
+ * Hold TextureClient ref until end of usage on host side if
+ * TextureFlags::RECYCLE is set. Host side's usage is checked via
+ * CompositableRef.
+ */
+ void HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient);
+
+ /**
+ * Notify id of Texture When host side end its use. Transaction id is used to
+ * make sure if there is no newer usage.
+ */
+ void NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId);
+
+ void CancelWaitForNotifyNotUsed(uint64_t aTextureId) override;
+
+ bool DestroyInTransaction(PTextureChild* aTexture) override;
+ bool DestroyInTransaction(const CompositableHandle& aHandle);
+
+ void RemoveTextureFromCompositable(CompositableClient* aCompositable,
+ TextureClient* aTexture) override;
+
+ // ISurfaceAllocator
+
+ /**
+ * See ISurfaceAllocator.h
+ * Can be used from any thread.
+ * If used outside the ImageBridgeChild thread, it will proxy a synchronous
+ * call on the ImageBridgeChild thread.
+ */
+ bool AllocUnsafeShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) override;
+ bool AllocShmem(size_t aSize, mozilla::ipc::Shmem* aShmem) override;
+
+ /**
+ * See ISurfaceAllocator.h
+ * Can be used from any thread.
+ * If used outside the ImageBridgeChild thread, it will proxy a synchronous
+ * call on the ImageBridgeChild thread.
+ */
+ bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override;
+
+ PTextureChild* CreateTexture(
+ const SurfaceDescriptor& aSharedData, ReadLockDescriptor&& aReadLock,
+ LayersBackend aLayersBackend, TextureFlags aFlags,
+ const dom::ContentParentId& aContentId, uint64_t aSerial,
+ wr::MaybeExternalImageId& aExternalImageId) override;
+
+ bool IsSameProcess() const override;
+
+ void UpdateFwdTransactionId() override { ++mFwdTransactionId; }
+ uint64_t GetFwdTransactionId() override { return mFwdTransactionId; }
+
+ bool InForwarderThread() override { return InImageBridgeChildThread(); }
+
+ void HandleFatalError(const char* aMsg) override;
+
+ wr::MaybeExternalImageId GetNextExternalImageId() override;
+
+ protected:
+ explicit ImageBridgeChild(uint32_t aNamespace);
+ bool DispatchAllocShmemInternal(size_t aSize, Shmem* aShmem, bool aUnsafe);
+
+ void Bind(Endpoint<PImageBridgeChild>&& aEndpoint);
+ void BindSameProcess(RefPtr<ImageBridgeParent> aParent);
+
+ void SendImageBridgeThreadId();
+
+ void WillShutdown();
+ void ShutdownStep1(SynchronousTask* aTask);
+ void ShutdownStep2(SynchronousTask* aTask);
+ void MarkShutDown();
+
+ void ActorDestroy(ActorDestroyReason aWhy) override;
+
+ bool CanSend() const;
+ bool CanPostTask() const;
+
+ static void ShutdownSingleton();
+
+ private:
+ uint32_t mNamespace;
+
+ CompositableTransaction* mTxn;
+
+ bool mCanSend;
+ mozilla::Atomic<bool> mDestroyed;
+
+ /**
+ * Transaction id of CompositableForwarder.
+ * It is incrementaed by UpdateFwdTransactionId() in each BeginTransaction()
+ * call.
+ */
+ uint64_t mFwdTransactionId;
+
+ /**
+ * Hold TextureClients refs until end of their usages on host side.
+ * It defer calling of TextureClient recycle callback.
+ */
+ std::unordered_map<uint64_t, RefPtr<TextureClient>>
+ mTexturesWaitingNotifyNotUsed;
+
+ /**
+ * Mapping from async compositable IDs to image containers.
+ */
+ Mutex mContainerMapLock MOZ_UNANNOTATED;
+ std::unordered_map<uint64_t, RefPtr<ImageContainerListener>>
+ mImageContainerListeners;
+ RefPtr<ImageContainerListener> FindListener(
+ const CompositableHandle& aHandle);
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif