Bug 584494: Avoid creating intermediate surfaces in D3D9 layers. r=roc a=blocking-betaN

This commit is contained in:
Bas Schouten 2010-10-21 22:41:04 +02:00
parent 50c51b53cc
commit a09e9678c4
12 changed files with 106 additions and 54 deletions

View File

@ -227,7 +227,7 @@ CanvasLayerD3D9::GetLayer()
}
void
CanvasLayerD3D9::RenderLayer()
CanvasLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
{
if (!mTexture) {
Updated(mBounds);
@ -246,7 +246,8 @@ CanvasLayerD3D9::RenderLayer()
device()->SetVertexShaderConstantF(CBvLayerQuad, quad, 1);
device()->SetVertexShaderConstantF(CBmLayerTransform, &mTransform._11, 4);
gfx3DMatrix transform = mTransform * aTransform;
device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
float opacity[4];
/*

View File

@ -70,7 +70,7 @@ public:
// LayerD3D9 implementation
virtual Layer* GetLayer();
virtual void RenderLayer();
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
virtual void CleanResources();
virtual void LayerManagerDestroyed();

View File

@ -48,7 +48,7 @@ ColorLayerD3D9::GetLayer()
}
void
ColorLayerD3D9::RenderLayer()
ColorLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
{
// XXX we might be able to improve performance by using
// IDirect3DDevice9::Clear
@ -63,14 +63,15 @@ ColorLayerD3D9::RenderLayer()
visibleRect.height),
1);
device()->SetVertexShaderConstantF(CBmLayerTransform, &mTransform._11, 4);
gfx3DMatrix transform = mTransform * aTransform;
device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
float color[4];
// color is premultiplied, so we need to adjust all channels
color[0] = (float)(mColor.r * GetOpacity());
color[1] = (float)(mColor.g * GetOpacity());
color[2] = (float)(mColor.b * GetOpacity());
color[3] = (float)(mColor.a * GetOpacity());
color[0] = (float)(mColor.r * GetOpacity() * aOpacity);
color[1] = (float)(mColor.g * GetOpacity() * aOpacity);
color[2] = (float)(mColor.b * GetOpacity() * aOpacity);
color[3] = (float)(mColor.a * GetOpacity() * aOpacity);
device()->SetPixelShaderConstantF(0, color, 1);

View File

@ -58,7 +58,7 @@ public:
// LayerD3D9 Implementation
virtual Layer* GetLayer();
virtual void RenderLayer();
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
};
} /* layers */

View File

@ -135,9 +135,9 @@ ContainerLayerD3D9::GetFirstChildD3D9()
}
void
ContainerLayerD3D9::RenderLayer()
ContainerLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
{
float opacity = GetOpacity();
float opacity = GetOpacity() * aOpacity;
nsRefPtr<IDirect3DSurface9> previousRenderTarget;
nsRefPtr<IDirect3DTexture9> renderTexture;
float previousRenderTargetOffset[4];
@ -145,12 +145,13 @@ ContainerLayerD3D9::RenderLayer()
float renderTargetOffset[] = { 0, 0, 0, 0 };
float oldViewMatrix[4][4];
gfx3DMatrix transform = mTransform * aTransform;
nsIntRect visibleRect = mVisibleRegion.GetBounds();
PRBool useIntermediate = (opacity != 1.0 || !mTransform.IsIdentity());
PRBool useIntermediate = ShouldUseIntermediate(opacity, transform);
if (useIntermediate) {
device()->GetRenderTarget(0, getter_AddRefs(previousRenderTarget));
device()->GetScissorRect(&oldClipRect);
device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT, getter_AddRefs(renderTexture),
@ -184,38 +185,54 @@ ContainerLayerD3D9::RenderLayer()
LayerD3D9 *layerToRender = GetFirstChildD3D9();
while (layerToRender) {
const nsIntRect *clipRect = layerToRender->GetLayer()->GetClipRect();
RECT r;
if (clipRect) {
r.left = (LONG)(clipRect->x - renderTargetOffset[0]);
r.top = (LONG)(clipRect->y - renderTargetOffset[1]);
r.right = (LONG)(clipRect->x - renderTargetOffset[0] + clipRect->width);
r.bottom = (LONG)(clipRect->y - renderTargetOffset[1] + clipRect->height);
} else {
if (useIntermediate) {
if (clipRect || useIntermediate) {
RECT r;
device()->GetScissorRect(&oldClipRect);
if (clipRect) {
r.left = (LONG)(clipRect->x - renderTargetOffset[0]);
r.top = (LONG)(clipRect->y - renderTargetOffset[1]);
r.right = (LONG)(clipRect->x - renderTargetOffset[0] + clipRect->width);
r.bottom = (LONG)(clipRect->y - renderTargetOffset[1] + clipRect->height);
} else {
r.left = 0;
r.top = 0;
} else {
r.left = visibleRect.x;
r.top = visibleRect.y;
r.right = visibleRect.width;
r.bottom = visibleRect.height;
}
r.right = r.left + visibleRect.width;
r.bottom = r.top + visibleRect.height;
nsRefPtr<IDirect3DSurface9> renderSurface;
device()->GetRenderTarget(0, getter_AddRefs(renderSurface));
D3DSURFACE_DESC desc;
renderSurface->GetDesc(&desc);
if (!useIntermediate) {
// Intersect with current clip rect.
r.left = NS_MAX<PRInt32>(oldClipRect.left, r.left);
r.right = NS_MIN<PRInt32>(oldClipRect.right, r.right);
r.top = NS_MAX<PRInt32>(oldClipRect.top, r.top);
r.bottom = NS_MAX<PRInt32>(oldClipRect.bottom, r.bottom);
} else {
// > 0 is implied during the intersection when useIntermediate == true;
r.left = NS_MAX<LONG>(0, r.left);
r.top = NS_MAX<LONG>(0, r.top);
}
r.bottom = NS_MIN<LONG>(r.bottom, desc.Height);
r.right = NS_MIN<LONG>(r.right, desc.Width);
device()->SetScissorRect(&r);
}
nsRefPtr<IDirect3DSurface9> renderSurface;
device()->GetRenderTarget(0, getter_AddRefs(renderSurface));
if (!useIntermediate) {
layerToRender->RenderLayer(opacity, transform);
} else {
layerToRender->RenderLayer(1.0, gfx3DMatrix());
}
D3DSURFACE_DESC desc;
renderSurface->GetDesc(&desc);
if (clipRect || useIntermediate) {
device()->SetScissorRect(&oldClipRect);
}
r.left = NS_MAX<LONG>(0, r.left);
r.top = NS_MAX<LONG>(0, r.top);
r.bottom = NS_MIN<LONG>(r.bottom, desc.Height);
r.right = NS_MIN<LONG>(r.right, desc.Width);
device()->SetScissorRect(&r);
layerToRender->RenderLayer();
Layer *nextSibling = layerToRender->GetLayer()->GetNextSibling();
layerToRender = nextSibling ? static_cast<LayerD3D9*>(nextSibling->
ImplData())
@ -224,7 +241,6 @@ ContainerLayerD3D9::RenderLayer()
if (useIntermediate) {
device()->SetRenderTarget(0, previousRenderTarget);
device()->SetScissorRect(&oldClipRect);
device()->SetVertexShaderConstantF(CBvRenderTargetOffset, previousRenderTargetOffset, 1);
device()->SetVertexShaderConstantF(CBmProjection, &oldViewMatrix[0][0], 4);
@ -235,7 +251,7 @@ ContainerLayerD3D9::RenderLayer()
visibleRect.height),
1);
device()->SetVertexShaderConstantF(CBmLayerTransform, &mTransform._11, 4);
device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
float opacityVector[4];
/*
@ -261,5 +277,32 @@ ContainerLayerD3D9::LayerManagerDestroyed()
}
}
bool
ContainerLayerD3D9::ShouldUseIntermediate(float aOpacity,
const gfx3DMatrix &aMatrix)
{
if (aOpacity == 1.0f && aMatrix.IsIdentity()) {
return false;
}
Layer *firstChild = GetFirstChild();
if (!firstChild || (!firstChild->GetNextSibling() &&
!firstChild->GetClipRect())) {
// If we forward our transform to a child without using an intermediate,
// we need to be sure that child does not have a clip rect, since its clip
// rect would be applied after our transform.
return false;
}
if (aMatrix.IsIdentity() && (!firstChild || !firstChild->GetNextSibling())) {
// If there's no transforms applied and a single child, opacity can always
// be forwarded to our only child.
return false;
}
return true;
}
} /* layers */
} /* mozilla */

View File

@ -65,9 +65,13 @@ public:
PRBool IsEmpty();
void RenderLayer();
void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
virtual void LayerManagerDestroyed();
private:
bool ShouldUseIntermediate(float aOpacity,
const gfx3DMatrix &aMatrix);
};
} /* layers */

View File

@ -148,7 +148,7 @@ ImageLayerD3D9::GetLayer()
}
void
ImageLayerD3D9::RenderLayer()
ImageLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
{
if (!GetContainer()) {
return;
@ -172,14 +172,15 @@ ImageLayerD3D9::RenderLayer()
yuvImage->mSize.height),
1);
device()->SetVertexShaderConstantF(CBmLayerTransform, &mTransform._11, 4);
gfx3DMatrix transform = mTransform * aTransform;
device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
float opacity[4];
/*
* We always upload a 4 component float, but the shader will
* only use the the first component since it's declared as a 'float'.
*/
opacity[0] = GetOpacity();
opacity[0] = GetOpacity() * aOpacity;
device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
mD3DManager->SetShaderMode(DeviceManagerD3D9::YCBCRLAYER);
@ -220,14 +221,15 @@ ImageLayerD3D9::RenderLayer()
cairoImage->mSize.height),
1);
device()->SetVertexShaderConstantF(CBmLayerTransform, &mTransform._11, 4);
gfx3DMatrix transform = mTransform * aTransform;
device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
float opacity[4];
/*
* We always upload a 4 component float, but the shader will
* only use the the first component since it's declared as a 'float'.
*/
opacity[0] = GetOpacity();
opacity[0] = GetOpacity() * aOpacity;
device()->SetPixelShaderConstantF(CBfLayerOpacity, opacity, 1);
mD3DManager->SetShaderMode(DeviceManagerD3D9::RGBALAYER);

View File

@ -87,7 +87,7 @@ public:
// LayerD3D9 Implementation
virtual Layer* GetLayer();
virtual void RenderLayer();
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
};
class THEBES_API ImageD3D9

View File

@ -298,7 +298,7 @@ LayerManagerD3D9::Render()
}
device()->SetScissorRect(&r);
static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer();
static_cast<LayerD3D9*>(mRoot->ImplData())->RenderLayer(1.0, gfx3DMatrix());
}
device()->EndScene();

View File

@ -251,7 +251,7 @@ public:
virtual Layer* GetLayer() = 0;
virtual void RenderLayer() = 0;
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform) = 0;
/* This function may be used on device resets to clear all VRAM resources
* that a layer might be using.

View File

@ -172,7 +172,7 @@ ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
}
void
ThebesLayerD3D9::RenderLayer()
ThebesLayerD3D9::RenderLayer(float aOpacity, const gfx3DMatrix &aTransform)
{
if (mVisibleRegion.IsEmpty()) {
return;
@ -225,14 +225,15 @@ ThebesLayerD3D9::RenderLayer()
mValidRegion = mVisibleRegion;
}
device()->SetVertexShaderConstantF(CBmLayerTransform, &mTransform._11, 4);
gfx3DMatrix transform = mTransform * aTransform;
device()->SetVertexShaderConstantF(CBmLayerTransform, &transform._11, 4);
float opacity[4];
/*
* We always upload a 4 component float, but the shader will use only the
* first component since it's declared as a 'float'.
*/
opacity[0] = GetOpacity();
opacity[0] = GetOpacity() * aOpacity;
device()->SetPixelShaderConstantF(0, opacity, 1);
#ifdef CAIRO_HAS_D2D_SURFACE

View File

@ -61,7 +61,7 @@ public:
/* LayerD3D9 implementation */
Layer* GetLayer();
virtual PRBool IsEmpty();
virtual void RenderLayer();
virtual void RenderLayer(float aOpacity, const gfx3DMatrix &aTransform);
virtual void CleanResources();
virtual void LayerManagerDestroyed();