Bug 570625, part 9: When updating thebes layers, swap out back/front buffers and invalidate the newly-painted region on the old front buffer. r=roc sr=shaver

This commit is contained in:
Chris Jones
2010-09-14 00:23:08 -05:00
parent 4595086453
commit 05706ca8f1
5 changed files with 133 additions and 90 deletions

View File

@@ -262,19 +262,17 @@ public:
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.
* Swap out the old backing buffer for |aBuffer| and attributes.
*/
void SetBackingBuffer(gfxASurface* aBuffer)
void SetBackingBuffer(gfxASurface* aBuffer,
const nsIntRect& aRect, const nsIntPoint& aRotation)
{
gfxIntSize prevSize = gfxIntSize(BufferDims().width, BufferDims().height);
NS_ABORT_IF_FALSE(aBuffer->GetSize() == prevSize,
gfxIntSize newSize = aBuffer->GetSize();
NS_ABORT_IF_FALSE(newSize == prevSize,
"Swapped-in buffer size doesn't match old buffer's!");
SetBuffer(aBuffer, BufferDims(), BufferRect(), BufferRotation());
SetBuffer(aBuffer,
nsIntSize(newSize.width, newSize.height), aRect, aRotation);
}
private:
@@ -1220,6 +1218,7 @@ BasicLayerManager::CreateCanvasLayer()
#ifdef MOZ_IPC
class BasicShadowableThebesLayer;
class BasicShadowableLayer : public ShadowableLayer
{
public:
@@ -1262,6 +1261,8 @@ public:
// shutdown anyway).
mShadow = nsnull;
}
virtual BasicShadowableThebesLayer* AsThebes() { return nsnull; }
};
static ShadowableLayer*
@@ -1370,11 +1371,17 @@ public:
virtual PRBool SupportsSurfaceDescriptor() const { return PR_TRUE; }
virtual void SetBackBuffer(const SurfaceDescriptor& aBuffer)
void SetBackBufferAndAttrs(const ThebesBuffer& aBuffer,
const nsIntRegion& aValidRegion,
float aXResolution, float aYResolution)
{
mBackBuffer = aBuffer;
mBackBuffer = aBuffer.buffer();
mValidRegion = aValidRegion;
mXResolution = aXResolution;
mYResolution = aYResolution;
nsRefPtr<gfxASurface> backBuffer = BasicManager()->OpenDescriptor(mBackBuffer);
mBuffer.SetBackingBuffer(backBuffer);
mBuffer.SetBackingBuffer(backBuffer, aBuffer.rect(), aBuffer.rotation());
}
virtual void Disconnect()
@@ -1383,6 +1390,8 @@ public:
BasicShadowableLayer::Disconnect();
}
virtual BasicShadowableThebesLayer* AsThebes() { return this; }
private:
BasicShadowLayerManager* BasicManager()
{
@@ -1421,6 +1430,7 @@ BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext,
"should have a back buffer by now");
BasicManager()->PaintedThebesBuffer(BasicManager()->Hold(this),
aRegionToDraw,
mBuffer.BufferRect(),
mBuffer.BufferRotation(),
mBackBuffer);
@@ -1695,24 +1705,20 @@ public:
MOZ_COUNT_DTOR(ShadowThebesLayerBuffer);
}
already_AddRefed<gfxASurface>
Swap(gfxASurface* aNewFrontBuffer, const nsIntSize& aBufferDims,
const nsIntRect& aBufferRect,
const nsIntPoint& aRotation=nsIntPoint(0, 0))
void Swap(gfxASurface* aNewBuffer,
const nsIntRect& aNewRect, const nsIntPoint& aNewRotation,
gfxASurface** aOldBuffer,
nsIntRect* aOldRect, nsIntPoint* aOldRotation)
{
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 newBackBuffer.forget();
*aOldRect = BufferRect();
*aOldRotation = BufferRotation();
gfxIntSize newSize = aNewBuffer->GetSize();
nsRefPtr<gfxASurface> oldBuffer;
oldBuffer = SetBuffer(aNewBuffer,
nsIntSize(newSize.width, newSize.height),
aNewRect, aNewRotation);
oldBuffer.forget(aOldBuffer);
}
protected:
@@ -1724,10 +1730,13 @@ protected:
}
};
class BasicShadowThebesLayer : public ShadowThebesLayer, BasicImplData {
public:
BasicShadowThebesLayer(BasicShadowLayerManager* aLayerManager) :
ShadowThebesLayer(aLayerManager, static_cast<BasicImplData*>(this))
BasicShadowThebesLayer(BasicShadowLayerManager* aLayerManager)
: ShadowThebesLayer(aLayerManager, static_cast<BasicImplData*>(this))
, mOldXResolution(1.0)
, mOldYResolution(1.0)
{
MOZ_COUNT_CTOR(BasicShadowThebesLayer);
}
@@ -1739,21 +1748,37 @@ public:
MOZ_COUNT_DTOR(BasicShadowThebesLayer);
}
virtual void SetValidRegion(const nsIntRegion& aRegion)
{
mOldValidRegion = mValidRegion;
ShadowThebesLayer::SetValidRegion(aRegion);
}
virtual void SetResolution(float aXResolution, float aYResolution)
{
mOldXResolution = mXResolution;
mOldYResolution = mYResolution;
ShadowThebesLayer::SetResolution(aXResolution, aYResolution);
}
virtual void Disconnect()
{
DestroyFrontBuffer();
ShadowThebesLayer::Disconnect();
}
virtual SurfaceDescriptor
Swap(const SurfaceDescriptor& aNewFront,
const nsIntRect& aBufferRect,
const nsIntPoint& aRotation);
virtual void
Swap(const ThebesBuffer& aNewFront, const nsIntRegion& aUpdatedRegion,
ThebesBuffer* aNewBack, nsIntRegion* aNewBackValidRegion,
float* aNewXResolution, float* aNewYResolution);
virtual void DestroyFrontBuffer()
{
nsRefPtr<gfxASurface> unused =
mFrontBuffer.Swap(nsnull, nsIntSize(), nsIntRect());
mFrontBuffer.Clear();
mOldValidRegion.SetEmpty();
mOldXResolution = 1.0;
mOldYResolution = 1.0;
if (IsSurfaceDescriptorValid(mFrontBufferDescriptor)) {
BasicManager()->ShadowLayerManager::DestroySharedSurface(&mFrontBufferDescriptor);
}
@@ -1773,24 +1798,38 @@ private:
ShadowThebesLayerBuffer mFrontBuffer;
// Describes the gfxASurface we hand out to |mFrontBuffer|.
SurfaceDescriptor mFrontBufferDescriptor;
// When we receive an update from our remote partner, we stow away
// our previous parameters that described our previous front buffer.
// Then when we Swap() back/front buffers, we can return these
// parameters to our partner (adjusted as needed).
nsIntRegion mOldValidRegion;
float mOldXResolution;
float mOldYResolution;
};
SurfaceDescriptor
BasicShadowThebesLayer::Swap(const SurfaceDescriptor& aNewFront,
const nsIntRect& aBufferRect,
const nsIntPoint& aRotation)
void
BasicShadowThebesLayer::Swap(const ThebesBuffer& aNewFront,
const nsIntRegion& aUpdatedRegion,
ThebesBuffer* aNewBack,
nsIntRegion* aNewBackValidRegion,
float* aNewXResolution, float* aNewYResolution)
{
SurfaceDescriptor newBackBuffer = mFrontBufferDescriptor;
aNewBack->buffer() = mFrontBufferDescriptor;
// We have to invalidate the pixels painted into the new buffer.
// They might overlap with our old pixels.
aNewBackValidRegion->Sub(mOldValidRegion, aUpdatedRegion);
*aNewXResolution = mOldXResolution;
*aNewYResolution = mOldYResolution;
nsRefPtr<gfxASurface> newFrontBuffer =
BasicManager()->OpenDescriptor(aNewFront);
gfxIntSize size = newFrontBuffer->GetSize();
BasicManager()->OpenDescriptor(aNewFront.buffer());
nsRefPtr<gfxASurface> unused =
mFrontBuffer.Swap(newFrontBuffer, nsIntSize(size.width, size.height),
aBufferRect, aRotation);
mFrontBufferDescriptor = aNewFront;
nsRefPtr<gfxASurface> unused;
mFrontBuffer.Swap(
newFrontBuffer, aNewFront.rect(), aNewFront.rotation(),
getter_AddRefs(unused), &aNewBack->rect(), &aNewBack->rotation());
return newBackBuffer;
mFrontBufferDescriptor = aNewFront.buffer();
}
void
@@ -2149,6 +2188,16 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
const EditReply& reply = replies[i];
switch (reply.type()) {
case EditReply::TOpThebesBufferSwap: {
MOZ_LAYERS_LOG(("[LayersForwarder] ThebesBufferSwap"));
const OpThebesBufferSwap& obs = reply.get_OpThebesBufferSwap();
BasicShadowableThebesLayer* thebes = GetBasicShadowable(obs)->AsThebes();
thebes->SetBackBufferAndAttrs(
obs.newBackBuffer(),
obs.newValidRegion(), obs.newXResolution(), obs.newYResolution());
break;
}
case EditReply::TOpBufferSwap: {
MOZ_LAYERS_LOG(("[LayersForwarder] BufferSwap"));