mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 574239: Have ThebesLayerD3D9 retain its content even across changes to the visible region. r=jrmuizel
This commit is contained in:
parent
8442c7897c
commit
4e102a00dd
@ -54,6 +54,12 @@ ThebesLayerD3D9::~ThebesLayerD3D9()
|
|||||||
mD3DManager->mThebesLayers.RemoveElement(this);
|
mD3DManager->mThebesLayers.RemoveElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retention threshold - amount of pixels intersection required to enable
|
||||||
|
* layer content retention. This is a guesstimate. Profiling could be done to
|
||||||
|
* figure out the optimal threshold.
|
||||||
|
*/
|
||||||
|
#define RETENTION_THRESHOLD 16384
|
||||||
|
|
||||||
void
|
void
|
||||||
ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
|
ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
|
||||||
@ -61,55 +67,123 @@ ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
|
|||||||
if (aRegion.IsEqual(mVisibleRegion)) {
|
if (aRegion.IsEqual(mVisibleRegion)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
nsIntRegion oldVisibleRegion = mVisibleRegion;
|
||||||
|
nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
|
||||||
|
|
||||||
ThebesLayer::SetVisibleRegion(aRegion);
|
ThebesLayer::SetVisibleRegion(aRegion);
|
||||||
|
|
||||||
mInvalidatedRect = mVisibleRegion.GetBounds();
|
nsIntRect oldBounds = oldVisibleRegion.GetBounds();
|
||||||
device()->CreateTexture(mInvalidatedRect.width, mInvalidatedRect.height, 1,
|
nsIntRect newBounds = mVisibleRegion.GetBounds();
|
||||||
|
|
||||||
|
device()->CreateTexture(newBounds.width, newBounds.height, 1,
|
||||||
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
||||||
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
|
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
|
||||||
|
|
||||||
|
// Old visible region will become the region that is covered by both the
|
||||||
|
// old and the new visible region.
|
||||||
|
oldVisibleRegion.And(oldVisibleRegion, mVisibleRegion);
|
||||||
|
// No point in retaining parts which were not valid.
|
||||||
|
oldVisibleRegion.And(oldVisibleRegion, mValidRegion);
|
||||||
|
|
||||||
|
nsIntRect largeRect = oldVisibleRegion.GetLargestRectangle();
|
||||||
|
|
||||||
|
// If we had no hardware texture before or have no retained area larger than
|
||||||
|
// the retention threshold, 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) {
|
||||||
|
mValidRegion.SetEmpty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<IDirect3DSurface9> srcSurface, dstSurface;
|
||||||
|
oldTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
|
||||||
|
mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||||
|
|
||||||
|
nsIntRegion retainedRegion;
|
||||||
|
nsIntRegionRectIterator iter(oldVisibleRegion);
|
||||||
|
const nsIntRect *r;
|
||||||
|
while ((r = iter.Next())) {
|
||||||
|
if (r->width * r->height > RETENTION_THRESHOLD) {
|
||||||
|
RECT oldRect, newRect;
|
||||||
|
|
||||||
|
// Calculate the retained rectangle's position on the old and the new
|
||||||
|
// surface.
|
||||||
|
oldRect.left = r->x - oldBounds.x;
|
||||||
|
oldRect.top = r->y - oldBounds.y;
|
||||||
|
oldRect.right = oldRect.left + r->width;
|
||||||
|
oldRect.bottom = oldRect.top + r->height;
|
||||||
|
|
||||||
|
newRect.left = r->x - newBounds.x;
|
||||||
|
newRect.top = r->y - newBounds.y;
|
||||||
|
newRect.right = newRect.left + r->width;
|
||||||
|
newRect.bottom = newRect.top + r->height;
|
||||||
|
|
||||||
|
// Copy data from our old texture to the new one
|
||||||
|
HRESULT hr = device()->
|
||||||
|
StretchRect(srcSurface, &oldRect, dstSurface, &newRect, D3DTEXF_NONE);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
retainedRegion.Or(retainedRegion, *r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Areas which were valid and were retained are still valid
|
||||||
|
mValidRegion.And(mValidRegion, retainedRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
|
ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
|
||||||
{
|
{
|
||||||
nsIntRegion invalidatedRegion;
|
mValidRegion.Sub(mValidRegion, aRegion);
|
||||||
invalidatedRegion.Or(aRegion, mInvalidatedRect);
|
|
||||||
invalidatedRegion.And(invalidatedRegion, mVisibleRegion);
|
|
||||||
mInvalidatedRect = invalidatedRegion.GetBounds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ThebesLayerD3D9::RenderLayer()
|
ThebesLayerD3D9::RenderLayer()
|
||||||
{
|
{
|
||||||
|
if (mVisibleRegion.IsEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||||
|
|
||||||
if (!mTexture) {
|
if (!mTexture) {
|
||||||
device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
|
device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
|
||||||
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
||||||
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
|
D3DPOOL_DEFAULT, getter_AddRefs(mTexture), NULL);
|
||||||
mInvalidatedRect = visibleRect;
|
mValidRegion.SetEmpty();
|
||||||
}
|
}
|
||||||
if (!mInvalidatedRect.IsEmpty()) {
|
|
||||||
nsIntRegion region = mInvalidatedRect;
|
if (!mValidRegion.IsEqual(mVisibleRegion)) {
|
||||||
|
nsIntRegion region;
|
||||||
|
region.Sub(mVisibleRegion, mValidRegion);
|
||||||
|
nsIntRect bounds = region.GetBounds();
|
||||||
|
|
||||||
gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32;;
|
gfxASurface::gfxImageFormat imageFormat = gfxASurface::ImageFormatARGB32;;
|
||||||
nsRefPtr<gfxASurface> destinationSurface;
|
nsRefPtr<gfxASurface> destinationSurface;
|
||||||
nsRefPtr<gfxContext> context;
|
nsRefPtr<gfxContext> context;
|
||||||
|
|
||||||
|
// XXX - Should optimize here to use IDirect3DSurface9::GetDC() for GDI
|
||||||
|
// rendering since we're always on windows. 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.
|
||||||
destinationSurface =
|
destinationSurface =
|
||||||
gfxPlatform::GetPlatform()->
|
gfxPlatform::GetPlatform()->
|
||||||
CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
|
CreateOffscreenSurface(gfxIntSize(bounds.width,
|
||||||
mInvalidatedRect.height),
|
bounds.height),
|
||||||
imageFormat);
|
imageFormat);
|
||||||
|
|
||||||
context = new gfxContext(destinationSurface);
|
context = new gfxContext(destinationSurface);
|
||||||
context->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
|
context->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||||
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||||
cbInfo.Callback(this, context, region, nsIntRegion(), cbInfo.CallbackData);
|
cbInfo.Callback(this, context, region, nsIntRegion(), cbInfo.CallbackData);
|
||||||
|
|
||||||
nsRefPtr<IDirect3DTexture9> tmpTexture;
|
nsRefPtr<IDirect3DTexture9> tmpTexture;
|
||||||
device()->CreateTexture(mInvalidatedRect.width, mInvalidatedRect.height, 1,
|
device()->CreateTexture(bounds.width, bounds.height, 1,
|
||||||
0, D3DFMT_A8R8G8B8,
|
0, D3DFMT_A8R8G8B8,
|
||||||
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
|
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
|
||||||
|
|
||||||
@ -118,8 +192,8 @@ ThebesLayerD3D9::RenderLayer()
|
|||||||
|
|
||||||
nsRefPtr<gfxImageSurface> imgSurface =
|
nsRefPtr<gfxImageSurface> imgSurface =
|
||||||
new gfxImageSurface((unsigned char *)r.pBits,
|
new gfxImageSurface((unsigned char *)r.pBits,
|
||||||
gfxIntSize(mInvalidatedRect.width,
|
gfxIntSize(bounds.width,
|
||||||
mInvalidatedRect.height),
|
bounds.height),
|
||||||
r.Pitch,
|
r.Pitch,
|
||||||
imageFormat);
|
imageFormat);
|
||||||
|
|
||||||
@ -138,10 +212,20 @@ ThebesLayerD3D9::RenderLayer()
|
|||||||
mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||||
tmpTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
|
tmpTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
|
||||||
|
|
||||||
POINT point;
|
nsIntRegionRectIterator iter(region);
|
||||||
point.x = mInvalidatedRect.x - visibleRect.x;
|
const nsIntRect *iterRect;
|
||||||
point.y = mInvalidatedRect.y - visibleRect.y;
|
while ((iterRect = iter.Next())) {
|
||||||
device()->UpdateSurface(srcSurface, NULL, dstSurface, &point);
|
RECT rect;
|
||||||
|
rect.left = iterRect->x - bounds.x;
|
||||||
|
rect.top = iterRect->y - bounds.y;
|
||||||
|
rect.right = rect.left + iterRect->width;
|
||||||
|
rect.bottom = rect.top + iterRect->height;
|
||||||
|
POINT point;
|
||||||
|
point.x = iterRect->x - visibleRect.x;
|
||||||
|
point.y = iterRect->y - visibleRect.y;
|
||||||
|
device()->UpdateSurface(srcSurface, &rect, dstSurface, &point);
|
||||||
|
}
|
||||||
|
mValidRegion = mVisibleRegion;
|
||||||
}
|
}
|
||||||
|
|
||||||
float quadTransform[4][4];
|
float quadTransform[4][4];
|
||||||
@ -183,12 +267,6 @@ ThebesLayerD3D9::CleanResources()
|
|||||||
mTexture = nsnull;
|
mTexture = nsnull;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nsIntRect&
|
|
||||||
ThebesLayerD3D9::GetInvalidatedRect()
|
|
||||||
{
|
|
||||||
return mInvalidatedRect;
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer*
|
Layer*
|
||||||
ThebesLayerD3D9::GetLayer()
|
ThebesLayerD3D9::GetLayer()
|
||||||
{
|
{
|
||||||
|
@ -65,16 +65,7 @@ public:
|
|||||||
virtual void RenderLayer();
|
virtual void RenderLayer();
|
||||||
virtual void CleanResources();
|
virtual void CleanResources();
|
||||||
|
|
||||||
/* ThebesLayerD3D9 */
|
|
||||||
nsIntRect GetVisibleRect() { return mVisibleRegion.GetBounds(); }
|
|
||||||
const nsIntRect &GetInvalidatedRect();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
|
||||||
* Currently invalidated rectangular area.
|
|
||||||
*/
|
|
||||||
nsIntRect mInvalidatedRect;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* D3D9 texture
|
* D3D9 texture
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user