Bug 612846 - Part 4 - Make ThebesLayerD3D10 support component alpha. r=Bas a=blocking2.0

This commit is contained in:
Matt Woodrow 2011-01-20 15:47:39 +13:00
Родитель 8ad676f560
Коммит 8ce139aa1a
4 изменённых файлов: 147 добавлений и 41 удалений

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

@ -43,6 +43,9 @@
#include "gfxD2DSurface.h"
#endif
#include "gfxTeeSurface.h"
#include "gfxUtils.h"
namespace mozilla {
namespace layers {
@ -117,7 +120,9 @@ ThebesLayerD3D10::RenderLayer()
SetEffectTransformAndOpacity();
ID3D10EffectTechnique *technique;
if (CanUseOpaqueSurface()) {
if (mTextureOnWhite) {
technique = effect()->GetTechniqueByName("RenderComponentAlphaLayer");
} else if (CanUseOpaqueSurface()) {
technique = effect()->GetTechniqueByName("RenderRGBLayerPremul");
} else {
technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
@ -130,6 +135,9 @@ ThebesLayerD3D10::RenderLayer()
if (mSRView) {
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView);
}
if (mSRViewOnWhite) {
effect()->GetVariableByName("tRGBWhite")->AsShaderResource()->SetResource(mSRViewOnWhite);
}
while ((iterRect = iter.Next())) {
effect()->GetVariableByName("vLayerQuad")->AsVector()->SetFloatVector(
@ -164,19 +172,28 @@ ThebesLayerD3D10::Validate()
return;
}
VerifyContentType();
SurfaceMode mode = GetSurfaceMode();
if (mode == SURFACE_COMPONENT_ALPHA &&
(!mParent || !mParent->SupportsComponentAlphaChildren())) {
mode = SURFACE_SINGLE_CHANNEL_ALPHA;
}
VerifyContentType(mode);
nsIntRect visibleRect = mVisibleRegion.GetBounds();
if (mTexture) {
if (!mTextureRegion.IsEqual(mVisibleRegion)) {
nsRefPtr<ID3D10Texture2D> oldTexture = mTexture;
mTexture = nsnull;
nsRefPtr<ID3D10Texture2D> oldTextureOnWhite = mTextureOnWhite;
mTextureOnWhite = nsnull;
nsIntRegion retainRegion = mTextureRegion;
nsIntRect oldBounds = mTextureRegion.GetBounds();
nsIntRect newBounds = mVisibleRegion.GetBounds();
CreateNewTexture(gfxIntSize(newBounds.width, newBounds.height));
CreateNewTextures(gfxIntSize(newBounds.width, newBounds.height), mode);
// Old visible region will become the region that is covered by both the
// old and the new visible region.
@ -199,13 +216,18 @@ ThebesLayerD3D10::Validate()
CopyRegion(oldTexture, oldBounds.TopLeft(),
mTexture, newBounds.TopLeft(),
retainRegion, &mValidRegion);
if (oldTextureOnWhite) {
CopyRegion(oldTextureOnWhite, oldBounds.TopLeft(),
mTextureOnWhite, newBounds.TopLeft(),
retainRegion, &mValidRegion);
}
}
mTextureRegion = mVisibleRegion;
}
}
if (!mTexture) {
CreateNewTexture(gfxIntSize(visibleRect.width, visibleRect.height));
if (!mTexture || (mode == SURFACE_COMPONENT_ALPHA && !mTextureOnWhite)) {
CreateNewTextures(gfxIntSize(visibleRect.width, visibleRect.height), mode);
mValidRegion.SetEmpty();
}
@ -225,7 +247,7 @@ ThebesLayerD3D10::Validate()
nsIntRegion region;
region.Sub(mVisibleRegion, mValidRegion);
DrawRegion(region);
DrawRegion(region, mode);
mValidRegion = mVisibleRegion;
}
@ -244,27 +266,47 @@ ThebesLayerD3D10::GetLayer()
}
void
ThebesLayerD3D10::VerifyContentType()
ThebesLayerD3D10::VerifyContentType(SurfaceMode aMode)
{
if (mD2DSurface) {
gfxASurface::gfxContentType type = CanUseOpaqueSurface() ?
gfxASurface::gfxContentType type = aMode != SURFACE_SINGLE_CHANNEL_ALPHA ?
gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA;
if (type != mD2DSurface->GetContentType()) {
mD2DSurface = new gfxD2DSurface(mTexture, type);
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurface = nsnull;
return;
if (type != mD2DSurface->GetContentType()) {
mD2DSurface = new gfxD2DSurface(mTexture, type);
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurface = nsnull;
return;
}
mValidRegion.SetEmpty();
}
if (aMode != SURFACE_COMPONENT_ALPHA && mTextureOnWhite) {
// If we've transitioned away from component alpha, we can delete those resources.
mD2DSurfaceOnWhite = nsnull;
mSRViewOnWhite = nsnull;
mTextureOnWhite = nsnull;
mValidRegion.SetEmpty();
}
}
}
static void
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
const nsIntPoint& aOffset, const gfxRGBA& aColor)
{
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
gfxUtils::PathForRegion(ctx, aRegion);
ctx->SetColor(aColor);
ctx->Fill();
}
void
ThebesLayerD3D10::DrawRegion(const nsIntRegion &aRegion)
ThebesLayerD3D10::DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode)
{
nsIntRect visibleRect = mVisibleRegion.GetBounds();
@ -272,7 +314,22 @@ ThebesLayerD3D10::DrawRegion(const nsIntRegion &aRegion)
return;
}
nsRefPtr<gfxContext> context = new gfxContext(mD2DSurface);
nsRefPtr<gfxASurface> destinationSurface;
if (aMode == SURFACE_COMPONENT_ALPHA) {
FillSurface(mD2DSurface, aRegion, visibleRect.TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(mD2DSurfaceOnWhite, aRegion, visibleRect.TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0));
gfxASurface* surfaces[2] = { mD2DSurface.get(), mD2DSurfaceOnWhite.get() };
destinationSurface = new gfxTeeSurface(surfaces, NS_ARRAY_LENGTH(surfaces));
// Using this surface as a source will likely go horribly wrong, since
// only the onBlack surface will really be used, so alpha information will
// be incorrect.
destinationSurface->SetAllowUseAsSource(PR_FALSE);
} else {
destinationSurface = mD2DSurface;
}
nsRefPtr<gfxContext> context = new gfxContext(destinationSurface);
nsIntRegionRectIterator iter(aRegion);
context->Translate(gfxPoint(-visibleRect.x, -visibleRect.y));
@ -283,7 +340,7 @@ ThebesLayerD3D10::DrawRegion(const nsIntRegion &aRegion)
}
context->Clip();
if (mD2DSurface->GetContentType() != gfxASurface::CONTENT_COLOR) {
if (aMode == SURFACE_SINGLE_CHANNEL_ALPHA) {
context->SetOperator(gfxContext::OPERATOR_CLEAR);
context->Paint();
context->SetOperator(gfxContext::OPERATOR_OVER);
@ -296,7 +353,7 @@ ThebesLayerD3D10::DrawRegion(const nsIntRegion &aRegion)
}
void
ThebesLayerD3D10::CreateNewTexture(const gfxIntSize &aSize)
ThebesLayerD3D10::CreateNewTextures(const gfxIntSize &aSize, SurfaceMode aMode)
{
if (aSize.width == 0 || aSize.height == 0) {
// Nothing to do.
@ -306,27 +363,54 @@ ThebesLayerD3D10::CreateNewTexture(const gfxIntSize &aSize)
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1);
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
desc.MiscFlags = D3D10_RESOURCE_MISC_GDI_COMPATIBLE;
HRESULT hr;
HRESULT hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
if (!mTexture) {
hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTexture));
if (FAILED(hr)) {
NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
return;
}
hr = device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
if (FAILED(hr)) {
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
}
mD2DSurface = new gfxD2DSurface(mTexture, aMode != SURFACE_SINGLE_CHANNEL_ALPHA ?
gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA);
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurface = nsnull;
return;
}
if (FAILED(hr)) {
NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
return;
}
hr = device()->CreateShaderResourceView(mTexture, NULL, getter_AddRefs(mSRView));
if (aMode == SURFACE_COMPONENT_ALPHA && !mTextureOnWhite) {
hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(mTextureOnWhite));
if (FAILED(hr)) {
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
}
if (FAILED(hr)) {
NS_WARNING("Failed to create new texture for ThebesLayerD3D10!");
return;
}
mD2DSurface = new gfxD2DSurface(mTexture, CanUseOpaqueSurface() ?
gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA);
hr = device()->CreateShaderResourceView(mTextureOnWhite, NULL, getter_AddRefs(mSRViewOnWhite));
if (!mD2DSurface || mD2DSurface->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurface = nsnull;
return;
if (FAILED(hr)) {
NS_WARNING("Failed to create shader resource view for ThebesLayerD3D10.");
}
mD2DSurfaceOnWhite = new gfxD2DSurface(mTextureOnWhite, gfxASurface::CONTENT_COLOR);
if (!mD2DSurfaceOnWhite || mD2DSurfaceOnWhite->CairoStatus()) {
NS_WARNING("Failed to create surface for ThebesLayerD3D10.");
mD2DSurfaceOnWhite = nsnull;
return;
}
}
}

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

@ -67,20 +67,29 @@ private:
/* Shader resource view for our texture */
nsRefPtr<ID3D10ShaderResourceView> mSRView;
/* Texture for render-on-whitew when doing component alpha */
nsRefPtr<ID3D10Texture2D> mTextureOnWhite;
/* Shader resource view for our render-on-white texture */
nsRefPtr<ID3D10ShaderResourceView> mSRViewOnWhite;
/* Visible region used when we drew the contents of the textures */
nsIntRegion mTextureRegion;
/* Checks if our D2D surface has the right content type */
void VerifyContentType();
void VerifyContentType(SurfaceMode aMode);
/* This contains the thebes surface */
nsRefPtr<gfxASurface> mD2DSurface;
/* This contains the thebes surface for our render-on-white texture */
nsRefPtr<gfxASurface> mD2DSurfaceOnWhite;
/* Have a region of our layer drawn */
void DrawRegion(const nsIntRegion &aRegion);
void DrawRegion(const nsIntRegion &aRegion, SurfaceMode aMode);
/* Create a new texture */
void CreateNewTexture(const gfxIntSize &aSize);
void CreateNewTextures(const gfxIntSize &aSize, SurfaceMode aMode);
/* Copy a texture region */
void CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset,

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

@ -434,9 +434,10 @@ gfxUtils::ImageFormatToDepth(gfxASurface::gfxImageFormat aFormat)
}
return 0;
}
static void
ClipToRegionInternal(gfxContext* aContext, const nsIntRegion& aRegion,
PRBool aSnap)
PathForRegionInternal(gfxContext* aContext, const nsIntRegion& aRegion,
PRBool aSnap)
{
aContext->NewPath();
nsIntRegionRectIterator iter(aRegion);
@ -444,19 +445,26 @@ ClipToRegionInternal(gfxContext* aContext, const nsIntRegion& aRegion,
while ((r = iter.Next()) != nsnull) {
aContext->Rectangle(gfxRect(r->x, r->y, r->width, r->height), aSnap);
}
aContext->Clip();
}
/*static*/ void
gfxUtils::ClipToRegion(gfxContext* aContext, const nsIntRegion& aRegion)
{
ClipToRegionInternal(aContext, aRegion, PR_FALSE);
PathForRegionInternal(aContext, aRegion, PR_FALSE);
aContext->Clip();
}
/*static*/ void
gfxUtils::ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion)
{
ClipToRegionInternal(aContext, aRegion, PR_TRUE);
PathForRegionInternal(aContext, aRegion, PR_TRUE);
aContext->Clip();
}
/*static*/ void
gfxUtils::PathForRegion(gfxContext* aContext, const nsIntRegion& aRegion)
{
PathForRegionInternal(aContext, aRegion, PR_FALSE);
}
PRBool

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

@ -96,6 +96,11 @@ public:
*/
static void ClipToRegionSnapped(gfxContext* aContext, const nsIntRegion& aRegion);
/**
* Draw a path around aRegion.
*/
static void PathForRegion(gfxContext* aContext, const nsIntRegion& aRegion);
/*
* Convert image format to depth value
*/