summaryrefslogtreecommitdiffstats
path: root/gfx/layers/TiledLayerBuffer.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/TiledLayerBuffer.h')
-rw-r--r--gfx/layers/TiledLayerBuffer.h214
1 files changed, 214 insertions, 0 deletions
diff --git a/gfx/layers/TiledLayerBuffer.h b/gfx/layers/TiledLayerBuffer.h
new file mode 100644
index 0000000000..8b2a7b900e
--- /dev/null
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 <type_traits>
+#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 TileCoordUnit {};
+template <>
+struct IsPixel<TileCoordUnit> : std::true_type {};
+
+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<TileCoordUnit> TileCoordIntSize;
+typedef gfx::IntPointTyped<TileCoordUnit> TileCoordIntPoint;
+
+/**
+ * Stores the origin and size of a tile buffer and handles switching between
+ * tile indices and tile coordinates.
+ *
+ * Tile coordinates in TileCoordIntPoint take the first tile offset into account
+ * which means that two TilesPlacement of the same layer and resolution give
+ * tile coordinates in the same coordinate space (useful when changing the
+ * offset and/or size of a tile buffer).
+ */
+struct TilesPlacement {
+ TileCoordIntPoint mFirst;
+ TileCoordIntSize mSize;
+
+ TilesPlacement(int aFirstX, int aFirstY, int aRetainedWidth,
+ int aRetainedHeight)
+ : mFirst(aFirstX, aFirstY), mSize(aRetainedWidth, aRetainedHeight) {}
+
+ int TileIndex(TileCoordIntPoint aCoord) const {
+ return (aCoord.x - mFirst.x) * mSize.height + aCoord.y - mFirst.y;
+ }
+
+ TileCoordIntPoint TileCoord(size_t aIndex) const {
+ return TileCoordIntPoint(mFirst.x + aIndex / mSize.height,
+ mFirst.y + aIndex % mSize.height);
+ }
+
+ bool HasTile(TileCoordIntPoint aCoord) const {
+ return aCoord.x >= mFirst.x && aCoord.x < mFirst.x + mSize.width &&
+ aCoord.y >= mFirst.y && aCoord.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() = default;
+
+ gfx::IntPoint GetTileOffset(TileCoordIntPoint 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; }
+
+ // 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;
+
+ /**
+ * 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 TileCoordIntPoint tileCoord = mTiles.TileCoord(i);
+ gfx::IntPoint tileOffset = GetTileOffset(tileCoord);
+
+ 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