diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 4767b6a7aad1..cece3f5427dd 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -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 frontBuffer = + BasicManager()->OpenDescriptor(mNewFrontBuffer); + nsRefPtr backBuffer = + BasicManager()->OpenDescriptor(mBackBuffer); + + nsRefPtr 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 newFrontBuffer = + BasicManager()->OpenDescriptor(aNewFront.buffer()); + + nsRefPtr 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, diff --git a/gfx/layers/ipc/PLayers.ipdl b/gfx/layers/ipc/PLayers.ipdl index 1c35025a05d9..8aaead7230ad 100644 --- a/gfx/layers/ipc/PLayers.ipdl +++ b/gfx/layers/ipc/PLayers.ipdl @@ -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; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index e1c324f06951..503988679c8b 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -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 diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index 86a75b3c2032..38aefd8533a0 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -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"); diff --git a/gfx/layers/ipc/ShadowLayersParent.cpp b/gfx/layers/ipc/ShadowLayersParent.cpp index 409cb379b85e..6917ebf90c45 100644 --- a/gfx/layers/ipc/ShadowLayersParent.cpp +++ b/gfx/layers/ipc/ShadowLayersParent.cpp @@ -195,12 +195,8 @@ ShadowLayersParent::RecvUpdate(const nsTArray& cset, ShadowThebesLayer* thebes = static_cast( 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; }