1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5  * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef GFX_TILEDLAYERBUFFER_H
8 #define GFX_TILEDLAYERBUFFER_H
9 
10 // Debug defines
11 //#define GFX_TILEDLAYER_DEBUG_OVERLAY
12 //#define GFX_TILEDLAYER_PREF_WARNINGS
13 //#define GFX_TILEDLAYER_RETAINING_LOG
14 
15 #include <stdint.h>     // for uint16_t, uint32_t
16 #include <sys/types.h>  // for int32_t
17 #include <type_traits>
18 #include "mozilla/gfx/gfxVars.h"
19 #include "mozilla/gfx/Logging.h"         // for gfxCriticalError
20 #include "mozilla/layers/LayersTypes.h"  // for TextureDumpMode
21 #include "nsDebug.h"                     // for NS_ASSERTION
22 #include "nsPoint.h"                     // for nsIntPoint
23 #include "nsRect.h"                      // for mozilla::gfx::IntRect
24 #include "nsRegion.h"                    // for nsIntRegion
25 #include "nsTArray.h"                    // for nsTArray
26 
27 namespace mozilla {
28 
29 struct TileCoordUnit {};
30 template <>
31 struct IsPixel<TileCoordUnit> : std::true_type {};
32 
33 namespace layers {
34 
35 // You can enable all the TILING_LOG print statements by
36 // changing the 0 to a 1 in the following #define.
37 #define ENABLE_TILING_LOG 0
38 
39 #if ENABLE_TILING_LOG
40 #  define TILING_LOG(...) printf_stderr(__VA_ARGS__);
41 #else
42 #  define TILING_LOG(...)
43 #endif
44 
45 // Normal integer division truncates towards zero,
46 // we instead want to floor to hangle negative numbers.
47 static inline int floor_div(int a, int b) {
48   int rem = a % b;
49   int div = a / b;
50   if (rem == 0) {
51     return div;
52   } else {
53     // If the signs are different substract 1.
54     int sub;
55     sub = a ^ b;
56     // The results of this shift is either 0 or -1.
57     sub >>= 8 * sizeof(int) - 1;
58     return div + sub;
59   }
60 }
61 
62 // Tiles are aligned to a grid with one of the grid points at (0,0) and other
63 // grid points spaced evenly in the x- and y-directions by GetTileSize()
64 // multiplied by mResolution. GetScaledTileSize() provides convenience for
65 // accessing these values.
66 //
67 // This tile buffer stores a valid region, which defines the areas that have
68 // up-to-date content. The contents of tiles within this region will be reused
69 // from paint to paint. It also stores the region that was modified in the last
70 // paint operation; this is useful when one tiled layer buffer shadows another
71 // (as in an off-main-thread-compositing scenario), so that the shadow tiled
72 // layer buffer can correctly reflect the updates of the master layer buffer.
73 //
74 // The associated Tile may be of any type as long as the derived class can
75 // validate and return tiles of that type. Tiles will be frequently copied, so
76 // the tile type should be a reference or some other type with an efficient
77 // copy constructor.
78 //
79 // The contents of the tile buffer will be rendered at the resolution specified
80 // in mResolution, which can be altered with SetResolution. The resolution
81 // should always be a factor of the tile length, to avoid tiles covering
82 // non-integer amounts of pixels.
83 
84 // Size and Point in number of tiles rather than in pixels
85 typedef gfx::IntSizeTyped<TileCoordUnit> TileCoordIntSize;
86 typedef gfx::IntPointTyped<TileCoordUnit> TileCoordIntPoint;
87 
88 /**
89  * Stores the origin and size of a tile buffer and handles switching between
90  * tile indices and tile coordinates.
91  *
92  * Tile coordinates in TileCoordIntPoint take the first tile offset into account
93  * which means that two TilesPlacement of the same layer and resolution give
94  * tile coordinates in the same coordinate space (useful when changing the
95  * offset and/or size of a tile buffer).
96  */
97 struct TilesPlacement {
98   TileCoordIntPoint mFirst;
99   TileCoordIntSize mSize;
100 
101   TilesPlacement(int aFirstX, int aFirstY, int aRetainedWidth,
102                  int aRetainedHeight)
103       : mFirst(aFirstX, aFirstY), mSize(aRetainedWidth, aRetainedHeight) {}
104 
105   int TileIndex(TileCoordIntPoint aCoord) const {
106     return (aCoord.x - mFirst.x) * mSize.height + aCoord.y - mFirst.y;
107   }
108 
109   TileCoordIntPoint TileCoord(size_t aIndex) const {
110     return TileCoordIntPoint(mFirst.x + aIndex / mSize.height,
111                              mFirst.y + aIndex % mSize.height);
112   }
113 
114   bool HasTile(TileCoordIntPoint aCoord) const {
115     return aCoord.x >= mFirst.x && aCoord.x < mFirst.x + mSize.width &&
116            aCoord.y >= mFirst.y && aCoord.y < mFirst.y + mSize.height;
117   }
118 };
119 
120 // Given a position i, this function returns the position inside the current
121 // tile.
122 inline int GetTileStart(int i, int aTileLength) {
123   return (i >= 0) ? (i % aTileLength)
124                   : ((aTileLength - (-i % aTileLength)) % aTileLength);
125 }
126 
127 // Rounds the given coordinate down to the nearest tile boundary.
128 inline int RoundDownToTileEdge(int aX, int aTileLength) {
129   return aX - GetTileStart(aX, aTileLength);
130 }
131 
132 template <typename Derived, typename Tile>
133 class TiledLayerBuffer {
134  public:
135   TiledLayerBuffer()
136       : mTiles(0, 0, 0, 0),
137         mResolution(1),
138         mTileSize(mozilla::gfx::gfxVars::TileSize()) {}
139 
140   ~TiledLayerBuffer() = default;
141 
142   gfx::IntPoint GetTileOffset(TileCoordIntPoint aPosition) const {
143     gfx::IntSize scaledTileSize = GetScaledTileSize();
144     return gfx::IntPoint(aPosition.x * scaledTileSize.width,
145                          aPosition.y * scaledTileSize.height) +
146            mTileOrigin;
147   }
148 
149   const TilesPlacement& GetPlacement() const { return mTiles; }
150 
151   const gfx::IntSize& GetTileSize() const { return mTileSize; }
152 
153   gfx::IntSize GetScaledTileSize() const {
154     return gfx::IntSize::Round(gfx::Size(mTileSize) / mResolution);
155   }
156 
157   unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
158 
159   Tile& GetTile(size_t i) { return mRetainedTiles[i]; }
160 
161   const nsIntRegion& GetValidRegion() const { return mValidRegion; }
162 
163   // Get and set draw scaling. mResolution affects the resolution at which the
164   // contents of the buffer are drawn. mResolution has no effect on the
165   // coordinate space of the valid region, but does affect the size of an
166   // individual tile's rect in relation to the valid region.
167   // Setting the resolution will invalidate the buffer.
168   float GetResolution() const { return mResolution; }
169   bool IsLowPrecision() const { return mResolution < 1; }
170 
171   void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml,
172             TextureDumpMode aCompress);
173 
174  protected:
175   nsIntRegion mValidRegion;
176 
177   /**
178    * mRetainedTiles is a rectangular buffer of mTiles.mSize.width x
179    * mTiles.mSize.height stored as column major with the same origin as
180    * mValidRegion.GetBounds(). Any tile that does not intersect mValidRegion is
181    * a PlaceholderTile. Only the region intersecting with mValidRegion should be
182    * read from a tile, another other region is assumed to be uninitialized. The
183    * contents of the tiles is scaled by mResolution.
184    */
185   nsTArray<Tile> mRetainedTiles;
186   TilesPlacement mTiles;
187   float mResolution;
188   gfx::IntSize mTileSize;
189   gfx::IntPoint mTileOrigin;
190 };
191 
192 template <typename Derived, typename Tile>
193 void TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
194                                            const char* aPrefix, bool aDumpHtml,
195                                            TextureDumpMode aCompress) {
196   for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
197     const TileCoordIntPoint tileCoord = mTiles.TileCoord(i);
198     gfx::IntPoint tileOffset = GetTileOffset(tileCoord);
199 
200     aStream << "\n"
201             << aPrefix << "Tile (x=" << tileOffset.x << ", y=" << tileOffset.y
202             << "): ";
203     if (!mRetainedTiles[i].IsPlaceholderTile()) {
204       mRetainedTiles[i].DumpTexture(aStream, aCompress);
205     } else {
206       aStream << "empty tile";
207     }
208   }
209 }
210 
211 }  // namespace layers
212 }  // namespace mozilla
213 
214 #endif  // GFX_TILEDLAYERBUFFER_H
215