Bug 783368 - Add resolution to TiledLayerBuffer. r=bgirard

Add the concept of resolution to TiledLayerBuffer and add support for it in
BasicTiledThebesLayer and TiledThebesLayerOGL.
This commit is contained in:
Chris Lord 2012-11-21 22:34:18 +00:00
Родитель f1ccd55d96
Коммит 919f718011
6 изменённых файлов: 108 добавлений и 56 удалений

Просмотреть файл

@ -29,7 +29,9 @@ namespace layers {
// template pattern.
//
// 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 GetTileLength().
// grid points spaced evenly in the x- and y-directions by GetTileLength()
// multiplied by mResolution. GetScaledTileLength() 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
@ -66,6 +68,11 @@ namespace layers {
// void SwapTiles(Tile& aTileA, Tile& aTileB);
//
// Swaps two tiles.
//
// 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.
template<typename Derived, typename Tile>
class TiledLayerBuffer
@ -74,20 +81,23 @@ public:
TiledLayerBuffer()
: mRetainedWidth(0)
, mRetainedHeight(0)
, mResolution(1)
{}
~TiledLayerBuffer() {}
// Given a tile origin aligned to a multiple of GetTileLength(),
// Given a tile origin aligned to a multiple of GetScaledTileLength,
// return the tile that describes that region.
// NOTE: To get the valid area of that tile you must intersect
// (aTileOrigin.x, aTileOrigin.y, GetTileLength(), GetTileLength())
// (aTileOrigin.x, aTileOrigin.y,
// GetScaledTileLength(), GetScaledTileLength())
// and GetValidRegion() to get the area of the tile that is valid.
Tile GetTile(const nsIntPoint& aTileOrigin) const;
// Given a tile x, y relative to the top left of the layer, this function
// will return the tile for
// (x*GetTileLength(), y*GetTileLength(), GetTileLength(), GetTileLength())
// (x*GetScaledTileLength(), y*GetScaledTileLength(),
// GetScaledTileLength(), GetScaledTileLength())
Tile GetTile(int x, int y) const;
// This operates the same as GetTile(aTileOrigin), but will also replace the
@ -101,6 +111,7 @@ public:
bool RemoveTile(int x, int y, Tile& aRemovedTile);
uint16_t GetTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE; }
uint32_t GetScaledTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE / mResolution; }
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
@ -110,13 +121,29 @@ public:
// Given a position i, this function returns the position inside the current tile.
int GetTileStart(int i) const {
return (i >= 0) ? (i % GetTileLength())
: ((GetTileLength() - (-i % GetTileLength())) % GetTileLength());
return (i >= 0) ? (i % GetScaledTileLength())
: ((GetScaledTileLength() - (-i % GetScaledTileLength())) %
GetScaledTileLength());
}
// Rounds the given coordinate down to the nearest tile boundary.
int RoundDownToTileEdge(int aX) const { return aX - GetTileStart(aX); }
// 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; }
void SetResolution(float aResolution) {
if (mResolution == aResolution) {
return;
}
Update(nsIntRegion(), nsIntRegion());
mResolution = aResolution;
}
protected:
// The implementor should call Update() to change
// the new valid region. This implementation will call
@ -132,11 +159,13 @@ protected:
* 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.
* another other region is assumed to be uninitialized. The contents of the
* tiles is scaled by mResolution.
*/
nsTArray<Tile> mRetainedTiles;
int mRetainedWidth; // in tiles
int mRetainedHeight; // in tiles
float mResolution;
private:
const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
@ -187,10 +216,10 @@ TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin) const
// TODO Cache firstTileOriginX/firstTileOriginY
// 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.
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetTileLength());
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetTileLength());
return GetTile(floor_div(aTileOrigin.x, GetTileLength()) - firstTileX,
floor_div(aTileOrigin.y, GetTileLength()) - firstTileY);
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetScaledTileLength());
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetScaledTileLength());
return GetTile(floor_div(aTileOrigin.x, GetScaledTileLength()) - firstTileX,
floor_div(aTileOrigin.y, GetScaledTileLength()) - firstTileY);
}
template<typename Derived, typename Tile> Tile
@ -204,10 +233,10 @@ template<typename Derived, typename Tile> bool
TiledLayerBuffer<Derived, Tile>::RemoveTile(const nsIntPoint& aTileOrigin,
Tile& aRemovedTile)
{
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetTileLength());
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetTileLength());
return RemoveTile(floor_div(aTileOrigin.x, GetTileLength()) - firstTileX,
floor_div(aTileOrigin.y, GetTileLength()) - firstTileY,
int firstTileX = floor_div(mValidRegion.GetBounds().x, GetScaledTileLength());
int firstTileY = floor_div(mValidRegion.GetBounds().y, GetScaledTileLength());
return RemoveTile(floor_div(aTileOrigin.x, GetScaledTileLength()) - firstTileX,
floor_div(aTileOrigin.y, GetScaledTileLength()) - firstTileY,
aRemovedTile);
}
@ -251,14 +280,14 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
// Compute tileRect(x,y,width,height) in layer space coordinate
// giving us the rect of the tile that hits the newBounds.
int width = GetTileLength() - GetTileStart(x);
int width = GetScaledTileLength() - GetTileStart(x);
if (x + width > newBound.XMost()) {
width = newBound.x + newBound.width - x;
}
tileY = 0;
for (int32_t y = newBound.y; y < newBound.YMost(); tileY++) {
int height = GetTileLength() - GetTileStart(y);
int height = GetScaledTileLength() - GetTileStart(y);
if (y + height > newBound.y + newBound.height) {
height = newBound.y + newBound.height - y;
}
@ -268,8 +297,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// This old tiles contains some valid area so move it to the new tile
// buffer. Replace the tile in the old buffer with a placeholder
// to leave the old buffer index unaffected.
int tileX = floor_div(x - oldBufferOrigin.x, GetTileLength());
int tileY = floor_div(y - oldBufferOrigin.y, GetTileLength());
int tileX = floor_div(x - oldBufferOrigin.x, GetScaledTileLength());
int tileY = floor_div(y - oldBufferOrigin.y, GetScaledTileLength());
int index = tileX * oldRetainedHeight + tileY;
// The tile may have been removed, skip over it in this case.
@ -328,14 +357,14 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// Compute tileRect(x,y,width,height) in layer space coordinate
// giving us the rect of the tile that hits the newBounds.
int tileStartX = RoundDownToTileEdge(x);
int width = GetTileLength() - GetTileStart(x);
int width = GetScaledTileLength() - GetTileStart(x);
if (x + width > newBound.XMost())
width = newBound.XMost() - x;
tileY = 0;
for (int y = newBound.y; y < newBound.y + newBound.height; tileY++) {
int tileStartY = RoundDownToTileEdge(y);
int height = GetTileLength() - GetTileStart(y);
int height = GetScaledTileLength() - GetTileStart(y);
if (y + height > newBound.YMost()) {
height = newBound.YMost() - y;
}
@ -350,8 +379,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
// because we can reuse all of the content from the
// previous buffer.
#ifdef DEBUG
int currTileX = floor_div(x - newBufferOrigin.x, GetTileLength());
int currTileY = floor_div(y - newBufferOrigin.y, GetTileLength());
int currTileX = floor_div(x - newBufferOrigin.x, GetScaledTileLength());
int currTileY = floor_div(y - newBufferOrigin.y, GetScaledTileLength());
int index = currTileX * mRetainedHeight + currTileY;
NS_ABORT_IF_FALSE(!newValidRegion.Intersects(tileRect) ||
!IsPlaceholder(newRetainedTiles.
@ -362,8 +391,8 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
continue;
}
int tileX = floor_div(x - newBufferOrigin.x, GetTileLength());
int tileY = floor_div(y - newBufferOrigin.y, GetTileLength());
int tileX = floor_div(x - newBufferOrigin.x, GetScaledTileLength());
int tileY = floor_div(y - newBufferOrigin.y, GetScaledTileLength());
int index = tileX * mRetainedHeight + tileY;
NS_ABORT_IF_FALSE(index >= 0 &&
static_cast<unsigned>(index) < newRetainedTiles.Length(),

Просмотреть файл

@ -105,11 +105,15 @@ BasicTiledLayerBuffer::PaintThebes(BasicTiledThebesLayer* aLayer,
const nsIntRect bounds = aPaintRegion.GetBounds();
{
SAMPLE_LABEL("BasicTiledLayerBuffer", "PaintThebesSingleBufferAlloc");
mSinglePaintBuffer = new gfxImageSurface(gfxIntSize(bounds.width, bounds.height), GetFormat(), !aLayer->CanUseOpaqueSurface());
mSinglePaintBuffer = new gfxImageSurface(
gfxIntSize(ceilf(bounds.width * mResolution),
ceilf(bounds.height * mResolution)),
GetFormat(), !aLayer->CanUseOpaqueSurface());
mSinglePaintBufferOffset = nsIntPoint(bounds.x, bounds.y);
}
nsRefPtr<gfxContext> ctxt = new gfxContext(mSinglePaintBuffer);
ctxt->NewPath();
ctxt->Scale(mResolution, mResolution);
ctxt->Translate(gfxPoint(-bounds.x, -bounds.y));
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 3) {
@ -165,9 +169,6 @@ BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
aTile = BasicTiledLayerTile(tmpTile);
}
gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
aDirtyRect.width, aDirtyRect.height);
// Use the gfxReusableSurfaceWrapper, which will reuse the surface
// if the compositor no longer has a read lock, otherwise the surface
// will be copied into a new writable surface.
@ -176,23 +177,35 @@ BasicTiledLayerBuffer::ValidateTileInternal(BasicTiledLayerTile aTile,
// Bug 742100, this gfxContext really should live on the stack.
nsRefPtr<gfxContext> ctxt = new gfxContext(writableSurface);
if (mSinglePaintBuffer) {
gfxRect drawRect(aDirtyRect.x - aTileOrigin.x, aDirtyRect.y - aTileOrigin.y,
aDirtyRect.width, aDirtyRect.height);
ctxt->SetOperator(gfxContext::OPERATOR_SOURCE);
ctxt->NewPath();
ctxt->SetSource(mSinglePaintBuffer.get(),
gfxPoint(mSinglePaintBufferOffset.x - aDirtyRect.x + drawRect.x,
mSinglePaintBufferOffset.y - aDirtyRect.y + drawRect.y));
gfxPoint((mSinglePaintBufferOffset.x - aDirtyRect.x + drawRect.x) *
mResolution,
(mSinglePaintBufferOffset.y - aDirtyRect.y + drawRect.y) *
mResolution));
drawRect.Scale(mResolution, mResolution);
ctxt->Rectangle(drawRect, true);
ctxt->Fill();
} else {
ctxt->NewPath();
ctxt->Scale(mResolution, mResolution);
ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
nsIntPoint a = aTileOrigin;
mCallback(mThebesLayer, ctxt, nsIntRegion(nsIntRect(a, nsIntSize(GetTileLength(), GetTileLength()))), nsIntRegion(), mCallbackData);
nsIntPoint a = nsIntPoint(aTileOrigin.x, aTileOrigin.y);
mCallback(mThebesLayer, ctxt,
nsIntRegion(nsIntRect(a, nsIntSize(GetScaledTileLength(),
GetScaledTileLength()))),
nsIntRegion(), mCallbackData);
}
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
DrawDebugOverlay(writableSurface, aTileOrigin.x, aTileOrigin.y);
DrawDebugOverlay(writableSurface, aTileOrigin.x * mResolution,
aTileOrigin.y * mResolution);
#endif
return aTile;
@ -303,26 +316,25 @@ BasicTiledThebesLayer::ComputeProgressiveUpdateRegion(const nsIntRegion& aInvali
nsIntRect paintBounds = aRegionToPaint.GetBounds();
int startX, incX, startY, incY;
int tileLength = mTiledBuffer.GetScaledTileLength();
if (aScrollOffset.x >= mLastScrollOffset.x) {
startX = mTiledBuffer.RoundDownToTileEdge(paintBounds.x);
incX = mTiledBuffer.GetTileLength();
incX = tileLength;
} else {
startX = mTiledBuffer.RoundDownToTileEdge(paintBounds.XMost() - 1);
incX = -mTiledBuffer.GetTileLength();
incX = -tileLength;
}
if (aScrollOffset.y >= mLastScrollOffset.y) {
startY = mTiledBuffer.RoundDownToTileEdge(paintBounds.y);
incY = mTiledBuffer.GetTileLength();
incY = tileLength;
} else {
startY = mTiledBuffer.RoundDownToTileEdge(paintBounds.YMost() - 1);
incY = -mTiledBuffer.GetTileLength();
incY = -tileLength;
}
// Find a tile to draw.
nsIntRect tileBounds(startX, startY,
mTiledBuffer.GetTileLength(),
mTiledBuffer.GetTileLength());
nsIntRect tileBounds(startX, startY, tileLength, tileLength);
int32_t scrollDiffX = aScrollOffset.x - mLastScrollOffset.x;
int32_t scrollDiffY = aScrollOffset.y - mLastScrollOffset.y;
// This loop will always terminate, as there is at least one tile area
@ -429,7 +441,7 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
// Only draw progressively when the resolution is unchanged.
if (gfxPlatform::UseProgressiveTilePainting() &&
!BasicManager()->HasShadowTarget() &&
mTiledBuffer.GetResolution() == resolution) {
mTiledBuffer.GetFrameResolution() == resolution) {
// Store the old valid region, then clear it before painting.
// We clip the old valid region to the visible region, as it only gets
// used to decide stale content (currently valid and previously visible)
@ -495,7 +507,7 @@ BasicTiledThebesLayer::PaintThebes(gfxContext* aContext,
} while (repeat);
} else {
mTiledBuffer.ClearPaintedRegion();
mTiledBuffer.SetResolution(resolution);
mTiledBuffer.SetFrameResolution(resolution);
mValidRegion = mVisibleRegion;
if (!layerDisplayPort.IsEmpty()) {
mValidRegion.And(mValidRegion, layerDisplayPort);

Просмотреть файл

@ -107,8 +107,8 @@ public:
}
}
const gfxSize& GetResolution() { return mResolution; }
void SetResolution(const gfxSize& aResolution) { mResolution = aResolution; }
const gfxSize& GetFrameResolution() { return mFrameResolution; }
void SetFrameResolution(const gfxSize& aResolution) { mFrameResolution = aResolution; }
bool HasFormatChanged(BasicTiledThebesLayer* aThebesLayer) const;
protected:
@ -133,7 +133,7 @@ private:
BasicTiledThebesLayer* mThebesLayer;
LayerManager::DrawThebesLayerCallback mCallback;
void* mCallbackData;
gfxSize mResolution;
gfxSize mFrameResolution;
bool mLastPaintOpaque;
// The buffer we use when UseSinglePaintBuffer() above is true.

Просмотреть файл

@ -136,6 +136,9 @@ ReusableTileStoreOGL::HarvestTiles(TiledThebesLayerOGL* aLayer,
const gfxSize& aOldResolution,
const gfxSize& aNewResolution)
{
NS_ASSERTION(aVideoMemoryTiledBuffer->GetResolution() == 1.0f,
"ReusableTileStoreOGL cannot harvest scaled tiles!");
gfxSize scaleFactor = gfxSize(aNewResolution.width / aOldResolution.width,
aNewResolution.height / aOldResolution.height);

Просмотреть файл

@ -46,7 +46,7 @@ TiledLayerBufferOGL::Upload(const BasicTiledLayerBuffer* aMainMemoryTiledBuffer,
long start = PR_IntervalNow();
#endif
mResolution = aResolution;
mFrameResolution = aResolution;
mMainMemoryTiledBuffer = aMainMemoryTiledBuffer;
mContext->MakeCurrent();
Update(aNewValidRegion, aInvalidateRegion);
@ -181,7 +181,7 @@ TiledThebesLayerOGL::ProcessUploadQueue()
&mVideoMemoryTiledBuffer,
mVideoMemoryTiledBuffer.GetValidRegion(),
mMainMemoryTiledBuffer.GetValidRegion(),
mVideoMemoryTiledBuffer.GetResolution(),
mVideoMemoryTiledBuffer.GetFrameResolution(),
resolution);
}
@ -192,6 +192,7 @@ TiledThebesLayerOGL::ProcessUploadQueue()
mVideoMemoryTiledBuffer.Upload(&mMainMemoryTiledBuffer,
mMainMemoryTiledBuffer.GetValidRegion(),
mRegionToUpload, resolution);
mVideoMemoryTiledBuffer.SetResolution(mMainMemoryTiledBuffer.GetResolution());
mValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
mMainMemoryTiledBuffer.ReadUnlock();
@ -252,26 +253,29 @@ TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOf
if (mReusableTileStore) {
mReusableTileStore->DrawTiles(this,
mVideoMemoryTiledBuffer.GetValidRegion(),
mVideoMemoryTiledBuffer.GetResolution(),
mVideoMemoryTiledBuffer.GetFrameResolution(),
GetEffectiveTransform(), aOffset, maskLayer);
}
// Render valid tiles.
const nsIntRegion& visibleRegion = GetEffectiveVisibleRegion();
const nsIntRect visibleRect = visibleRegion.GetBounds();
float resolution = mVideoMemoryTiledBuffer.GetResolution();
gfx3DMatrix transform = GetEffectiveTransform();
transform.Scale(1/resolution, 1/resolution, 1);
uint32_t rowCount = 0;
uint32_t tileX = 0;
for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
rowCount++;
int32_t tileStartX = mVideoMemoryTiledBuffer.GetTileStart(x);
int16_t w = mVideoMemoryTiledBuffer.GetTileLength() - tileStartX;
int32_t w = mVideoMemoryTiledBuffer.GetScaledTileLength() - tileStartX;
if (x + w > visibleRect.x + visibleRect.width)
w = visibleRect.x + visibleRect.width - x;
int tileY = 0;
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
int32_t tileStartY = mVideoMemoryTiledBuffer.GetTileStart(y);
int16_t h = mVideoMemoryTiledBuffer.GetTileLength() - tileStartY;
int32_t h = mVideoMemoryTiledBuffer.GetScaledTileLength() - tileStartY;
if (y + h > visibleRect.y + visibleRect.height)
h = visibleRect.y + visibleRect.height - y;
@ -281,10 +285,12 @@ TiledThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOf
if (tileTexture != mVideoMemoryTiledBuffer.GetPlaceholderTile()) {
nsIntRegion tileDrawRegion = nsIntRegion(nsIntRect(x, y, w, h));
tileDrawRegion.And(tileDrawRegion, mValidRegion);
tileDrawRegion.ScaleRoundOut(resolution, resolution);
nsIntPoint tileOffset(x - tileStartX, y - tileStartY);
uint16_t tileSize = mVideoMemoryTiledBuffer.GetTileLength();
RenderTile(tileTexture, GetEffectiveTransform(), aOffset, tileDrawRegion,
nsIntPoint tileOffset((x - tileStartX) * resolution,
(y - tileStartY) * resolution);
uint32_t tileSize = mVideoMemoryTiledBuffer.GetTileLength();
RenderTile(tileTexture, transform, aOffset, tileDrawRegion,
tileOffset, nsIntSize(tileSize, tileSize), maskLayer);
}
tileY++;

Просмотреть файл

@ -80,7 +80,9 @@ public:
TiledTexture GetPlaceholderTile() const { return TiledTexture(); }
const gfxSize& GetResolution() { return mResolution; }
// Stores the absolute resolution of the containing frame, calculated
// by the sum of the resolutions of all parent layers' FrameMetrics.
const gfxSize& GetFrameResolution() { return mFrameResolution; }
protected:
TiledTexture ValidateTile(TiledTexture aTile,
@ -96,7 +98,7 @@ protected:
private:
nsRefPtr<gl::GLContext> mContext;
const BasicTiledLayerBuffer* mMainMemoryTiledBuffer;
gfxSize mResolution;
gfxSize mFrameResolution;
void GetFormatAndTileForImageFormat(gfxASurface::gfxImageFormat aFormat,
GLenum& aOutFormat,