Bug 577462: Use GetDC where possible for ThebesLayerD3D9 textures. r=jrmuizel

This commit is contained in:
Bas Schouten 2010-07-14 00:19:45 +02:00
Родитель 4b895ef379
Коммит 1c1caaf043
1 изменённых файлов: 114 добавлений и 33 удалений

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

@ -38,9 +38,32 @@
#include "ThebesLayerD3D9.h" #include "ThebesLayerD3D9.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
#include "gfxWindowsPlatform.h"
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
// Returns true if it's OK to save the contents of aLayer in an
// opaque surface (a surface without an alpha channel).
// If we can use a surface without an alpha channel, we should, because
// it will often make painting of antialiased text faster and higher
// quality.
static PRBool
UseOpaqueSurface(Layer* aLayer)
{
// If the visible content in the layer is opaque, there is no need
// for an alpha channel.
if (aLayer->IsOpaqueContent())
return PR_TRUE;
// Also, if this layer is the bottommost layer in a container which
// doesn't need an alpha channel, we can use an opaque surface for this
// layer too. Any transparent areas must be covered by something else
// in the container.
ContainerLayer* parent = aLayer->GetParent();
return parent && parent->GetFirstChild() == aLayer &&
UseOpaqueSurface(parent);
}
ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager) ThebesLayerD3D9::ThebesLayerD3D9(LayerManagerD3D9 *aManager)
: ThebesLayer(aManager, NULL) : ThebesLayer(aManager, NULL)
, LayerD3D9(aManager) , LayerD3D9(aManager)
@ -67,16 +90,35 @@ ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
if (aRegion.IsEqual(mVisibleRegion)) { if (aRegion.IsEqual(mVisibleRegion)) {
return; return;
} }
nsIntRegion oldVisibleRegion = mVisibleRegion;
nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
nsIntRegion oldVisibleRegion = mVisibleRegion;
ThebesLayer::SetVisibleRegion(aRegion); ThebesLayer::SetVisibleRegion(aRegion);
if (!mTexture) {
// If we don't need to retain content initialize lazily. This is good also
// because we might get mIsOpaqueSurface set later than the first call to
// SetVisibleRegion.
return;
}
D3DFORMAT fmt = UseOpaqueSurface(this) ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
D3DSURFACE_DESC desc;
mTexture->GetLevelDesc(0, &desc);
if (fmt != desc.Format) {
// The new format isn't compatible with the old texture, toss out the old
// texture.
mTexture = nsnull;
}
nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
nsIntRect oldBounds = oldVisibleRegion.GetBounds(); nsIntRect oldBounds = oldVisibleRegion.GetBounds();
nsIntRect newBounds = mVisibleRegion.GetBounds(); nsIntRect newBounds = mVisibleRegion.GetBounds();
device()->CreateTexture(newBounds.width, newBounds.height, 1, device()->CreateTexture(newBounds.width, newBounds.height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DUSAGE_RENDERTARGET, fmt,
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL); D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
// Old visible region will become the region that is covered by both the // Old visible region will become the region that is covered by both the
@ -149,11 +191,26 @@ ThebesLayerD3D9::RenderLayer()
if (mVisibleRegion.IsEmpty()) { if (mVisibleRegion.IsEmpty()) {
return; return;
} }
HRESULT hr;
nsIntRect visibleRect = mVisibleRegion.GetBounds(); nsIntRect visibleRect = mVisibleRegion.GetBounds();
D3DFORMAT fmt = UseOpaqueSurface(this) ? D3DFMT_X8R8G8B8 : D3DFMT_A8R8G8B8;
if (mTexture) {
D3DSURFACE_DESC desc;
mTexture->GetLevelDesc(0, &desc);
if (fmt != desc.Format) {
// The new format isn't compatible with the old texture, toss out the old
// texture.
mTexture = nsnull;
mValidRegion.SetEmpty();
}
}
if (!mTexture) { if (!mTexture) {
device()->CreateTexture(visibleRect.width, visibleRect.height, 1, device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DUSAGE_RENDERTARGET, fmt,
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL); D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
mValidRegion.SetEmpty(); mValidRegion.SetEmpty();
} }
@ -163,30 +220,53 @@ ThebesLayerD3D9::RenderLayer()
region.Sub(mVisibleRegion, mValidRegion); region.Sub(mVisibleRegion, mValidRegion);
nsIntRect bounds = region.GetBounds(); nsIntRect bounds = region.GetBounds();
gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32;; gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32;
nsRefPtr<gfxASurface> destinationSurface; nsRefPtr<gfxASurface> destinationSurface;
nsRefPtr<gfxContext> context; nsRefPtr<gfxContext> context;
// XXX - Should optimize here to use IDirect3DSurface9::GetDC() for GDI nsRefPtr<IDirect3DTexture9> tmpTexture;
// rendering since we're always on windows. We may consider retaining a device()->CreateTexture(bounds.width, bounds.height, 1,
// SYSTEMMEM texture texture the size of our DEFAULT texture and then use 0, fmt,
// UpdateTexture and add dirty rects to update in a single call. D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
nsRefPtr<IDirect3DSurface9> surf;
HDC dc;
if (UseOpaqueSurface(this)) {
hr = tmpTexture->GetSurfaceLevel(0, getter_AddRefs(surf));
if (FAILED(hr)) {
// Uh-oh, bail.
NS_WARNING("Failed to get texture surface level.");
return;
}
hr = surf->GetDC(&dc);
if (FAILED(hr)) {
NS_WARNING("Failed to get device context for texture surface.");
return;
}
destinationSurface = new gfxWindowsSurface(dc);
} else {
// XXX - We may consider retaining a SYSTEMMEM texture texture the size
// of our DEFAULT texture and then use UpdateTexture and add dirty rects
// to update in a single call.
destinationSurface = destinationSurface =
gfxPlatform::GetPlatform()-> gfxPlatform::GetPlatform()->
CreateOffscreenSurface(gfxIntSize(bounds.width, CreateOffscreenSurface(gfxIntSize(bounds.width,
bounds.height), bounds.height),
imageFormat); imageFormat);
}
context = new gfxContext(destinationSurface); context = new gfxContext(destinationSurface);
context->Translate(gfxPoint(-bounds.x, -bounds.y)); context->Translate(gfxPoint(-bounds.x, -bounds.y));
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo(); LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
cbInfo.Callback(this, context, region, nsIntRegion(), cbInfo.CallbackData); cbInfo.Callback(this, context, region, nsIntRegion(), cbInfo.CallbackData);
nsRefPtr<IDirect3DTexture9> tmpTexture; if (UseOpaqueSurface(this)) {
device()->CreateTexture(bounds.width, bounds.height, 1, surf->ReleaseDC(dc);
0, D3DFMT_A8R8G8B8, } else {
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
D3DLOCKED_RECT r; D3DLOCKED_RECT r;
tmpTexture->LockRect(0, &r, NULL, 0); tmpTexture->LockRect(0, &r, NULL, 0);
@ -205,6 +285,7 @@ ThebesLayerD3D9::RenderLayer()
imgSurface = NULL; imgSurface = NULL;
tmpTexture->UnlockRect(0); tmpTexture->UnlockRect(0);
}
nsRefPtr<IDirect3DSurface9> srcSurface; nsRefPtr<IDirect3DSurface9> srcSurface;
nsRefPtr<IDirect3DSurface9> dstSurface; nsRefPtr<IDirect3DSurface9> dstSurface;