Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 EnableAsyncCompositable(CompositableClient* aCompositable,
bool aEnable) 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, 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) const 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;
void ActorDealloc() 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