Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 514129 Details for
Bug 635373
[patch]
D3D9 and D3D10 fix
bug635373 (text/plain), 13.53 KB, created by
Robert O'Callahan (:roc) (email my personal email if necessary)
(
hide
)
Description:
D3D9 and D3D10 fix
Filename:
MIME Type:
Creator:
Robert O'Callahan (:roc) (email my personal email if necessary)
Size:
13.53 KB
patch
obsolete
>From: Robert O'Callahan <robert@ocallahan.org> >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 > >diff --git a/gfx/layers/d3d10/ThebesLayerD3D10.cpp b/gfx/layers/d3d10/ThebesLayerD3D10.cpp >--- 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; > } >diff --git a/gfx/layers/d3d10/ThebesLayerD3D10.h b/gfx/layers/d3d10/ThebesLayerD3D10.h >--- a/gfx/layers/d3d10/ThebesLayerD3D10.h >+++ b/gfx/layers/d3d10/ThebesLayerD3D10.h >@@ -70,18 +70,21 @@ private: > 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; >+ /* 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); > > /* This contains the thebes surface */ > nsRefPtr<gfxASurface> mD2DSurface; > > /* This contains the thebes surface for our render-on-white texture */ >diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.cpp b/gfx/layers/d3d9/ThebesLayerD3D9.cpp >--- 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);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Flags:
bas.schouten
: review+
beltzner
: approval2.0-
Actions:
View
|
Diff
|
Review
Attachments on
bug 635373
:
513923
|
513924
|
513926
|
514069
|
514078
|
514128
| 514129 |
514156
|
514449
|
514973
|
514974
|
522336