From 9bdf6932e48d78efe18fdf18d1e3d99cc05149c8 Mon Sep 17 00:00:00 2001 From: "Benoit Girard ext:(%2C%20Chris%20Lord%20%3Cchrislord.net%40gmail.com%3E)" Date: Mon, 19 Aug 2013 14:59:22 +0100 Subject: [PATCH] Bug 747811 - Make the tiles backend safe across processes. r=nrc,BenWa The tiles backend passes raw pointers to transfer tiled buffers between the main thread and the compositor. This patch changes that to use shared memory and tile descriptors instead, as well as changing the memory management slightly to facilitate that. --- gfx/layers/TiledLayerBuffer.h | 12 ++- gfx/layers/client/TextureClient.cpp | 15 ++-- gfx/layers/client/TextureClient.h | 3 +- gfx/layers/client/TiledContentClient.cpp | 73 ++++++++++----- gfx/layers/client/TiledContentClient.h | 46 ++++++++-- gfx/layers/composite/TiledContentHost.cpp | 28 ++---- gfx/layers/composite/TiledContentHost.h | 14 ++- gfx/layers/ipc/CompositableForwarder.h | 3 +- .../ipc/CompositableTransactionParent.cpp | 4 +- gfx/layers/ipc/ImageBridgeChild.h | 2 +- gfx/layers/ipc/LayerTransaction.ipdlh | 4 +- gfx/layers/ipc/LayersSurfaces.ipdlh | 21 +++++ gfx/layers/ipc/ShadowLayers.cpp | 6 +- gfx/layers/ipc/ShadowLayers.h | 4 +- gfx/thebes/gfxBaseSharedMemorySurface.h | 25 ++++++ gfx/thebes/gfxReusableSurfaceWrapper.cpp | 88 ++++++++++++------- gfx/thebes/gfxReusableSurfaceWrapper.h | 44 ++++++---- 17 files changed, 265 insertions(+), 127 deletions(-) diff --git a/gfx/layers/TiledLayerBuffer.h b/gfx/layers/TiledLayerBuffer.h index fb9f2cd780b7..486be2563803 100644 --- a/gfx/layers/TiledLayerBuffer.h +++ b/gfx/layers/TiledLayerBuffer.h @@ -184,6 +184,8 @@ private: }; class BasicTiledLayerBuffer; +class SurfaceDescriptorTiles; +class ISurfaceAllocator; // Shadow layers may implement this interface in order to be notified when a // tiled layer buffer is updated. @@ -192,11 +194,13 @@ class TiledLayerComposer public: /** * Update the current retained layer with the updated layer data. - * The BasicTiledLayerBuffer is expected to be in the ReadLock state - * prior to this being called. aTiledBuffer is copy constructed and - * is retained until it has been uploaded/copyed and unlocked. + * It is expected that the tiles described by aTiledDescriptor are all in the + * ReadLock state, so that the locks can be adopted when recreating a + * BasicTiledLayerBuffer locally. This lock will be retained until the buffer + * has completed uploading. */ - virtual void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* aTiledBuffer) = 0; + virtual void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator, + const SurfaceDescriptorTiles& aTiledDescriptor) = 0; /** * If some part of the buffer is being rendered at a lower precision, this diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 6ece7970c854..f689fee49bda 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -15,6 +15,7 @@ #include "BasicLayers.h" // for PaintContext #include "mozilla/layers/YCbCrImageDataSerializer.h" #include "gfxReusableSurfaceWrapper.h" +#include "gfxSharedImageSurface.h" #include "gfxPlatform.h" #include "mozilla/layers/ImageDataSerializer.h" #include "gfx2DGlue.h" @@ -462,9 +463,10 @@ DeprecatedTextureClientShmemYCbCr::EnsureAllocated(gfx::IntSize aSize, DeprecatedTextureClientTile::DeprecatedTextureClientTile(CompositableForwarder* aForwarder, - const TextureInfo& aTextureInfo) + const TextureInfo& aTextureInfo, + gfxReusableSurfaceWrapper* aSurface) : DeprecatedTextureClient(aForwarder, aTextureInfo) - , mSurface(nullptr) + , mSurface(aSurface) { mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED; } @@ -474,10 +476,11 @@ DeprecatedTextureClientTile::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gf { if (!mSurface || mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) { - gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(aSize.width, aSize.height), - gfxPlatform::GetPlatform()->OptimalFormatForContent(aType), - aType != gfxASurface::CONTENT_COLOR); - mSurface = new gfxReusableSurfaceWrapper(tmpTile); + nsRefPtr sharedImage = + gfxSharedImageSurface::CreateUnsafe(mForwarder, + gfxIntSize(aSize.width, aSize.height), + gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)); + mSurface = new gfxReusableSurfaceWrapper(mForwarder, sharedImage); mContentType = aType; } return true; diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index ccf781acbbc8..211b33c9120a 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -474,7 +474,8 @@ class DeprecatedTextureClientTile : public DeprecatedTextureClient public: DeprecatedTextureClientTile(const DeprecatedTextureClientTile& aOther); DeprecatedTextureClientTile(CompositableForwarder* aForwarder, - const TextureInfo& aTextureInfo); + const TextureInfo& aTextureInfo, + gfxReusableSurfaceWrapper* aSurface = nullptr); ~DeprecatedTextureClientTile(); virtual bool EnsureAllocated(gfx::IntSize aSize, diff --git a/gfx/layers/client/TiledContentClient.cpp b/gfx/layers/client/TiledContentClient.cpp index ef58d52beb1c..38942474f360 100644 --- a/gfx/layers/client/TiledContentClient.cpp +++ b/gfx/layers/client/TiledContentClient.cpp @@ -73,17 +73,16 @@ TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer, void TiledContentClient::LockCopyAndWrite(TiledBufferType aType) { - // Create a heap copy owned and released by the compositor. This is needed - // since we're sending this over an async message and content needs to be - // be able to modify the tiled buffer in the next transaction. - // TODO: Remove me once Bug 747811 lands. BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER ? &mLowPrecisionTiledBuffer : &mTiledBuffer; - BasicTiledLayerBuffer* heapCopy = new BasicTiledLayerBuffer(buffer->DeepCopy()); + // Take an extra ReadLock on behalf of the TiledContentHost. This extra + // reference will be adopted when the descriptor is opened by + // gfxReusableSurfaceWrapper::Open. buffer->ReadLock(); - mForwarder->PaintedTiledLayerBuffer(this, heapCopy); + + mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles()); buffer->ClearPaintedRegion(); } @@ -113,6 +112,53 @@ BasicTiledLayerBuffer::GetContentType() const } +BasicTileDescriptor +BasicTiledLayerTile::GetTileDescriptor() +{ + return BasicTileDescriptor(GetSurface()->GetShmem()); +} + +/* static */ BasicTiledLayerTile +BasicTiledLayerTile::OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc) +{ + nsRefPtr surface = + gfxReusableSurfaceWrapper::Open(aAllocator, aDesc.reusableSurface()); + return BasicTiledLayerTile( + new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface)); +} + +SurfaceDescriptorTiles +BasicTiledLayerBuffer::GetSurfaceDescriptorTiles() +{ + InfallibleTArray tiles; + + for (size_t i = 0; i < mRetainedTiles.Length(); i++) { + TileDescriptor tileDesc; + if (mRetainedTiles.SafeElementAt(i, GetPlaceholderTile()) == GetPlaceholderTile()) { + tileDesc = PlaceholderTileDescriptor(); + } else { + tileDesc = mRetainedTiles[i].GetTileDescriptor(); + } + tiles.AppendElement(tileDesc); + } + return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion, + tiles, mRetainedWidth, mRetainedHeight, + mResolution); +} + +/* static */ BasicTiledLayerBuffer +BasicTiledLayerBuffer::OpenDescriptor(ISurfaceAllocator *aAllocator, + const SurfaceDescriptorTiles& aDescriptor) +{ + return BasicTiledLayerBuffer(aAllocator, + aDescriptor.validRegion(), + aDescriptor.paintedRegion(), + aDescriptor.tiles(), + aDescriptor.retainedWidth(), + aDescriptor.retainedHeight(), + aDescriptor.resolution()); +} + void BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, @@ -463,20 +509,5 @@ BasicTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion, return isBufferChanged; } -BasicTiledLayerBuffer -BasicTiledLayerBuffer::DeepCopy() const -{ - BasicTiledLayerBuffer result = *this; - - for (size_t i = 0; i < result.mRetainedTiles.Length(); i++) { - if (result.mRetainedTiles[i].IsPlaceholderTile()) continue; - - result.mRetainedTiles[i].mDeprecatedTextureClient = - new DeprecatedTextureClientTile(*result.mRetainedTiles[i].mDeprecatedTextureClient); - } - - return result; -} - } } diff --git a/gfx/layers/client/TiledContentClient.h b/gfx/layers/client/TiledContentClient.h index 37235587052c..4149aaf182c6 100644 --- a/gfx/layers/client/TiledContentClient.h +++ b/gfx/layers/client/TiledContentClient.h @@ -9,10 +9,13 @@ #include "mozilla/layers/ContentClient.h" #include "TiledLayerBuffer.h" #include "gfxPlatform.h" +#include "mozilla/layers/ISurfaceAllocator.h" namespace mozilla { namespace layers { +class BasicTileDescriptor; + /** * Represent a single tile in tiled buffer. The buffer keeps tiles, * each tile keeps a reference to a texture client. The texture client @@ -33,6 +36,10 @@ struct BasicTiledLayerTile { : mDeprecatedTextureClient(nullptr) {} + BasicTiledLayerTile(DeprecatedTextureClientTile* aTextureClient) + : mDeprecatedTextureClient(aTextureClient) + {} + BasicTiledLayerTile(const BasicTiledLayerTile& o) { mDeprecatedTextureClient = o.mDeprecatedTextureClient; #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY @@ -63,6 +70,9 @@ struct BasicTiledLayerTile { GetSurface()->ReadLock(); } + BasicTileDescriptor GetTileDescriptor(); + static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc); + gfxReusableSurfaceWrapper* GetSurface() { return mDeprecatedTextureClient->GetReusableSurfaceWrapper(); } @@ -107,6 +117,30 @@ public: , mLastPaintOpaque(false) {} + BasicTiledLayerBuffer(ISurfaceAllocator* aAllocator, + const nsIntRegion& aValidRegion, + const nsIntRegion& aPaintedRegion, + const InfallibleTArray& aTiles, + int aRetainedWidth, + int aRetainedHeight, + float aResolution) + { + mValidRegion = aValidRegion; + mPaintedRegion = aPaintedRegion; + mRetainedWidth = aRetainedWidth; + mRetainedHeight = aRetainedHeight; + mResolution = aResolution; + + for(size_t i = 0; i < aTiles.Length(); i++) { + if (aTiles[i].type() == TileDescriptor::TPlaceholderTileDescriptor) { + mRetainedTiles.AppendElement(GetPlaceholderTile()); + } else { + const BasicTileDescriptor& basicTileDesc = aTiles[i].get_BasicTileDescriptor(); + mRetainedTiles.AppendElement(BasicTiledLayerTile::OpenDescriptor(aAllocator, basicTileDesc)); + } + } + } + void PaintThebes(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion, LayerManager::DrawThebesLayerCallback aCallback, @@ -142,14 +176,10 @@ public: LayerManager::DrawThebesLayerCallback aCallback, void* aCallbackData); - /** - * Copy this buffer duplicating the texture hosts under the tiles - * XXX This should go. It is a hack because we need to keep the - * surface wrappers alive whilst they are locked by the compositor. - * Once we properly implement the texture host/client architecture - * for tiled layers we shouldn't need this. - */ - BasicTiledLayerBuffer DeepCopy() const; + SurfaceDescriptorTiles GetSurfaceDescriptorTiles(); + + static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator, + const SurfaceDescriptorTiles& aDescriptor); protected: BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile, diff --git a/gfx/layers/composite/TiledContentHost.cpp b/gfx/layers/composite/TiledContentHost.cpp index 8c0f0457df52..15235f3f9d14 100644 --- a/gfx/layers/composite/TiledContentHost.cpp +++ b/gfx/layers/composite/TiledContentHost.cpp @@ -54,12 +54,6 @@ TiledLayerBufferComposite::ValidateTile(TiledTexture aTile, return aTile; } -TiledContentHost::~TiledContentHost() -{ - mMainMemoryTiledBuffer.ReadUnlock(); - mLowPrecisionMainMemoryTiledBuffer.ReadUnlock(); -} - void TiledContentHost::Attach(Layer* aLayer, Compositor* aCompositor) { @@ -68,25 +62,21 @@ TiledContentHost::Attach(Layer* aLayer, Compositor* aCompositor) } void -TiledContentHost::PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer) +TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator, + const SurfaceDescriptorTiles& aTiledDescriptor) { - if (mTiledBuffer->IsLowPrecision()) { - mLowPrecisionMainMemoryTiledBuffer.ReadUnlock(); - mLowPrecisionMainMemoryTiledBuffer = *mTiledBuffer; + if (aTiledDescriptor.resolution() < 1) { + mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor); mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload, mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion()); mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion(); mPendingLowPrecisionUpload = true; } else { - mMainMemoryTiledBuffer.ReadUnlock(); - mMainMemoryTiledBuffer = *mTiledBuffer; + mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor); mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion()); mMainMemoryTiledBuffer.ClearPaintedRegion(); mPendingUpload = true; } - - // TODO: Remove me once Bug 747811 lands. - delete mTiledBuffer; } void @@ -109,8 +99,6 @@ TiledContentHost::ProcessLowPrecisionUploadQueue() mVideoMemoryTiledBuffer.GetFrameResolution()); nsIntRegion validRegion = mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(); - mLowPrecisionMainMemoryTiledBuffer.ReadUnlock(); - mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer(); mLowPrecisionRegionToUpload = nsIntRegion(); mPendingLowPrecisionUpload = false; @@ -133,12 +121,8 @@ TiledContentHost::ProcessUploadQueue(nsIntRegion* aNewValidRegion, *aNewValidRegion = mVideoMemoryTiledBuffer.GetValidRegion(); - mMainMemoryTiledBuffer.ReadUnlock(); // Release all the tiles by replacing the tile buffer with an empty - // tiled buffer. This will prevent us from doing a double unlock when - // calling ~TiledThebesLayerComposite. - // XXX: This wont be needed when we do progressive upload and lock - // tile by tile. + // tiled buffer. mMainMemoryTiledBuffer = BasicTiledLayerBuffer(); mRegionToUpload = nsIntRegion(); mPendingUpload = false; diff --git a/gfx/layers/composite/TiledContentHost.h b/gfx/layers/composite/TiledContentHost.h index 601d1f213c46..5771ed0b6ffd 100644 --- a/gfx/layers/composite/TiledContentHost.h +++ b/gfx/layers/composite/TiledContentHost.h @@ -8,6 +8,7 @@ #include "ContentHost.h" #include "ClientTiledThebesLayer.h" // for BasicTiledLayerBuffer +#include "mozilla/layers/ISurfaceAllocator.h" #include "mozilla/layers/TextureHost.h" namespace mozilla { @@ -137,8 +138,14 @@ public: : ContentHost(aTextureInfo) , mPendingUpload(false) , mPendingLowPrecisionUpload(false) - {} - ~TiledContentHost(); + { + MOZ_COUNT_CTOR(TiledContentHost); + } + + ~TiledContentHost() + { + MOZ_COUNT_DTOR(TiledContentHost); + } virtual LayerRenderState GetRenderState() MOZ_OVERRIDE { @@ -159,7 +166,8 @@ public: return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(); } - void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer); + void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator, + const SurfaceDescriptorTiles& aTiledDescriptor); // Renders a single given tile. void RenderTile(const TiledTexture& aTile, diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index 89fc97be3a81..869c43be1ea7 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -18,6 +18,7 @@ namespace layers { class CompositableClient; class TextureFactoryIdentifier; class SurfaceDescriptor; +class SurfaceDescriptorTiles; class ThebesBufferData; class DeprecatedTextureClient; class TextureClient; @@ -85,7 +86,7 @@ public: virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0; virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, - BasicTiledLayerBuffer* aTiledLayerBuffer) = 0; + const SurfaceDescriptorTiles& aTiledDescriptor) = 0; /** * Communicate to the compositor that the texture identified by aCompositable diff --git a/gfx/layers/ipc/CompositableTransactionParent.cpp b/gfx/layers/ipc/CompositableTransactionParent.cpp index 10096812fc16..d0a9b2afffa9 100644 --- a/gfx/layers/ipc/CompositableTransactionParent.cpp +++ b/gfx/layers/ipc/CompositableTransactionParent.cpp @@ -196,8 +196,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer(); NS_ASSERTION(tileComposer, "compositable is not a tile composer"); - BasicTiledLayerBuffer* p = reinterpret_cast(op.tiledLayerBuffer()); - tileComposer->PaintedTiledLayerBuffer(p); + const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor(); + tileComposer->PaintedTiledLayerBuffer(this, tileDesc); break; } case CompositableOperation::TOpUseTexture: { diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 3b8157a5fb9a..350a2c7e12f8 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -259,7 +259,7 @@ public: TextureClient* aClient) MOZ_OVERRIDE; virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, - BasicTiledLayerBuffer* aTiledLayerBuffer) MOZ_OVERRIDE + const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE { NS_RUNTIMEABORT("should not be called"); } diff --git a/gfx/layers/ipc/LayerTransaction.ipdlh b/gfx/layers/ipc/LayerTransaction.ipdlh index a007abc80fab..38acc011018d 100644 --- a/gfx/layers/ipc/LayerTransaction.ipdlh +++ b/gfx/layers/ipc/LayerTransaction.ipdlh @@ -245,9 +245,7 @@ struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; }; // Paint (buffer update) struct OpPaintTiledLayerBuffer { PCompositable compositable; - // Bug 747811 - // FIXME: We need to support sharing tile across process. - uintptr_t tiledLayerBuffer; + SurfaceDescriptorTiles tileLayerDescriptor; }; struct OpCreatedTexture { diff --git a/gfx/layers/ipc/LayersSurfaces.ipdlh b/gfx/layers/ipc/LayersSurfaces.ipdlh index 71f2eda8d91d..e7b1d22677e4 100644 --- a/gfx/layers/ipc/LayersSurfaces.ipdlh +++ b/gfx/layers/ipc/LayersSurfaces.ipdlh @@ -53,6 +53,27 @@ struct SharedTextureDescriptor { bool inverted; }; +struct BasicTileDescriptor { + Shmem reusableSurface; +}; + +struct PlaceholderTileDescriptor { +}; + +union TileDescriptor { + BasicTileDescriptor; + PlaceholderTileDescriptor; +}; + +struct SurfaceDescriptorTiles { + nsIntRegion validRegion; + nsIntRegion paintedRegion; + TileDescriptor[] tiles; + int retainedWidth; + int retainedHeight; + float resolution; +}; + // XXX - soon to be removed struct SurfaceDescriptorGralloc { PGrallocBuffer buffer; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 6435f31b3a2e..b2e6f3b663d8 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -295,12 +295,10 @@ ShadowLayerForwarder::RepositionChild(ShadowableLayer* aContainer, void ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable, - BasicTiledLayerBuffer* aTiledLayerBuffer) + const SurfaceDescriptorTiles& aTileLayerDescriptor) { - if (XRE_GetProcessType() != GeckoProcessType_Default) - NS_RUNTIMEABORT("PaintedTiledLayerBuffer must be made IPC safe (not share pointers)"); mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(), - uintptr_t(aTiledLayerBuffer))); + aTileLayerDescriptor)); } void diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index 5d8dcf6251a8..97e38808e03d 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -46,10 +46,10 @@ class ColorLayerComposite; class CanvasLayerComposite; class RefLayerComposite; class SurfaceDescriptor; +class SurfaceDescriptorTiles; class ThebesBuffer; class TiledLayerComposer; class Transaction; -class SurfaceDescriptor; class CanvasSurface; class DeprecatedTextureClientShmem; class ShmemTextureClient; @@ -262,7 +262,7 @@ public: * copy on write, tiling). */ virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, - BasicTiledLayerBuffer* aTiledLayerBuffer) MOZ_OVERRIDE; + const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE; /** * Notify the compositor that a compositable will be updated asynchronously diff --git a/gfx/thebes/gfxBaseSharedMemorySurface.h b/gfx/thebes/gfxBaseSharedMemorySurface.h index 4d36ec974bff..0407d87a88e8 100644 --- a/gfx/thebes/gfxBaseSharedMemorySurface.h +++ b/gfx/thebes/gfxBaseSharedMemorySurface.h @@ -13,11 +13,13 @@ #include "gfxASurface.h" #include "gfxImageSurface.h" #include "cairo.h" +#include "pratom.h" struct SharedImageInfo { int32_t width; int32_t height; int32_t format; + int32_t readCount; }; inline SharedImageInfo* @@ -33,6 +35,7 @@ template class gfxBaseSharedMemorySurface : public Base { typedef mozilla::ipc::SharedMemory SharedMemory; typedef mozilla::ipc::Shmem Shmem; + friend class gfxReusableSurfaceWrapper; public: virtual ~gfxBaseSharedMemorySurface() @@ -123,6 +126,28 @@ private: shmInfo->width = this->mSize.width; shmInfo->height = this->mSize.height; shmInfo->format = this->mFormat; + shmInfo->readCount = 0; + } + + int32_t + ReadLock() + { + SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); + return PR_ATOMIC_INCREMENT(&shmInfo->readCount); + } + + int32_t + ReadUnlock() + { + SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); + return PR_ATOMIC_DECREMENT(&shmInfo->readCount); + } + + int32_t + GetReadCount() + { + SharedImageInfo* shmInfo = GetShmInfoPtr(mShmem); + return shmInfo->readCount; } static size_t GetAlignedSize(const gfxIntSize& aSize, long aStride) diff --git a/gfx/thebes/gfxReusableSurfaceWrapper.cpp b/gfx/thebes/gfxReusableSurfaceWrapper.cpp index b37d9814cfce..4b5b5a67bee2 100644 --- a/gfx/thebes/gfxReusableSurfaceWrapper.cpp +++ b/gfx/thebes/gfxReusableSurfaceWrapper.cpp @@ -3,52 +3,42 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gfxReusableSurfaceWrapper.h" -#include "gfxImageSurface.h" +#include "gfxSharedImageSurface.h" -gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(gfxImageSurface* aSurface) - : mSurface(aSurface) - , mFormat(aSurface->Format()) - , mSurfaceData(aSurface->Data()) - , mReadCount(0) +using mozilla::ipc::Shmem; +using mozilla::layers::ISurfaceAllocator; + +gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(ISurfaceAllocator* aAllocator, + gfxSharedImageSurface* aSurface) + : mAllocator(aAllocator) + , mSurface(aSurface) { MOZ_COUNT_CTOR(gfxReusableSurfaceWrapper); + ReadLock(); } -class DeleteImageOnMainThread : public nsRunnable { -public: - DeleteImageOnMainThread(gfxImageSurface *aImage) - : mImage(aImage) - {} - - NS_IMETHOD Run() - { - return NS_OK; - } -private: - nsRefPtr mImage; -}; - gfxReusableSurfaceWrapper::~gfxReusableSurfaceWrapper() { - NS_ABORT_IF_FALSE(mReadCount == 0, "Should not be locked when released"); MOZ_COUNT_DTOR(gfxReusableSurfaceWrapper); - if (!NS_IsMainThread()) { - NS_DispatchToMainThread(new DeleteImageOnMainThread(mSurface)); - } + ReadUnlock(); } void gfxReusableSurfaceWrapper::ReadLock() { - NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadOnlyLock"); - mReadCount++; + NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadLock"); + mSurface->ReadLock(); } void gfxReusableSurfaceWrapper::ReadUnlock() { - mReadCount--; - NS_ABORT_IF_FALSE(mReadCount >= 0, "Should not be negative"); + int32_t readCount = mSurface->ReadUnlock(); + NS_ABORT_IF_FALSE(readCount >= 0, "Read count should not be negative"); + + if (readCount == 0) { + mAllocator->DeallocShmem(mSurface->GetShmem()); + } } gfxReusableSurfaceWrapper* @@ -56,18 +46,52 @@ gfxReusableSurfaceWrapper::GetWritable(gfxImageSurface** aSurface) { NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call GetWritable"); - if (mReadCount == 0) { + int32_t readCount = mSurface->GetReadCount(); + NS_ABORT_IF_FALSE(readCount > 0, "A ReadLock must be held when calling GetWritable"); + if (readCount == 1) { *aSurface = mSurface; return this; } // Something else is reading the surface, copy it - gfxImageSurface* copySurface = new gfxImageSurface(mSurface->GetSize(), mSurface->Format(), false); + nsRefPtr copySurface = + gfxSharedImageSurface::CreateUnsafe(mAllocator, mSurface->GetSize(), mSurface->Format()); copySurface->CopyFrom(mSurface); *aSurface = copySurface; - // We need to create a new wrapper since this wrapper has a read only lock. - gfxReusableSurfaceWrapper* wrapper = new gfxReusableSurfaceWrapper(copySurface); + // We need to create a new wrapper since this wrapper has an external ReadLock + gfxReusableSurfaceWrapper* wrapper = new gfxReusableSurfaceWrapper(mAllocator, copySurface); + + // No need to release the ReadLock on the surface, this will happen when + // the wrapper is destroyed. + return wrapper; } +const unsigned char* +gfxReusableSurfaceWrapper::GetReadOnlyData() const +{ + NS_ABORT_IF_FALSE(mSurface->GetReadCount() > 0, "Should have read lock"); + return mSurface->Data(); +} + +gfxASurface::gfxImageFormat +gfxReusableSurfaceWrapper::Format() +{ + return mSurface->Format(); +} + +Shmem& +gfxReusableSurfaceWrapper::GetShmem() +{ + return mSurface->GetShmem(); +} + +/* static */ already_AddRefed +gfxReusableSurfaceWrapper::Open(ISurfaceAllocator* aAllocator, const Shmem& aShmem) +{ + nsRefPtr sharedImage = gfxSharedImageSurface::Open(aShmem); + nsRefPtr wrapper = new gfxReusableSurfaceWrapper(aAllocator, sharedImage); + wrapper->ReadUnlock(); + return wrapper.forget(); +} diff --git a/gfx/thebes/gfxReusableSurfaceWrapper.h b/gfx/thebes/gfxReusableSurfaceWrapper.h index 346ec35b3802..29a507b9da95 100644 --- a/gfx/thebes/gfxReusableSurfaceWrapper.h +++ b/gfx/thebes/gfxReusableSurfaceWrapper.h @@ -9,11 +9,12 @@ #include "nsISupportsImpl.h" #include "nsAutoPtr.h" #include "mozilla/Atomics.h" +#include "mozilla/layers/ISurfaceAllocator.h" -class gfxImageSurface; +class gfxSharedImageSurface; /** - * Provides a cross thread wrapper for a gfxImageSurface + * Provides a cross thread wrapper for a gfxSharedImageSurface * that has copy-on-write schemantics. * * Only the owner thread can write to the surface and aquire @@ -32,42 +33,51 @@ class gfxReusableSurfaceWrapper { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxReusableSurfaceWrapper) public: /** - * Pass the gfxASurface to the wrapper. - * The wrapper should hold the only strong reference - * to the surface and its memebers. + * Pass the gfxSharedImageSurface to the wrapper. The wrapper will ReadLock + * on creation and ReadUnlock on destruction. */ - gfxReusableSurfaceWrapper(gfxImageSurface* aSurface); + gfxReusableSurfaceWrapper(mozilla::layers::ISurfaceAllocator* aAllocator, gfxSharedImageSurface* aSurface); ~gfxReusableSurfaceWrapper(); - const unsigned char* GetReadOnlyData() const { - NS_ABORT_IF_FALSE(mReadCount > 0, "Should have read lock"); - return mSurfaceData; - } + const unsigned char* GetReadOnlyData() const; - const gfxASurface::gfxImageFormat& Format() { return mFormat; } + mozilla::ipc::Shmem& GetShmem(); + + /** + * Create a gfxReusableSurfaceWrapper from the shared memory segment of a + * gfxSharedImageSurface. A ReadLock must be held, which will be adopted by + * the returned gfxReusableSurfaceWrapper. + */ + static already_AddRefed + Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem); + + gfxASurface::gfxImageFormat Format(); /** * Get a writable copy of the image. * If necessary this will copy the wrapper. If there are no contention - * the same wrapper will be returned. + * the same wrapper will be returned. A ReadLock must be held when + * calling this function, and calling it will give up this lock. */ gfxReusableSurfaceWrapper* GetWritable(gfxImageSurface** aSurface); /** * A read only lock count is recorded, any attempts to - * call GetWritable() while this count is positive will + * call GetWritable() while this count is greater than one will * create a new surface/wrapper pair. + * + * When a surface's read count falls to zero, its memory will be + * deallocated. It is the responsibility of the user to make sure + * that all locks are matched with an equal number of unlocks. */ void ReadLock(); void ReadUnlock(); private: NS_DECL_OWNINGTHREAD - nsRefPtr mSurface; - const gfxASurface::gfxImageFormat mFormat; - const unsigned char* mSurfaceData; - mozilla::Atomic mReadCount; + mozilla::layers::ISurfaceAllocator* mAllocator; + nsRefPtr mSurface; }; #endif // GFXCOWSURFACEWRAPPER