Bug 586683 - Part 3 - Add resolution handling to ThebesLayerD3D9. r=Bas a=blocking2.0

This commit is contained in:
Matt Woodrow 2011-02-09 09:39:09 +13:00
Родитель 5f23a55e32
Коммит 9c3c36cf34
2 изменённых файлов: 105 добавлений и 35 удалений

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

@ -76,7 +76,8 @@ ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
void
ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion)
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion,
float aXRes, float aYRes)
{
nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface;
aSrc->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
@ -90,16 +91,17 @@ ThebesLayerD3D9::CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffse
RECT oldRect, newRect;
// Calculate the retained rectangle's position on the old and the new
// surface.
oldRect.left = r->x - aSrcOffset.x;
oldRect.top = r->y - aSrcOffset.y;
oldRect.right = oldRect.left + r->width;
oldRect.bottom = oldRect.top + r->height;
// surface. We need to scale these rectangles since the visible
// region is in unscaled units, and the texture size has been scaled.
oldRect.left = UINT(floor((r->x - aSrcOffset.x) * aXRes));
oldRect.top = UINT(floor((r->y - aSrcOffset.y) * aYRes));
oldRect.right = oldRect.left + UINT(ceil(r->width * aXRes));
oldRect.bottom = oldRect.top + UINT(ceil(r->height * aYRes));
newRect.left = r->x - aDestOffset.x;
newRect.top = r->y - aDestOffset.y;
newRect.right = newRect.left + r->width;
newRect.bottom = newRect.top + r->height;
newRect.left = UINT(floor((r->x - aDestOffset.x) * aXRes));
newRect.top = UINT(floor((r->y - aDestOffset.y) * aYRes));
newRect.right = newRect.left + UINT(ceil(r->width * aXRes));
newRect.bottom = newRect.top + UINT(ceil(r->height * aYRes));
// Copy data from our old texture to the new one
HRESULT hr = device()->
@ -125,6 +127,15 @@ ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode)
{
nsIntRect visibleRect = mVisibleRegion.GetBounds();
float xres, yres;
GetDesiredResolutions(xres, yres);
// If our resolution changed, we need new sized textures, delete the old ones.
if (ResolutionChanged(xres, yres)) {
mTexture = nsnull;
mTextureOnWhite = nsnull;
}
if (HaveTextures(aMode)) {
if (mTextureRect != visibleRect) {
nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
@ -147,10 +158,10 @@ ThebesLayerD3D9::UpdateTextures(SurfaceMode aMode)
mValidRegion.SetEmpty();
} else {
CopyRegion(oldTexture, mTextureRect.TopLeft(), mTexture, visibleRect.TopLeft(),
retainRegion, &mValidRegion);
retainRegion, &mValidRegion, xres, yres);
if (aMode == SURFACE_COMPONENT_ALPHA) {
CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(), mTextureOnWhite, visibleRect.TopLeft(),
retainRegion, &mValidRegion);
retainRegion, &mValidRegion, xres, yres);
}
}
@ -326,7 +337,7 @@ public:
OpaqueRenderer(const nsIntRegion& aUpdateRegion) :
mUpdateRegion(aUpdateRegion), mDC(NULL) {}
~OpaqueRenderer() { End(); }
already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer);
already_AddRefed<gfxWindowsSurface> Begin(LayerD3D9* aLayer, float aXRes, float aYRes);
void End();
IDirect3DTexture9* GetTexture() { return mTmpTexture; }
@ -338,12 +349,15 @@ private:
};
already_AddRefed<gfxWindowsSurface>
OpaqueRenderer::Begin(LayerD3D9* aLayer)
OpaqueRenderer::Begin(LayerD3D9* aLayer, float aXRes, float aYRes)
{
nsIntRect bounds = mUpdateRegion.GetBounds();
gfxIntSize scaledSize;
scaledSize.width = PRInt32(ceil(bounds.width * aXRes));
scaledSize.height = PRInt32(ceil(bounds.height * aYRes));
HRESULT hr = aLayer->device()->
CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_X8R8G8B8,
CreateTexture(scaledSize.width, scaledSize.height, 1, 0, D3DFMT_X8R8G8B8,
D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), NULL);
if (FAILED(hr)) {
@ -381,9 +395,11 @@ OpaqueRenderer::End()
static void
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
const nsIntPoint& aOffset, const gfxRGBA& aColor)
const nsIntPoint& aOffset, const gfxRGBA& aColor,
float aXRes, float aYRes)
{
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
ctx->Scale(aXRes, aYRes);
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
gfxUtils::ClipToRegion(ctx, aRegion);
ctx->SetColor(aColor);
@ -391,13 +407,18 @@ FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
}
void
ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
{
HRESULT hr;
nsIntRect visibleRect = mVisibleRegion.GetBounds();
float xres, yres;
GetDesiredResolutions(xres, yres);
nsRefPtr<gfxASurface> destinationSurface;
nsIntRect bounds = aRegion.GetBounds();
gfxIntSize scaledSize;
scaledSize.width = PRInt32(ceil(bounds.width * xres));
scaledSize.height = PRInt32(ceil(bounds.height * yres));
nsRefPtr<IDirect3DTexture9> tmpTexture;
OpaqueRenderer opaqueRenderer(aRegion);
OpaqueRenderer opaqueRendererOnWhite(aRegion);
@ -405,11 +426,11 @@ ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
switch (aMode)
{
case SURFACE_OPAQUE:
destinationSurface = opaqueRenderer.Begin(this);
destinationSurface = opaqueRenderer.Begin(this, xres, yres);
break;
case SURFACE_SINGLE_CHANNEL_ALPHA: {
hr = device()->CreateTexture(bounds.width, bounds.height, 1,
hr = device()->CreateTexture(scaledSize.width, scaledSize.height, 1,
0, D3DFMT_A8R8G8B8,
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
@ -432,11 +453,11 @@ ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
}
case SURFACE_COMPONENT_ALPHA: {
nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this);
nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this);
nsRefPtr<gfxWindowsSurface> onBlack = opaqueRenderer.Begin(this, xres, yres);
nsRefPtr<gfxWindowsSurface> onWhite = opaqueRendererOnWhite.Begin(this, xres, yres);
if (onBlack && onWhite) {
FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0));
FillSurface(onBlack, aRegion, bounds.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0), xres, yres);
FillSurface(onWhite, aRegion, bounds.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0), xres, yres);
gfxASurface* surfaces[2] = { onBlack.get(), onWhite.get() };
destinationSurface = new gfxTeeSurface(surfaces, NS_ARRAY_LENGTH(surfaces));
// Using this surface as a source will likely go horribly wrong, since
@ -452,7 +473,10 @@ ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
return;
nsRefPtr<gfxContext> context = new gfxContext(destinationSurface);
// Draw content scaled at our current resolution.
context->Scale(xres, yres);
context->Translate(gfxPoint(-bounds.x, -bounds.y));
aRegion.ExtendForScaling(xres, yres);
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
cbInfo.Callback(this, context, aRegion, nsIntRegion(), cbInfo.CallbackData);
@ -472,8 +496,7 @@ ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
nsRefPtr<gfxImageSurface> imgSurface =
new gfxImageSurface((unsigned char *)r.pBits,
gfxIntSize(bounds.width,
bounds.height),
scaledSize,
r.Pitch,
gfxASurface::ImageFormatARGB32);
@ -505,6 +528,8 @@ ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
}
NS_ASSERTION(srcTextures.Length() == destTextures.Length(), "Mismatched lengths");
// Copy to the texture. We need to scale these rectangles since the visible
// region is in unscaled units, and the texture sizes have been scaled.
for (PRUint32 i = 0; i < srcTextures.Length(); ++i) {
nsRefPtr<IDirect3DSurface9> srcSurface;
nsRefPtr<IDirect3DSurface9> dstSurface;
@ -516,13 +541,13 @@ ThebesLayerD3D9::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
const nsIntRect *iterRect;
while ((iterRect = iter.Next())) {
RECT rect;
rect.left = iterRect->x - bounds.x;
rect.top = iterRect->y - bounds.y;
rect.right = rect.left + iterRect->width;
rect.bottom = rect.top + iterRect->height;
rect.left = UINT(floor((iterRect->x - bounds.x) * xres));
rect.top = UINT(floor((iterRect->y - bounds.y) * yres));
rect.right = rect.left + UINT(ceil(iterRect->width * xres));
rect.bottom = rect.top + UINT(ceil(iterRect->height * yres));
POINT point;
point.x = iterRect->x - visibleRect.x;
point.y = iterRect->y - visibleRect.y;
point.x = UINT(floor((iterRect->x - visibleRect.x) * xres));
point.y = UINT(floor((iterRect->y - visibleRect.y) * yres));
device()->UpdateSurface(srcSurface, &rect, dstSurface, &point);
}
}
@ -536,19 +561,53 @@ ThebesLayerD3D9::CreateNewTextures(const gfxIntSize &aSize,
// Nothing to do.
return;
}
// Scale the requested size (in unscaled units) to the actual
// texture size we require.
gfxIntSize scaledSize;
float xres, yres;
GetDesiredResolutions(xres, yres);
scaledSize.width = PRInt32(ceil(aSize.width * xres));
scaledSize.height = PRInt32(ceil(aSize.height * yres));
mTexture = nsnull;
mTextureOnWhite = nsnull;
device()->CreateTexture(aSize.width, aSize.height, 1,
device()->CreateTexture(scaledSize.width, scaledSize.height, 1,
D3DUSAGE_RENDERTARGET,
aMode != SURFACE_SINGLE_CHANNEL_ALPHA ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
if (aMode == SURFACE_COMPONENT_ALPHA) {
device()->CreateTexture(aSize.width, aSize.height, 1,
device()->CreateTexture(scaledSize.width, scaledSize.height, 1,
D3DUSAGE_RENDERTARGET,
D3DFMT_X8R8G8B8,
D3DPOOL_DEFAULT, getter_AddRefs(mTextureOnWhite), NULL);
}
mXResolution = xres;
mYResolution = yres;
}
void
ThebesLayerD3D9::GetDesiredResolutions(float& aXRes, float& aYRes)
{
const gfx3DMatrix& transform = GetLayer()->GetEffectiveTransform();
gfxMatrix transform2d;
if (transform.Is2D(&transform2d)) {
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
gfxSize scale = transform2d.ScaleFactors(PR_TRUE);
aXRes = gfxUtils::ClampToScaleFactor(scale.width);
aYRes = gfxUtils::ClampToScaleFactor(scale.height);
} else {
aXRes = 1.0;
aYRes = 1.0;
}
}
bool
ThebesLayerD3D9::ResolutionChanged(float aXRes, float aYRes)
{
return aXRes != mXResolution ||
aYRes != mYResolution;
}
} /* namespace layers */

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

@ -96,14 +96,25 @@ private:
void RenderVisibleRegion();
/* Have a region of our layer drawn */
void DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode);
void DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode);
/* Create a new texture */
void CreateNewTextures(const gfxIntSize &aSize, SurfaceMode aMode);
void CopyRegion(IDirect3DTexture9* aSrc, const nsIntPoint &aSrcOffset,
IDirect3DTexture9* aDest, const nsIntPoint &aDestOffset,
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion);
const nsIntRegion &aCopyRegion, nsIntRegion* aValidRegion,
float aXRes, float aYRes);
/**
* Calculate the desired texture resolution based on
* the layer managers resolution, and the current
* transforms scale factor.
*/
void GetDesiredResolutions(float& aXRes, float& aYRes);
/* Check if the current texture resolution matches */
bool ResolutionChanged(float aXRes, float aYRes);
};
} /* layers */