2012-04-25 02:48:33 +00:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
|
|
|
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include "ReusableTileStoreOGL.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace layers {
|
|
|
|
|
|
|
|
ReusableTileStoreOGL::~ReusableTileStoreOGL()
|
|
|
|
{
|
|
|
|
if (mTiles.Length() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
mContext->MakeCurrent();
|
2012-04-30 22:47:42 +00:00
|
|
|
for (PRUint32 i = 0; i < mTiles.Length(); i++)
|
2012-04-25 02:48:33 +00:00
|
|
|
mContext->fDeleteTextures(1, &mTiles[i]->mTexture.mTextureHandle);
|
|
|
|
mTiles.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ReusableTileStoreOGL::HarvestTiles(TiledLayerBufferOGL* aVideoMemoryTiledBuffer,
|
2012-04-26 16:53:14 +00:00
|
|
|
const nsIntSize& aContentSize,
|
2012-04-25 02:48:33 +00:00
|
|
|
const nsIntRegion& aOldValidRegion,
|
|
|
|
const nsIntRegion& aNewValidRegion,
|
|
|
|
const gfxSize& aOldResolution,
|
|
|
|
const gfxSize& aNewResolution)
|
|
|
|
{
|
|
|
|
gfxSize scaleFactor = gfxSize(aNewResolution.width / aOldResolution.width,
|
|
|
|
aNewResolution.height / aOldResolution.height);
|
|
|
|
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
|
|
printf_stderr("Seeing if there are any tiles we can reuse\n");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Iterate over existing harvested tiles and release any that are contained
|
2012-04-26 16:53:14 +00:00
|
|
|
// within the new valid region, or that fall outside of the layer.
|
2012-04-25 02:48:33 +00:00
|
|
|
mContext->MakeCurrent();
|
2012-04-30 22:47:42 +00:00
|
|
|
for (PRUint32 i = 0; i < mTiles.Length();) {
|
2012-04-25 02:48:33 +00:00
|
|
|
ReusableTiledTextureOGL* tile = mTiles[i];
|
|
|
|
|
2012-04-26 16:53:14 +00:00
|
|
|
nsIntRect tileRect;
|
2012-04-25 02:48:33 +00:00
|
|
|
bool release = false;
|
|
|
|
if (tile->mResolution == aNewResolution) {
|
2012-04-26 16:53:14 +00:00
|
|
|
if (aNewValidRegion.Contains(tile->mTileRegion)) {
|
2012-04-25 02:48:33 +00:00
|
|
|
release = true;
|
2012-04-26 16:53:14 +00:00
|
|
|
} else {
|
|
|
|
tileRect = tile->mTileRegion.GetBounds();
|
|
|
|
}
|
2012-04-25 02:48:33 +00:00
|
|
|
} else {
|
|
|
|
nsIntRegion transformedTileRegion(tile->mTileRegion);
|
|
|
|
transformedTileRegion.ScaleRoundOut(tile->mResolution.width / aNewResolution.width,
|
|
|
|
tile->mResolution.height / aNewResolution.height);
|
|
|
|
if (aNewValidRegion.Contains(transformedTileRegion))
|
|
|
|
release = true;
|
2012-04-26 16:53:14 +00:00
|
|
|
else
|
|
|
|
tileRect = transformedTileRegion.GetBounds();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!release) {
|
|
|
|
if (tileRect.width > aContentSize.width ||
|
|
|
|
tileRect.height > aContentSize.height)
|
|
|
|
release = true;
|
2012-04-25 02:48:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (release) {
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
|
|
nsIntRect tileBounds = tile->mTileRegion.GetBounds();
|
|
|
|
printf_stderr("Releasing obsolete reused tile at %d,%d, x%f\n",
|
|
|
|
tileBounds.x, tileBounds.y, tile->mResolution.width);
|
|
|
|
#endif
|
|
|
|
mContext->fDeleteTextures(1, &tile->mTexture.mTextureHandle);
|
|
|
|
mTiles.RemoveElementAt(i);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate over the tiles and decide which ones we're going to harvest.
|
|
|
|
// We harvest any tile that is entirely outside of the new valid region, or
|
|
|
|
// any tile that is partially outside of the valid region and whose
|
|
|
|
// resolution has changed.
|
|
|
|
// XXX Tile iteration needs to be abstracted, or have some utility functions
|
|
|
|
// to make it simpler.
|
|
|
|
uint16_t tileSize = aVideoMemoryTiledBuffer->GetTileLength();
|
|
|
|
nsIntRect validBounds = aOldValidRegion.GetBounds();
|
|
|
|
for (int x = validBounds.x; x < validBounds.XMost();) {
|
|
|
|
int w = tileSize - x % tileSize;
|
|
|
|
if (x + w > validBounds.x + validBounds.width)
|
|
|
|
w = validBounds.x + validBounds.width - x;
|
|
|
|
|
|
|
|
for (int y = validBounds.y; y < validBounds.YMost();) {
|
|
|
|
int h = tileSize - y % tileSize;
|
|
|
|
if (y + h > validBounds.y + validBounds.height)
|
|
|
|
h = validBounds.y + validBounds.height - y;
|
|
|
|
|
|
|
|
// If the new valid region doesn't contain this tile region,
|
|
|
|
// harvest the tile.
|
|
|
|
nsIntRegion tileRegion;
|
|
|
|
tileRegion.And(aOldValidRegion, nsIntRect(x, y, w, h));
|
|
|
|
|
|
|
|
nsIntRegion intersectingRegion;
|
|
|
|
bool retainTile = false;
|
|
|
|
if (aNewResolution != aOldResolution) {
|
|
|
|
// Reconcile resolution changes.
|
|
|
|
// If the resolution changes, we know the backing layer will have been
|
|
|
|
// invalidated, so retain tiles that are partially encompassed by the
|
|
|
|
// new valid area, instead of just tiles that don't intersect at all.
|
|
|
|
nsIntRegion transformedTileRegion(tileRegion);
|
|
|
|
transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height);
|
|
|
|
if (!aNewValidRegion.Contains(transformedTileRegion))
|
|
|
|
retainTile = true;
|
|
|
|
} else if (intersectingRegion.And(tileRegion, aNewValidRegion).IsEmpty()) {
|
|
|
|
retainTile = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retainTile) {
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
|
|
printf_stderr("Retaining tile at %d,%d, x%f for reuse\n", x, y, aOldResolution.width);
|
|
|
|
#endif
|
|
|
|
TiledTexture removedTile;
|
|
|
|
if (aVideoMemoryTiledBuffer->RemoveTile(nsIntPoint(x, y), removedTile)) {
|
|
|
|
ReusableTiledTextureOGL* reusedTile =
|
2012-04-30 14:19:17 +00:00
|
|
|
new ReusableTiledTextureOGL(removedTile, nsIntPoint(x, y), tileRegion,
|
|
|
|
tileSize, aOldResolution);
|
2012-04-25 02:48:33 +00:00
|
|
|
mTiles.AppendElement(reusedTile);
|
|
|
|
}
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
|
|
else
|
|
|
|
printf_stderr("Failed to retain tile for reuse\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
y += h;
|
|
|
|
}
|
|
|
|
|
|
|
|
x += w;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now prune our reused tile store of its oldest tiles if it gets too large.
|
|
|
|
while (mTiles.Length() > aVideoMemoryTiledBuffer->GetTileCount() * mSizeLimit) {
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
|
|
nsIntRect tileBounds = mTiles[0]->mTileRegion.GetBounds();
|
|
|
|
printf_stderr("Releasing old reused tile at %d,%d, x%f\n",
|
|
|
|
tileBounds.x, tileBounds.y, mTiles[0]->mResolution.width);
|
|
|
|
#endif
|
|
|
|
mContext->fDeleteTextures(1, &mTiles[0]->mTexture.mTextureHandle);
|
|
|
|
mTiles.RemoveElementAt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
|
|
printf_stderr("Retained %d tiles\n", mTiles.Length());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ReusableTileStoreOGL::DrawTiles(TiledThebesLayerOGL* aLayer,
|
2012-04-26 16:53:14 +00:00
|
|
|
const nsIntSize& aContentSize,
|
2012-04-25 02:48:33 +00:00
|
|
|
const nsIntRegion& aValidRegion,
|
|
|
|
const gfxSize& aResolution,
|
|
|
|
const gfx3DMatrix& aTransform,
|
2012-03-18 23:02:38 +00:00
|
|
|
const nsIntPoint& aRenderOffset,
|
|
|
|
Layer* aMaskLayer)
|
2012-04-25 02:48:33 +00:00
|
|
|
{
|
|
|
|
// Render old tiles to fill in gaps we haven't had the time to render yet.
|
2012-04-30 22:47:42 +00:00
|
|
|
for (PRUint32 i = 0; i < mTiles.Length(); i++) {
|
2012-04-25 02:48:33 +00:00
|
|
|
ReusableTiledTextureOGL* tile = mTiles[i];
|
|
|
|
|
|
|
|
// Work out the scaling factor in case of resolution differences.
|
|
|
|
gfxSize scaleFactor = gfxSize(aResolution.width / tile->mResolution.width,
|
|
|
|
aResolution.height / tile->mResolution.height);
|
|
|
|
|
|
|
|
// Get the valid tile region, in the given coordinate space.
|
|
|
|
nsIntRegion transformedTileRegion(tile->mTileRegion);
|
|
|
|
if (aResolution != tile->mResolution)
|
|
|
|
transformedTileRegion.ScaleRoundOut(scaleFactor.width, scaleFactor.height);
|
|
|
|
|
|
|
|
// Skip drawing tiles that will be completely drawn over.
|
|
|
|
if (aValidRegion.Contains(transformedTileRegion))
|
|
|
|
continue;
|
|
|
|
|
2012-04-26 16:53:14 +00:00
|
|
|
// Skip drawing tiles that have fallen outside of the layer area (these
|
|
|
|
// will be discarded next time tiles are harvested).
|
|
|
|
nsIntRect transformedTileRect = transformedTileRegion.GetBounds();
|
|
|
|
if (transformedTileRect.XMost() > aContentSize.width ||
|
|
|
|
transformedTileRect.YMost() > aContentSize.height)
|
|
|
|
continue;
|
|
|
|
|
2012-04-25 02:48:33 +00:00
|
|
|
// Reconcile the resolution difference by adjusting the transform.
|
|
|
|
gfx3DMatrix transform = aTransform;
|
|
|
|
if (aResolution != tile->mResolution)
|
|
|
|
transform.Scale(scaleFactor.width, scaleFactor.height, 1);
|
|
|
|
|
|
|
|
// XXX We should clip here to make sure we don't overlap with the valid
|
|
|
|
// region, otherwise we may end up with rendering artifacts on
|
|
|
|
// semi-transparent layers.
|
|
|
|
// Similarly, if we have multiple tiles covering the same area, we will
|
|
|
|
// end up with rendering artifacts if the aLayer isn't opaque.
|
2012-04-30 14:19:17 +00:00
|
|
|
uint16_t tileStartX = tile->mTileOrigin.x % tile->mTileSize;
|
|
|
|
uint16_t tileStartY = tile->mTileOrigin.y % tile->mTileSize;
|
|
|
|
nsIntPoint tileOffset(tile->mTileOrigin.x - tileStartX, tile->mTileOrigin.y - tileStartY);
|
2012-04-25 02:48:33 +00:00
|
|
|
nsIntSize textureSize(tile->mTileSize, tile->mTileSize);
|
2012-03-18 23:02:38 +00:00
|
|
|
aLayer->RenderTile(tile->mTexture, transform, aRenderOffset, tile->mTileRegion, tileOffset, textureSize, aMaskLayer);
|
2012-04-25 02:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // mozilla
|
|
|
|
} // layers
|