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