зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1007821. Use image surfaces for transparent content on D3D9. r=bas
This gives us a 6% improvement on CART on WinXP.
This commit is contained in:
Родитель
e61f896f90
Коммит
83d2297b91
|
@ -402,6 +402,74 @@ OpaqueRenderer::End()
|
||||||
mD3D9ThebesSurface = nullptr;
|
mD3D9ThebesSurface = nullptr;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
class TransparentRenderer {
|
||||||
|
public:
|
||||||
|
TransparentRenderer(const nsIntRegion& aUpdateRegion) :
|
||||||
|
mUpdateRegion(aUpdateRegion) {}
|
||||||
|
~TransparentRenderer() { End(); }
|
||||||
|
already_AddRefed<gfxImageSurface> Begin(LayerD3D9* aLayer);
|
||||||
|
void End();
|
||||||
|
IDirect3DTexture9* GetTexture() { return mTmpTexture; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const nsIntRegion& mUpdateRegion;
|
||||||
|
nsRefPtr<IDirect3DTexture9> mTmpTexture;
|
||||||
|
nsRefPtr<gfxImageSurface> mD3D9ThebesSurface;
|
||||||
|
};
|
||||||
|
|
||||||
|
already_AddRefed<gfxImageSurface>
|
||||||
|
TransparentRenderer::Begin(LayerD3D9* aLayer)
|
||||||
|
{
|
||||||
|
nsIntRect bounds = mUpdateRegion.GetBounds();
|
||||||
|
|
||||||
|
HRESULT hr = aLayer->device()->
|
||||||
|
CreateTexture(bounds.width, bounds.height, 1, 0, D3DFMT_A8R8G8B8,
|
||||||
|
D3DPOOL_SYSTEMMEM, getter_AddRefs(mTmpTexture), nullptr);
|
||||||
|
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
aLayer->ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
D3DLOCKED_RECT r;
|
||||||
|
hr = mTmpTexture->LockRect(0, &r, nullptr, 0);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
// Uh-oh, bail.
|
||||||
|
NS_WARNING("Failed to lock the texture");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
nsRefPtr<gfxImageSurface> result =
|
||||||
|
new gfxImageSurface((unsigned char *)r.pBits,
|
||||||
|
bounds.Size(),
|
||||||
|
r.Pitch,
|
||||||
|
gfxImageFormat::ARGB32);
|
||||||
|
|
||||||
|
if (!result || result->CairoStatus()) {
|
||||||
|
NS_WARNING("Failed to d3d9 cairo surface.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
mD3D9ThebesSurface = result;
|
||||||
|
|
||||||
|
return result.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TransparentRenderer::End()
|
||||||
|
{
|
||||||
|
// gfxImageSurface returned from ::Begin() should be released before the
|
||||||
|
// texture is used. This will assert that this is the case
|
||||||
|
#if 1
|
||||||
|
if (mD3D9ThebesSurface) {
|
||||||
|
mD3D9ThebesSurface->AddRef();
|
||||||
|
nsrefcnt c = mD3D9ThebesSurface->Release();
|
||||||
|
if (c != 1)
|
||||||
|
NS_RUNTIMEABORT("Reference mD3D9ThebesSurface must be released by caller of Begin() before calling End()");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
mD3D9ThebesSurface = nullptr;
|
||||||
|
if (mTmpTexture)
|
||||||
|
mTmpTexture->UnlockRect(0);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
||||||
|
@ -418,13 +486,13 @@ void
|
||||||
ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
||||||
const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates)
|
const nsTArray<ReadbackProcessor::Update>& aReadbackUpdates)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
|
||||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||||
|
|
||||||
nsRefPtr<gfxASurface> destinationSurface;
|
nsRefPtr<gfxASurface> destinationSurface;
|
||||||
nsIntRect bounds = aRegion.GetBounds();
|
nsIntRect bounds = aRegion.GetBounds();
|
||||||
nsRefPtr<IDirect3DTexture9> tmpTexture;
|
nsRefPtr<IDirect3DTexture9> tmpTexture;
|
||||||
OpaqueRenderer opaqueRenderer(aRegion);
|
OpaqueRenderer opaqueRenderer(aRegion);
|
||||||
|
TransparentRenderer transparentRenderer(aRegion);
|
||||||
OpaqueRenderer opaqueRendererOnWhite(aRegion);
|
OpaqueRenderer opaqueRendererOnWhite(aRegion);
|
||||||
|
|
||||||
switch (aMode)
|
switch (aMode)
|
||||||
|
@ -434,25 +502,11 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: {
|
case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: {
|
||||||
hr = device()->CreateTexture(bounds.width, bounds.height, 1,
|
destinationSurface = transparentRenderer.Begin(this);
|
||||||
0, D3DFMT_A8R8G8B8,
|
|
||||||
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), nullptr);
|
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
|
||||||
ReportFailure(NS_LITERAL_CSTRING("Failed to create temporary texture in system memory."), hr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
nsRefPtr<gfxWindowsSurface> dest = new gfxWindowsSurface(
|
|
||||||
gfxIntSize(bounds.width, bounds.height), gfxImageFormat::ARGB32);
|
|
||||||
// If the contents of this layer don't require component alpha in the
|
// If the contents of this layer don't require component alpha in the
|
||||||
// end of rendering, it's safe to enable Cleartype since all the Cleartype
|
// end of rendering, it's safe to enable Cleartype since all the Cleartype
|
||||||
// glyphs must be over (or under) opaque pixels.
|
// glyphs must be over (or under) opaque pixels.
|
||||||
dest->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
|
destinationSurface->SetSubpixelAntialiasingEnabled(!(mContentFlags & CONTENT_COMPONENT_ALPHA));
|
||||||
destinationSurface = dest.forget();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,36 +577,13 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
||||||
destTextures.AppendElement(mTexture);
|
destTextures.AppendElement(mTexture);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA: {
|
case SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA:
|
||||||
LockTextureRectD3D9 textureLock(tmpTexture);
|
// Must release reference to dest surface before ending drawing
|
||||||
if (!textureLock.HasLock()) {
|
|
||||||
NS_WARNING("Failed to lock ThebesLayer tmpTexture texture.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
D3DLOCKED_RECT r = textureLock.GetLockRect();
|
|
||||||
|
|
||||||
nsRefPtr<gfxImageSurface> imgSurface =
|
|
||||||
new gfxImageSurface((unsigned char *)r.pBits,
|
|
||||||
bounds.Size(),
|
|
||||||
r.Pitch,
|
|
||||||
gfxImageFormat::ARGB32);
|
|
||||||
|
|
||||||
if (destinationSurface) {
|
|
||||||
nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
|
|
||||||
context->SetSource(destinationSurface);
|
|
||||||
context->SetOperator(gfxContext::OPERATOR_SOURCE);
|
|
||||||
context->Paint();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must release reference to dest surface before ending drawing
|
|
||||||
destinationSurface = nullptr;
|
destinationSurface = nullptr;
|
||||||
imgSurface = nullptr;
|
transparentRenderer.End();
|
||||||
|
srcTextures.AppendElement(transparentRenderer.GetTexture());
|
||||||
srcTextures.AppendElement(tmpTexture);
|
|
||||||
destTextures.AppendElement(mTexture);
|
destTextures.AppendElement(mTexture);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case SurfaceMode::SURFACE_COMPONENT_ALPHA: {
|
case SurfaceMode::SURFACE_COMPONENT_ALPHA: {
|
||||||
// Must release reference to dest surface before ending drawing
|
// Must release reference to dest surface before ending drawing
|
||||||
|
|
Загрузка…
Ссылка в новой задаче