Bug 1150549 - Simplify TiledContentHost. r=jrmuizel

This commit is contained in:
Nicolas Silva 2015-05-22 13:38:13 +02:00
parent b66ef4e88c
commit c3d731247c
8 changed files with 407 additions and 398 deletions

View File

@ -285,8 +285,14 @@ CreateTexturedEffect(TextureSource* aSource,
{
MOZ_ASSERT(aSource);
if (aSourceOnWhite) {
if ((aSource->GetFormat() != gfx::SurfaceFormat::R8G8B8X8 &&
aSource->GetFormat() != gfx::SurfaceFormat::B8G8R8X8) ||
aSource->GetFormat() != aSourceOnWhite->GetFormat()) {
printf_stderr("XXXX - source %i - on white %i\n", (int)aSource->GetFormat(), (int)aSourceOnWhite->GetFormat());
}
MOZ_ASSERT(aSource->GetFormat() == gfx::SurfaceFormat::R8G8B8X8 ||
aSourceOnWhite->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
aSource->GetFormat() == gfx::SurfaceFormat::B8G8R8X8);
MOZ_ASSERT(aSource->GetFormat() == aSourceOnWhite->GetFormat());
return MakeAndAddRef<EffectComponentAlpha>(aSource, aSourceOnWhite, aFilter);
}

View File

@ -94,7 +94,9 @@ class TiledLayerBuffer
{
public:
TiledLayerBuffer()
: mRetainedWidth(0)
: mFirstTileX(0)
, mFirstTileY(0)
, mRetainedWidth(0)
, mRetainedHeight(0)
, mResolution(1)
, mTileSize(gfxPlatform::GetPlatform()->GetTileWidth(), gfxPlatform::GetPlatform()->GetTileHeight())
@ -108,13 +110,21 @@ public:
// (aTileOrigin.x, aTileOrigin.y,
// GetScaledTileSize().width, GetScaledTileSize().height)
// and GetValidRegion() to get the area of the tile that is valid.
Tile GetTile(const nsIntPoint& aTileOrigin) const;
Tile& GetTile(const gfx::IntPoint& aTileOrigin);
// Given a tile x, y relative to the top left of the layer, this function
// will return the tile for
// (x*GetScaledTileSize().width, y*GetScaledTileSize().height,
// GetScaledTileSize().width, GetScaledTileSize().height)
Tile GetTile(int x, int y) const;
Tile& GetTile(int x, int y);
int TileIndex(const gfx::IntPoint& aTileOrigin) const;
int TileIndex(int x, int y) const { return x * mRetainedHeight + y; }
bool HasTile(int index) const { return index >= 0 && index < (int)mRetainedTiles.Length(); }
bool HasTile(const gfx::IntPoint& aTileOrigin) const;
bool HasTile(int x, int y) const {
return x >= 0 && x < mRetainedWidth && y >= 0 && y < mRetainedHeight;
}
const gfx::IntSize& GetTileSize() const { return mTileSize; }
@ -155,14 +165,6 @@ public:
// individual tile's rect in relation to the valid region.
// Setting the resolution will invalidate the buffer.
float GetResolution() const { return mResolution; }
void SetResolution(float aResolution) {
if (mResolution == aResolution) {
return;
}
Update(nsIntRegion(), nsIntRegion());
mResolution = aResolution;
}
bool IsLowPrecision() const { return mResolution < 1; }
typedef Tile* Iterator;
@ -178,6 +180,10 @@ protected:
// to the implementor.
void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion);
// Return a reference to this tile in GetTile when the requested tile offset
// does not exist.
Tile mPlaceHolderTile;
nsIntRegion mValidRegion;
nsIntRegion mPaintedRegion;
@ -190,6 +196,8 @@ protected:
* tiles is scaled by mResolution.
*/
nsTArray<Tile> mRetainedTiles;
int mFirstTileX;
int mFirstTileY;
int mRetainedWidth; // in tiles
int mRetainedHeight; // in tiles
float mResolution;
@ -249,24 +257,39 @@ static inline int floor_div(int a, int b)
}
}
template<typename Derived, typename Tile> Tile
TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin) const
template<typename Derived, typename Tile> bool
TiledLayerBuffer<Derived, Tile>::HasTile(const gfx::IntPoint& aTileOrigin) const {
gfx::IntSize scaledTileSize = GetScaledTileSize();
return HasTile(floor_div(aTileOrigin.x, scaledTileSize.width) - mFirstTileX,
floor_div(aTileOrigin.y, scaledTileSize.height) - mFirstTileY);
}
template<typename Derived, typename Tile> Tile&
TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin)
{
if (HasTile(aTileOrigin)) {
return mRetainedTiles[TileIndex(aTileOrigin)];
}
return mPlaceHolderTile;
}
template<typename Derived, typename Tile> int
TiledLayerBuffer<Derived, Tile>::TileIndex(const gfx::IntPoint& aTileOrigin) const
{
// TODO Cache firstTileOriginX/firstTileOriginY
// Find the tile x/y of the first tile and the target tile relative to the (0, 0)
// origin, the difference is the tile x/y relative to the start of the tile buffer.
gfx::IntSize scaledTileSize = GetScaledTileSize();
int firstTileX = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
int firstTileY = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
return GetTile(floor_div(aTileOrigin.x, scaledTileSize.width) - firstTileX,
floor_div(aTileOrigin.y, scaledTileSize.height) - firstTileY);
return TileIndex(floor_div(aTileOrigin.x, scaledTileSize.width) - mFirstTileX,
floor_div(aTileOrigin.y, scaledTileSize.height) - mFirstTileY);
}
template<typename Derived, typename Tile> Tile
TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y) const
template<typename Derived, typename Tile> Tile&
TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y)
{
int index = x * mRetainedHeight + y;
return mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile());
if (HasTile(x, y)) {
return mRetainedTiles[TileIndex(x, y)];
}
return mPlaceHolderTile;
}
template<typename Derived, typename Tile> void
@ -282,15 +305,15 @@ TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
int32_t tileStartY = GetTileStart(y, scaledTileSize.height);
Tile tileTexture =
GetTile(nsIntPoint(RoundDownToTileEdge(x, scaledTileSize.width),
RoundDownToTileEdge(y, scaledTileSize.height)));
nsIntPoint tileOrigin = nsIntPoint(RoundDownToTileEdge(x, scaledTileSize.width),
RoundDownToTileEdge(y, scaledTileSize.height));
Tile& tileTexture = GetTile(tileOrigin);
int32_t h = scaledTileSize.height - tileStartY;
aStream << "\n" << aPrefix << "Tile (x=" <<
RoundDownToTileEdge(x, scaledTileSize.width) << ", y=" <<
RoundDownToTileEdge(y, scaledTileSize.height) << "): ";
if (tileTexture != AsDerived().GetPlaceholderTile()) {
if (!tileTexture.IsPlaceholderTile()) {
tileTexture.DumpTexture(aStream);
} else {
aStream << "empty tile";
@ -597,6 +620,10 @@ TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
mRetainedTiles = newRetainedTiles;
mValidRegion = newValidRegion;
mFirstTileX = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
mFirstTileY = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
}

View File

@ -374,7 +374,7 @@ int32_t
gfxMemorySharedReadLock::ReadUnlock()
{
int32_t readCount = PR_ATOMIC_DECREMENT(&mReadCount);
NS_ASSERTION(readCount >= 0, "ReadUnlock called without ReadLock.");
MOZ_ASSERT(readCount >= 0);
return readCount;
}
@ -424,7 +424,7 @@ gfxShmSharedReadLock::ReadUnlock() {
}
ShmReadLockInfo* info = GetShmReadLockInfoPtr();
int32_t readCount = PR_ATOMIC_DECREMENT(&info->readCount);
NS_ASSERTION(readCount >= 0, "ReadUnlock called without a ReadLock.");
MOZ_ASSERT(readCount >= 0);
if (readCount <= 0) {
mAllocator->FreeShmemSection(mShmemSection);
}
@ -520,6 +520,7 @@ TileClient::TileClient(const TileClient& o)
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
mCompositableClient = o.mCompositableClient;
mUpdateRect = o.mUpdateRect;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
@ -539,6 +540,7 @@ TileClient::operator=(const TileClient& o)
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
mCompositableClient = o.mCompositableClient;
mUpdateRect = o.mUpdateRect;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
@ -609,6 +611,8 @@ CopyFrontToBack(TextureClient* aFront,
gfx::IntPoint rectToCopyTopLeft = aRectToCopy.TopLeft();
aFront->CopyToTextureClient(aBack, &aRectToCopy, &rectToCopyTopLeft);
aFront->Unlock();
return true;
}
@ -705,9 +709,9 @@ TileClient::DiscardBackBuffer()
mManager->ReportClientLost(*mBackBufferOnWhite);
}
} else {
mManager->ReturnTextureClient(*mBackBuffer);
mManager->ReturnTextureClientDeferred(*mBackBuffer);
if (mBackBufferOnWhite) {
mManager->ReturnTextureClient(*mBackBufferOnWhite);
mManager->ReturnTextureClientDeferred(*mBackBufferOnWhite);
}
}
mBackLock->ReadUnlock();
@ -816,23 +820,17 @@ TileClient::GetTileDescriptor()
if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) {
return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()),
mUpdateRect,
TileLock(uintptr_t(mFrontLock.get())));
} else {
gfxShmSharedReadLock *lock = static_cast<gfxShmSharedReadLock*>(mFrontLock.get());
return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()),
mUpdateRect,
TileLock(lock->GetShmemSection()));
}
}
void
ClientTiledLayerBuffer::ReadUnlock() {
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].ReadUnlock();
}
}
void
ClientTiledLayerBuffer::ReadLock() {
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
@ -873,9 +871,12 @@ ClientTiledLayerBuffer::GetSurfaceDescriptorTiles()
tileDesc = mRetainedTiles[i].GetTileDescriptor();
}
tiles.AppendElement(tileDesc);
mRetainedTiles[i].mUpdateRect = IntRect();
}
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
tiles, mRetainedWidth, mRetainedHeight,
tiles,
mFirstTileX, mFirstTileY,
mRetainedWidth, mRetainedHeight,
mResolution, mFrameResolution.xScale,
mFrameResolution.yScale);
}
@ -1136,6 +1137,8 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
&createdTextureClient, extraPainted,
&backBufferOnWhite);
aTile.mUpdateRect = offsetScaledDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
extraPainted.MoveBy(aTileOrigin);
extraPainted.And(extraPainted, mNewValidRegion);
mPaintedRegion.Or(mPaintedRegion, extraPainted);

View File

@ -270,6 +270,7 @@ struct TileClient
RefPtr<gfxSharedReadLock> mBackLock;
RefPtr<gfxSharedReadLock> mFrontLock;
RefPtr<ClientLayerManager> mManager;
gfx::IntRect mUpdateRect;
CompositableClient* mCompositableClient;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
TimeStamp mLastUpdate;
@ -418,8 +419,6 @@ public:
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);
void ReadUnlock();
void ReadLock();
void Release();
@ -445,6 +444,15 @@ public:
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
void SetResolution(float aResolution) {
if (mResolution == aResolution) {
return;
}
Update(nsIntRegion(), nsIntRegion());
mResolution = aResolution;
}
protected:
TileClient ValidateTile(TileClient aTile,
const nsIntPoint& aTileRect,

View File

@ -326,6 +326,7 @@ protected:
virtual ~TextureHost();
public:
/**
* Factory method.
*/

View File

@ -29,198 +29,28 @@ class Layer;
TiledLayerBufferComposite::TiledLayerBufferComposite()
: mFrameResolution()
, mHasDoubleBufferedTiles(false)
, mIsValid(false)
{}
TiledLayerBufferComposite::~TiledLayerBufferComposite()
{
Clear();
}
/* static */ void
TiledLayerBufferComposite::RecycleCallback(TextureHost* textureHost, void* aClosure)
{
textureHost->CompositorRecycle();
}
TiledLayerBufferComposite::TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
const nsIntRegion& aOldPaintedRegion,
Compositor* aCompositor)
{
mIsValid = true;
mHasDoubleBufferedTiles = false;
mValidRegion = aDescriptor.validRegion();
mPaintedRegion = aDescriptor.paintedRegion();
mRetainedWidth = aDescriptor.retainedWidth();
mRetainedHeight = aDescriptor.retainedHeight();
mResolution = aDescriptor.resolution();
mFrameResolution = CSSToParentLayerScale2D(aDescriptor.frameXResolution(),
aDescriptor.frameYResolution());
if (mResolution == 0 || IsNaN(mResolution)) {
// There are divisions by mResolution so this protects the compositor process
// against malicious content processes and fuzzing.
mIsValid = false;
return;
}
// Combine any valid content that wasn't already uploaded
nsIntRegion oldPaintedRegion(aOldPaintedRegion);
oldPaintedRegion.And(oldPaintedRegion, mValidRegion);
mPaintedRegion.Or(mPaintedRegion, oldPaintedRegion);
bool isSameProcess = aAllocator->IsSameProcess();
const InfallibleTArray<TileDescriptor>& tiles = aDescriptor.tiles();
for(size_t i = 0; i < tiles.Length(); i++) {
CompositableTextureHostRef texture;
CompositableTextureHostRef textureOnWhite;
const TileDescriptor& tileDesc = tiles[i];
switch (tileDesc.type()) {
case TileDescriptor::TTexturedTileDescriptor : {
texture = TextureHost::AsTextureHost(tileDesc.get_TexturedTileDescriptor().textureParent());
MaybeTexture onWhite = tileDesc.get_TexturedTileDescriptor().textureOnWhite();
if (onWhite.type() == MaybeTexture::TPTextureParent) {
textureOnWhite = TextureHost::AsTextureHost(onWhite.get_PTextureParent());
}
const TileLock& ipcLock = tileDesc.get_TexturedTileDescriptor().sharedLock();
nsRefPtr<gfxSharedReadLock> sharedLock;
if (ipcLock.type() == TileLock::TShmemSection) {
sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_ShmemSection());
} else {
if (!isSameProcess) {
// Trying to use a memory based lock instead of a shmem based one in
// the cross-process case is a bad security violation.
NS_ERROR("A client process may be trying to peek at the host's address space!");
// This tells the TiledContentHost that deserialization failed so that
// it can propagate the error.
mIsValid = false;
mRetainedTiles.Clear();
return;
}
sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t());
if (sharedLock) {
// The corresponding AddRef is in TiledClient::GetTileDescriptor
sharedLock.get()->Release();
}
}
CompositableTextureSourceRef textureSource;
CompositableTextureSourceRef textureSourceOnWhite;
if (texture) {
texture->SetCompositor(aCompositor);
texture->PrepareTextureSource(textureSource);
}
if (textureOnWhite) {
textureOnWhite->SetCompositor(aCompositor);
textureOnWhite->PrepareTextureSource(textureSourceOnWhite);
}
mRetainedTiles.AppendElement(TileHost(sharedLock,
texture.get(),
textureOnWhite.get(),
textureSource.get(),
textureSourceOnWhite.get()));
break;
}
default:
NS_WARNING("Unrecognised tile descriptor type");
// Fall through
case TileDescriptor::TPlaceholderTileDescriptor :
mRetainedTiles.AppendElement(GetPlaceholderTile());
break;
}
if (texture && !texture->HasInternalBuffer()) {
mHasDoubleBufferedTiles = true;
}
}
}
void
TiledLayerBufferComposite::ReadUnlock()
{
if (!IsValid()) {
return;
}
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
mRetainedTiles[i].ReadUnlock();
}
}
void
TiledLayerBufferComposite::ReleaseTextureHosts()
{
if (!IsValid()) {
return;
}
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
mRetainedTiles[i].mTextureHost = nullptr;
mRetainedTiles[i].mTextureHostOnWhite = nullptr;
mRetainedTiles[i].mTextureSource = nullptr;
mRetainedTiles[i].mTextureSourceOnWhite = nullptr;
}
}
void
TiledLayerBufferComposite::Upload()
{
if(!IsValid()) {
return;
}
// The TextureClients were created with the TextureFlags::IMMEDIATE_UPLOAD flag,
// so calling Update on all the texture hosts will perform the texture upload.
Update(mValidRegion, mPaintedRegion);
ClearPaintedRegion();
}
TileHost
TiledLayerBufferComposite::ValidateTile(TileHost aTile,
const IntPoint& aTileOrigin,
const nsIntRegion& aDirtyRect)
{
if (aTile.IsPlaceholderTile()) {
NS_WARNING("Placeholder tile encountered in painted region");
return aTile;
}
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
printf_stderr("Upload tile %i, %i\n", aTileOrigin.x, aTileOrigin.y);
long start = PR_IntervalNow();
#endif
MOZ_ASSERT(aTile.mTextureHost->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD);
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
MOZ_ASSERT(!aTile.mTextureHostOnWhite);
// We possibly upload the entire texture contents here. This is a purposeful
// decision, as sub-image upload can often be slow and/or unreliable, but
// we may want to reevaluate this in the future.
// For !HasInternalBuffer() textures, this is likely a no-op.
aTile.mTextureHost->Updated(nullptr);
#else
nsIntRegion tileUpdated = aDirtyRect.MovedBy(-aTileOrigin);
aTile.mTextureHost->Updated(&tileUpdated);
if (aTile.mTextureHostOnWhite) {
aTile.mTextureHostOnWhite->Updated(&tileUpdated);
}
#endif
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
if (PR_IntervalNow() - start > 1) {
printf_stderr("Tile Time to upload %i\n", PR_IntervalNow() - start);
}
#endif
return aTile;
}
void
TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
{
MOZ_ASSERT(aCompositor);
if (!IsValid()) {
return;
}
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].mTextureHost->SetCompositor(aCompositor);
if (mRetainedTiles[i].mTextureHostOnWhite) {
mRetainedTiles[i].mTextureHostOnWhite->SetCompositor(aCompositor);
for (TileHost& tile : mRetainedTiles) {
if (tile.IsPlaceholderTile()) continue;
tile.mTextureHost->SetCompositor(aCompositor);
if (tile.mTextureHostOnWhite) {
tile.mTextureHostOnWhite->SetCompositor(aCompositor);
}
}
}
@ -229,10 +59,6 @@ TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
: ContentHost(aTextureInfo)
, mTiledBuffer(TiledLayerBufferComposite())
, mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
, mOldTiledBuffer(TiledLayerBufferComposite())
, mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite())
, mPendingUpload(false)
, mPendingLowPrecisionUpload(false)
{
MOZ_COUNT_CTOR(TiledContentHost);
}
@ -240,28 +66,6 @@ TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
TiledContentHost::~TiledContentHost()
{
MOZ_COUNT_DTOR(TiledContentHost);
// Unlock any buffers that may still be locked. If we have a pending upload,
// we will need to unlock the buffer that was about to be uploaded.
// If a buffer that was being composited had double-buffered tiles, we will
// need to unlock that buffer too.
if (mPendingUpload) {
mTiledBuffer.ReadUnlock();
if (mOldTiledBuffer.HasDoubleBufferedTiles()) {
mOldTiledBuffer.ReadUnlock();
}
} else if (mTiledBuffer.HasDoubleBufferedTiles()) {
mTiledBuffer.ReadUnlock();
}
if (mPendingLowPrecisionUpload) {
mLowPrecisionTiledBuffer.ReadUnlock();
if (mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mOldLowPrecisionTiledBuffer.ReadUnlock();
}
} else if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mLowPrecisionTiledBuffer.ReadUnlock();
}
}
void
@ -277,33 +81,10 @@ TiledContentHost::Detach(Layer* aLayer,
AttachFlags aFlags /* = NO_FLAGS */)
{
if (!mKeepAttached || aLayer == mLayer || aFlags & FORCE_DETACH) {
// Unlock any buffers that may still be locked. If we have a pending upload,
// we will need to unlock the buffer that was about to be uploaded.
// If a buffer that was being composited had double-buffered tiles, we will
// need to unlock that buffer too.
if (mPendingUpload) {
mTiledBuffer.ReadUnlock();
if (mOldTiledBuffer.HasDoubleBufferedTiles()) {
mOldTiledBuffer.ReadUnlock();
}
} else if (mTiledBuffer.HasDoubleBufferedTiles()) {
mTiledBuffer.ReadUnlock();
}
if (mPendingLowPrecisionUpload) {
mLowPrecisionTiledBuffer.ReadUnlock();
if (mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mOldLowPrecisionTiledBuffer.ReadUnlock();
}
} else if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mLowPrecisionTiledBuffer.ReadUnlock();
}
mTiledBuffer = TiledLayerBufferComposite();
mLowPrecisionTiledBuffer = TiledLayerBufferComposite();
mOldTiledBuffer = TiledLayerBufferComposite();
mOldLowPrecisionTiledBuffer = TiledLayerBufferComposite();
// Clear the TiledLayerBuffers, which will take care of releasing the
// copy-on-write locks.
mTiledBuffer.Clear();
mLowPrecisionTiledBuffer.Clear();
}
CompositableHost::Detach(aLayer,aFlags);
}
@ -313,60 +94,280 @@ TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aTiledDescriptor)
{
if (aTiledDescriptor.resolution() < 1) {
if (mPendingLowPrecisionUpload) {
mLowPrecisionTiledBuffer.ReadUnlock();
} else {
mPendingLowPrecisionUpload = true;
// If the old buffer has double-buffered tiles, hang onto it so we can
// unlock it after we've composited the new buffer.
// We only need to hang onto the locks, but not the textures.
// Releasing the textures here can help prevent a memory spike in the
// situation that the client starts rendering new content before we get
// to composite the new buffer.
if (mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mOldLowPrecisionTiledBuffer = mLowPrecisionTiledBuffer;
mOldLowPrecisionTiledBuffer.ReleaseTextureHosts();
}
}
mLowPrecisionTiledBuffer =
TiledLayerBufferComposite(aAllocator,
aTiledDescriptor,
mLowPrecisionTiledBuffer.GetPaintedRegion(),
mCompositor);
if (!mLowPrecisionTiledBuffer.IsValid()) {
// Something bad happened. Stop here, return false (kills the child process),
// and do as little work as possible on the received data as it appears
// to be corrupted.
mPendingLowPrecisionUpload = false;
mPendingUpload = false;
if (!mLowPrecisionTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
return false;
}
} else {
if (mPendingUpload) {
mTiledBuffer.ReadUnlock();
} else {
mPendingUpload = true;
if (mTiledBuffer.HasDoubleBufferedTiles()) {
mOldTiledBuffer = mTiledBuffer;
mOldTiledBuffer.ReleaseTextureHosts();
}
}
mTiledBuffer = TiledLayerBufferComposite(aAllocator,
aTiledDescriptor,
mTiledBuffer.GetPaintedRegion(),
mCompositor);
if (!mTiledBuffer.IsValid()) {
// Something bad happened. Stop here, return false (kills the child process),
// and do as little work as possible on the received data as it appears
// to be corrupted.
mPendingLowPrecisionUpload = false;
mPendingUpload = false;
if (!mTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
return false;
}
}
return true;
}
void
UseTileTexture(CompositableTextureHostRef& aTexture,
CompositableTextureSourceRef& aTextureSource,
const IntRect& aUpdateRect,
TextureHost* aNewTexture,
Compositor* aCompositor)
{
if (aTexture && aTexture->GetFormat() != aNewTexture->GetFormat()) {
// Only reuse textures if their format match the new texture's.
aTextureSource = nullptr;
aTexture = nullptr;
}
aTexture = aNewTexture;
if (aTexture) {
if (aCompositor) {
aTexture->SetCompositor(aCompositor);
}
if (!aUpdateRect.IsEmpty()) {
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
aTexture->Updated(nullptr);
#else
// We possibly upload the entire texture contents here. This is a purposeful
// decision, as sub-image upload can often be slow and/or unreliable, but
// we may want to reevaluate this in the future.
// For !HasInternalBuffer() textures, this is likely a no-op.
nsIntRegion region = aUpdateRect;
aTexture->Updated(&region);
#endif
}
aTexture->PrepareTextureSource(aTextureSource);
}
}
bool
GetCopyOnWriteLock(const TileLock& ipcLock, TileHost& aTile, ISurfaceAllocator* aAllocator) {
MOZ_ASSERT(aAllocator);
nsRefPtr<gfxSharedReadLock> sharedLock;
if (ipcLock.type() == TileLock::TShmemSection) {
sharedLock = gfxShmSharedReadLock::Open(aAllocator, ipcLock.get_ShmemSection());
} else {
if (!aAllocator->IsSameProcess()) {
// Trying to use a memory based lock instead of a shmem based one in
// the cross-process case is a bad security violation.
NS_ERROR("A client process may be trying to peek at the host's address space!");
return false;
}
sharedLock = reinterpret_cast<gfxMemorySharedReadLock*>(ipcLock.get_uintptr_t());
if (sharedLock) {
// The corresponding AddRef is in TiledClient::GetTileDescriptor
sharedLock.get()->Release();
}
}
aTile.mSharedLock = sharedLock;
return true;
}
bool
TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
Compositor* aCompositor,
ISurfaceAllocator* aAllocator)
{
if (mResolution != aTiles.resolution()) {
Clear();
}
MOZ_ASSERT(aAllocator);
MOZ_ASSERT(aCompositor);
if (!aAllocator || !aCompositor) {
return false;
}
if (aTiles.resolution() == 0 || IsNaN(aTiles.resolution())) {
// There are divisions by mResolution so this protects the compositor process
// against malicious content processes and fuzzing.
return false;
}
int newFirstTileX = aTiles.firstTileX();
int newFirstTileY = aTiles.firstTileY();
int oldFirstTileX = mFirstTileX;
int oldFirstTileY = mFirstTileY;
int newRetainedWidth = aTiles.retainedWidth();
int newRetainedHeight = aTiles.retainedHeight();
int oldRetainedWidth = mRetainedWidth;
int oldRetainedHeight = mRetainedHeight;
const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
nsTArray<TileHost> oldTiles;
mRetainedTiles.SwapElements(oldTiles);
mRetainedTiles.SetLength(tileDescriptors.Length());
// Step 1, we need to unlock tiles that don't have an internal buffer after the
// next frame where they are replaced.
// Since we are about to replace the tiles' textures, we need to keep their locks
// somewhere (in mPreviousSharedLock) until we composite the layer.
for (size_t i = 0; i < oldTiles.Length(); ++i) {
TileHost& tile = oldTiles[i];
// It can happen that we still have a previous lock at this point,
// if we changed a tile's front buffer (causing mSharedLock to
// go into mPreviousSharedLock, and then did not composite that tile until
// the next transaction, either because the tile is offscreen or because the
// two transactions happened with no composition in between (over-production).
tile.ReadUnlockPrevious();
if (tile.mTextureHost && !tile.mTextureHost->HasInternalBuffer()) {
MOZ_ASSERT(tile.mSharedLock);
int tileX = i % oldRetainedWidth + oldFirstTileX;
int tileY = i / oldRetainedWidth + oldFirstTileY;
if (tileX >= newFirstTileX && tileY >= newFirstTileY &&
tileX < (newFirstTileX + newRetainedWidth) &&
tileY < (newFirstTileY + newRetainedHeight)) {
// This tile still exist in the new buffer
tile.mPreviousSharedLock = tile.mSharedLock;
tile.mSharedLock = nullptr;
} else {
// This tile does not exist anymore in the new buffer because the size
// changed.
tile.ReadUnlock();
}
}
// By now we should not have anything in mSharedLock.
MOZ_ASSERT(!tile.mSharedLock);
}
// Step 2, move the tiles in mRetainedTiles at places that correspond to where
// they should be with the new retained with and height rather than the
// old one.
for (size_t i = 0; i < tileDescriptors.Length(); i++) {
int tileX = i % newRetainedWidth + newFirstTileX;
int tileY = i / newRetainedWidth + newFirstTileY;
// First, get the already existing tiles to the right place in the array,
// and use placeholders where there was no tiles.
if (tileX < oldFirstTileX || tileY < oldFirstTileY ||
tileX >= (oldFirstTileX + oldRetainedWidth) ||
tileY >= (oldFirstTileY + oldRetainedHeight)) {
mRetainedTiles[i] = GetPlaceholderTile();
} else {
mRetainedTiles[i] = oldTiles[(tileY - oldFirstTileY) * oldRetainedWidth +
(tileX - oldFirstTileX)];
// If we hit this assertion it means we probably mixed something up in the
// logic that tries to reuse tiles on the compositor side. It is most likely
// benign, but we are missing some fast paths so let's try to make it not happen.
MOZ_ASSERT(tileX == mRetainedTiles[i].x && tileY == mRetainedTiles[i].y);
}
}
// It is important to remove the duplicated reference to tiles before calling
// TextureHost::PrepareTextureSource, etc. because depending on the textures
// ref counts we may or may not get some of the fast paths.
oldTiles.Clear();
// Step 3, handle the texture updates and release the copy-on-write locks.
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
const TileDescriptor& tileDesc = tileDescriptors[i];
TileHost& tile = mRetainedTiles[i];
switch (tileDesc.type()) {
case TileDescriptor::TTexturedTileDescriptor: {
const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
const TileLock& ipcLock = texturedDesc.sharedLock();
if (!GetCopyOnWriteLock(ipcLock, tile, aAllocator)) {
return false;
}
RefPtr<TextureHost> textureHost = TextureHost::AsTextureHost(
texturedDesc.textureParent()
);
RefPtr<TextureHost> textureOnWhite = nullptr;
if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
textureOnWhite = TextureHost::AsTextureHost(
texturedDesc.textureOnWhite().get_PTextureParent()
);
}
UseTileTexture(tile.mTextureHost,
tile.mTextureSource,
texturedDesc.updateRect(),
textureHost,
aCompositor);
if (textureOnWhite) {
UseTileTexture(tile.mTextureHostOnWhite,
tile.mTextureSourceOnWhite,
texturedDesc.updateRect(),
textureOnWhite,
aCompositor);
} else {
// We could still have component alpha textures from a previous frame.
tile.mTextureSourceOnWhite = nullptr;
tile.mTextureHostOnWhite = nullptr;
}
if (textureHost->HasInternalBuffer()) {
// Now that we did the texture upload (in UseTileTexture), we can release
// the lock.
tile.ReadUnlock();
}
break;
}
default:
NS_WARNING("Unrecognised tile descriptor type");
case TileDescriptor::TPlaceholderTileDescriptor: {
if (tile.mTextureHost) {
tile.mTextureHost->UnbindTextureSource();
tile.mTextureSource = nullptr;
}
if (tile.mTextureHostOnWhite) {
tile.mTextureHostOnWhite->UnbindTextureSource();
tile.mTextureSourceOnWhite = nullptr;
}
// we may have a previous lock, and are about to loose our reference to it.
// It is okay to unlock it because we just destroyed the texture source.
tile.ReadUnlockPrevious();
tile = GetPlaceholderTile();
break;
}
}
tile.x = i % newRetainedWidth + newFirstTileX;
tile.y = i / newRetainedWidth + newFirstTileY;
}
mFirstTileX = newFirstTileX;
mFirstTileY = newFirstTileY;
mRetainedWidth = newRetainedWidth;
mRetainedHeight = newRetainedHeight;
mValidRegion = aTiles.validRegion();
mResolution = aTiles.resolution();
mFrameResolution = CSSToParentLayerScale2D(aTiles.frameXResolution(),
aTiles.frameYResolution());
return true;
}
void
TiledLayerBufferComposite::Clear()
{
for (TileHost& tile : mRetainedTiles) {
tile.ReadUnlock();
tile.ReadUnlockPrevious();
}
mRetainedTiles.Clear();
mFirstTileX = 0;
mFirstTileY = 0;
mRetainedWidth = 0;
mRetainedHeight = 0;
mValidRegion = nsIntRegion();
mPaintedRegion = nsIntRegion();
mResolution = 1.0;
}
void
TiledContentHost::Composite(EffectChain& aEffectChain,
float aOpacity,
@ -376,25 +377,6 @@ TiledContentHost::Composite(EffectChain& aEffectChain,
const nsIntRegion* aVisibleRegion /* = nullptr */)
{
MOZ_ASSERT(mCompositor);
if (mPendingUpload) {
mTiledBuffer.SetCompositor(mCompositor);
mTiledBuffer.Upload();
// For a single-buffered tiled buffer, Upload will upload the shared memory
// surface to texture memory and we no longer need to read from them.
if (!mTiledBuffer.HasDoubleBufferedTiles()) {
mTiledBuffer.ReadUnlock();
}
}
if (mPendingLowPrecisionUpload) {
mLowPrecisionTiledBuffer.SetCompositor(mCompositor);
mLowPrecisionTiledBuffer.Upload();
if (!mLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mLowPrecisionTiledBuffer.ReadUnlock();
}
}
// Reduce the opacity of the low-precision buffer to make it a
// little more subtle and less jarring. In particular, text
// rendered at low-resolution and scaled tends to look pretty
@ -440,24 +422,11 @@ TiledContentHost::Composite(EffectChain& aEffectChain,
aFilter, aClipRect, *renderRegion, aTransform);
RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aFilter,
aClipRect, *renderRegion, aTransform);
// Now release the old buffer if it had double-buffered tiles, as we can
// guarantee that they're no longer on the screen (and so any locks that may
// have been held have been released).
if (mPendingUpload && mOldTiledBuffer.HasDoubleBufferedTiles()) {
mOldTiledBuffer.ReadUnlock();
mOldTiledBuffer = TiledLayerBufferComposite();
}
if (mPendingLowPrecisionUpload && mOldLowPrecisionTiledBuffer.HasDoubleBufferedTiles()) {
mOldLowPrecisionTiledBuffer.ReadUnlock();
mOldLowPrecisionTiledBuffer = TiledLayerBufferComposite();
}
mPendingUpload = mPendingLowPrecisionUpload = false;
}
void
TiledContentHost::RenderTile(const TileHost& aTile,
TiledContentHost::RenderTile(TileHost& aTile,
const gfxRGBA* aBackgroundColor,
EffectChain& aEffectChain,
float aOpacity,
@ -524,6 +493,7 @@ TiledContentHost::RenderTile(const TileHost& aTile,
}
mCompositor->DrawDiagnostics(flags,
aScreenRegion, aClipRect, aTransform, mFlashCounter);
aTile.ReadUnlockPrevious();
}
void
@ -591,10 +561,10 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
h = visibleRect.y + visibleRect.height - y;
}
TileHost tileTexture = aLayerBuffer.
GetTile(IntPoint(aLayerBuffer.RoundDownToTileEdge(x, scaledTileSize.width),
aLayerBuffer.RoundDownToTileEdge(y, scaledTileSize.height)));
if (tileTexture != aLayerBuffer.GetPlaceholderTile()) {
nsIntPoint tileOrigin = nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x, scaledTileSize.width),
aLayerBuffer.RoundDownToTileEdge(y, scaledTileSize.height));
TileHost& tileTexture = aLayerBuffer.GetTile(tileOrigin);
if (!tileTexture.IsPlaceholderTile()) {
nsIntRegion tileDrawRegion;
tileDrawRegion.And(IntRect(x, y, w, h), aLayerBuffer.GetValidRegion());
tileDrawRegion.And(tileDrawRegion, aVisibleRegion);

View File

@ -52,6 +52,8 @@ public:
// essentially, this is a sentinel used to represent an invalid or blank
// tile.
TileHost()
: x(-1)
, y(-1)
{}
// Constructs a TileHost from a gfxSharedReadLock and TextureHost.
@ -65,6 +67,8 @@ public:
, mTextureHostOnWhite(aTextureHostOnWhite)
, mTextureSource(aSource)
, mTextureSourceOnWhite(aSourceOnWhite)
, x(-1)
, y(-1)
{}
TileHost(const TileHost& o) {
@ -73,6 +77,9 @@ public:
mTextureSource = o.mTextureSource;
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
mSharedLock = o.mSharedLock;
mPreviousSharedLock = o.mPreviousSharedLock;
x = o.x;
y = o.y;
}
TileHost& operator=(const TileHost& o) {
if (this == &o) {
@ -83,6 +90,9 @@ public:
mTextureSource = o.mTextureSource;
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
mSharedLock = o.mSharedLock;
mPreviousSharedLock = o.mPreviousSharedLock;
x = o.x;
y = o.y;
return *this;
}
@ -98,6 +108,14 @@ public:
void ReadUnlock() {
if (mSharedLock) {
mSharedLock->ReadUnlock();
mSharedLock = nullptr;
}
}
void ReadUnlockPrevious() {
if (mPreviousSharedLock) {
mPreviousSharedLock->ReadUnlock();
mPreviousSharedLock = nullptr;
}
}
@ -111,10 +129,14 @@ public:
}
RefPtr<gfxSharedReadLock> mSharedLock;
RefPtr<gfxSharedReadLock> mPreviousSharedLock;
CompositableTextureHostRef mTextureHost;
CompositableTextureHostRef mTextureHostOnWhite;
mutable CompositableTextureSourceRef mTextureSource;
mutable CompositableTextureSourceRef mTextureSourceOnWhite;
// This is not strictly necessary but makes debugging whole lot easier.
int x;
int y;
};
class TiledLayerBufferComposite
@ -123,13 +145,14 @@ class TiledLayerBufferComposite
friend class TiledLayerBuffer<TiledLayerBufferComposite, TileHost>;
public:
typedef TiledLayerBuffer<TiledLayerBufferComposite, TileHost>::Iterator Iterator;
TiledLayerBufferComposite();
TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
const SurfaceDescriptorTiles& aDescriptor,
const nsIntRegion& aOldPaintedRegion,
Compositor* aCompositor);
~TiledLayerBufferComposite();
bool UseTiles(const SurfaceDescriptorTiles& aTileDescriptors,
Compositor* aCompositor,
ISurfaceAllocator* aAllocator);
void Clear();
TileHost GetPlaceholderTile() const { return TileHost(); }
@ -137,43 +160,16 @@ public:
// by the sum of the resolutions of all parent layers' FrameMetrics.
const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; }
void ReadUnlock();
void ReleaseTextureHosts();
/**
* This will synchronously upload any necessary texture contents, making the
* sources immediately available for compositing. For texture hosts that
* don't have an internal buffer, this is unlikely to actually do anything.
*/
void Upload();
void SetCompositor(Compositor* aCompositor);
bool HasDoubleBufferedTiles() { return mHasDoubleBufferedTiles; }
bool IsValid() const { return mIsValid; }
// Recycle callback for TextureHost.
// Used when TiledContentClient is present in client side.
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
protected:
TileHost ValidateTile(TileHost aTile,
const gfx::IntPoint& aTileRect,
const nsIntRegion& dirtyRect);
// do nothing, the desctructor in the texture host takes care of releasing resources
void ReleaseTile(TileHost aTile) {}
void SwapTiles(TileHost& aTileA, TileHost& aTileB) { std::swap(aTileA, aTileB); }
void UnlockTile(TileHost aTile) {}
void PostValidate(const nsIntRegion& aPaintRegion) {}
private:
CSSToParentLayerScale2D mFrameResolution;
bool mHasDoubleBufferedTiles;
bool mIsValid;
};
/**
@ -233,11 +229,10 @@ public:
virtual void SetCompositor(Compositor* aCompositor) override
{
MOZ_ASSERT(aCompositor);
CompositableHost::SetCompositor(aCompositor);
mTiledBuffer.SetCompositor(aCompositor);
mLowPrecisionTiledBuffer.SetCompositor(aCompositor);
mOldTiledBuffer.SetCompositor(aCompositor);
mOldLowPrecisionTiledBuffer.SetCompositor(aCompositor);
}
virtual bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
@ -279,7 +274,7 @@ private:
gfx::Matrix4x4 aTransform);
// Renders a single given tile.
void RenderTile(const TileHost& aTile,
void RenderTile(TileHost& aTile,
const gfxRGBA* aBackgroundColor,
EffectChain& aEffectChain,
float aOpacity,
@ -294,10 +289,6 @@ private:
TiledLayerBufferComposite mTiledBuffer;
TiledLayerBufferComposite mLowPrecisionTiledBuffer;
TiledLayerBufferComposite mOldTiledBuffer;
TiledLayerBufferComposite mOldLowPrecisionTiledBuffer;
bool mPendingUpload;
bool mPendingLowPrecisionUpload;
};
}

View File

@ -315,6 +315,7 @@ union MaybeTexture {
struct TexturedTileDescriptor {
PTexture texture;
MaybeTexture textureOnWhite;
IntRect updateRect;
TileLock sharedLock;
};
@ -330,6 +331,8 @@ struct SurfaceDescriptorTiles {
nsIntRegion validRegion;
nsIntRegion paintedRegion;
TileDescriptor[] tiles;
int firstTileX;
int firstTileY;
int retainedWidth;
int retainedHeight;
float resolution;