diff options
Diffstat (limited to 'gfx/layers/client/TiledContentClient.h')
-rw-r--r-- | gfx/layers/client/TiledContentClient.h | 545 |
1 files changed, 545 insertions, 0 deletions
diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h new file mode 100644 index 000000000..cf55450f8 --- /dev/null +++ b/gfx/layers/client/TiledContentClient.h @@ -0,0 +1,545 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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_TILEDCONTENTCLIENT_H +#define MOZILLA_GFX_TILEDCONTENTCLIENT_H + +#include <stddef.h> // for size_t +#include <stdint.h> // for uint16_t +#include <algorithm> // for swap +#include <limits> +#include "Layers.h" // for LayerManager, etc +#include "TiledLayerBuffer.h" // for TiledLayerBuffer +#include "Units.h" // for CSSPoint +#include "gfxTypes.h" +#include "mozilla/Attributes.h" // for override +#include "mozilla/RefPtr.h" // for RefPtr +#include "mozilla/ipc/Shmem.h" // for Shmem +#include "mozilla/ipc/SharedMemory.h" // for SharedMemory +#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform +#include "mozilla/layers/CompositableClient.h" // for CompositableClient +#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc +#include "mozilla/layers/LayersMessages.h" // for TileDescriptor +#include "mozilla/layers/LayersTypes.h" // for TextureDumpMode +#include "mozilla/layers/TextureClient.h" +#include "mozilla/layers/TextureClientPool.h" +#include "ClientLayerManager.h" +#include "mozilla/mozalloc.h" // for operator delete +#include "nsISupportsImpl.h" // for MOZ_COUNT_DTOR +#include "nsPoint.h" // for nsIntPoint +#include "nsRect.h" // for mozilla::gfx::IntRect +#include "nsRegion.h" // for nsIntRegion +#include "nsTArray.h" // for nsTArray, nsTArray_Impl, etc +#include "nsExpirationTracker.h" +#include "mozilla/layers/ISurfaceAllocator.h" + +namespace mozilla { +namespace layers { + +class ClientTiledPaintedLayer; +class ClientLayerManager; + +/** + * Represent a single tile in tiled buffer. The buffer keeps tiles, + * each tile keeps a reference to a texture client and a read-lock. This + * read-lock is used to help implement a copy-on-write mechanism. The tile + * should be locked before being sent to the compositor. The compositor should + * unlock the read-lock as soon as it has finished with the buffer in the + * TextureHost to prevent more textures being created than is necessary. + * Ideal place to store per tile debug information. + */ +struct TileClient +{ + // Placeholder + TileClient(); + ~TileClient(); + + TileClient(const TileClient& o); + + TileClient& operator=(const TileClient& o); + + bool operator== (const TileClient& o) const + { + return mFrontBuffer == o.mFrontBuffer; + } + + bool operator!= (const TileClient& o) const + { + return mFrontBuffer != o.mFrontBuffer; + } + + void SetTextureAllocator(TextureClientAllocator* aAllocator) + { + mAllocator = aAllocator; + } + + bool IsPlaceholderTile() const + { + return mBackBuffer == nullptr && mFrontBuffer == nullptr; + } + + void DiscardBuffers() + { + DiscardFrontBuffer(); + DiscardBackBuffer(); + } + + nsExpirationState *GetExpirationState() { return &mExpirationState; } + + TileDescriptor GetTileDescriptor(); + + /** + * For debugging. + */ + void Dump(std::stringstream& aStream); + + /** + * Swaps the front and back buffers. + */ + void Flip(); + + void DumpTexture(std::stringstream& aStream, TextureDumpMode aCompress) { + // TODO We should combine the OnWhite/OnBlack here an just output a single image. + CompositableClient::DumpTextureClient(aStream, mFrontBuffer, aCompress); + } + + /** + * Returns an unlocked TextureClient that can be used for writing new + * data to the tile. This may flip the front-buffer to the back-buffer if + * the front-buffer is still locked by the host, or does not have an + * internal buffer (and so will always be locked). + * + * If getting the back buffer required copying pixels from the front buffer + * then the copied region is stored in aAddPaintedRegion so the host side + * knows to upload it. + * + * If nullptr is returned, aTextureClientOnWhite is undefined. + */ + TextureClient* GetBackBuffer(CompositableClient&, + const nsIntRegion& aDirtyRegion, + gfxContentType aContent, SurfaceMode aMode, + nsIntRegion& aAddPaintedRegion, + RefPtr<TextureClient>* aTextureClientOnWhite); + + void DiscardFrontBuffer(); + + void DiscardBackBuffer(); + + /* We wrap the back buffer in a class that disallows assignment + * so that we can track when ever it changes so that we can update + * the expiry tracker for expiring the back buffers */ + class PrivateProtector { + public: + void Set(TileClient * container, RefPtr<TextureClient>); + void Set(TileClient * container, TextureClient*); + // Implicitly convert to TextureClient* because we can't chain + // implicit conversion that would happen on RefPtr<TextureClient> + operator TextureClient*() const { return mBuffer; } + RefPtr<TextureClient> operator ->() { return mBuffer; } + private: + PrivateProtector& operator=(const PrivateProtector &); + RefPtr<TextureClient> mBuffer; + } mBackBuffer; + RefPtr<TextureClient> mBackBufferOnWhite; + RefPtr<TextureClient> mFrontBuffer; + RefPtr<TextureClient> mFrontBufferOnWhite; + RefPtr<TextureClientAllocator> mAllocator; + gfx::IntRect mUpdateRect; + bool mWasPlaceholder; +#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY + TimeStamp mLastUpdate; +#endif + nsIntRegion mInvalidFront; + nsIntRegion mInvalidBack; + nsExpirationState mExpirationState; +private: + // Copies dirty pixels from the front buffer into the back buffer, + // and records the copied region in aAddPaintedRegion. + void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion, + nsIntRegion& aAddPaintedRegion); +}; + +/** + * This struct stores all the data necessary to perform a paint so that it + * doesn't need to be recalculated on every repeated transaction. + */ +struct BasicTiledLayerPaintData { + /* + * The scroll offset of the content from the nearest ancestor layer that + * represents scrollable content with a display port set. + */ + ParentLayerPoint mScrollOffset; + + /* + * The scroll offset of the content from the nearest ancestor layer that + * represents scrollable content with a display port set, for the last + * layer update transaction. + */ + ParentLayerPoint mLastScrollOffset; + + /* + * The transform matrix to go from this layer's Layer units to + * the scroll ancestor's ParentLayer units. The "scroll ancestor" is + * the closest ancestor layer which scrolls, and is used to obtain + * the composition bounds that are relevant for this layer. + */ + LayerToParentLayerMatrix4x4 mTransformToCompBounds; + + /* + * The critical displayport of the content from the nearest ancestor layer + * that represents scrollable content with a display port set. isNothing() + * if a critical displayport is not set. + */ + Maybe<LayerIntRect> mCriticalDisplayPort; + + /* + * The render resolution of the document that the content this layer + * represents is in. + */ + CSSToParentLayerScale2D mResolution; + + /* + * The composition bounds of the layer, in Layer coordinates. This is + * used to make sure that tiled updates to regions that are visible to the + * user are grouped coherently. + */ + LayerRect mCompositionBounds; + + /* + * Low precision updates are always executed a tile at a time in repeated + * transactions. This counter is set to 1 on the first transaction of a low + * precision update, and incremented for each subsequent transaction. + */ + uint16_t mLowPrecisionPaintCount; + + /* + * Whether this is the first time this layer is painting + */ + bool mFirstPaint : 1; + + /* + * Whether there is further work to complete this paint. This is used to + * determine whether or not to repeat the transaction when painting + * progressively. + */ + bool mPaintFinished : 1; + + /* + * Whether or not there is an async transform animation active + */ + bool mHasTransformAnimation : 1; + + /* + * Initializes/clears data to prepare for paint action. + */ + void ResetPaintData(); +}; + +class SharedFrameMetricsHelper +{ +public: + SharedFrameMetricsHelper(); + ~SharedFrameMetricsHelper(); + + /** + * This is called by the BasicTileLayer to determine if it is still interested + * in the update of this display-port to continue. We can return true here + * to abort the current update and continue with any subsequent ones. This + * is useful for slow-to-render pages when the display-port starts lagging + * behind enough that continuing to draw it is wasted effort. + */ + bool UpdateFromCompositorFrameMetrics(const LayerMetricsWrapper& aLayer, + bool aHasPendingNewThebesContent, + bool aLowPrecision, + AsyncTransform& aViewTransform); + + /** + * Determines if the compositor's upcoming composition bounds has fallen + * outside of the contents display port. If it has then the compositor + * will start to checker board. Checker boarding is when the compositor + * tries to composite a tile and it is not available. Historically + * a tile with a checker board pattern was used. Now a blank tile is used. + */ + bool AboutToCheckerboard(const FrameMetrics& aContentMetrics, + const FrameMetrics& aCompositorMetrics); +private: + bool mLastProgressiveUpdateWasLowPrecision; + bool mProgressiveUpdateWasInDanger; +}; + +/** + * Provide an instance of TiledLayerBuffer backed by drawable TextureClients. + * This buffer provides an implementation of ValidateTile using a + * thebes callback and can support painting using a single paint buffer. + * Whether a single paint buffer is used is controlled by + * gfxPrefs::PerTileDrawing(). + */ +class ClientTiledLayerBuffer +{ +public: + ClientTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer, + CompositableClient& aCompositableClient) + : mPaintedLayer(aPaintedLayer) + , mCompositableClient(aCompositableClient) + , mLastPaintContentType(gfxContentType::COLOR) + , mLastPaintSurfaceMode(SurfaceMode::SURFACE_OPAQUE) + , mWasLastPaintProgressive(false) + {} + + virtual void PaintThebes(const nsIntRegion& aNewValidRegion, + const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion, + LayerManager::DrawPaintedLayerCallback aCallback, + void* aCallbackData, + bool aIsProgressive = false) = 0; + + virtual bool SupportsProgressiveUpdate() = 0; + virtual bool ProgressiveUpdate(nsIntRegion& aValidRegion, + nsIntRegion& aInvalidRegion, + const nsIntRegion& aOldValidRegion, + BasicTiledLayerPaintData* aPaintData, + LayerManager::DrawPaintedLayerCallback aCallback, + void* aCallbackData) = 0; + virtual void ResetPaintedAndValidState() = 0; + + virtual const nsIntRegion& GetValidRegion() = 0; + + virtual bool IsLowPrecision() const = 0; + + virtual void Dump(std::stringstream& aStream, + const char* aPrefix, + bool aDumpHtml, + TextureDumpMode aCompress) {} + + const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; } + void SetFrameResolution(const CSSToParentLayerScale2D& aResolution) { mFrameResolution = aResolution; } + + bool HasFormatChanged() const; + +protected: + void UnlockTile(TileClient& aTile); + gfxContentType GetContentType(SurfaceMode* aMode = nullptr) const; + + ClientTiledPaintedLayer& mPaintedLayer; + CompositableClient& mCompositableClient; + + gfxContentType mLastPaintContentType; + SurfaceMode mLastPaintSurfaceMode; + CSSToParentLayerScale2D mFrameResolution; + + bool mWasLastPaintProgressive; +}; + +class ClientMultiTiledLayerBuffer + : public TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient> + , public ClientTiledLayerBuffer +{ + friend class TiledLayerBuffer<ClientMultiTiledLayerBuffer, TileClient>; +public: + ClientMultiTiledLayerBuffer(ClientTiledPaintedLayer& aPaintedLayer, + CompositableClient& aCompositableClient, + ClientLayerManager* aManager, + SharedFrameMetricsHelper* aHelper); + + void PaintThebes(const nsIntRegion& aNewValidRegion, + const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion, + LayerManager::DrawPaintedLayerCallback aCallback, + void* aCallbackData, + bool aIsProgressive = false) override; + + virtual bool SupportsProgressiveUpdate() override { return true; } + /** + * Performs a progressive update of a given tiled buffer. + * See ComputeProgressiveUpdateRegion below for parameter documentation. + */ + bool ProgressiveUpdate(nsIntRegion& aValidRegion, + nsIntRegion& aInvalidRegion, + const nsIntRegion& aOldValidRegion, + BasicTiledLayerPaintData* aPaintData, + LayerManager::DrawPaintedLayerCallback aCallback, + void* aCallbackData) override; + + void ResetPaintedAndValidState() override { + mPaintedRegion.SetEmpty(); + mValidRegion.SetEmpty(); + mTiles.mSize.width = 0; + mTiles.mSize.height = 0; + DiscardBuffers(); + mRetainedTiles.Clear(); + } + + + const nsIntRegion& GetValidRegion() override { + return TiledLayerBuffer::GetValidRegion(); + } + + bool IsLowPrecision() const override { + return TiledLayerBuffer::IsLowPrecision(); + } + + void Dump(std::stringstream& aStream, + const char* aPrefix, + bool aDumpHtml, + TextureDumpMode aCompress) override { + TiledLayerBuffer::Dump(aStream, aPrefix, aDumpHtml, aCompress); + } + + void ReadLock(); + + void Release(); + + void DiscardBuffers(); + + SurfaceDescriptorTiles GetSurfaceDescriptorTiles(); + + void SetResolution(float aResolution) { + if (mResolution == aResolution) { + return; + } + + Update(nsIntRegion(), nsIntRegion(), nsIntRegion()); + mResolution = aResolution; + } + +protected: + bool ValidateTile(TileClient& aTile, + const nsIntPoint& aTileRect, + const nsIntRegion& dirtyRect); + + void Update(const nsIntRegion& aNewValidRegion, + const nsIntRegion& aPaintRegion, + const nsIntRegion& aDirtyRegion); + + TileClient GetPlaceholderTile() const { return TileClient(); } + +private: + RefPtr<ClientLayerManager> mManager; + LayerManager::DrawPaintedLayerCallback mCallback; + void* mCallbackData; + + // The region that will be made valid during Update(). Once Update() is + // completed then this is identical to mValidRegion. + nsIntRegion mNewValidRegion; + + SharedFrameMetricsHelper* mSharedFrameMetricsHelper; + // When using Moz2D's CreateTiledDrawTarget we maintain a list of gfx::Tiles + std::vector<gfx::Tile> mMoz2DTiles; + /** + * While we're adding tiles, this is used to keep track of the position of + * the top-left of the top-left-most tile. When we come to wrap the tiles in + * TiledDrawTarget we subtract the value of this member from each tile's + * offset so that all the tiles have a positive offset, then add a + * translation to the TiledDrawTarget to compensate. This is important so + * that the mRect of the TiledDrawTarget is always at a positive x/y + * position, otherwise its GetSize() methods will be broken. + */ + gfx::IntPoint mTilingOrigin; + /** + * Calculates the region to update in a single progressive update transaction. + * This employs some heuristics to update the most 'sensible' region to + * update at this point in time, and how large an update should be performed + * at once to maintain visual coherency. + * + * aInvalidRegion is the current invalid region. + * aOldValidRegion is the valid region of mTiledBuffer at the beginning of the + * current transaction. + * aRegionToPaint will be filled with the region to update. This may be empty, + * which indicates that there is no more work to do. + * aIsRepeated should be true if this function has already been called during + * this transaction. + * + * Returns true if it should be called again, false otherwise. In the case + * that aRegionToPaint is empty, this will return aIsRepeated for convenience. + */ + bool ComputeProgressiveUpdateRegion(const nsIntRegion& aInvalidRegion, + const nsIntRegion& aOldValidRegion, + nsIntRegion& aRegionToPaint, + BasicTiledLayerPaintData* aPaintData, + bool aIsRepeated); +}; + +class TiledContentClient : public CompositableClient +{ +public: + TiledContentClient(ClientLayerManager* aManager, + const char* aName = "") + : CompositableClient(aManager->AsShadowForwarder()) + , mName(aName) + {} + +protected: + ~TiledContentClient() + {} + +public: + virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix); + + virtual void Dump(std::stringstream& aStream, + const char* aPrefix="", + bool aDumpHtml=false, + TextureDumpMode aCompress=TextureDumpMode::Compress) override; + + virtual TextureInfo GetTextureInfo() const override + { + return TextureInfo(CompositableType::CONTENT_TILED); + } + + + virtual ClientTiledLayerBuffer* GetTiledBuffer() = 0; + virtual ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() = 0; + + enum TiledBufferType { + TILED_BUFFER, + LOW_PRECISION_TILED_BUFFER + }; + virtual void UpdatedBuffer(TiledBufferType aType) = 0; + +private: + const char* mName; +}; + +/** + * An implementation of TiledContentClient that supports + * multiple tiles and a low precision buffer. + */ +class MultiTiledContentClient : public TiledContentClient +{ +public: + MultiTiledContentClient(ClientTiledPaintedLayer& aPaintedLayer, + ClientLayerManager* aManager); + +protected: + ~MultiTiledContentClient() + { + MOZ_COUNT_DTOR(MultiTiledContentClient); + + mTiledBuffer.DiscardBuffers(); + mLowPrecisionTiledBuffer.DiscardBuffers(); + } + +public: + void ClearCachedResources() override; + void UpdatedBuffer(TiledBufferType aType) override; + + ClientTiledLayerBuffer* GetTiledBuffer() override { return &mTiledBuffer; } + ClientTiledLayerBuffer* GetLowPrecisionTiledBuffer() override { + if (mHasLowPrecision) { + return &mLowPrecisionTiledBuffer; + } + return nullptr; + } + +private: + SharedFrameMetricsHelper mSharedFrameMetricsHelper; + ClientMultiTiledLayerBuffer mTiledBuffer; + ClientMultiTiledLayerBuffer mLowPrecisionTiledBuffer; + bool mHasLowPrecision; +}; + +} // namespace layers +} // namespace mozilla + +#endif |