diff options
Diffstat (limited to 'gfx/layers/TiledLayerBuffer.h')
-rw-r--r-- | gfx/layers/TiledLayerBuffer.h | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/gfx/layers/TiledLayerBuffer.h b/gfx/layers/TiledLayerBuffer.h new file mode 100644 index 000000000..c1efcc39e --- /dev/null +++ b/gfx/layers/TiledLayerBuffer.h @@ -0,0 +1,220 @@ +/* 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 GFX_TILEDLAYERBUFFER_H +#define GFX_TILEDLAYERBUFFER_H + +// Debug defines +//#define GFX_TILEDLAYER_DEBUG_OVERLAY +//#define GFX_TILEDLAYER_PREF_WARNINGS +//#define GFX_TILEDLAYER_RETAINING_LOG + +#include <stdint.h> // for uint16_t, uint32_t +#include <sys/types.h> // for int32_t +#include "LayersLogging.h" // for print_stderr +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/gfx/Logging.h" // for gfxCriticalError +#include "mozilla/layers/LayersTypes.h" // for TextureDumpMode +#include "nsDebug.h" // for NS_ASSERTION +#include "nsPoint.h" // for nsIntPoint +#include "nsRect.h" // for mozilla::gfx::IntRect +#include "nsRegion.h" // for nsIntRegion +#include "nsTArray.h" // for nsTArray + +namespace mozilla { + +struct TileUnit {}; +template<> struct IsPixel<TileUnit> : mozilla::TrueType {}; + +namespace layers { + +// You can enable all the TILING_LOG print statements by +// changing the 0 to a 1 in the following #define. +#define ENABLE_TILING_LOG 0 + +#if ENABLE_TILING_LOG +# define TILING_LOG(...) printf_stderr(__VA_ARGS__); +#else +# define TILING_LOG(...) +#endif + +// Normal integer division truncates towards zero, +// we instead want to floor to hangle negative numbers. +static inline int floor_div(int a, int b) +{ + int rem = a % b; + int div = a/b; + if (rem == 0) { + return div; + } else { + // If the signs are different substract 1. + int sub; + sub = a ^ b; + // The results of this shift is either 0 or -1. + sub >>= 8*sizeof(int)-1; + return div+sub; + } +} + +// Tiles are aligned to a grid with one of the grid points at (0,0) and other +// grid points spaced evenly in the x- and y-directions by GetTileSize() +// multiplied by mResolution. GetScaledTileSize() provides convenience for +// accessing these values. +// +// This tile buffer stores a valid region, which defines the areas that have +// up-to-date content. The contents of tiles within this region will be reused +// from paint to paint. It also stores the region that was modified in the last +// paint operation; this is useful when one tiled layer buffer shadows another +// (as in an off-main-thread-compositing scenario), so that the shadow tiled +// layer buffer can correctly reflect the updates of the master layer buffer. +// +// The associated Tile may be of any type as long as the derived class can +// validate and return tiles of that type. Tiles will be frequently copied, so +// the tile type should be a reference or some other type with an efficient +// copy constructor. +// +// The contents of the tile buffer will be rendered at the resolution specified +// in mResolution, which can be altered with SetResolution. The resolution +// should always be a factor of the tile length, to avoid tiles covering +// non-integer amounts of pixels. + +// Size and Point in number of tiles rather than in pixels +typedef gfx::IntSizeTyped<TileUnit> TileIntSize; +typedef gfx::IntPointTyped<TileUnit> TileIntPoint; + +/** + * Stores the origin and size of a tile buffer and handles switching between + * tile indices and tile positions. + * + * Tile positions in TileIntPoint take the first tile offset into account which + * means that two TilesPlacement of the same layer and resolution give tile + * positions in the same coordinate space (useful when changing the offset and/or + * size of a tile buffer). + */ +struct TilesPlacement { + // in tiles + TileIntPoint mFirst; + TileIntSize mSize; + + TilesPlacement(int aFirstX, int aFirstY, + int aRetainedWidth, int aRetainedHeight) + : mFirst(aFirstX, aFirstY) + , mSize(aRetainedWidth, aRetainedHeight) + {} + + int TileIndex(TileIntPoint aPosition) const { + return (aPosition.x - mFirst.x) * mSize.height + aPosition.y - mFirst.y; + } + + TileIntPoint TilePosition(size_t aIndex) const { + return TileIntPoint( + mFirst.x + aIndex / mSize.height, + mFirst.y + aIndex % mSize.height + ); + } + + bool HasTile(TileIntPoint aPosition) const { + return aPosition.x >= mFirst.x && aPosition.x < mFirst.x + mSize.width && + aPosition.y >= mFirst.y && aPosition.y < mFirst.y + mSize.height; + } +}; + + +// Given a position i, this function returns the position inside the current tile. +inline int GetTileStart(int i, int aTileLength) { + return (i >= 0) ? (i % aTileLength) + : ((aTileLength - (-i % aTileLength)) % + aTileLength); +} + +// Rounds the given coordinate down to the nearest tile boundary. +inline int RoundDownToTileEdge(int aX, int aTileLength) { return aX - GetTileStart(aX, aTileLength); } + +template<typename Derived, typename Tile> +class TiledLayerBuffer +{ +public: + TiledLayerBuffer() + : mTiles(0, 0, 0, 0) + , mResolution(1) + , mTileSize(mozilla::gfx::gfxVars::TileSize()) + {} + + ~TiledLayerBuffer() {} + + gfx::IntPoint GetTileOffset(TileIntPoint aPosition) const { + gfx::IntSize scaledTileSize = GetScaledTileSize(); + return gfx::IntPoint(aPosition.x * scaledTileSize.width, + aPosition.y * scaledTileSize.height) + mTileOrigin; + } + + const TilesPlacement& GetPlacement() const { return mTiles; } + + const gfx::IntSize& GetTileSize() const { return mTileSize; } + + gfx::IntSize GetScaledTileSize() const { return gfx::IntSize::Round(gfx::Size(mTileSize) / mResolution); } + + unsigned int GetTileCount() const { return mRetainedTiles.Length(); } + + Tile& GetTile(size_t i) { return mRetainedTiles[i]; } + + const nsIntRegion& GetValidRegion() const { return mValidRegion; } + const nsIntRegion& GetPaintedRegion() const { return mPaintedRegion; } + void ClearPaintedRegion() { mPaintedRegion.SetEmpty(); } + + // Get and set draw scaling. mResolution affects the resolution at which the + // contents of the buffer are drawn. mResolution has no effect on the + // coordinate space of the valid region, but does affect the size of an + // individual tile's rect in relation to the valid region. + // Setting the resolution will invalidate the buffer. + float GetResolution() const { return mResolution; } + bool IsLowPrecision() const { return mResolution < 1; } + + void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml, + TextureDumpMode aCompress); + +protected: + + nsIntRegion mValidRegion; + nsIntRegion mPaintedRegion; + + /** + * mRetainedTiles is a rectangular buffer of mTiles.mSize.width x mTiles.mSize.height + * stored as column major with the same origin as mValidRegion.GetBounds(). + * Any tile that does not intersect mValidRegion is a PlaceholderTile. + * Only the region intersecting with mValidRegion should be read from a tile, + * another other region is assumed to be uninitialized. The contents of the + * tiles is scaled by mResolution. + */ + nsTArray<Tile> mRetainedTiles; + TilesPlacement mTiles; + float mResolution; + gfx::IntSize mTileSize; + gfx::IntPoint mTileOrigin; +}; + +template<typename Derived, typename Tile> void +TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream, + const char* aPrefix, + bool aDumpHtml, + TextureDumpMode aCompress) +{ + for (size_t i = 0; i < mRetainedTiles.Length(); ++i) { + const TileIntPoint tilePosition = mTiles.TilePosition(i); + gfx::IntPoint tileOffset = GetTileOffset(tilePosition); + + aStream << "\n" << aPrefix << "Tile (x=" << + tileOffset.x << ", y=" << tileOffset.y << "): "; + if (!mRetainedTiles[i].IsPlaceholderTile()) { + mRetainedTiles[i].DumpTexture(aStream, aCompress); + } else { + aStream << "empty tile"; + } + } +} + +} // namespace layers +} // namespace mozilla + +#endif // GFX_TILEDLAYERBUFFER_H |