зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1170189 - Use TilesPlacement to handle tile coordinates conversion. r=BenWa
This commit is contained in:
Родитель
e7216099d2
Коммит
49ec8aec24
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче