Bug 599359, part 2: When we allocate a new front/back buffer pair, pre-fill the new front buffer with what we painted into the back buffer to stabilize the first Swap(). r=vlad a=blocking-fennec

This commit is contained in:
Chris Jones 2010-09-28 17:05:30 -05:00
parent 6bee72a35f
commit 374601de26
5 changed files with 99 additions and 26 deletions

View File

@ -1432,6 +1432,10 @@ private:
// copy of the descriptor here so that we can call
// DestroySharedSurface() on the descriptor.
SurfaceDescriptor mBackBuffer;
// When we allocate a new front buffer, we keep a temporary record
// of it until reach PaintBuffer(). Then we pre-fill back->front
// and destroy our record.
SurfaceDescriptor mNewFrontBuffer;
nsIntSize mBufferSize;
};
@ -1449,8 +1453,39 @@ BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext,
NS_ABORT_IF_FALSE(IsSurfaceDescriptorValid(mBackBuffer),
"should have a back buffer by now");
nsIntRegion updatedRegion = aRegionToDraw;
if (IsSurfaceDescriptorValid(mNewFrontBuffer)) {
// We just allocated a new buffer pair. We want to "pre-fill"
// the new front buffer by copying to it what we just painted
// into the back buffer. This starts off our Swap()s from a
// stable base: the first swap will return the same valid region
// as our new back buffer. Thereafter, we only need to
// invalidate what was painted into the back buffer.
nsRefPtr<gfxASurface> frontBuffer =
BasicManager()->OpenDescriptor(mNewFrontBuffer);
nsRefPtr<gfxASurface> backBuffer =
BasicManager()->OpenDescriptor(mBackBuffer);
nsRefPtr<gfxContext> ctx = new gfxContext(frontBuffer);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->DrawSurface(backBuffer, backBuffer->GetSize());
BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
mValidRegion,
mXResolution,
mYResolution,
mBuffer.BufferRect(),
mNewFrontBuffer);
// Clear temporary record of new front buffer
mNewFrontBuffer = SurfaceDescriptor();
// And pretend that we didn't update anything, in order to
// stabilize the first swap.
updatedRegion.SetEmpty();
}
BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this),
aRegionToDraw,
updatedRegion,
mBuffer.BufferRect(),
mBuffer.BufferRotation(),
mBackBuffer);
@ -1471,19 +1506,15 @@ BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType,
mBackBuffer = SurfaceDescriptor();
}
SurfaceDescriptor tmpFront;
// XXX error handling
NS_ABORT_IF_FALSE(!IsSurfaceDescriptorValid(mNewFrontBuffer),
"Bad! Did we create a buffer twice without painting?");
if (!BasicManager()->AllocDoubleBuffer(gfxIntSize(aSize.width, aSize.height),
aType,
&tmpFront,
&mNewFrontBuffer,
&mBackBuffer))
NS_RUNTIMEABORT("creating ThebesLayer 'back buffer' failed!");
mBufferSize = aSize;
nsIntRect bufRect = mVisibleRegion.GetBounds();
BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
bufRect,
tmpFront);
return BasicManager()->OpenDescriptor(mBackBuffer);
}
@ -1769,6 +1800,10 @@ public:
MOZ_COUNT_DTOR(BasicShadowThebesLayer);
}
virtual void SetFrontBuffer(const ThebesBuffer& aNewFront,
const nsIntRegion& aValidRegion,
float aXResolution, float aYResolution);
virtual void SetValidRegion(const nsIntRegion& aRegion)
{
mOldValidRegion = mValidRegion;
@ -1829,6 +1864,25 @@ private:
float mOldYResolution;
};
void
BasicShadowThebesLayer::SetFrontBuffer(const ThebesBuffer& aNewFront,
const nsIntRegion& aValidRegion,
float aXResolution, float aYResolution)
{
mValidRegion = mOldValidRegion = aValidRegion;
mXResolution = mOldXResolution = aXResolution;
mYResolution = mOldYResolution = aYResolution;
nsRefPtr<gfxASurface> newFrontBuffer =
BasicManager()->OpenDescriptor(aNewFront.buffer());
nsRefPtr<gfxASurface> unused;
nsIntRect unusedRect;
nsIntPoint unusedRotation;
mFrontBuffer.Swap(newFrontBuffer, aNewFront.rect(), aNewFront.rotation(),
getter_AddRefs(unused), &unusedRect, &unusedRotation);
mFrontBufferDescriptor = aNewFront.buffer();
}
void
BasicShadowThebesLayer::Swap(const ThebesBuffer& aNewFront,
const nsIntRegion& aUpdatedRegion,

View File

@ -82,10 +82,18 @@ union SurfaceDescriptor {
SurfaceDescriptorX11;
};
struct ThebesBuffer {
SurfaceDescriptor buffer;
nsIntRect rect;
nsIntPoint rotation;
};
struct OpCreateThebesBuffer {
PLayer layer;
nsIntRect bufferRect;
SurfaceDescriptor initialFront;
ThebesBuffer initialFront;
nsIntRegion frontValidRegion;
float xResolution;
float yResolution;
};
struct OpDestroyThebesFrontBuffer { PLayer layer; };
@ -152,11 +160,6 @@ struct OpRemoveChild { PLayer container; PLayer childLayer; };
// Paint (buffer update)
struct ThebesBuffer {
SurfaceDescriptor buffer;
nsIntRect rect;
nsIntPoint rotation;
};
struct OpPaintThebesBuffer {
PLayer layer;
ThebesBuffer newFrontBuffer;

View File

@ -183,12 +183,19 @@ ShadowLayerForwarder::CreatedCanvasLayer(ShadowableLayer* aCanvas)
void
ShadowLayerForwarder::CreatedThebesBuffer(ShadowableLayer* aThebes,
nsIntRect aBufferRect,
const nsIntRegion& aFrontValidRegion,
float aXResolution,
float aYResolution,
const nsIntRect& aBufferRect,
const SurfaceDescriptor& aTempFrontBuffer)
{
mTxn->AddEdit(OpCreateThebesBuffer(NULL, Shadow(aThebes),
aBufferRect,
aTempFrontBuffer));
ThebesBuffer(aTempFrontBuffer,
aBufferRect,
nsIntPoint(0, 0)),
aFrontValidRegion,
aXResolution,
aYResolution));
}
void

View File

@ -143,13 +143,16 @@ public:
*
* It is expected that Created*Buffer() will be followed by a
* Painted*Buffer() in the same transaction, so that
* |aInitialFrontBuffer| is never actually drawn to screen.
* |aInitialFrontBuffer| is never actually drawn to screen. It is
* OK if it is drawn though.
*/
/**
* |aBufferRect| is the screen rect covered by |aInitialFrontBuffer|.
*/
void CreatedThebesBuffer(ShadowableLayer* aThebes,
nsIntRect aBufferRect,
const nsIntRegion& aFrontValidRegion,
float aXResolution, float aYResolution,
const nsIntRect& aBufferRect,
const SurfaceDescriptor& aInitialFrontBuffer);
/**
* For the next two methods, |aSize| is the size of
@ -394,6 +397,16 @@ public:
mAllocator = aParent;
}
/**
* CONSTRUCTION PHASE ONLY
*
* Override the front buffer and its valid region with the specified
* values. This is called when a new buffer has been created.
*/
virtual void SetFrontBuffer(const ThebesBuffer& aNewFront,
const nsIntRegion& aValidRegion,
float aXResolution, float aYResolution) = 0;
virtual void InvalidateRegion(const nsIntRegion& aRegion)
{
NS_RUNTIMEABORT("ShadowThebesLayers can't fill invalidated regions");

View File

@ -195,12 +195,8 @@ ShadowLayersParent::RecvUpdate(const nsTArray<Edit>& cset,
ShadowThebesLayer* thebes = static_cast<ShadowThebesLayer*>(
AsShadowLayer(otb)->AsLayer());
ThebesBuffer unusedBuffer;
nsIntRegion unusedRegion; float unusedXRes, unusedYRes;
thebes->Swap(
ThebesBuffer(otb.initialFront(), otb.bufferRect(), nsIntPoint(0, 0)),
unusedRegion,
&unusedBuffer, &unusedRegion, &unusedXRes, &unusedYRes);
thebes->SetFrontBuffer(otb.initialFront(), otb.frontValidRegion(),
otb.xResolution(), otb.yResolution());
break;
}