michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=8 et : michael@0: */ 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: #ifndef mozilla_layers_ShadowLayers_h michael@0: #define mozilla_layers_ShadowLayers_h 1 michael@0: michael@0: #include // for size_t michael@0: #include // for uint64_t michael@0: #include "gfxTypes.h" michael@0: #include "mozilla/Attributes.h" // for MOZ_OVERRIDE michael@0: #include "mozilla/WidgetUtils.h" // for ScreenRotation michael@0: #include "mozilla/dom/ScreenOrientation.h" // for ScreenOrientation michael@0: #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc michael@0: #include "mozilla/layers/CompositableForwarder.h" michael@0: #include "mozilla/layers/CompositorTypes.h" // for OpenMode, etc michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsRegion.h" // for nsIntRegion michael@0: #include "nsTArrayForwardDeclare.h" // for InfallibleTArray michael@0: michael@0: struct nsIntPoint; michael@0: struct nsIntRect; michael@0: michael@0: namespace mozilla { michael@0: namespace layers { michael@0: michael@0: class ClientTiledLayerBuffer; michael@0: class CanvasClient; michael@0: class CanvasLayerComposite; michael@0: class CanvasSurface; michael@0: class ColorLayerComposite; michael@0: class CompositableChild; michael@0: class ContainerLayerComposite; michael@0: class ContentClient; michael@0: class ContentClientRemote; michael@0: class EditReply; michael@0: class ImageClient; michael@0: class ImageLayerComposite; michael@0: class Layer; michael@0: class OptionalThebesBuffer; michael@0: class PLayerChild; michael@0: class PLayerTransactionChild; michael@0: class PLayerTransactionParent; michael@0: class LayerTransactionChild; michael@0: class RefLayerComposite; michael@0: class ShadowableLayer; michael@0: class ShmemTextureClient; michael@0: class SurfaceDescriptor; michael@0: class TextureClient; michael@0: class ThebesLayerComposite; michael@0: class ThebesBuffer; michael@0: class ThebesBufferData; michael@0: class TiledLayerComposer; michael@0: class Transaction; michael@0: michael@0: michael@0: /** michael@0: * We want to share layer trees across thread contexts and address michael@0: * spaces for several reasons; chief among them michael@0: * michael@0: * - a parent process can paint a child process's layer tree while michael@0: * the child process is blocked, say on content script. This is michael@0: * important on mobile devices where UI responsiveness is key. michael@0: * michael@0: * - a dedicated "compositor" process can asynchronously (wrt the michael@0: * browser process) composite and animate layer trees, allowing a michael@0: * form of pipeline parallelism between compositor/browser/content michael@0: * michael@0: * - a dedicated "compositor" process can take all responsibility for michael@0: * accessing the GPU, which is desirable on systems with michael@0: * buggy/leaky drivers because the compositor process can die while michael@0: * browser and content live on (and failover mechanisms can be michael@0: * installed to quickly bring up a replacement compositor) michael@0: * michael@0: * The Layers model has a crisply defined API, which makes it easy to michael@0: * safely "share" layer trees. The ShadowLayers API extends Layers to michael@0: * allow a remote, parent process to access a child process's layer michael@0: * tree. michael@0: * michael@0: * ShadowLayerForwarder publishes a child context's layer tree to a michael@0: * parent context. This comprises recording layer-tree modifications michael@0: * into atomic transactions and pushing them over IPC. michael@0: * michael@0: * LayerManagerComposite grafts layer subtrees published by child-context michael@0: * ShadowLayerForwarder(s) into a parent-context layer tree. michael@0: * michael@0: * (Advanced note: because our process tree may have a height >2, a michael@0: * non-leaf subprocess may both receive updates from child processes michael@0: * and publish them to parent processes. Put another way, michael@0: * LayerManagers may be both LayerManagerComposites and michael@0: * ShadowLayerForwarders.) michael@0: * michael@0: * There are only shadow types for layers that have different shadow michael@0: * vs. not-shadow behavior. ColorLayers and ContainerLayers behave michael@0: * the same way in both regimes (so far). michael@0: * michael@0: * michael@0: * The mecanism to shadow the layer tree on the compositor through IPC works as michael@0: * follows: michael@0: * The layer tree is managed on the content thread, and shadowed in the compositor michael@0: * thread. The shadow layer tree is only kept in sync with whatever happens in michael@0: * the content thread. To do this we use IPDL protocols. IPDL is a domain michael@0: * specific language that describes how two processes or thread should michael@0: * communicate. C++ code is generated from .ipdl files to implement the message michael@0: * passing, synchronization and serialization logic. To use the generated code michael@0: * we implement classes that inherit the generated IPDL actor. the ipdl actors michael@0: * of a protocol PX are PXChild or PXParent (the generated class), and we michael@0: * conventionally implement XChild and XParent. The Parent side of the protocol michael@0: * is the one that lives on the compositor thread. Think of IPDL actors as michael@0: * endpoints of communication. they are useful to send messages and also to michael@0: * dispatch the message to the right actor on the other side. One nice property michael@0: * of an IPDL actor is that when an actor, say PXChild is sent in a message, the michael@0: * PXParent comes out in the other side. we use this property a lot to dispatch michael@0: * messages to the right layers and compositable, each of which have their own michael@0: * ipdl actor on both side. michael@0: * michael@0: * Most of the synchronization logic happens in layer transactions and michael@0: * compositable transactions. michael@0: * A transaction is a set of changes to the layers and/or the compositables michael@0: * that are sent and applied together to the compositor thread to keep the michael@0: * LayerComposite in a coherent state. michael@0: * Layer transactions maintain the shape of the shadow layer tree, and michael@0: * synchronize the texture data held by compositables. Layer transactions michael@0: * are always between the content thread and the compositor thread. michael@0: * Compositable transactions are subset of a layer transaction with which only michael@0: * compositables and textures can be manipulated, and does not always originate michael@0: * from the content thread. (See CompositableForwarder.h and ImageBridgeChild.h) michael@0: */ michael@0: michael@0: class ShadowLayerForwarder : public CompositableForwarder michael@0: { michael@0: friend class ContentClientIncremental; michael@0: friend class ClientLayerManager; michael@0: michael@0: public: michael@0: virtual ~ShadowLayerForwarder(); michael@0: michael@0: /** michael@0: * Setup the IPDL actor for aCompositable to be part of layers michael@0: * transactions. michael@0: */ michael@0: void Connect(CompositableClient* aCompositable); michael@0: michael@0: virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData, michael@0: TextureFlags aFlags) MOZ_OVERRIDE; michael@0: michael@0: virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable, michael@0: const TextureInfo& aTextureInfo, michael@0: const nsIntRect& aBufferRect) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Adds an edit in the layers transaction in order to attach michael@0: * the corresponding compositable and layer on the compositor side. michael@0: * Connect must have been called on aCompositable beforehand. michael@0: */ michael@0: void Attach(CompositableClient* aCompositable, michael@0: ShadowableLayer* aLayer); michael@0: michael@0: /** michael@0: * Adds an edit in the transaction in order to attach a Compositable that michael@0: * is not managed by this ShadowLayerForwarder (for example, by ImageBridge michael@0: * in the case of async-video). michael@0: * Since the compositable is not managed by this forwarder, we can't use michael@0: * the compositable or it's IPDL actor here, so we use an ID instead, that michael@0: * is matched on the compositor side. michael@0: */ michael@0: void AttachAsyncCompositable(uint64_t aCompositableID, michael@0: ShadowableLayer* aLayer); michael@0: michael@0: /** michael@0: * Begin recording a transaction to be forwarded atomically to a michael@0: * LayerManagerComposite. michael@0: */ michael@0: void BeginTransaction(const nsIntRect& aTargetBounds, michael@0: ScreenRotation aRotation, michael@0: const nsIntRect& aClientBounds, michael@0: mozilla::dom::ScreenOrientation aOrientation); michael@0: michael@0: /** michael@0: * The following methods may only be called after BeginTransaction() michael@0: * but before EndTransaction(). They mirror the LayerManager michael@0: * interface in Layers.h. michael@0: */ michael@0: michael@0: /** michael@0: * Notify the shadow manager that a new, "real" layer has been michael@0: * created, and a corresponding shadow layer should be created in michael@0: * the compositing process. michael@0: */ michael@0: void CreatedThebesLayer(ShadowableLayer* aThebes); michael@0: void CreatedContainerLayer(ShadowableLayer* aContainer); michael@0: void CreatedImageLayer(ShadowableLayer* aImage); michael@0: void CreatedColorLayer(ShadowableLayer* aColor); michael@0: void CreatedCanvasLayer(ShadowableLayer* aCanvas); michael@0: void CreatedRefLayer(ShadowableLayer* aRef); michael@0: michael@0: /** michael@0: * At least one attribute of |aMutant| has changed, and |aMutant| michael@0: * needs to sync to its shadow layer. This initial implementation michael@0: * forwards all attributes when any is mutated. michael@0: */ michael@0: void Mutated(ShadowableLayer* aMutant); michael@0: michael@0: void SetRoot(ShadowableLayer* aRoot); michael@0: /** michael@0: * Insert |aChild| after |aAfter| in |aContainer|. |aAfter| can be michael@0: * nullptr to indicated that |aChild| should be appended to the end of michael@0: * |aContainer|'s child list. michael@0: */ michael@0: void InsertAfter(ShadowableLayer* aContainer, michael@0: ShadowableLayer* aChild, michael@0: ShadowableLayer* aAfter = nullptr); michael@0: void RemoveChild(ShadowableLayer* aContainer, michael@0: ShadowableLayer* aChild); michael@0: void RepositionChild(ShadowableLayer* aContainer, michael@0: ShadowableLayer* aChild, michael@0: ShadowableLayer* aAfter = nullptr); michael@0: michael@0: /** michael@0: * Set aMaskLayer as the mask on aLayer. michael@0: * Note that only image layers are properly supported michael@0: * LayerTransactionParent::UpdateMask and accompanying ipdl michael@0: * will need changing to update properties for other kinds michael@0: * of mask layer. michael@0: */ michael@0: void SetMask(ShadowableLayer* aLayer, michael@0: ShadowableLayer* aMaskLayer); michael@0: michael@0: /** michael@0: * See CompositableForwarder::UseTiledLayerBuffer michael@0: */ michael@0: virtual void UseTiledLayerBuffer(CompositableClient* aCompositable, michael@0: const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Notify the compositor that a compositable will be updated asynchronously michael@0: * through ImageBridge, using an ID to connect the protocols on the michael@0: * compositor side. michael@0: */ michael@0: void AttachAsyncCompositable(PLayerTransactionChild* aLayer, uint64_t aID); michael@0: michael@0: virtual void RemoveTextureFromCompositable(CompositableClient* aCompositable, michael@0: TextureClient* aTexture) MOZ_OVERRIDE; michael@0: michael@0: virtual void RemoveTexture(TextureClient* aTexture) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Communicate to the compositor that aRegion in the texture identified by aLayer michael@0: * and aIdentifier has been updated to aThebesBuffer. michael@0: */ michael@0: virtual void UpdateTextureRegion(CompositableClient* aCompositable, michael@0: const ThebesBufferData& aThebesBufferData, michael@0: const nsIntRegion& aUpdatedRegion) MOZ_OVERRIDE; michael@0: michael@0: virtual void UpdateTextureIncremental(CompositableClient* aCompositable, michael@0: TextureIdentifier aTextureId, michael@0: SurfaceDescriptor& aDescriptor, michael@0: const nsIntRegion& aUpdatedRegion, michael@0: const nsIntRect& aBufferRect, michael@0: const nsIntPoint& aBufferRotation) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Communicate the picture rect of an image to the compositor michael@0: */ michael@0: void UpdatePictureRect(CompositableClient* aCompositable, michael@0: const nsIntRect& aRect); michael@0: michael@0: /** michael@0: * See CompositableForwarder::UpdatedTexture michael@0: */ michael@0: virtual void UpdatedTexture(CompositableClient* aCompositable, michael@0: TextureClient* aTexture, michael@0: nsIntRegion* aRegion) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * See CompositableForwarder::UseTexture michael@0: */ michael@0: virtual void UseTexture(CompositableClient* aCompositable, michael@0: TextureClient* aClient) MOZ_OVERRIDE; michael@0: virtual void UseComponentAlphaTextures(CompositableClient* aCompositable, michael@0: TextureClient* aClientOnBlack, michael@0: TextureClient* aClientOnWhite) MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * End the current transaction and forward it to LayerManagerComposite. michael@0: * |aReplies| are directions from the LayerManagerComposite to the michael@0: * caller of EndTransaction(). michael@0: */ michael@0: bool EndTransaction(InfallibleTArray* aReplies, michael@0: const nsIntRegion& aRegionToClear, michael@0: bool aScheduleComposite, michael@0: bool* aSent); michael@0: michael@0: /** michael@0: * Set an actor through which layer updates will be pushed. michael@0: */ michael@0: void SetShadowManager(PLayerTransactionChild* aShadowManager); michael@0: michael@0: /** michael@0: * True if this is forwarding to a LayerManagerComposite. michael@0: */ michael@0: bool HasShadowManager() const { return !!mShadowManager; } michael@0: LayerTransactionChild* GetShadowManager() const { return mShadowManager.get(); } michael@0: michael@0: virtual void WindowOverlayChanged() { mWindowOverlayChanged = true; } michael@0: michael@0: /** michael@0: * The following Alloc/Open/Destroy interfaces abstract over the michael@0: * details of working with surfaces that are shared across michael@0: * processes. They provide the glue between C++ Layers and the michael@0: * LayerComposite IPC system. michael@0: * michael@0: * The basic lifecycle is michael@0: * michael@0: * - a Layer needs a buffer. Its ShadowableLayer subclass calls michael@0: * AllocBuffer(), then calls one of the Created*Buffer() methods michael@0: * above to transfer the (temporary) front buffer to its michael@0: * LayerComposite in the other process. The Layer needs a michael@0: * gfxASurface to paint, so the ShadowableLayer uses michael@0: * OpenDescriptor(backBuffer) to get that surface, and hands it michael@0: * out to the Layer. michael@0: * michael@0: * - a Layer has painted new pixels. Its ShadowableLayer calls one michael@0: * of the Painted*Buffer() methods above with the back buffer michael@0: * descriptor. This notification is forwarded to the LayerComposite, michael@0: * which uses OpenDescriptor() to access the newly-painted pixels. michael@0: * The LayerComposite then updates its front buffer in a Layer- and michael@0: * platform-dependent way, and sends a surface descriptor back to michael@0: * the ShadowableLayer that becomes its new back back buffer. michael@0: * michael@0: * - a Layer wants to destroy its buffers. Its ShadowableLayer michael@0: * calls Destroyed*Buffer(), which gives up control of the back michael@0: * buffer descriptor. The actual back buffer surface is then michael@0: * destroyed using DestroySharedSurface() just before notifying michael@0: * the parent process. When the parent process is notified, the michael@0: * LayerComposite also calls DestroySharedSurface() on its front michael@0: * buffer, and the double-buffer pair is gone. michael@0: */ michael@0: michael@0: // ISurfaceAllocator michael@0: virtual bool AllocUnsafeShmem(size_t aSize, michael@0: mozilla::ipc::SharedMemory::SharedMemoryType aType, michael@0: mozilla::ipc::Shmem* aShmem) MOZ_OVERRIDE; michael@0: virtual bool AllocShmem(size_t aSize, michael@0: mozilla::ipc::SharedMemory::SharedMemoryType aType, michael@0: mozilla::ipc::Shmem* aShmem) MOZ_OVERRIDE; michael@0: virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) MOZ_OVERRIDE; michael@0: michael@0: virtual bool IPCOpen() const MOZ_OVERRIDE; michael@0: virtual bool IsSameProcess() const MOZ_OVERRIDE; michael@0: michael@0: /** michael@0: * Construct a shadow of |aLayer| on the "other side", at the michael@0: * LayerManagerComposite. michael@0: */ michael@0: PLayerChild* ConstructShadowFor(ShadowableLayer* aLayer); michael@0: michael@0: /** michael@0: * Flag the next paint as the first for a document. michael@0: */ michael@0: void SetIsFirstPaint() { mIsFirstPaint = true; } michael@0: michael@0: static void PlatformSyncBeforeUpdate(); michael@0: michael@0: protected: michael@0: ShadowLayerForwarder(); michael@0: michael@0: #ifdef DEBUG michael@0: void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const; michael@0: #else michael@0: void CheckSurfaceDescriptor(const SurfaceDescriptor* aDescriptor) const {} michael@0: #endif michael@0: michael@0: RefPtr mShadowManager; michael@0: michael@0: #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC michael@0: // from ISurfaceAllocator michael@0: virtual PGrallocBufferChild* AllocGrallocBuffer(const gfx::IntSize& aSize, michael@0: uint32_t aFormat, michael@0: uint32_t aUsage, michael@0: MaybeMagicGrallocBufferHandle* aHandle) MOZ_OVERRIDE; michael@0: michael@0: virtual void DeallocGrallocBuffer(PGrallocBufferChild* aChild) MOZ_OVERRIDE; michael@0: #endif michael@0: michael@0: private: michael@0: michael@0: Transaction* mTxn; michael@0: DiagnosticTypes mDiagnosticTypes; michael@0: bool mIsFirstPaint; michael@0: bool mWindowOverlayChanged; michael@0: }; michael@0: michael@0: class CompositableClient; michael@0: michael@0: /** michael@0: * A ShadowableLayer is a Layer can be shared with a parent context michael@0: * through a ShadowLayerForwarder. A ShadowableLayer maps to a michael@0: * Shadow*Layer in a parent context. michael@0: * michael@0: * Note that ShadowLayers can themselves be ShadowableLayers. michael@0: */ michael@0: class ShadowableLayer michael@0: { michael@0: public: michael@0: virtual ~ShadowableLayer() {} michael@0: michael@0: virtual Layer* AsLayer() = 0; michael@0: michael@0: /** michael@0: * True if this layer has a shadow in a parent process. michael@0: */ michael@0: bool HasShadow() { return !!mShadow; } michael@0: michael@0: /** michael@0: * Return the IPC handle to a Shadow*Layer referring to this if one michael@0: * exists, nullptr if not. michael@0: */ michael@0: PLayerChild* GetShadow() { return mShadow; } michael@0: michael@0: virtual CompositableClient* GetCompositableClient() { return nullptr; } michael@0: protected: michael@0: ShadowableLayer() : mShadow(nullptr) {} michael@0: michael@0: PLayerChild* mShadow; michael@0: }; michael@0: michael@0: } // namespace layers michael@0: } // namespace mozilla michael@0: michael@0: #endif // ifndef mozilla_layers_ShadowLayers_h