Bug 1170189 - Use TilesPlacement to handle tile coordinates conversion. r=BenWa

This commit is contained in:
Nicolas Silva 2015-06-10 17:56:34 +02:00
parent e7216099d2
commit 49ec8aec24
3 changed files with 104 additions and 83 deletions

View File

@ -26,6 +26,10 @@
#endif
namespace mozilla {
struct TileUnit {};
template<> struct IsPixel<TileUnit> : mozilla::TrueType {};
namespace layers {
// You can enable all the TILING_LOG print statements by
@ -38,6 +42,24 @@ namespace layers {
# 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;
}
}
// An abstract implementation of a tile buffer. This code covers the logic of
// moving and reusing tiles and leaves the validation up to the implementor. To
// avoid the overhead of virtual dispatch, we employ the curiously recurring
@ -89,17 +111,56 @@ namespace layers {
// 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) {
return aPosition.x >= mFirst.x && aPosition.x < mFirst.x + mSize.width &&
aPosition.y >= mFirst.y && aPosition.y < mFirst.y + mSize.height;
}
};
template<typename Derived, typename Tile>
class TiledLayerBuffer
{
public:
TiledLayerBuffer()
: mFirstTileX(0)
, mFirstTileY(0)
, mRetainedWidth(0)
, mRetainedHeight(0)
: mTiles(0, 0, 0, 0)
, mResolution(1)
, mTileSize(gfxPlatform::GetPlatform()->GetTileWidth(), gfxPlatform::GetPlatform()->GetTileHeight())
, mTileSize(gfxPlatform::GetPlatform()->GetTileWidth(),
gfxPlatform::GetPlatform()->GetTileHeight())
{}
~TiledLayerBuffer() {}
@ -118,12 +179,12 @@ public:
Tile& GetTile(int x, int y);
int TileIndex(const gfx::IntPoint& aTileOrigin) const;
int TileIndex(int x, int y) const { return x * mRetainedHeight + y; }
int TileIndex(int x, int y) const { return x * mTiles.mSize.height + y; }
bool HasTile(int index) const { return index >= 0 && index < (int)mRetainedTiles.Length(); }
bool HasTile(const gfx::IntPoint& aTileOrigin) const;
bool HasTile(int x, int y) const {
return x >= 0 && x < mRetainedWidth && y >= 0 && y < mRetainedHeight;
return x >= 0 && x < mTiles.mSize.width && y >= 0 && y < mTiles.mSize.height;
}
const gfx::IntSize& GetTileSize() const { return mTileSize; }
@ -139,8 +200,8 @@ public:
void ResetPaintedAndValidState() {
mPaintedRegion.SetEmpty();
mValidRegion.SetEmpty();
mRetainedWidth = 0;
mRetainedHeight = 0;
mTiles.mSize.width = 0;
mTiles.mSize.height = 0;
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (!mRetainedTiles[i].IsPlaceholderTile()) {
AsDerived().ReleaseTile(mRetainedTiles[i]);
@ -188,7 +249,7 @@ protected:
nsIntRegion mPaintedRegion;
/**
* mRetainedTiles is a rectangular buffer of mRetainedWidth x mRetainedHeight
* 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,
@ -196,10 +257,7 @@ protected:
* tiles is scaled by mResolution.
*/
nsTArray<Tile> mRetainedTiles;
int mFirstTileX;
int mFirstTileY;
int mRetainedWidth; // in tiles
int mRetainedHeight; // in tiles
TilesPlacement mTiles;
float mResolution;
gfx::IntSize mTileSize;
@ -239,29 +297,11 @@ public:
virtual const nsIntRegion& GetValidRegion() const = 0;
};
// 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;
}
}
template<typename Derived, typename Tile> bool
TiledLayerBuffer<Derived, Tile>::HasTile(const gfx::IntPoint& aTileOrigin) const {
gfx::IntSize scaledTileSize = GetScaledTileSize();
return HasTile(floor_div(aTileOrigin.x, scaledTileSize.width) - mFirstTileX,
floor_div(aTileOrigin.y, scaledTileSize.height) - mFirstTileY);
return HasTile(floor_div(aTileOrigin.x, scaledTileSize.width) - mTiles.mFirst.x,
floor_div(aTileOrigin.y, scaledTileSize.height) - mTiles.mFirst.y);
}
template<typename Derived, typename Tile> Tile&
@ -279,8 +319,8 @@ TiledLayerBuffer<Derived, Tile>::TileIndex(const gfx::IntPoint& aTileOrigin) con
// Find the tile x/y of the first tile and the target tile relative to the (0, 0)
// origin, the difference is the tile x/y relative to the start of the tile buffer.
gfx::IntSize scaledTileSize = GetScaledTileSize();
return TileIndex(floor_div(aTileOrigin.x, scaledTileSize.width) - mFirstTileX,
floor_div(aTileOrigin.y, scaledTileSize.height) - mFirstTileY);
return TileIndex(floor_div(aTileOrigin.x, scaledTileSize.width) - mTiles.mFirst.x,
floor_div(aTileOrigin.y, scaledTileSize.height) - mTiles.mFirst.y);
}
template<typename Derived, typename Tile> Tile&
@ -342,7 +382,7 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
// This is the reason we break the style guide with newValidRegion instead
// of aNewValidRegion - so that the names match better and code easier to read
const nsIntRegion& oldValidRegion = mValidRegion;
const int oldRetainedHeight = mRetainedHeight;
const int oldRetainedHeight = mTiles.mSize.height;
#ifdef GFX_TILEDLAYER_RETAINING_LOG
{ // scope ss
@ -426,8 +466,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
// Keep track of the number of horizontal/vertical tiles
// in the buffer so that we can easily look up a tile.
mRetainedWidth = tileX;
mRetainedHeight = tileY;
mTiles.mSize.width = tileX;
mTiles.mSize.height = tileY;
#ifdef GFX_TILEDLAYER_RETAINING_LOG
{ // scope ss
@ -621,8 +661,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
mRetainedTiles = newRetainedTiles;
mValidRegion = newValidRegion;
mFirstTileX = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
mFirstTileY = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
mTiles.mFirst.x = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
mTiles.mFirst.y = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
}

View File

@ -874,8 +874,8 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
}
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
tiles,
mFirstTileX, mFirstTileY,
mRetainedWidth, mRetainedHeight,
mTiles.mFirst.x, mTiles.mFirst.y,
mTiles.mSize.width, mTiles.mSize.height,
mResolution, mFrameResolution.xScale,
mFrameResolution.yScale);
}

View File

@ -195,27 +195,22 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
return false;
}
int newFirstTileX = aTiles.firstTileX();
int newFirstTileY = aTiles.firstTileY();
int oldFirstTileX = mFirstTileX;
int oldFirstTileY = mFirstTileY;
int newRetainedWidth = aTiles.retainedWidth();
int newRetainedHeight = aTiles.retainedHeight();
int oldRetainedWidth = mRetainedWidth;
int oldRetainedHeight = mRetainedHeight;
TilesPlacement oldTiles = mTiles;
TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
aTiles.retainedWidth(), aTiles.retainedHeight());
const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
nsTArray<TileHost> oldTiles;
mRetainedTiles.SwapElements(oldTiles);
nsTArray<TileHost> oldRetainedTiles;
mRetainedTiles.SwapElements(oldRetainedTiles);
mRetainedTiles.SetLength(tileDescriptors.Length());
// Step 1, we need to unlock tiles that don't have an internal buffer after the
// next frame where they are replaced.
// Since we are about to replace the tiles' textures, we need to keep their locks
// somewhere (in mPreviousSharedLock) until we composite the layer.
for (size_t i = 0; i < oldTiles.Length(); ++i) {
TileHost& tile = oldTiles[i];
for (size_t i = 0; i < oldRetainedTiles.Length(); ++i) {
TileHost& tile = oldRetainedTiles[i];
// It can happen that we still have a previous lock at this point,
// if we changed a tile's front buffer (causing mSharedLock to
// go into mPreviousSharedLock, and then did not composite that tile until
@ -225,12 +220,8 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
MOZ_ASSERT(tile.mSharedLock);
int tileX = i / oldRetainedHeight + oldFirstTileX;
int tileY = i % oldRetainedHeight + oldFirstTileY;
if (tileX >= newFirstTileX && tileY >= newFirstTileY &&
tileX < (newFirstTileX + newRetainedWidth) &&
tileY < (newFirstTileY + newRetainedHeight)) {
const TileIntPoint tilePosition = oldTiles.TilePosition(i);
if (newTiles.HasTile(tilePosition)) {
// This tile still exist in the new buffer
tile.mPreviousSharedLock = tile.mSharedLock;
tile.mSharedLock = nullptr;
@ -249,29 +240,25 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
// they should be with the new retained with and height rather than the
// old one.
for (size_t i = 0; i < tileDescriptors.Length(); i++) {
int tileX = i / newRetainedHeight + newFirstTileX;
int tileY = i % newRetainedHeight + newFirstTileY;
const TileIntPoint tilePosition = newTiles.TilePosition(i);
// First, get the already existing tiles to the right place in the array,
// and use placeholders where there was no tiles.
if (tileX < oldFirstTileX || tileY < oldFirstTileY ||
tileX >= (oldFirstTileX + oldRetainedWidth) ||
tileY >= (oldFirstTileY + oldRetainedHeight)) {
if (!oldTiles.HasTile(tilePosition)) {
mRetainedTiles[i] = GetPlaceholderTile();
} else {
mRetainedTiles[i] = oldTiles[(tileX - oldFirstTileX) * oldRetainedHeight +
(tileY - oldFirstTileY)];
mRetainedTiles[i] = oldRetainedTiles[oldTiles.TileIndex(tilePosition)];
// If we hit this assertion it means we probably mixed something up in the
// logic that tries to reuse tiles on the compositor side. It is most likely
// benign, but we are missing some fast paths so let's try to make it not happen.
MOZ_ASSERT(tileX == mRetainedTiles[i].x && tileY == mRetainedTiles[i].y);
MOZ_ASSERT(tilePosition.x == mRetainedTiles[i].x &&
tilePosition.y == mRetainedTiles[i].y);
}
}
// It is important to remove the duplicated reference to tiles before calling
// TextureHost::PrepareTextureSource, etc. because depending on the textures
// ref counts we may or may not get some of the fast paths.
oldTiles.Clear();
oldRetainedTiles.Clear();
// Step 3, handle the texture updates and release the copy-on-write locks.
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
@ -345,17 +332,13 @@ TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
break;
}
}
tile.x = i / newRetainedHeight + newFirstTileX;
tile.y = i % newRetainedHeight + newFirstTileY;
TileIntPoint tilePosition = newTiles.TilePosition(i);
tile.x = tilePosition.x;
tile.y = tilePosition.y;
}
mFirstTileX = newFirstTileX;
mFirstTileY = newFirstTileY;
mRetainedWidth = newRetainedWidth;
mRetainedHeight = newRetainedHeight;
mTiles = newTiles;
mValidRegion = aTiles.validRegion();
mResolution = aTiles.resolution();
mFrameResolution = CSSToParentLayerScale2D(aTiles.frameXResolution(),
aTiles.frameYResolution());
@ -371,10 +354,8 @@ TiledLayerBufferComposite::Clear()
tile.ReadUnlockPrevious();
}
mRetainedTiles.Clear();
mFirstTileX = 0;
mFirstTileY = 0;
mRetainedWidth = 0;
mRetainedHeight = 0;
mTiles.mFirst = TileIntPoint();
mTiles.mSize = TileIntSize();
mValidRegion = nsIntRegion();
mPaintedRegion = nsIntRegion();
mResolution = 1.0;