Bug 570625, part 1: Only use back/front buffers for BasicThebesLayer and update back->front in the compositor process. r=roc sr=shaver

This commit is contained in:
Chris Jones 2010-09-14 00:23:08 -05:00
parent f5894e967e
commit 7e002c08ab
4 changed files with 94 additions and 35 deletions

View File

@ -155,6 +155,18 @@ protected:
void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
float aXRes, float aYRes);
/**
* |BufferRect()| is the rect of device pixels that this
* ThebesLayerBuffer covers. That is what DrawBufferWithRotation()
* will paint when it's called.
*
* |BufferDims()| is the actual dimensions of the underlying surface
* maintained by this, also in device pixels. It is *not*
* necessarily true that |BufferRect().Size() == BufferDims()|.
* They may differ if a ThebesLayer is drawn at a non-1.0
* resolution.
*/
const nsIntSize& BufferDims() const { return mBufferDims; }
const nsIntRect& BufferRect() const { return mBufferRect; }
const nsIntPoint& BufferRotation() const { return mBufferRotation; }

View File

@ -261,6 +261,22 @@ public:
virtual already_AddRefed<gfxASurface>
CreateBuffer(ContentType aType, const nsIntSize& aSize);
/**
* Swap out the old backing buffer for |aBuffer|.
*
* CAVEAT EMPTOR: |aBuffer| must have the same dimensions and pixels
* as the previous buffer. If not, rendering glitches will occur.
* This is a rather dangerous and low-level interface added in bug
* 570625 as an intermediate step to a better interface.
*/
void SetBackingBuffer(gfxASurface* aBuffer)
{
gfxIntSize prevSize = gfxIntSize(BufferDims().width, BufferDims().height);
NS_ABORT_IF_FALSE(aBuffer->GetSize() == prevSize,
"Swapped-in buffer size doesn't match old buffer's!");
SetBuffer(aBuffer, BufferDims(), BufferRect(), BufferRotation());
}
private:
BasicThebesLayer* mLayer;
};
@ -1343,6 +1359,7 @@ public:
virtual void SetBackBuffer(gfxSharedImageSurface* aBuffer)
{
mBackBuffer = aBuffer;
mBuffer.SetBackingBuffer(aBuffer);
}
virtual void Disconnect()
@ -1367,6 +1384,8 @@ private:
NS_OVERRIDE virtual already_AddRefed<gfxASurface>
CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize);
// We give a ref to this buffer to our ThebesLayerBuffer, and keep
// this ref here that we can destroy its underlying shmem segment.
nsRefPtr<gfxSharedImageSurface> mBackBuffer;
nsIntSize mBufferSize;
};
@ -1384,11 +1403,6 @@ BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext,
if (HasShadow()) {
NS_ABORT_IF_FALSE(!!mBackBuffer, "should have a back buffer by now");
nsRefPtr<gfxContext> tmpCtx = new gfxContext(mBackBuffer);
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->DrawSurface(aContext->OriginalSurface(),
gfxIntSize(mBufferSize.width, mBufferSize.height));
BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this),
mBuffer.BufferRect(),
mBuffer.BufferRotation(),
@ -1400,31 +1414,35 @@ already_AddRefed<gfxASurface>
BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType,
const nsIntSize& aSize)
{
if (HasShadow()) {
if (mBackBuffer) {
BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer);
mBackBuffer = nsnull;
BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this));
}
nsRefPtr<gfxSharedImageSurface> tmpFront;
// XXX error handling
if (!BasicManager()->AllocDoubleBuffer(gfxIntSize(aSize.width, aSize.height),
gfxASurface::ImageFormatARGB32,
getter_AddRefs(tmpFront),
getter_AddRefs(mBackBuffer)))
NS_RUNTIMEABORT("creating ThebesLayer 'back buffer' failed!");
mBufferSize = aSize;
BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
// only |aSize| really matters
// here, since Painted() soon
// follows
nsIntRect(nsIntPoint(0, 0), aSize),
tmpFront);
if (!HasShadow()) {
return BasicThebesLayer::CreateBuffer(aType, aSize);
}
return Base::CreateBuffer(aType, aSize);
if (mBackBuffer) {
BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this),
mBackBuffer);
mBackBuffer = nsnull;
}
gfxASurface::gfxImageFormat format = (aType == gfxASurface::CONTENT_COLOR) ?
gfxASurface::ImageFormatRGB24 :
gfxASurface::ImageFormatARGB32;
nsRefPtr<gfxSharedImageSurface> tmpFront;
// XXX error handling
if (!BasicManager()->AllocDoubleBuffer(gfxIntSize(aSize.width, aSize.height),
format,
getter_AddRefs(tmpFront),
getter_AddRefs(mBackBuffer)))
NS_RUNTIMEABORT("creating ThebesLayer 'back buffer' failed!");
mBufferSize = aSize;
BasicManager()->CreatedThebesBuffer(BasicManager()->Hold(this),
// only |aSize| really matters
// here, since Painted() soon
// follows
nsIntRect(nsIntPoint(0, 0), aSize),
tmpFront);
return nsRefPtr<gfxASurface>(mBackBuffer).forget();
}
@ -1671,6 +1689,15 @@ public:
nsRefPtr<gfxASurface> newBackBuffer = SetBuffer(aNewFrontBuffer,
aBufferDims,
aBufferRect, aRotation);
if (newBackBuffer && aNewFrontBuffer) {
// Copy the new pixels in the new front buffer to our previous
// front buffer. This is intended to be optimized! Many
// factors are involved.
nsRefPtr<gfxContext> tmpCtx = new gfxContext(newBackBuffer);
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->DrawSurface(aNewFrontBuffer,
gfxIntSize(aBufferDims.width, aBufferDims.height));
}
return static_cast<gfxSharedImageSurface*>(newBackBuffer.forget().get());
}
@ -1717,7 +1744,7 @@ public:
virtual void DestroyFrontBuffer()
{
nsRefPtr<gfxSharedImageSurface> frontBuffer =
mFrontBuffer.Swap(0, nsIntSize(), nsIntRect());
mFrontBuffer.Swap(nsnull, nsIntSize(), nsIntRect());
if (frontBuffer) {
BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer);
}

View File

@ -52,6 +52,7 @@
namespace mozilla {
namespace layers {
typedef nsTArray<nsRefPtr<gfxSharedImageSurface> > BufferArray;
typedef std::vector<Edit> EditVector;
typedef std::set<ShadowableLayer*> ShadowableLayerSet;
@ -72,10 +73,16 @@ public:
NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
mMutants.insert(aLayer);
}
void AddBufferToDestroy(gfxSharedImageSurface* aBuffer)
{
NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?");
mDyingBuffers.AppendElement(aBuffer);
}
void End()
{
mCset.clear();
mDyingBuffers.Clear();
mMutants.clear();
mOpen = PR_FALSE;
}
@ -84,6 +91,7 @@ public:
PRBool Finished() const { return !mOpen && Empty(); }
EditVector mCset;
BufferArray mDyingBuffers;
ShadowableLayerSet mMutants;
private:
@ -188,9 +196,11 @@ ShadowLayerForwarder::CreatedCanvasBuffer(ShadowableLayer* aCanvas,
}
void
ShadowLayerForwarder::DestroyedThebesBuffer(ShadowableLayer* aThebes)
ShadowLayerForwarder::DestroyedThebesBuffer(ShadowableLayer* aThebes,
gfxSharedImageSurface* aBackBufferToDestroy)
{
mTxn->AddEdit(OpDestroyThebesFrontBuffer(NULL, Shadow(aThebes)));
mTxn->AddBufferToDestroy(aBackBufferToDestroy);
}
void
@ -277,6 +287,12 @@ ShadowLayerForwarder::EndTransaction(nsTArray<EditReply>* aReplies)
return PR_TRUE;
}
MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));
for (PRUint32 i = 0; i < mTxn->mDyingBuffers.Length(); ++i) {
DestroySharedSurface(mTxn->mDyingBuffers[i]);
}
MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
for (ShadowableLayerSet::const_iterator it = mTxn->mMutants.begin();

View File

@ -161,11 +161,15 @@ public:
gfxSharedImageSurface* aInitialFrontSurface);
/**
* The specified layer should destroy its front buffer. This can
* happen when a new front/back buffer pair have been created
* because of a layer resize, e.g.
* The specified layer is destroying its buffers.
* |aBackBufferToDestroy| is deallocated when this transaction is
* posted to the parent. During the parent-side transaction, the
* shadow is told to destroy its front buffer. This can happen when
* a new front/back buffer pair have been created because of a layer
* resize, e.g.
*/
void DestroyedThebesBuffer(ShadowableLayer* aThebes);
void DestroyedThebesBuffer(ShadowableLayer* aThebes,
gfxSharedImageSurface* aBackBufferToDestroy);
void DestroyedImageBuffer(ShadowableLayer* aImage);
void DestroyedCanvasBuffer(ShadowableLayer* aCanvas);