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_CONTENTCLIENT_H michael@0: #define MOZILLA_GFX_CONTENTCLIENT_H michael@0: michael@0: #include // for uint32_t michael@0: #include "RotatedBuffer.h" // for RotatedContentBuffer, etc michael@0: #include "gfxTypes.h" michael@0: #include "gfxPlatform.h" // for gfxPlatform michael@0: #include "mozilla/Assertions.h" // for MOZ_CRASH michael@0: #include "mozilla/Attributes.h" // for MOZ_OVERRIDE michael@0: #include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef michael@0: #include "mozilla/gfx/Point.h" // for IntSize michael@0: #include "mozilla/layers/CompositableClient.h" // for CompositableClient michael@0: #include "mozilla/layers/CompositableForwarder.h" michael@0: #include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc michael@0: #include "mozilla/layers/ISurfaceAllocator.h" michael@0: #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor michael@0: #include "mozilla/layers/TextureClient.h" // for TextureClient michael@0: #include "mozilla/mozalloc.h" // for operator delete michael@0: #include "nsCOMPtr.h" // for already_AddRefed michael@0: #include "nsPoint.h" // for nsIntPoint michael@0: #include "nsRect.h" // for nsIntRect michael@0: #include "nsRegion.h" // for nsIntRegion michael@0: #include "nsTArray.h" // for nsTArray michael@0: michael@0: class gfxContext; michael@0: michael@0: namespace mozilla { michael@0: namespace gfx { michael@0: class DrawTarget; michael@0: } michael@0: michael@0: namespace layers { michael@0: michael@0: class BasicLayerManager; michael@0: class ThebesLayer; michael@0: michael@0: /** michael@0: * A compositable client for Thebes layers. These are different to Image/Canvas michael@0: * clients due to sending a valid region across IPC and because we do a lot more michael@0: * optimisation work, encapsualted in RotatedContentBuffers. michael@0: * michael@0: * We use content clients for OMTC and non-OMTC, basic rendering so that michael@0: * BasicThebesLayer has only one interface to deal with. We support single and michael@0: * double buffered flavours. For tiled layers, we do not use a ContentClient michael@0: * although we do have a ContentHost, and we do use texture clients and texture michael@0: * hosts. michael@0: * michael@0: * The interface presented by ContentClient is used by the BasicThebesLayer michael@0: * methods - PaintThebes, which is the same for MT and OMTC, and PaintBuffer michael@0: * which is different (the OMTC one does a little more). The 'buffer' in the michael@0: * names of a lot of these method is actually the TextureClient. But, 'buffer' michael@0: * for the RotatedContentBuffer (as in SetBuffer) means a gfxSurface. See the michael@0: * comments for SetBuffer and SetBufferProvider in RotatedContentBuffer. To keep michael@0: * these mapped buffers alive, we store a pointer in mOldTextures if the michael@0: * RotatedContentBuffer's surface is not the one from our texture client, once we michael@0: * are done painting we unmap the surface/texture client and don't need to keep michael@0: * it alive anymore, so we clear mOldTextures. michael@0: * michael@0: * The sequence for painting is: call BeginPaint on the content client; michael@0: * call BeginPaintBuffer on the content client. That will initialise the buffer michael@0: * for painting, by calling RotatedContentBuffer::BeginPaint (usually) which michael@0: * will call back to ContentClient::FinalizeFrame to finalize update of the michael@0: * buffers before drawing (i.e., it finalizes the previous frame). Then call michael@0: * BorrowDrawTargetForPainting to get a DrawTarget to paint into. Then paint. michael@0: * Then return that DrawTarget using ReturnDrawTarget. michael@0: * Call EndPaint on the content client; michael@0: * michael@0: * SwapBuffers is called in response to the transaction reply from the compositor. michael@0: */ michael@0: class ContentClient : public CompositableClient michael@0: { michael@0: public: michael@0: /** michael@0: * Creates, configures, and returns a new content client. If necessary, a michael@0: * message will be sent to the compositor to create a corresponding content michael@0: * host. michael@0: */ michael@0: static TemporaryRef CreateContentClient(CompositableForwarder* aFwd); michael@0: michael@0: ContentClient(CompositableForwarder* aForwarder) michael@0: : CompositableClient(aForwarder) michael@0: {} michael@0: virtual ~ContentClient() michael@0: {} michael@0: michael@0: michael@0: virtual void Clear() = 0; michael@0: virtual RotatedContentBuffer::PaintState BeginPaintBuffer(ThebesLayer* aLayer, michael@0: uint32_t aFlags) = 0; michael@0: virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const RotatedContentBuffer::PaintState& aPaintState, michael@0: RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0; michael@0: virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0; michael@0: michael@0: // Called as part of the layers transation reply. Conveys data about our michael@0: // buffer(s) from the compositor. If appropriate we should swap references michael@0: // to our buffers. michael@0: virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {} michael@0: michael@0: // call before and after painting into this content client michael@0: virtual void BeginPaint() {} michael@0: virtual void EndPaint(); michael@0: }; michael@0: michael@0: /** michael@0: * A ContentClient for use with OMTC. michael@0: */ michael@0: class ContentClientRemote : public ContentClient michael@0: { michael@0: public: michael@0: ContentClientRemote(CompositableForwarder* aForwarder) michael@0: : ContentClient(aForwarder) michael@0: {} michael@0: michael@0: virtual void Updated(const nsIntRegion& aRegionToDraw, michael@0: const nsIntRegion& aVisibleRegion, michael@0: bool aDidSelfCopy) = 0; michael@0: }; michael@0: michael@0: // thin wrapper around RotatedContentBuffer, for on-mtc michael@0: class ContentClientBasic : public ContentClient michael@0: , protected RotatedContentBuffer michael@0: { michael@0: public: michael@0: ContentClientBasic(); michael@0: michael@0: typedef RotatedContentBuffer::PaintState PaintState; michael@0: typedef RotatedContentBuffer::ContentType ContentType; michael@0: michael@0: virtual void Clear() { RotatedContentBuffer::Clear(); } michael@0: virtual PaintState BeginPaintBuffer(ThebesLayer* aLayer, michael@0: uint32_t aFlags) MOZ_OVERRIDE michael@0: { michael@0: return RotatedContentBuffer::BeginPaint(aLayer, aFlags); michael@0: } michael@0: virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState, michael@0: RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE michael@0: { michael@0: return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter); michael@0: } michael@0: virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE michael@0: { michael@0: BorrowDrawTarget::ReturnDrawTarget(aReturned); michael@0: } michael@0: michael@0: void DrawTo(ThebesLayer* aLayer, michael@0: gfx::DrawTarget* aTarget, michael@0: float aOpacity, michael@0: gfx::CompositionOp aOp, michael@0: gfx::SourceSurface* aMask, michael@0: const gfx::Matrix* aMaskTransform) michael@0: { michael@0: RotatedContentBuffer::DrawTo(aLayer, aTarget, aOpacity, aOp, michael@0: aMask, aMaskTransform); michael@0: } michael@0: michael@0: virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, michael@0: RefPtr* aBlackDT, RefPtr* aWhiteDT) MOZ_OVERRIDE; michael@0: michael@0: virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE michael@0: { michael@0: MOZ_CRASH("Should not be called on non-remote ContentClient"); michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * A ContentClientRemote backed by a RotatedContentBuffer. michael@0: * michael@0: * When using a ContentClientRemote, SurfaceDescriptors are created on michael@0: * the rendering side and destroyed on the compositing side. They are only michael@0: * passed from one side to the other when the TextureClient/Hosts are created. michael@0: * *Ownership* of the SurfaceDescriptor moves from the rendering side to the michael@0: * compositing side with the create message (send from CreateBuffer) which michael@0: * tells the compositor that TextureClients have been created and that the michael@0: * compositor should assign the corresponding TextureHosts to our corresponding michael@0: * ContentHost. michael@0: * michael@0: * If the size or type of our buffer(s) change(s), then we simply destroy and michael@0: * create them. michael@0: */ michael@0: // Version using new texture clients michael@0: class ContentClientRemoteBuffer : public ContentClientRemote michael@0: , protected RotatedContentBuffer michael@0: { michael@0: using RotatedContentBuffer::BufferRect; michael@0: using RotatedContentBuffer::BufferRotation; michael@0: public: michael@0: ContentClientRemoteBuffer(CompositableForwarder* aForwarder) michael@0: : ContentClientRemote(aForwarder) michael@0: , RotatedContentBuffer(ContainsVisibleBounds) michael@0: , mIsNewBuffer(false) michael@0: , mFrontAndBackBufferDiffer(false) michael@0: , mSurfaceFormat(gfx::SurfaceFormat::B8G8R8A8) michael@0: {} michael@0: michael@0: typedef RotatedContentBuffer::PaintState PaintState; michael@0: typedef RotatedContentBuffer::ContentType ContentType; michael@0: michael@0: virtual void Clear() michael@0: { michael@0: RotatedContentBuffer::Clear(); michael@0: mTextureClient = nullptr; michael@0: mTextureClientOnWhite = nullptr; michael@0: } michael@0: michael@0: virtual PaintState BeginPaintBuffer(ThebesLayer* aLayer, michael@0: uint32_t aFlags) MOZ_OVERRIDE michael@0: { michael@0: return RotatedContentBuffer::BeginPaint(aLayer, aFlags); michael@0: } michael@0: virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState, michael@0: RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE michael@0: { michael@0: return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter); michael@0: } michael@0: virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE michael@0: { michael@0: BorrowDrawTarget::ReturnDrawTarget(aReturned); michael@0: } michael@0: michael@0: /** michael@0: * Begin/End Paint map a gfxASurface from the texture client michael@0: * into the buffer of RotatedBuffer. The surface is only michael@0: * valid when the texture client is locked, so is mapped out michael@0: * of RotatedContentBuffer when we are done painting. michael@0: * None of the underlying buffer attributes (rect, rotation) michael@0: * are affected by mapping/unmapping. michael@0: */ michael@0: virtual void BeginPaint() MOZ_OVERRIDE; michael@0: virtual void EndPaint() MOZ_OVERRIDE; michael@0: michael@0: virtual void Updated(const nsIntRegion& aRegionToDraw, michael@0: const nsIntRegion& aVisibleRegion, michael@0: bool aDidSelfCopy); michael@0: michael@0: virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) MOZ_OVERRIDE; michael@0: michael@0: // Expose these protected methods from the superclass. michael@0: virtual const nsIntRect& BufferRect() const michael@0: { michael@0: return RotatedContentBuffer::BufferRect(); michael@0: } michael@0: virtual const nsIntPoint& BufferRotation() const michael@0: { michael@0: return RotatedContentBuffer::BufferRotation(); michael@0: } michael@0: michael@0: virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, michael@0: RefPtr* aBlackDT, RefPtr* aWhiteDT) MOZ_OVERRIDE; michael@0: michael@0: virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE michael@0: { michael@0: return mTextureInfo; michael@0: } michael@0: michael@0: protected: michael@0: void DestroyBuffers(); michael@0: michael@0: virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw, michael@0: const nsIntRegion& aVisibleRegion, michael@0: bool aDidSelfCopy); michael@0: michael@0: void BuildTextureClients(gfx::SurfaceFormat aFormat, michael@0: const nsIntRect& aRect, michael@0: uint32_t aFlags); michael@0: michael@0: // Create the front buffer for the ContentClient/Host pair if necessary michael@0: // and notify the compositor that we have created the buffer(s). michael@0: virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) = 0; michael@0: virtual void DestroyFrontBuffer() {} michael@0: michael@0: bool CreateAndAllocateTextureClient(RefPtr& aClient, michael@0: TextureFlags aFlags = 0); michael@0: michael@0: virtual void AbortTextureClientCreation() michael@0: { michael@0: mTextureClient = nullptr; michael@0: mTextureClientOnWhite = nullptr; michael@0: mIsNewBuffer = false; michael@0: } michael@0: michael@0: RefPtr mTextureClient; michael@0: RefPtr mTextureClientOnWhite; michael@0: // keep a record of texture clients we have created and need to keep around michael@0: // (for RotatedBuffer to access), then unlock and remove them when we are done michael@0: // painting. michael@0: nsTArray > mOldTextures; michael@0: michael@0: TextureInfo mTextureInfo; michael@0: bool mIsNewBuffer; michael@0: bool mFrontAndBackBufferDiffer; michael@0: gfx::IntSize mSize; michael@0: gfx::SurfaceFormat mSurfaceFormat; michael@0: }; michael@0: michael@0: /** michael@0: * A double buffered ContentClient. mTextureClient is the back buffer, which michael@0: * we draw into. mFrontClient is the front buffer which we may read from, but michael@0: * not write to, when the compositor does not have the 'soft' lock. We can write michael@0: * into mTextureClient at any time. michael@0: * michael@0: * The ContentHost keeps a reference to both corresponding texture hosts, in michael@0: * response to our UpdateTextureRegion message, the compositor swaps its michael@0: * references. In response to the compositor's reply we swap our references michael@0: * (in SwapBuffers). michael@0: */ michael@0: class ContentClientDoubleBuffered : public ContentClientRemoteBuffer michael@0: { michael@0: public: michael@0: ContentClientDoubleBuffered(CompositableForwarder* aFwd) michael@0: : ContentClientRemoteBuffer(aFwd) michael@0: { michael@0: mTextureInfo.mCompositableType = COMPOSITABLE_CONTENT_DOUBLE; michael@0: } michael@0: virtual ~ContentClientDoubleBuffered() {} michael@0: michael@0: virtual void Clear() MOZ_OVERRIDE michael@0: { michael@0: ContentClientRemoteBuffer::Clear(); michael@0: mFrontClient = nullptr; michael@0: mFrontClientOnWhite = nullptr; michael@0: } michael@0: michael@0: virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) MOZ_OVERRIDE; michael@0: michael@0: virtual void BeginPaint() MOZ_OVERRIDE; michael@0: michael@0: virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) MOZ_OVERRIDE; michael@0: virtual void DestroyFrontBuffer() MOZ_OVERRIDE; michael@0: michael@0: private: michael@0: void UpdateDestinationFrom(const RotatedBuffer& aSource, michael@0: const nsIntRegion& aUpdateRegion); michael@0: michael@0: virtual void AbortTextureClientCreation() MOZ_OVERRIDE michael@0: { michael@0: mTextureClient = nullptr; michael@0: mTextureClientOnWhite = nullptr; michael@0: mFrontClient = nullptr; michael@0: mFrontClientOnWhite = nullptr; michael@0: } michael@0: michael@0: RefPtr mFrontClient; michael@0: RefPtr mFrontClientOnWhite; michael@0: nsIntRegion mFrontUpdatedRegion; michael@0: nsIntRect mFrontBufferRect; michael@0: nsIntPoint mFrontBufferRotation; michael@0: }; michael@0: michael@0: /** michael@0: * A single buffered ContentClient. We have a single TextureClient/Host michael@0: * which we update and then send a message to the compositor that we are michael@0: * done updating. It is not safe for the compositor to use the corresponding michael@0: * TextureHost's memory directly, it must upload it to video memory of some michael@0: * kind. We are free to modify the TextureClient once we receive reply from michael@0: * the compositor. michael@0: */ michael@0: class ContentClientSingleBuffered : public ContentClientRemoteBuffer michael@0: { michael@0: public: michael@0: ContentClientSingleBuffered(CompositableForwarder* aFwd) michael@0: : ContentClientRemoteBuffer(aFwd) michael@0: { michael@0: mTextureInfo.mCompositableType = COMPOSITABLE_CONTENT_SINGLE; michael@0: } michael@0: virtual ~ContentClientSingleBuffered() {} michael@0: michael@0: virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) MOZ_OVERRIDE; michael@0: michael@0: protected: michael@0: virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) MOZ_OVERRIDE {} michael@0: }; michael@0: michael@0: /** michael@0: * A single buffered ContentClient that creates temporary buffers which are michael@0: * used to update the host-side texture. The ownership of the buffers is michael@0: * passed to the host side during the transaction, and we need to create michael@0: * new ones each frame. michael@0: */ michael@0: class ContentClientIncremental : public ContentClientRemote michael@0: , public BorrowDrawTarget michael@0: { michael@0: public: michael@0: ContentClientIncremental(CompositableForwarder* aFwd) michael@0: : ContentClientRemote(aFwd) michael@0: , mContentType(gfxContentType::COLOR_ALPHA) michael@0: , mHasBuffer(false) michael@0: , mHasBufferOnWhite(false) michael@0: { michael@0: mTextureInfo.mCompositableType = BUFFER_CONTENT_INC; michael@0: } michael@0: michael@0: typedef RotatedContentBuffer::PaintState PaintState; michael@0: typedef RotatedContentBuffer::ContentType ContentType; michael@0: michael@0: virtual TextureInfo GetTextureInfo() const michael@0: { michael@0: return mTextureInfo; michael@0: } michael@0: michael@0: virtual void Clear() michael@0: { michael@0: mBufferRect.SetEmpty(); michael@0: mHasBuffer = false; michael@0: mHasBufferOnWhite = false; michael@0: } michael@0: michael@0: virtual PaintState BeginPaintBuffer(ThebesLayer* aLayer, michael@0: uint32_t aFlags) MOZ_OVERRIDE; michael@0: virtual gfx::DrawTarget* BorrowDrawTargetForPainting(const PaintState& aPaintState, michael@0: RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE; michael@0: virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE michael@0: { michael@0: BorrowDrawTarget::ReturnDrawTarget(aReturned); michael@0: } michael@0: michael@0: virtual void Updated(const nsIntRegion& aRegionToDraw, michael@0: const nsIntRegion& aVisibleRegion, michael@0: bool aDidSelfCopy); michael@0: michael@0: virtual void EndPaint() michael@0: { michael@0: if (IsSurfaceDescriptorValid(mUpdateDescriptor)) { michael@0: mForwarder->DestroySharedSurface(&mUpdateDescriptor); michael@0: } michael@0: if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) { michael@0: mForwarder->DestroySharedSurface(&mUpdateDescriptorOnWhite); michael@0: } michael@0: ContentClientRemote::EndPaint(); michael@0: } michael@0: michael@0: private: michael@0: michael@0: enum BufferType{ michael@0: BUFFER_BLACK, michael@0: BUFFER_WHITE michael@0: }; michael@0: michael@0: void NotifyBufferCreated(ContentType aType, uint32_t aFlags) michael@0: { michael@0: mTextureInfo.mTextureFlags = aFlags & ~TEXTURE_DEALLOCATE_CLIENT; michael@0: mContentType = aType; michael@0: michael@0: mForwarder->CreatedIncrementalBuffer(this, michael@0: mTextureInfo, michael@0: mBufferRect); michael@0: michael@0: } michael@0: michael@0: TemporaryRef GetUpdateSurface(BufferType aType, michael@0: const nsIntRegion& aUpdateRegion); michael@0: michael@0: TextureInfo mTextureInfo; michael@0: nsIntRect mBufferRect; michael@0: nsIntPoint mBufferRotation; michael@0: michael@0: SurfaceDescriptor mUpdateDescriptor; michael@0: SurfaceDescriptor mUpdateDescriptorOnWhite; michael@0: michael@0: ContentType mContentType; michael@0: michael@0: bool mHasBuffer; michael@0: bool mHasBufferOnWhite; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif