Bug 635373. If we need to resample a ThebesLayer texture, make sure we make all the pixels of the texture valid in case they get sampled. r=bas

This commit is contained in:
Robert O'Callahan 2011-04-01 10:33:46 +13:00
parent 07c2424cf5
commit bfb12d86f0
3 changed files with 86 additions and 43 deletions

View File

@ -54,6 +54,7 @@ namespace layers {
ThebesLayerD3D10::ThebesLayerD3D10(LayerManagerD3D10 *aManager)
: ThebesLayer(aManager, NULL)
, LayerD3D10(aManager)
, mCurrentSurfaceMode(SURFACE_OPAQUE)
{
mImplData = static_cast<LayerD3D10*>(this);
}
@ -119,20 +120,24 @@ ThebesLayerD3D10::RenderLayer()
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;
@ -154,10 +159,10 @@ ThebesLayerD3D10::RenderLayer()
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);
@ -176,11 +181,34 @@ ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
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);
@ -199,27 +227,22 @@ ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
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
@ -234,47 +257,41 @@ ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
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);
@ -285,11 +302,11 @@ ThebesLayerD3D10::Validate(ReadbackProcessor *aReadback)
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;
}
}

View File

@ -75,8 +75,11 @@ private:
/* 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;
/* Area of layer currently stored in texture(s) */
nsIntRect mTextureRect;
/* Last surface mode set in Validate() */
SurfaceMode mCurrentSurfaceMode;
/* Checks if our D2D surface has the right content type */
void VerifyContentType(SurfaceMode aMode);

View File

@ -208,11 +208,34 @@ ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback)
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)) {
@ -232,7 +255,7 @@ ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback)
// 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!");
@ -245,7 +268,7 @@ ThebesLayerD3D9::RenderThebesLayer(ReadbackProcessor* aReadback)
DrawRegion(drawRegion, mode, readbackUpdates);
mValidRegion = mVisibleRegion;
mValidRegion = neededRegion;
}
SetShaderTransformAndOpacity();