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.
This commit is contained in:
Benoit Girard ext:(%2C%20Chris%20Lord%20%3Cchrislord.net%40gmail.com%3E) 2013-08-19 14:59:22 +01:00
parent a09be6f7fe
commit 1b95e41dd6
17 changed files with 265 additions and 127 deletions

View File

@ -184,6 +184,8 @@ private:
}; };
class BasicTiledLayerBuffer; class BasicTiledLayerBuffer;
class SurfaceDescriptorTiles;
class ISurfaceAllocator;
// Shadow layers may implement this interface in order to be notified when a // Shadow layers may implement this interface in order to be notified when a
// tiled layer buffer is updated. // tiled layer buffer is updated.
@ -192,11 +194,13 @@ class TiledLayerComposer
public: public:
/** /**
* Update the current retained layer with the updated layer data. * Update the current retained layer with the updated layer data.
* The BasicTiledLayerBuffer is expected to be in the ReadLock state * It is expected that the tiles described by aTiledDescriptor are all in the
* prior to this being called. aTiledBuffer is copy constructed and * ReadLock state, so that the locks can be adopted when recreating a
* is retained until it has been uploaded/copyed and unlocked. * 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 * If some part of the buffer is being rendered at a lower precision, this

View File

@ -15,6 +15,7 @@
#include "BasicLayers.h" // for PaintContext #include "BasicLayers.h" // for PaintContext
#include "mozilla/layers/YCbCrImageDataSerializer.h" #include "mozilla/layers/YCbCrImageDataSerializer.h"
#include "gfxReusableSurfaceWrapper.h" #include "gfxReusableSurfaceWrapper.h"
#include "gfxSharedImageSurface.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
#include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/ImageDataSerializer.h"
#include "gfx2DGlue.h" #include "gfx2DGlue.h"
@ -462,9 +463,10 @@ DeprecatedTextureClientShmemYCbCr::EnsureAllocated(gfx::IntSize aSize,
DeprecatedTextureClientTile::DeprecatedTextureClientTile(CompositableForwarder* aForwarder, DeprecatedTextureClientTile::DeprecatedTextureClientTile(CompositableForwarder* aForwarder,
const TextureInfo& aTextureInfo) const TextureInfo& aTextureInfo,
gfxReusableSurfaceWrapper* aSurface)
: DeprecatedTextureClient(aForwarder, aTextureInfo) : DeprecatedTextureClient(aForwarder, aTextureInfo)
, mSurface(nullptr) , mSurface(aSurface)
{ {
mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED; mTextureInfo.mDeprecatedTextureHostFlags = TEXTURE_HOST_TILED;
} }
@ -474,10 +476,11 @@ DeprecatedTextureClientTile::EnsureAllocated(gfx::IntSize aSize, gfxASurface::gf
{ {
if (!mSurface || if (!mSurface ||
mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) { mSurface->Format() != gfxPlatform::GetPlatform()->OptimalFormatForContent(aType)) {
gfxImageSurface* tmpTile = new gfxImageSurface(gfxIntSize(aSize.width, aSize.height), nsRefPtr<gfxSharedImageSurface> sharedImage =
gfxPlatform::GetPlatform()->OptimalFormatForContent(aType), gfxSharedImageSurface::CreateUnsafe(mForwarder,
aType != gfxASurface::CONTENT_COLOR); gfxIntSize(aSize.width, aSize.height),
mSurface = new gfxReusableSurfaceWrapper(tmpTile); gfxPlatform::GetPlatform()->OptimalFormatForContent(aType));
mSurface = new gfxReusableSurfaceWrapper(mForwarder, sharedImage);
mContentType = aType; mContentType = aType;
} }
return true; return true;

View File

@ -474,7 +474,8 @@ class DeprecatedTextureClientTile : public DeprecatedTextureClient
public: public:
DeprecatedTextureClientTile(const DeprecatedTextureClientTile& aOther); DeprecatedTextureClientTile(const DeprecatedTextureClientTile& aOther);
DeprecatedTextureClientTile(CompositableForwarder* aForwarder, DeprecatedTextureClientTile(CompositableForwarder* aForwarder,
const TextureInfo& aTextureInfo); const TextureInfo& aTextureInfo,
gfxReusableSurfaceWrapper* aSurface = nullptr);
~DeprecatedTextureClientTile(); ~DeprecatedTextureClientTile();
virtual bool EnsureAllocated(gfx::IntSize aSize, virtual bool EnsureAllocated(gfx::IntSize aSize,

View File

@ -73,17 +73,16 @@ TiledContentClient::TiledContentClient(ClientTiledThebesLayer* aThebesLayer,
void void
TiledContentClient::LockCopyAndWrite(TiledBufferType aType) 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 BasicTiledLayerBuffer* buffer = aType == LOW_PRECISION_TILED_BUFFER
? &mLowPrecisionTiledBuffer ? &mLowPrecisionTiledBuffer
: &mTiledBuffer; : &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(); buffer->ReadLock();
mForwarder->PaintedTiledLayerBuffer(this, heapCopy);
mForwarder->PaintedTiledLayerBuffer(this, buffer->GetSurfaceDescriptorTiles());
buffer->ClearPaintedRegion(); 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<gfxReusableSurfaceWrapper> surface =
gfxReusableSurfaceWrapper::Open(aAllocator, aDesc.reusableSurface());
return BasicTiledLayerTile(
new DeprecatedTextureClientTile(nullptr, TextureInfo(BUFFER_TILED), surface));
}
SurfaceDescriptorTiles
BasicTiledLayerBuffer::GetSurfaceDescriptorTiles()
{
InfallibleTArray<TileDescriptor> 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 void
BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion, BasicTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion, const nsIntRegion& aPaintRegion,
@ -463,20 +509,5 @@ BasicTiledLayerBuffer::ProgressiveUpdate(nsIntRegion& aValidRegion,
return isBufferChanged; 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;
}
} }
} }

View File

@ -9,10 +9,13 @@
#include "mozilla/layers/ContentClient.h" #include "mozilla/layers/ContentClient.h"
#include "TiledLayerBuffer.h" #include "TiledLayerBuffer.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
#include "mozilla/layers/ISurfaceAllocator.h"
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
class BasicTileDescriptor;
/** /**
* Represent a single tile in tiled buffer. The buffer keeps tiles, * Represent a single tile in tiled buffer. The buffer keeps tiles,
* each tile keeps a reference to a texture client. The texture client * each tile keeps a reference to a texture client. The texture client
@ -33,6 +36,10 @@ struct BasicTiledLayerTile {
: mDeprecatedTextureClient(nullptr) : mDeprecatedTextureClient(nullptr)
{} {}
BasicTiledLayerTile(DeprecatedTextureClientTile* aTextureClient)
: mDeprecatedTextureClient(aTextureClient)
{}
BasicTiledLayerTile(const BasicTiledLayerTile& o) { BasicTiledLayerTile(const BasicTiledLayerTile& o) {
mDeprecatedTextureClient = o.mDeprecatedTextureClient; mDeprecatedTextureClient = o.mDeprecatedTextureClient;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
@ -63,6 +70,9 @@ struct BasicTiledLayerTile {
GetSurface()->ReadLock(); GetSurface()->ReadLock();
} }
BasicTileDescriptor GetTileDescriptor();
static BasicTiledLayerTile OpenDescriptor(ISurfaceAllocator *aAllocator, const BasicTileDescriptor& aDesc);
gfxReusableSurfaceWrapper* GetSurface() { gfxReusableSurfaceWrapper* GetSurface() {
return mDeprecatedTextureClient->GetReusableSurfaceWrapper(); return mDeprecatedTextureClient->GetReusableSurfaceWrapper();
} }
@ -107,6 +117,30 @@ public:
, mLastPaintOpaque(false) , mLastPaintOpaque(false)
{} {}
BasicTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const nsIntRegion& aValidRegion,
const nsIntRegion& aPaintedRegion,
const InfallibleTArray<TileDescriptor>& 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, void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion, const nsIntRegion& aPaintRegion,
LayerManager::DrawThebesLayerCallback aCallback, LayerManager::DrawThebesLayerCallback aCallback,
@ -142,14 +176,10 @@ public:
LayerManager::DrawThebesLayerCallback aCallback, LayerManager::DrawThebesLayerCallback aCallback,
void* aCallbackData); void* aCallbackData);
/** SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
* Copy this buffer duplicating the texture hosts under the tiles
* XXX This should go. It is a hack because we need to keep the static BasicTiledLayerBuffer OpenDescriptor(ISurfaceAllocator* aAllocator,
* surface wrappers alive whilst they are locked by the compositor. const SurfaceDescriptorTiles& aDescriptor);
* Once we properly implement the texture host/client architecture
* for tiled layers we shouldn't need this.
*/
BasicTiledLayerBuffer DeepCopy() const;
protected: protected:
BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile, BasicTiledLayerTile ValidateTile(BasicTiledLayerTile aTile,

View File

@ -54,12 +54,6 @@ TiledLayerBufferComposite::ValidateTile(TiledTexture aTile,
return aTile; return aTile;
} }
TiledContentHost::~TiledContentHost()
{
mMainMemoryTiledBuffer.ReadUnlock();
mLowPrecisionMainMemoryTiledBuffer.ReadUnlock();
}
void void
TiledContentHost::Attach(Layer* aLayer, Compositor* aCompositor) TiledContentHost::Attach(Layer* aLayer, Compositor* aCompositor)
{ {
@ -68,25 +62,21 @@ TiledContentHost::Attach(Layer* aLayer, Compositor* aCompositor)
} }
void void
TiledContentHost::PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer) TiledContentHost::PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor)
{ {
if (mTiledBuffer->IsLowPrecision()) { if (aTiledDescriptor.resolution() < 1) {
mLowPrecisionMainMemoryTiledBuffer.ReadUnlock(); mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor);
mLowPrecisionMainMemoryTiledBuffer = *mTiledBuffer;
mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload, mLowPrecisionRegionToUpload.Or(mLowPrecisionRegionToUpload,
mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion()); mLowPrecisionMainMemoryTiledBuffer.GetPaintedRegion());
mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion(); mLowPrecisionMainMemoryTiledBuffer.ClearPaintedRegion();
mPendingLowPrecisionUpload = true; mPendingLowPrecisionUpload = true;
} else { } else {
mMainMemoryTiledBuffer.ReadUnlock(); mMainMemoryTiledBuffer = BasicTiledLayerBuffer::OpenDescriptor(aAllocator, aTiledDescriptor);
mMainMemoryTiledBuffer = *mTiledBuffer;
mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion()); mRegionToUpload.Or(mRegionToUpload, mMainMemoryTiledBuffer.GetPaintedRegion());
mMainMemoryTiledBuffer.ClearPaintedRegion(); mMainMemoryTiledBuffer.ClearPaintedRegion();
mPendingUpload = true; mPendingUpload = true;
} }
// TODO: Remove me once Bug 747811 lands.
delete mTiledBuffer;
} }
void void
@ -109,8 +99,6 @@ TiledContentHost::ProcessLowPrecisionUploadQueue()
mVideoMemoryTiledBuffer.GetFrameResolution()); mVideoMemoryTiledBuffer.GetFrameResolution());
nsIntRegion validRegion = mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(); nsIntRegion validRegion = mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
mLowPrecisionMainMemoryTiledBuffer.ReadUnlock();
mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer(); mLowPrecisionMainMemoryTiledBuffer = BasicTiledLayerBuffer();
mLowPrecisionRegionToUpload = nsIntRegion(); mLowPrecisionRegionToUpload = nsIntRegion();
mPendingLowPrecisionUpload = false; mPendingLowPrecisionUpload = false;
@ -133,12 +121,8 @@ TiledContentHost::ProcessUploadQueue(nsIntRegion* aNewValidRegion,
*aNewValidRegion = mVideoMemoryTiledBuffer.GetValidRegion(); *aNewValidRegion = mVideoMemoryTiledBuffer.GetValidRegion();
mMainMemoryTiledBuffer.ReadUnlock();
// Release all the tiles by replacing the tile buffer with an empty // Release all the tiles by replacing the tile buffer with an empty
// tiled buffer. This will prevent us from doing a double unlock when // tiled buffer.
// calling ~TiledThebesLayerComposite.
// XXX: This wont be needed when we do progressive upload and lock
// tile by tile.
mMainMemoryTiledBuffer = BasicTiledLayerBuffer(); mMainMemoryTiledBuffer = BasicTiledLayerBuffer();
mRegionToUpload = nsIntRegion(); mRegionToUpload = nsIntRegion();
mPendingUpload = false; mPendingUpload = false;

View File

@ -8,6 +8,7 @@
#include "ContentHost.h" #include "ContentHost.h"
#include "ClientTiledThebesLayer.h" // for BasicTiledLayerBuffer #include "ClientTiledThebesLayer.h" // for BasicTiledLayerBuffer
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/TextureHost.h" #include "mozilla/layers/TextureHost.h"
namespace mozilla { namespace mozilla {
@ -137,8 +138,14 @@ public:
: ContentHost(aTextureInfo) : ContentHost(aTextureInfo)
, mPendingUpload(false) , mPendingUpload(false)
, mPendingLowPrecisionUpload(false) , mPendingLowPrecisionUpload(false)
{} {
~TiledContentHost(); MOZ_COUNT_CTOR(TiledContentHost);
}
~TiledContentHost()
{
MOZ_COUNT_DTOR(TiledContentHost);
}
virtual LayerRenderState GetRenderState() MOZ_OVERRIDE virtual LayerRenderState GetRenderState() MOZ_OVERRIDE
{ {
@ -159,7 +166,8 @@ public:
return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion(); return mLowPrecisionVideoMemoryTiledBuffer.GetValidRegion();
} }
void PaintedTiledLayerBuffer(const BasicTiledLayerBuffer* mTiledBuffer); void PaintedTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor);
// Renders a single given tile. // Renders a single given tile.
void RenderTile(const TiledTexture& aTile, void RenderTile(const TiledTexture& aTile,

View File

@ -18,6 +18,7 @@ namespace layers {
class CompositableClient; class CompositableClient;
class TextureFactoryIdentifier; class TextureFactoryIdentifier;
class SurfaceDescriptor; class SurfaceDescriptor;
class SurfaceDescriptorTiles;
class ThebesBufferData; class ThebesBufferData;
class DeprecatedTextureClient; class DeprecatedTextureClient;
class TextureClient; class TextureClient;
@ -85,7 +86,7 @@ public:
virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0; virtual void DestroyThebesBuffer(CompositableClient* aCompositable) = 0;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
BasicTiledLayerBuffer* aTiledLayerBuffer) = 0; const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
/** /**
* Communicate to the compositor that the texture identified by aCompositable * Communicate to the compositor that the texture identified by aCompositable

View File

@ -196,8 +196,8 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer(); TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer();
NS_ASSERTION(tileComposer, "compositable is not a tile composer"); NS_ASSERTION(tileComposer, "compositable is not a tile composer");
BasicTiledLayerBuffer* p = reinterpret_cast<BasicTiledLayerBuffer*>(op.tiledLayerBuffer()); const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
tileComposer->PaintedTiledLayerBuffer(p); tileComposer->PaintedTiledLayerBuffer(this, tileDesc);
break; break;
} }
case CompositableOperation::TOpUseTexture: { case CompositableOperation::TOpUseTexture: {

View File

@ -259,7 +259,7 @@ public:
TextureClient* aClient) MOZ_OVERRIDE; TextureClient* aClient) MOZ_OVERRIDE;
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
BasicTiledLayerBuffer* aTiledLayerBuffer) MOZ_OVERRIDE const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE
{ {
NS_RUNTIMEABORT("should not be called"); NS_RUNTIMEABORT("should not be called");
} }

View File

@ -245,9 +245,7 @@ struct OpSetDiagnosticTypes { DiagnosticTypes diagnostics; };
// Paint (buffer update) // Paint (buffer update)
struct OpPaintTiledLayerBuffer { struct OpPaintTiledLayerBuffer {
PCompositable compositable; PCompositable compositable;
// Bug 747811 SurfaceDescriptorTiles tileLayerDescriptor;
// FIXME: We need to support sharing tile across process.
uintptr_t tiledLayerBuffer;
}; };
struct OpCreatedTexture { struct OpCreatedTexture {

View File

@ -53,6 +53,27 @@ struct SharedTextureDescriptor {
bool inverted; 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 // XXX - soon to be removed
struct SurfaceDescriptorGralloc { struct SurfaceDescriptorGralloc {
PGrallocBuffer buffer; PGrallocBuffer buffer;

View File

@ -295,12 +295,10 @@ ShadowLayerForwarder::RepositionChild(ShadowableLayer* aContainer,
void void
ShadowLayerForwarder::PaintedTiledLayerBuffer(CompositableClient* aCompositable, 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(), mTxn->AddNoSwapPaint(OpPaintTiledLayerBuffer(nullptr, aCompositable->GetIPDLActor(),
uintptr_t(aTiledLayerBuffer))); aTileLayerDescriptor));
} }
void void

View File

@ -46,10 +46,10 @@ class ColorLayerComposite;
class CanvasLayerComposite; class CanvasLayerComposite;
class RefLayerComposite; class RefLayerComposite;
class SurfaceDescriptor; class SurfaceDescriptor;
class SurfaceDescriptorTiles;
class ThebesBuffer; class ThebesBuffer;
class TiledLayerComposer; class TiledLayerComposer;
class Transaction; class Transaction;
class SurfaceDescriptor;
class CanvasSurface; class CanvasSurface;
class DeprecatedTextureClientShmem; class DeprecatedTextureClientShmem;
class ShmemTextureClient; class ShmemTextureClient;
@ -262,7 +262,7 @@ public:
* copy on write, tiling). * copy on write, tiling).
*/ */
virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable, virtual void PaintedTiledLayerBuffer(CompositableClient* aCompositable,
BasicTiledLayerBuffer* aTiledLayerBuffer) MOZ_OVERRIDE; const SurfaceDescriptorTiles& aTileLayerDescriptor) MOZ_OVERRIDE;
/** /**
* Notify the compositor that a compositable will be updated asynchronously * Notify the compositor that a compositable will be updated asynchronously

View File

@ -13,11 +13,13 @@
#include "gfxASurface.h" #include "gfxASurface.h"
#include "gfxImageSurface.h" #include "gfxImageSurface.h"
#include "cairo.h" #include "cairo.h"
#include "pratom.h"
struct SharedImageInfo { struct SharedImageInfo {
int32_t width; int32_t width;
int32_t height; int32_t height;
int32_t format; int32_t format;
int32_t readCount;
}; };
inline SharedImageInfo* inline SharedImageInfo*
@ -33,6 +35,7 @@ template <typename Base, typename Sub>
class gfxBaseSharedMemorySurface : public Base { class gfxBaseSharedMemorySurface : public Base {
typedef mozilla::ipc::SharedMemory SharedMemory; typedef mozilla::ipc::SharedMemory SharedMemory;
typedef mozilla::ipc::Shmem Shmem; typedef mozilla::ipc::Shmem Shmem;
friend class gfxReusableSurfaceWrapper;
public: public:
virtual ~gfxBaseSharedMemorySurface() virtual ~gfxBaseSharedMemorySurface()
@ -123,6 +126,28 @@ private:
shmInfo->width = this->mSize.width; shmInfo->width = this->mSize.width;
shmInfo->height = this->mSize.height; shmInfo->height = this->mSize.height;
shmInfo->format = this->mFormat; 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) static size_t GetAlignedSize(const gfxIntSize& aSize, long aStride)

View File

@ -3,52 +3,42 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */ * You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxReusableSurfaceWrapper.h" #include "gfxReusableSurfaceWrapper.h"
#include "gfxImageSurface.h" #include "gfxSharedImageSurface.h"
gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(gfxImageSurface* aSurface) using mozilla::ipc::Shmem;
: mSurface(aSurface) using mozilla::layers::ISurfaceAllocator;
, mFormat(aSurface->Format())
, mSurfaceData(aSurface->Data()) gfxReusableSurfaceWrapper::gfxReusableSurfaceWrapper(ISurfaceAllocator* aAllocator,
, mReadCount(0) gfxSharedImageSurface* aSurface)
: mAllocator(aAllocator)
, mSurface(aSurface)
{ {
MOZ_COUNT_CTOR(gfxReusableSurfaceWrapper); MOZ_COUNT_CTOR(gfxReusableSurfaceWrapper);
ReadLock();
} }
class DeleteImageOnMainThread : public nsRunnable {
public:
DeleteImageOnMainThread(gfxImageSurface *aImage)
: mImage(aImage)
{}
NS_IMETHOD Run()
{
return NS_OK;
}
private:
nsRefPtr<gfxImageSurface> mImage;
};
gfxReusableSurfaceWrapper::~gfxReusableSurfaceWrapper() gfxReusableSurfaceWrapper::~gfxReusableSurfaceWrapper()
{ {
NS_ABORT_IF_FALSE(mReadCount == 0, "Should not be locked when released");
MOZ_COUNT_DTOR(gfxReusableSurfaceWrapper); MOZ_COUNT_DTOR(gfxReusableSurfaceWrapper);
if (!NS_IsMainThread()) { ReadUnlock();
NS_DispatchToMainThread(new DeleteImageOnMainThread(mSurface));
}
} }
void void
gfxReusableSurfaceWrapper::ReadLock() gfxReusableSurfaceWrapper::ReadLock()
{ {
NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadOnlyLock"); NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call ReadLock");
mReadCount++; mSurface->ReadLock();
} }
void void
gfxReusableSurfaceWrapper::ReadUnlock() gfxReusableSurfaceWrapper::ReadUnlock()
{ {
mReadCount--; int32_t readCount = mSurface->ReadUnlock();
NS_ABORT_IF_FALSE(mReadCount >= 0, "Should not be negative"); NS_ABORT_IF_FALSE(readCount >= 0, "Read count should not be negative");
if (readCount == 0) {
mAllocator->DeallocShmem(mSurface->GetShmem());
}
} }
gfxReusableSurfaceWrapper* gfxReusableSurfaceWrapper*
@ -56,18 +46,52 @@ gfxReusableSurfaceWrapper::GetWritable(gfxImageSurface** aSurface)
{ {
NS_CheckThreadSafe(_mOwningThread.GetThread(), "Only the owner thread can call GetWritable"); 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; *aSurface = mSurface;
return this; return this;
} }
// Something else is reading the surface, copy it // Something else is reading the surface, copy it
gfxImageSurface* copySurface = new gfxImageSurface(mSurface->GetSize(), mSurface->Format(), false); nsRefPtr<gfxSharedImageSurface> copySurface =
gfxSharedImageSurface::CreateUnsafe(mAllocator, mSurface->GetSize(), mSurface->Format());
copySurface->CopyFrom(mSurface); copySurface->CopyFrom(mSurface);
*aSurface = copySurface; *aSurface = copySurface;
// We need to create a new wrapper since this wrapper has a read only lock. // We need to create a new wrapper since this wrapper has an external ReadLock
gfxReusableSurfaceWrapper* wrapper = new gfxReusableSurfaceWrapper(copySurface); 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; 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>
gfxReusableSurfaceWrapper::Open(ISurfaceAllocator* aAllocator, const Shmem& aShmem)
{
nsRefPtr<gfxSharedImageSurface> sharedImage = gfxSharedImageSurface::Open(aShmem);
nsRefPtr<gfxReusableSurfaceWrapper> wrapper = new gfxReusableSurfaceWrapper(aAllocator, sharedImage);
wrapper->ReadUnlock();
return wrapper.forget();
}

View File

@ -9,11 +9,12 @@
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "mozilla/Atomics.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. * that has copy-on-write schemantics.
* *
* Only the owner thread can write to the surface and aquire * Only the owner thread can write to the surface and aquire
@ -32,42 +33,51 @@ class gfxReusableSurfaceWrapper {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxReusableSurfaceWrapper) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxReusableSurfaceWrapper)
public: public:
/** /**
* Pass the gfxASurface to the wrapper. * Pass the gfxSharedImageSurface to the wrapper. The wrapper will ReadLock
* The wrapper should hold the only strong reference * on creation and ReadUnlock on destruction.
* to the surface and its memebers.
*/ */
gfxReusableSurfaceWrapper(gfxImageSurface* aSurface); gfxReusableSurfaceWrapper(mozilla::layers::ISurfaceAllocator* aAllocator, gfxSharedImageSurface* aSurface);
~gfxReusableSurfaceWrapper(); ~gfxReusableSurfaceWrapper();
const unsigned char* GetReadOnlyData() const { const unsigned char* GetReadOnlyData() const;
NS_ABORT_IF_FALSE(mReadCount > 0, "Should have read lock");
return mSurfaceData;
}
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<gfxReusableSurfaceWrapper>
Open(mozilla::layers::ISurfaceAllocator* aAllocator, const mozilla::ipc::Shmem& aShmem);
gfxASurface::gfxImageFormat Format();
/** /**
* Get a writable copy of the image. * Get a writable copy of the image.
* If necessary this will copy the wrapper. If there are no contention * 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); gfxReusableSurfaceWrapper* GetWritable(gfxImageSurface** aSurface);
/** /**
* A read only lock count is recorded, any attempts to * 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. * 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 ReadLock();
void ReadUnlock(); void ReadUnlock();
private: private:
NS_DECL_OWNINGTHREAD NS_DECL_OWNINGTHREAD
nsRefPtr<gfxImageSurface> mSurface; mozilla::layers::ISurfaceAllocator* mAllocator;
const gfxASurface::gfxImageFormat mFormat; nsRefPtr<gfxSharedImageSurface> mSurface;
const unsigned char* mSurfaceData;
mozilla::Atomic<int32_t> mReadCount;
}; };
#endif // GFXCOWSURFACEWRAPPER #endif // GFXCOWSURFACEWRAPPER