author | Chris Jones <jones.chris.g@gmail.com> |
Tue, 14 Sep 2010 00:23:08 -0500 | |
changeset 54101 | 5004f6392fb29c0a3a3a54d4b2ffc7ac5bbec4bf |
parent 54100 | 324632361f18ce038234184757d878b5fe21f550 |
child 54102 | fdb0145ee11701331295c7e115a8e15b21bb6f8f |
push id | 15768 |
push user | dougt@mozilla.com |
push date | Thu, 16 Sep 2010 01:40:23 +0000 |
treeherder | mozilla-central@cdb90b48f19f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc, shaver |
bugs | 570625 |
milestone | 2.0b6pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/ThebesLayerBuffer.h +++ b/gfx/layers/ThebesLayerBuffer.h @@ -150,16 +150,28 @@ protected: TOP, BOTTOM }; nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide); void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide, float aOpacity, float aXRes, float aYRes); 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; } already_AddRefed<gfxASurface> SetBuffer(gfxASurface* aBuffer, const nsIntSize& aBufferDims, const nsIntRect& aBufferRect, const nsIntPoint& aBufferRotation) { nsRefPtr<gfxASurface> tmp = mBuffer.forget();
--- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -256,16 +256,32 @@ public: * to aTarget. */ void DrawTo(ThebesLayer* aLayer, PRBool aIsOpaqueContent, gfxContext* aTarget, float aOpacity); 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; }; class BasicThebesLayer : public ThebesLayer, BasicImplData { public: typedef BasicThebesLayerBuffer Buffer; @@ -1338,16 +1354,17 @@ public: } virtual Layer* AsLayer() { return this; } virtual ShadowableLayer* AsShadowableLayer() { return this; } virtual void SetBackBuffer(gfxSharedImageSurface* aBuffer) { mBackBuffer = aBuffer; + mBuffer.SetBackingBuffer(aBuffer); } virtual void Disconnect() { mBackBuffer = nsnull; BasicShadowableLayer::Disconnect(); } @@ -1362,16 +1379,18 @@ private: const nsIntRegion& aRegionToDraw, const nsIntRegion& aRegionToInvalidate, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData); 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; }; void BasicShadowableThebesLayer::PaintBuffer(gfxContext* aContext, const nsIntRegion& aRegionToDraw, const nsIntRegion& aRegionToInvalidate, @@ -1379,57 +1398,56 @@ BasicShadowableThebesLayer::PaintBuffer( void* aCallbackData) { Base::PaintBuffer(aContext, aRegionToDraw, aRegionToInvalidate, aCallback, aCallbackData); 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(), mBackBuffer); } } already_AddRefed<gfxASurface> BasicShadowableThebesLayer::CreateBuffer(Buffer::ContentType aType, const nsIntSize& aSize) { - if (HasShadow()) { - if (mBackBuffer) { - BasicManager()->ShadowLayerForwarder::DestroySharedSurface(mBackBuffer); - mBackBuffer = nsnull; + if (!HasShadow()) { + return BasicThebesLayer::CreateBuffer(aType, aSize); + } - BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this)); - } + if (mBackBuffer) { + BasicManager()->DestroyedThebesBuffer(BasicManager()->Hold(this), + mBackBuffer); + mBackBuffer = nsnull; + } - 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; + 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 Base::CreateBuffer(aType, 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(); } class BasicShadowableImageLayer : public BasicImageLayer, public BasicShadowableLayer { public: BasicShadowableImageLayer(BasicShadowLayerManager* aManager) : @@ -1666,16 +1684,25 @@ public: already_AddRefed<gfxSharedImageSurface> Swap(gfxSharedImageSurface* aNewFrontBuffer, const nsIntSize& aBufferDims, const nsIntRect& aBufferRect, const nsIntPoint& aRotation=nsIntPoint(0, 0)) { 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()); } protected: virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType, const nsIntSize& aSize) { NS_RUNTIMEABORT("ShadowThebesLayer can't paint content"); @@ -1712,17 +1739,17 @@ public: gfxIntSize size = aNewFront->GetSize(); return mFrontBuffer.Swap(aNewFront, nsIntSize(size.width, size.height), aBufferRect, aRotation); } virtual void DestroyFrontBuffer() { nsRefPtr<gfxSharedImageSurface> frontBuffer = - mFrontBuffer.Swap(0, nsIntSize(), nsIntRect()); + mFrontBuffer.Swap(nsnull, nsIntSize(), nsIntRect()); if (frontBuffer) { BasicManager()->ShadowLayerManager::DestroySharedSurface(frontBuffer); } } virtual void Paint(gfxContext* aContext, LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData,
--- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -47,16 +47,17 @@ #include "mozilla/layers/PLayersChild.h" #include "mozilla/layers/PLayersParent.h" #include "ShadowLayers.h" #include "ShadowLayerChild.h" namespace mozilla { namespace layers { +typedef nsTArray<nsRefPtr<gfxSharedImageSurface> > BufferArray; typedef std::vector<Edit> EditVector; typedef std::set<ShadowableLayer*> ShadowableLayerSet; class Transaction { public: Transaction() : mOpen(PR_FALSE) {} @@ -67,28 +68,35 @@ public: NS_ABORT_IF_FALSE(!Finished(), "forgot BeginTransaction?"); mCset.push_back(aEdit); } void AddMutant(ShadowableLayer* aLayer) { 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; } PRBool Empty() const { return mCset.empty() && mMutants.empty(); } PRBool Finished() const { return !mOpen && Empty(); } EditVector mCset; + BufferArray mDyingBuffers; ShadowableLayerSet mMutants; private: PRBool mOpen; // disabled Transaction(const Transaction&); Transaction& operator=(const Transaction&); @@ -183,19 +191,21 @@ ShadowLayerForwarder::CreatedCanvasBuffe gfxSharedImageSurface* aTempFrontSurface) { mTxn->AddEdit(OpCreateCanvasBuffer(NULL, Shadow(aCanvas), aSize, aTempFrontSurface->GetShmem())); } void -ShadowLayerForwarder::DestroyedThebesBuffer(ShadowableLayer* aThebes) +ShadowLayerForwarder::DestroyedThebesBuffer(ShadowableLayer* aThebes, + gfxSharedImageSurface* aBackBufferToDestroy) { mTxn->AddEdit(OpDestroyThebesFrontBuffer(NULL, Shadow(aThebes))); + mTxn->AddBufferToDestroy(aBackBufferToDestroy); } void ShadowLayerForwarder::DestroyedImageBuffer(ShadowableLayer* aImage) { mTxn->AddEdit(OpDestroyImageFrontBuffer(NULL, Shadow(aImage))); } @@ -272,16 +282,22 @@ ShadowLayerForwarder::EndTransaction(nsT AutoTxnEnd _(mTxn); if (mTxn->Empty()) { MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?), skipping Update()")); 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(); it != mTxn->mMutants.end(); ++it) { ShadowableLayer* shadow = *it; Layer* mutant = shadow->AsLayer(); NS_ABORT_IF_FALSE(!!mutant, "unshadowable layer?");
--- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -156,21 +156,25 @@ public: void CreatedImageBuffer(ShadowableLayer* aImage, nsIntSize aSize, gfxSharedImageSurface* aInitialFrontSurface); void CreatedCanvasBuffer(ShadowableLayer* aCanvas, nsIntSize aSize, 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); /** * At least one attribute of |aMutant| has changed, and |aMutant| * needs to sync to its shadow layer. This initial implementation * forwards all attributes when any is mutated.