michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 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_GFX_BUFFERHOST_H michael@0: #define MOZILLA_GFX_BUFFERHOST_H michael@0: michael@0: #include // for uint64_t michael@0: #include // for FILE michael@0: #include "gfxRect.h" // for gfxRect michael@0: #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc michael@0: #include "mozilla/Attributes.h" // for MOZ_OVERRIDE michael@0: #include "mozilla/RefPtr.h" // for RefPtr, RefCounted, etc michael@0: #include "mozilla/gfx/Point.h" // for Point michael@0: #include "mozilla/gfx/Rect.h" // for Rect michael@0: #include "mozilla/gfx/Types.h" // for Filter michael@0: #include "mozilla/ipc/ProtocolUtils.h" michael@0: #include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc michael@0: #include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc michael@0: #include "mozilla/layers/PCompositableParent.h" michael@0: #include "mozilla/layers/TextureHost.h" // for TextureHost michael@0: #include "mozilla/mozalloc.h" // for operator delete michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsRegion.h" // for nsIntRegion michael@0: #include "nscore.h" // for nsACString michael@0: #include "Units.h" // for CSSToScreenScale michael@0: michael@0: struct nsIntPoint; michael@0: struct nsIntRect; michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class Matrix4x4; michael@0: class DataSourceSurface; michael@0: } michael@0: michael@0: namespace layers { michael@0: michael@0: // Some properties of a Layer required for tiling michael@0: struct TiledLayerProperties michael@0: { michael@0: nsIntRegion mVisibleRegion; michael@0: nsIntRegion mValidRegion; michael@0: CSSToScreenScale mEffectiveResolution; michael@0: }; michael@0: michael@0: class Layer; michael@0: class SurfaceDescriptor; michael@0: class Compositor; michael@0: class ISurfaceAllocator; michael@0: class ThebesBufferData; michael@0: class TiledLayerComposer; michael@0: class CompositableParentManager; michael@0: struct EffectChain; michael@0: michael@0: /** michael@0: * A base class for doing CompositableHost and platform dependent task on TextureHost. michael@0: */ michael@0: class CompositableBackendSpecificData michael@0: { michael@0: protected: michael@0: virtual ~CompositableBackendSpecificData() { } michael@0: michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(CompositableBackendSpecificData) michael@0: michael@0: CompositableBackendSpecificData() michael@0: { michael@0: } michael@0: michael@0: virtual void SetCompositor(Compositor* aCompositor) {} michael@0: virtual void ClearData() michael@0: { michael@0: mCurrentReleaseFenceTexture = nullptr; michael@0: ClearPendingReleaseFenceTextureList(); michael@0: } michael@0: michael@0: /** michael@0: * Store a texture currently used for Composition. michael@0: * This function is called when the texutre might receive ReleaseFence michael@0: * as a result of Composition. michael@0: */ michael@0: void SetCurrentReleaseFenceTexture(TextureHost* aTexture) michael@0: { michael@0: if (mCurrentReleaseFenceTexture) { michael@0: mPendingReleaseFenceTextures.push_back(mCurrentReleaseFenceTexture); michael@0: } michael@0: mCurrentReleaseFenceTexture = aTexture; michael@0: } michael@0: michael@0: virtual std::vector< RefPtr >& GetPendingReleaseFenceTextureList() michael@0: { michael@0: return mPendingReleaseFenceTextures; michael@0: } michael@0: michael@0: virtual void ClearPendingReleaseFenceTextureList() michael@0: { michael@0: return mPendingReleaseFenceTextures.clear(); michael@0: } michael@0: protected: michael@0: /** michael@0: * Store a TextureHost currently used for Composition michael@0: * and it might receive ReleaseFence for the texutre. michael@0: */ michael@0: RefPtr mCurrentReleaseFenceTexture; michael@0: /** michael@0: * Store TextureHosts that might have ReleaseFence to be delivered michael@0: * to TextureClient by CompositableHost. michael@0: */ michael@0: std::vector< RefPtr > mPendingReleaseFenceTextures; michael@0: }; michael@0: michael@0: /** michael@0: * The compositor-side counterpart to CompositableClient. Responsible for michael@0: * updating textures and data about textures from IPC and how textures are michael@0: * composited (tiling, double buffering, etc.). michael@0: * michael@0: * Update (for images/canvases) and UpdateThebes (for Thebes) are called during michael@0: * the layers transaction to update the Compositbale's textures from the michael@0: * content side. The actual update (and any syncronous upload) is done by the michael@0: * TextureHost, but it is coordinated by the CompositableHost. michael@0: * michael@0: * Composite is called by the owning layer when it is composited. CompositableHost michael@0: * will use its TextureHost(s) and call Compositor::DrawQuad to do the actual michael@0: * rendering. michael@0: */ michael@0: class CompositableHost michael@0: { michael@0: protected: michael@0: virtual ~CompositableHost(); michael@0: michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(CompositableHost) michael@0: CompositableHost(const TextureInfo& aTextureInfo); michael@0: michael@0: static TemporaryRef Create(const TextureInfo& aTextureInfo); michael@0: michael@0: virtual CompositableType GetType() = 0; michael@0: michael@0: virtual CompositableBackendSpecificData* GetCompositableBackendSpecificData() michael@0: { michael@0: return mBackendData; michael@0: } michael@0: michael@0: virtual void SetCompositableBackendSpecificData(CompositableBackendSpecificData* aBackendData) michael@0: { michael@0: mBackendData = aBackendData; michael@0: } michael@0: michael@0: // If base class overrides, it should still call the parent implementation michael@0: virtual void SetCompositor(Compositor* aCompositor); michael@0: michael@0: // composite the contents of this buffer host to the compositor's surface michael@0: virtual void Composite(EffectChain& aEffectChain, michael@0: float aOpacity, michael@0: const gfx::Matrix4x4& aTransform, michael@0: const gfx::Filter& aFilter, michael@0: const gfx::Rect& aClipRect, michael@0: const nsIntRegion* aVisibleRegion = nullptr, michael@0: TiledLayerProperties* aLayerProperties = nullptr) = 0; michael@0: michael@0: /** michael@0: * Update the content host. michael@0: * aUpdated is the region which should be updated michael@0: * aUpdatedRegionBack is the region in aNewBackResult which has been updated michael@0: */ michael@0: virtual bool UpdateThebes(const ThebesBufferData& aData, michael@0: const nsIntRegion& aUpdated, michael@0: const nsIntRegion& aOldValidRegionBack, michael@0: nsIntRegion* aUpdatedRegionBack) michael@0: { michael@0: NS_ERROR("should be implemented or not used"); michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Update the content host using a surface that only contains the updated michael@0: * region. michael@0: * michael@0: * Takes ownership of aSurface, and is responsible for freeing it. michael@0: * michael@0: * @param aTextureId Texture to update. michael@0: * @param aSurface Surface containing the update area. Its contents are relative michael@0: * to aUpdated.TopLeft() michael@0: * @param aUpdated Area of the content host to update. michael@0: * @param aBufferRect New area covered by the content host. michael@0: * @param aBufferRotation New buffer rotation. michael@0: */ michael@0: virtual void UpdateIncremental(TextureIdentifier aTextureId, michael@0: SurfaceDescriptor& aSurface, michael@0: const nsIntRegion& aUpdated, michael@0: const nsIntRect& aBufferRect, michael@0: const nsIntPoint& aBufferRotation) michael@0: { michael@0: MOZ_ASSERT(false, "should be implemented or not used"); michael@0: } michael@0: michael@0: /** michael@0: * Ensure that a suitable texture host exists in this compsitable. michael@0: * michael@0: * Only used with ContentHostIncremental. michael@0: * michael@0: * No SurfaceDescriptor or TextureIdentifier is provider as we michael@0: * don't have a single surface for the texture contents, and we michael@0: * need to allocate our own one to be updated later. michael@0: */ michael@0: virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator, michael@0: const TextureInfo& aTextureInfo, michael@0: const nsIntRect& aBufferRect) michael@0: { michael@0: NS_ERROR("should be implemented or not used"); michael@0: return false; michael@0: } michael@0: michael@0: /** michael@0: * Returns the front buffer. michael@0: */ michael@0: virtual TextureHost* GetAsTextureHost() { return nullptr; } michael@0: michael@0: virtual LayerRenderState GetRenderState() = 0; michael@0: michael@0: virtual void SetPictureRect(const nsIntRect& aPictureRect) michael@0: { michael@0: MOZ_ASSERT(false, "Should have been overridden"); michael@0: } michael@0: michael@0: /** michael@0: * Adds a mask effect using this texture as the mask, if possible. michael@0: * @return true if the effect was added, false otherwise. michael@0: */ michael@0: bool AddMaskEffect(EffectChain& aEffects, michael@0: const gfx::Matrix4x4& aTransform, michael@0: bool aIs3D = false); michael@0: michael@0: void RemoveMaskEffect(); michael@0: michael@0: Compositor* GetCompositor() const michael@0: { michael@0: return mCompositor; michael@0: } michael@0: michael@0: Layer* GetLayer() const { return mLayer; } michael@0: void SetLayer(Layer* aLayer) { mLayer = aLayer; } michael@0: michael@0: virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; } michael@0: michael@0: typedef uint32_t AttachFlags; michael@0: static const AttachFlags NO_FLAGS = 0; michael@0: static const AttachFlags ALLOW_REATTACH = 1; michael@0: static const AttachFlags KEEP_ATTACHED = 2; michael@0: static const AttachFlags FORCE_DETACH = 2; michael@0: michael@0: virtual void Attach(Layer* aLayer, michael@0: Compositor* aCompositor, michael@0: AttachFlags aFlags = NO_FLAGS) michael@0: { michael@0: MOZ_ASSERT(aCompositor, "Compositor is required"); michael@0: NS_ASSERTION(aFlags & ALLOW_REATTACH || !mAttached, michael@0: "Re-attaching compositables must be explicitly authorised"); michael@0: SetCompositor(aCompositor); michael@0: SetLayer(aLayer); michael@0: mAttached = true; michael@0: mKeepAttached = aFlags & KEEP_ATTACHED; michael@0: } michael@0: // Detach this compositable host from its layer. michael@0: // If we are used for async video, then it is not safe to blindly detach since michael@0: // we might be re-attached to a different layer. aLayer is the layer which the michael@0: // caller expects us to be attached to, we will only detach if we are in fact michael@0: // attached to that layer. If we are part of a normal layer, then we will be michael@0: // detached in any case. if aLayer is null, then we will only detach if we are michael@0: // not async. michael@0: // Only force detach if the IPDL tree is being shutdown. michael@0: void Detach(Layer* aLayer = nullptr, AttachFlags aFlags = NO_FLAGS) michael@0: { michael@0: if (!mKeepAttached || michael@0: aLayer == mLayer || michael@0: aFlags & FORCE_DETACH) { michael@0: SetLayer(nullptr); michael@0: mAttached = false; michael@0: mKeepAttached = false; michael@0: if (mBackendData) { michael@0: mBackendData->ClearData(); michael@0: } michael@0: } michael@0: } michael@0: bool IsAttached() { return mAttached; } michael@0: michael@0: #ifdef MOZ_DUMP_PAINTING michael@0: virtual void Dump(FILE* aFile=nullptr, michael@0: const char* aPrefix="", michael@0: bool aDumpHtml=false) { } michael@0: static void DumpTextureHost(FILE* aFile, TextureHost* aTexture); michael@0: michael@0: virtual TemporaryRef GetAsSurface() { return nullptr; } michael@0: #endif michael@0: michael@0: virtual void PrintInfo(nsACString& aTo, const char* aPrefix) { } michael@0: michael@0: virtual void UseTextureHost(TextureHost* aTexture); michael@0: virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack, michael@0: TextureHost* aTextureOnWhite); michael@0: michael@0: virtual void RemoveTextureHost(TextureHost* aTexture); michael@0: michael@0: // Called every time this is composited michael@0: void BumpFlashCounter() { michael@0: mFlashCounter = mFlashCounter >= DIAGNOSTIC_FLASH_COUNTER_MAX michael@0: ? DIAGNOSTIC_FLASH_COUNTER_MAX : mFlashCounter + 1; michael@0: } michael@0: michael@0: static PCompositableParent* michael@0: CreateIPDLActor(CompositableParentManager* mgr, michael@0: const TextureInfo& textureInfo, michael@0: uint64_t asyncID); michael@0: michael@0: static bool DestroyIPDLActor(PCompositableParent* actor); michael@0: michael@0: static CompositableHost* FromIPDLActor(PCompositableParent* actor); michael@0: michael@0: uint64_t GetCompositorID() const { return mCompositorID; } michael@0: michael@0: uint64_t GetAsyncID() const { return mAsyncID; } michael@0: michael@0: void SetCompositorID(uint64_t aID) { mCompositorID = aID; } michael@0: michael@0: void SetAsyncID(uint64_t aID) { mAsyncID = aID; } michael@0: michael@0: protected: michael@0: TextureInfo mTextureInfo; michael@0: uint64_t mAsyncID; michael@0: uint64_t mCompositorID; michael@0: Compositor* mCompositor; michael@0: Layer* mLayer; michael@0: RefPtr mBackendData; michael@0: uint32_t mFlashCounter; // used when the pref "layers.flash-borders" is true. michael@0: bool mAttached; michael@0: bool mKeepAttached; michael@0: }; michael@0: michael@0: /** michael@0: * Global CompositableMap, to use in the compositor thread only. michael@0: * michael@0: * PCompositable and PLayer can, in the case of async textures, be managed by michael@0: * different top level protocols. In this case they don't share the same michael@0: * communication channel and we can't send an OpAttachCompositable (PCompositable, michael@0: * PLayer) message. michael@0: * michael@0: * In order to attach a layer and the right compositable if the the compositable michael@0: * is async, we store references to the async compositables in a CompositableMap michael@0: * that is accessed only on the compositor thread. During a layer transaction we michael@0: * send the message OpAttachAsyncCompositable(ID, PLayer), and on the compositor michael@0: * side we lookup the ID in the map and attach the correspondig compositable to michael@0: * the layer. michael@0: * michael@0: * CompositableMap must be global because the image bridge doesn't have any michael@0: * reference to whatever we have created with PLayerTransaction. So, the only way to michael@0: * actually connect these two worlds is to have something global that they can michael@0: * both query (in the same thread). The map is not allocated the map on the michael@0: * stack to avoid the badness of static initialization. michael@0: * michael@0: * Also, we have a compositor/PLayerTransaction protocol/etc. per layer manager, and the michael@0: * ImageBridge is used by all the existing compositors that have a video, so michael@0: * there isn't an instance or "something" that lives outside the boudaries of a michael@0: * given layer manager on the compositor thread except the image bridge and the michael@0: * thread itself. michael@0: */ michael@0: namespace CompositableMap { michael@0: void Create(); michael@0: void Destroy(); michael@0: PCompositableParent* Get(uint64_t aID); michael@0: void Set(uint64_t aID, PCompositableParent* aParent); michael@0: void Erase(uint64_t aID); michael@0: void Clear(); michael@0: } // CompositableMap michael@0: michael@0: michael@0: } // namespace michael@0: } // namespace michael@0: michael@0: #endif