зеркало из https://github.com/mozilla/gecko-dev.git
Bug 574239: Have ThebesLayerD3D9 retain its content even across changes to the visible region. r=jrmuizel
This commit is contained in:
Родитель
b12eec77e4
Коммит
b94e5f575a
|
@ -54,6 +54,12 @@ ThebesLayerD3D9::~ThebesLayerD3D9()
|
|||
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
|
||||
ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
|
||||
|
@ -61,55 +67,123 @@ ThebesLayerD3D9::SetVisibleRegion(const nsIntRegion &aRegion)
|
|||
if (aRegion.IsEqual(mVisibleRegion)) {
|
||||
return;
|
||||
}
|
||||
nsIntRegion oldVisibleRegion = mVisibleRegion;
|
||||
nsRefPtr<IDirect3DTexture9> oldTexture = mTexture;
|
||||
|
||||
ThebesLayer::SetVisibleRegion(aRegion);
|
||||
|
||||
mInvalidatedRect = mVisibleRegion.GetBounds();
|
||||
device()->CreateTexture(mInvalidatedRect.width, mInvalidatedRect.height, 1,
|
||||
nsIntRect oldBounds = oldVisibleRegion.GetBounds();
|
||||
nsIntRect newBounds = mVisibleRegion.GetBounds();
|
||||
|
||||
device()->CreateTexture(newBounds.width, newBounds.height, 1,
|
||||
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
||||
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
|
||||
ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion)
|
||||
{
|
||||
nsIntRegion invalidatedRegion;
|
||||
invalidatedRegion.Or(aRegion, mInvalidatedRect);
|
||||
invalidatedRegion.And(invalidatedRegion, mVisibleRegion);
|
||||
mInvalidatedRect = invalidatedRegion.GetBounds();
|
||||
mValidRegion.Sub(mValidRegion, aRegion);
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerD3D9::RenderLayer()
|
||||
{
|
||||
if (mVisibleRegion.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
nsIntRect visibleRect = mVisibleRegion.GetBounds();
|
||||
|
||||
if (!mTexture) {
|
||||
device()->CreateTexture(visibleRect.width, visibleRect.height, 1,
|
||||
D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
|
||||
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;;
|
||||
nsRefPtr<gfxASurface> destinationSurface;
|
||||
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 =
|
||||
gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenSurface(gfxIntSize(mInvalidatedRect.width,
|
||||
mInvalidatedRect.height),
|
||||
CreateOffscreenSurface(gfxIntSize(bounds.width,
|
||||
bounds.height),
|
||||
imageFormat);
|
||||
|
||||
context = new gfxContext(destinationSurface);
|
||||
context->Translate(gfxPoint(-mInvalidatedRect.x, -mInvalidatedRect.y));
|
||||
context->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||
cbInfo.Callback(this, context, region, nsIntRegion(), cbInfo.CallbackData);
|
||||
|
||||
nsRefPtr<IDirect3DTexture9> tmpTexture;
|
||||
device()->CreateTexture(mInvalidatedRect.width, mInvalidatedRect.height, 1,
|
||||
device()->CreateTexture(bounds.width, bounds.height, 1,
|
||||
0, D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_SYSTEMMEM, getter_AddRefs(tmpTexture), NULL);
|
||||
|
||||
|
@ -118,8 +192,8 @@ ThebesLayerD3D9::RenderLayer()
|
|||
|
||||
nsRefPtr<gfxImageSurface> imgSurface =
|
||||
new gfxImageSurface((unsigned char *)r.pBits,
|
||||
gfxIntSize(mInvalidatedRect.width,
|
||||
mInvalidatedRect.height),
|
||||
gfxIntSize(bounds.width,
|
||||
bounds.height),
|
||||
r.Pitch,
|
||||
imageFormat);
|
||||
|
||||
|
@ -138,10 +212,20 @@ ThebesLayerD3D9::RenderLayer()
|
|||
mTexture->GetSurfaceLevel(0, getter_AddRefs(dstSurface));
|
||||
tmpTexture->GetSurfaceLevel(0, getter_AddRefs(srcSurface));
|
||||
|
||||
POINT point;
|
||||
point.x = mInvalidatedRect.x - visibleRect.x;
|
||||
point.y = mInvalidatedRect.y - visibleRect.y;
|
||||
device()->UpdateSurface(srcSurface, NULL, dstSurface, &point);
|
||||
nsIntRegionRectIterator iter(region);
|
||||
const nsIntRect *iterRect;
|
||||
while ((iterRect = iter.Next())) {
|
||||
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];
|
||||
|
@ -183,12 +267,6 @@ ThebesLayerD3D9::CleanResources()
|
|||
mTexture = nsnull;
|
||||
}
|
||||
|
||||
const nsIntRect&
|
||||
ThebesLayerD3D9::GetInvalidatedRect()
|
||||
{
|
||||
return mInvalidatedRect;
|
||||
}
|
||||
|
||||
Layer*
|
||||
ThebesLayerD3D9::GetLayer()
|
||||
{
|
||||
|
|
|
@ -65,16 +65,7 @@ public:
|
|||
virtual void RenderLayer();
|
||||
virtual void CleanResources();
|
||||
|
||||
/* ThebesLayerD3D9 */
|
||||
nsIntRect GetVisibleRect() { return mVisibleRegion.GetBounds(); }
|
||||
const nsIntRect &GetInvalidatedRect();
|
||||
|
||||
private:
|
||||
/*
|
||||
* Currently invalidated rectangular area.
|
||||
*/
|
||||
nsIntRect mInvalidatedRect;
|
||||
|
||||
/*
|
||||
* D3D9 texture
|
||||
*/
|
||||
|
|
Загрузка…
Ссылка в новой задаче