--- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp
+++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp
@@ -49,16 +49,17 @@
#include "ReadbackProcessor.h"
namespace mozilla {
namespace layers {
ThebesLayerD3D10::ThebesLayerD3D10(LayerManagerD3D10 *aManager)
: ThebesLayer(aManager, NULL)
, LayerD3D10(aManager)
+ , mCurrentSurfaceMode(SURFACE_OPAQUE)
{
mImplData = static_cast<LayerD3D10*>(this);
}
ThebesLayerD3D10::~ThebesLayerD3D10()
{
}
@@ -114,30 +115,34 @@ void ThebesLayerD3D10::CopyRegion(ID3D10
void
ThebesLayerD3D10::RenderLayer()
{
if (!mTexture) {
return;
}
- nsIntRect visibleRect = mVisibleRegion.GetBounds();
-
SetEffectTransformAndOpacity();
ID3D10EffectTechnique *technique;
- if (mTextureOnWhite) {
+ switch (mCurrentSurfaceMode) {
+ case SURFACE_COMPONENT_ALPHA:
technique = effect()->GetTechniqueByName("RenderComponentAlphaLayer");
- } else if (CanUseOpaqueSurface()) {
+ break;
+ case SURFACE_OPAQUE:
technique = effect()->GetTechniqueByName("RenderRGBLayerPremul");
- } else {
+ break;
+ case SURFACE_SINGLE_CHANNEL_ALPHA:
technique = effect()->GetTechniqueByName("RenderRGBALayerPremul");
+ break;
+ default:
+ NS_ERROR("Unknown mode");
+ return;
}
-
nsIntRegionRectIterator iter(mVisibleRegion);
const nsIntRect *iterRect;
if (mSRView) {
effect()->GetVariableByName("tRGB")->AsShaderResource()->SetResource(mSRView);
}
if (mSRViewOnWhite) {
effect()->GetVariableByName("tRGBWhite")->AsShaderResource()->SetResource(mSRViewOnWhite);
@@ -149,20 +154,20 @@ ThebesLayerD3D10::RenderLayer()
(float)iterRect->x,
(float)iterRect->y,
(float)iterRect->width,
(float)iterRect->height)
);
effect()->GetVariableByName("vTextureCoords")->AsVector()->SetFloatVector(
ShaderConstantRectD3D10(
- (float)(iterRect->x - visibleRect.x) / (float)visibleRect.width,
- (float)(iterRect->y - visibleRect.y) / (float)visibleRect.height,
- (float)iterRect->width / (float)visibleRect.width,
- (float)iterRect->height / (float)visibleRect.height)
+ (float)(iterRect->x - mTextureRect.x) / (float)mTextureRect.width,
+ (float)(iterRect->y - mTextureRect.y) / (float)mTextureRect.height,
+ (float)iterRect->width / (float)mTextureRect.width,
+ (float)iterRect->height / (float)mTextureRect.height)
);
technique->GetPassByIndex(0)->Apply(0);
device()->Draw(4, 0);
}
// Set back to default.
effect()->GetVariableByName("vTextureCoords")->AsVector()->
@@ -171,21 +176,44 @@ ThebesLayerD3D10::RenderLayer()
void
ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
{
if (mVisibleRegion.IsEmpty()) {
return;
}
+ nsIntRect newTextureRect = mVisibleRegion.GetBounds();
+
SurfaceMode mode = GetSurfaceMode();
if (mode == SURFACE_COMPONENT_ALPHA &&
(!mParent || !mParent->SupportsComponentAlphaChildren())) {
mode = SURFACE_SINGLE_CHANNEL_ALPHA;
}
+ // If we have a transform that requires resampling of our texture, then
+ // we need to make sure we don't sample pixels that haven't been drawn.
+ // We clamp sample coordinates to the texture rect, but when the visible region
+ // doesn't fill the entire texture rect we need to make sure we draw all the
+ // pixels in the texture rect anyway in case they get sampled.
+ nsIntRegion neededRegion = mVisibleRegion;
+ if (neededRegion.GetBounds() != newTextureRect ||
+ neededRegion.GetNumRects() > 1) {
+ gfxMatrix transform2d;
+ if (!GetEffectiveTransform().Is2D(&transform2d) ||
+ transform2d.HasNonIntegerTranslation()) {
+ neededRegion = newTextureRect;
+ if (mode == SURFACE_OPAQUE) {
+ // We're going to paint outside the visible region, but layout hasn't
+ // promised that it will paint opaquely there, so we'll have to
+ // treat this layer as transparent.
+ mode = SURFACE_SINGLE_CHANNEL_ALPHA;
+ }
+ }
+ }
+ mCurrentSurfaceMode = mode;
VerifyContentType(mode);
float xres, yres;
GetDesiredResolutions(xres, yres);
// If our resolution changed, we need new sized textures, delete the old ones.
if (ResolutionChanged(xres, yres)) {
@@ -194,107 +222,96 @@ ThebesLayerD3D10::Validate(ReadbackProce
}
nsTArray<ReadbackProcessor::Update> readbackUpdates;
nsIntRegion readbackRegion;
if (aReadback && UsedForReadback()) {
aReadback->GetThebesLayerUpdates(this, &readbackUpdates, &readbackRegion);
}
- nsIntRect visibleRect = mVisibleRegion.GetBounds();
-
if (mTexture) {
- if (!mTextureRegion.IsEqual(mVisibleRegion)) {
+ if (mTextureRect != newTextureRect) {
nsRefPtr<ID3D10Texture2D> oldTexture = mTexture;
mTexture = nsnull;
nsRefPtr<ID3D10Texture2D> oldTextureOnWhite = mTextureOnWhite;
mTextureOnWhite = nsnull;
- nsIntRegion retainRegion = mTextureRegion;
- nsIntRect oldBounds = mTextureRegion.GetBounds();
- nsIntRect newBounds = mVisibleRegion.GetBounds();
-
- CreateNewTextures(gfxIntSize(newBounds.width, newBounds.height), mode);
-
+ nsIntRegion retainRegion = mTextureRect;
// Old visible region will become the region that is covered by both the
// old and the new visible region.
retainRegion.And(retainRegion, mVisibleRegion);
// No point in retaining parts which were not valid.
retainRegion.And(retainRegion, mValidRegion);
+ CreateNewTextures(gfxIntSize(newTextureRect.width, newTextureRect.height), mode);
+
nsIntRect largeRect = retainRegion.GetLargestRectangle();
// If we had no hardware texture before, have no retained area larger than
// the retention threshold or the requested resolution has changed,
// we're not retaining and are done here. If our texture creation failed
// this can mean a device reset is pending and we should silently ignore the
// failure. In the future when device failures are properly handled we
// should test for the type of failure and gracefully handle different
// failures. See bug 569081.
if (!oldTexture || !mTexture ||
largeRect.width * largeRect.height < RETENTION_THRESHOLD ||
ResolutionChanged(xres, yres)) {
mValidRegion.SetEmpty();
} else {
- CopyRegion(oldTexture, oldBounds.TopLeft(),
- mTexture, newBounds.TopLeft(),
+ CopyRegion(oldTexture, mTextureRect.TopLeft(),
+ mTexture, newTextureRect.TopLeft(),
retainRegion, &mValidRegion,
xres, yres);
if (oldTextureOnWhite) {
- CopyRegion(oldTextureOnWhite, oldBounds.TopLeft(),
- mTextureOnWhite, newBounds.TopLeft(),
+ CopyRegion(oldTextureOnWhite, mTextureRect.TopLeft(),
+ mTextureOnWhite, newTextureRect.TopLeft(),
retainRegion, &mValidRegion,
xres, yres);
}
}
}
}
- mTextureRegion = mVisibleRegion;
+ mTextureRect = newTextureRect;
if (!mTexture || (mode == SURFACE_COMPONENT_ALPHA && !mTextureOnWhite)) {
- CreateNewTextures(gfxIntSize(visibleRect.width, visibleRect.height), mode);
+ CreateNewTextures(gfxIntSize(newTextureRect.width, newTextureRect.height), mode);
mValidRegion.SetEmpty();
}
- if (!mValidRegion.IsEqual(mVisibleRegion)) {
+ nsIntRegion drawRegion;
+ drawRegion.Sub(neededRegion, mValidRegion);
+
+ if (!drawRegion.IsEmpty()) {
LayerManagerD3D10::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
if (!cbInfo.Callback) {
NS_ERROR("D3D10 should never need to update ThebesLayers in an empty transaction");
return;
}
- /* We use the bounds of the visible region because we draw the bounds of
- * this region when we draw this entire texture. We have to make sure that
- * the areas that aren't filled with content get their background drawn.
- * This is an issue for opaque surfaces, which otherwise won't get their
- * background painted.
- */
- nsIntRegion region;
- region.Sub(mVisibleRegion, mValidRegion);
-
- DrawRegion(region, mode);
+ DrawRegion(drawRegion, mode);
if (readbackUpdates.Length() > 0) {
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
- visibleRect.width, visibleRect.height,
+ newTextureRect.width, newTextureRect.height,
1, 1, 0, D3D10_USAGE_STAGING,
D3D10_CPU_ACCESS_READ);
nsRefPtr<ID3D10Texture2D> readbackTexture;
device()->CreateTexture2D(&desc, NULL, getter_AddRefs(readbackTexture));
device()->CopyResource(readbackTexture, mTexture);
for (int i = 0; i < readbackUpdates.Length(); i++) {
mD3DManager->readbackManager()->PostTask(readbackTexture,
&readbackUpdates[i],
- gfxPoint(visibleRect.x, visibleRect.y));
+ gfxPoint(newTextureRect.x, newTextureRect.y));
}
}
- mValidRegion = mVisibleRegion;
+ mValidRegion = neededRegion;
}
}
void
ThebesLayerD3D10::LayerManagerDestroyed()
{
mD3DManager = nsnull;
}
--- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp
+++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp
@@ -203,21 +203,44 @@ ThebesLayerD3D9::RenderVisibleRegion()
void
ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback)
{
if (mVisibleRegion.IsEmpty()) {
return;
}
+ nsIntRect newTextureRect = mVisibleRegion.GetBounds();
+
SurfaceMode mode = GetSurfaceMode();
if (mode == SURFACE_COMPONENT_ALPHA &&
(!mParent || !mParent->SupportsComponentAlphaChildren())) {
mode = SURFACE_SINGLE_CHANNEL_ALPHA;
}
+ // If we have a transform that requires resampling of our texture, then
+ // we need to make sure we don't sample pixels that haven't been drawn.
+ // We clamp sample coordinates to the texture rect, but when the visible region
+ // doesn't fill the entire texture rect we need to make sure we draw all the
+ // pixels in the texture rect anyway in case they get sampled.
+ nsIntRegion neededRegion = mVisibleRegion;
+ if (neededRegion.GetBounds() != newTextureRect ||
+ neededRegion.GetNumRects() > 1) {
+ gfxMatrix transform2d;
+ if (!GetEffectiveTransform().Is2D(&transform2d) ||
+ transform2d.HasNonIntegerTranslation()) {
+ neededRegion = newTextureRect;
+ if (mode == SURFACE_OPAQUE) {
+ // We're going to paint outside the visible region, but layout hasn't
+ // promised that it will paint opaquely there, so we'll have to
+ // treat this layer as transparent.
+ mode = SURFACE_SINGLE_CHANNEL_ALPHA;
+ }
+ }
+ }
+
VerifyContentType(mode);
UpdateTextures(mode);
if (!HaveTextures(mode)) {
NS_WARNING("Texture creation failed");
return;
}
nsTArray<ReadbackProcessor::Update> readbackUpdates;
@@ -227,30 +250,30 @@ ThebesLayerD3D9::RenderThebesLayer(Readb
}
// Because updates to D3D9 ThebesLayers are rendered with the CPU, we don't
// have to do readback from D3D9 surfaces. Instead we make sure that any area
// needed for readback is included in the drawRegion we ask layout to render.
// Then the readback areas we need can be copied out of the temporary
// destinationSurface in DrawRegion.
nsIntRegion drawRegion;
- drawRegion.Sub(mVisibleRegion, mValidRegion);
+ drawRegion.Sub(neededRegion, mValidRegion);
drawRegion.Or(drawRegion, readbackRegion);
// NS_ASSERTION(mVisibleRegion.Contains(region), "Bad readback region!");
if (!drawRegion.IsEmpty()) {
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
if (!cbInfo.Callback) {
NS_ERROR("D3D9 should never need to update ThebesLayers in an empty transaction");
return;
}
DrawRegion(drawRegion, mode, readbackUpdates);
- mValidRegion = mVisibleRegion;
+ mValidRegion = neededRegion;
}
SetShaderTransformAndOpacity();
if (mode == SURFACE_COMPONENT_ALPHA) {
mD3DManager->SetShaderMode(DeviceManagerD3D9::COMPONENTLAYERPASS1);
device()->SetTexture(0, mTexture);
device()->SetTexture(1, mTextureOnWhite);