try: -b do -p linux64-mulet,macosx64,android-api-9,android-api-11,emulator -u reftest -t none
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -89,37 +89,47 @@ namespace layers {
// should always be a factor of the tile length, to avoid tiles covering
// non-integer amounts of pixels.
template<typename Derived, typename Tile>
class TiledLayerBuffer
{
public:
TiledLayerBuffer()
- : mRetainedWidth(0)
+ : mFirstTileX(0)
+ , mFirstTileY(0)
+ , mRetainedWidth(0)
, mRetainedHeight(0)
, mResolution(1)
, mTileSize(gfxPlatform::GetPlatform()->GetTileWidth(), gfxPlatform::GetPlatform()->GetTileHeight())
{}
~TiledLayerBuffer() {}
// Given a tile origin aligned to a multiple of GetScaledTileSize,
// return the tile that describes that region.
// NOTE: To get the valid area of that tile you must intersect
// (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; }
gfx::IntSize GetScaledTileSize() const { return RoundedToInt(gfx::Size(mTileSize) / mResolution); }
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
const nsIntRegion& GetValidRegion() const { return mValidRegion; }
@@ -150,51 +160,49 @@ public:
int RoundDownToTileEdge(int aX, int aTileLength) const { return aX - GetTileStart(aX, aTileLength); }
// Get and set draw scaling. mResolution affects the resolution at which the
// contents of the buffer are drawn. mResolution has no effect on the
// coordinate space of the valid region, but does affect the size of an
// 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;
Iterator TilesBegin() { return mRetainedTiles.Elements(); }
Iterator TilesEnd() { return mRetainedTiles.Elements() + mRetainedTiles.Length(); }
void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml);
protected:
// The implementor should call Update() to change
// the new valid region. This implementation will call
// validateTile on each tile that is dirty, which is left
// 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;
/**
* mRetainedTiles is a rectangular buffer of mRetainedWidth x mRetainedHeight
* stored as column major with the same origin as mValidRegion.GetBounds().
* Any tile that does not intersect mValidRegion is a PlaceholderTile.
* Only the region intersecting with mValidRegion should be read from a tile,
* another other region is assumed to be uninitialized. The contents of the
* tiles is scaled by mResolution.
*/
nsTArray<Tile> mRetainedTiles;
+ int mFirstTileX;
+ int mFirstTileY;
int mRetainedWidth; // in tiles
int mRetainedHeight; // in tiles
float mResolution;
gfx::IntSize mTileSize;
private:
const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
Derived& AsDerived() { return *static_cast<Derived*>(this); }
@@ -244,58 +252,74 @@ static inline int floor_div(int a, int b
int sub;
sub = a ^ b;
// The results of this shift is either 0 or -1.
sub >>= 8*sizeof(int)-1;
return div+sub;
}
}
-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)
{
- // TODO Cache firstTileOriginX/firstTileOriginY
+ if (HasTile(aTileOrigin)) {
+ return mRetainedTiles[TileIndex(aTileOrigin)];
+ }
+ return mPlaceHolderTile;
+}
+
+template<typename Derived, typename Tile> int
+TiledLayerBuffer<Derived, Tile>::TileIndex(const gfx::IntPoint& aTileOrigin) const
+{
// 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
TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
const char* aPrefix,
bool aDumpHtml)
{
nsIntRect visibleRect = GetValidRegion().GetBounds();
gfx::IntSize scaledTileSize = GetScaledTileSize();
for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
int32_t tileStartX = GetTileStart(x, scaledTileSize.width);
int32_t w = scaledTileSize.width - tileStartX;
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";
}
y += h;
}
x += w;
}
@@ -592,15 +616,19 @@ TiledLayerBuffer<Derived, Tile>::Update(
}
#endif
// At this point, oldTileCount should be zero
MOZ_ASSERT(oldTileCount == 0, "Failed to release old tiles");
mRetainedTiles = newRetainedTiles;
mValidRegion = newValidRegion;
+
+ mFirstTileX = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
+ mFirstTileY = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
+
mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
}
} // layers
} // mozilla
#endif // GFX_TILEDLAYERBUFFER_H
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -369,17 +369,17 @@ gfxMemorySharedReadLock::ReadLock()
return PR_ATOMIC_INCREMENT(&mReadCount);
}
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;
}
int32_t
gfxMemorySharedReadLock::GetReadCount()
{
NS_ASSERT_OWNINGTHREAD(gfxMemorySharedReadLock);
@@ -419,17 +419,17 @@ gfxShmSharedReadLock::ReadLock() {
int32_t
gfxShmSharedReadLock::ReadUnlock() {
if (!mAllocSuccess) {
return 0;
}
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);
}
return readCount;
}
int32_t
gfxShmSharedReadLock::GetReadCount() {
@@ -515,16 +515,17 @@ TileClient::TileClient(const TileClient&
{
mBackBuffer.Set(this, o.mBackBuffer);
mBackBufferOnWhite = o.mBackBufferOnWhite;
mFrontBuffer = o.mFrontBuffer;
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
mCompositableClient = o.mCompositableClient;
+ mUpdateRegion = o.mUpdateRegion;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mManager = o.mManager;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
}
@@ -534,16 +535,17 @@ TileClient::operator=(const TileClient&
if (this == &o) return *this;
mBackBuffer.Set(this, o.mBackBuffer);
mBackBufferOnWhite = o.mBackBufferOnWhite;
mFrontBuffer = o.mFrontBuffer;
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
mCompositableClient = o.mCompositableClient;
+ mUpdateRegion = o.mUpdateRegion;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
mManager = o.mManager;
mInvalidFront = o.mInvalidFront;
mInvalidBack = o.mInvalidBack;
return *this;
}
@@ -604,16 +606,18 @@ CopyFrontToBack(TextureClient* aFront,
if (!aBack->Lock(OpenMode::OPEN_READ_WRITE)) {
NS_WARNING("Failed to lock the tile's back buffer");
return false;
}
gfx::IntPoint rectToCopyTopLeft = aRectToCopy.TopLeft();
aFront->CopyToTextureClient(aBack, &aRectToCopy, &rectToCopyTopLeft);
+
+ aFront->Unlock();
return true;
}
void
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
nsIntRegion& aAddPaintedRegion)
{
if (mBackBuffer && mFrontBuffer) {
@@ -700,19 +704,19 @@ TileClient::DiscardBackBuffer()
// Our current back-buffer is still locked by the compositor. This can occur
// when the client is producing faster than the compositor can consume. In
// this case we just want to drop it and not return it to the pool.
mManager->ReportClientLost(*mBackBuffer);
if (mBackBufferOnWhite) {
mManager->ReportClientLost(*mBackBufferOnWhite);
}
} else {
- mManager->ReturnTextureClient(*mBackBuffer);
+ mManager->ReturnTextureClientDeferred(*mBackBuffer);
if (mBackBufferOnWhite) {
- mManager->ReturnTextureClient(*mBackBufferOnWhite);
+ mManager->ReturnTextureClientDeferred(*mBackBufferOnWhite);
}
}
mBackLock->ReadUnlock();
if (mBackBuffer->IsLocked()) {
mBackBuffer->Unlock();
}
if (mBackBufferOnWhite && mBackBufferOnWhite->IsLocked()) {
mBackBufferOnWhite->Unlock();
@@ -811,34 +815,28 @@ TileClient::GetTileDescriptor()
// reference count doesn't go to zero before the host receives the message.
// see TiledLayerBufferComposite::TiledLayerBufferComposite
mFrontLock.get()->AddRef();
}
if (mFrontLock->GetType() == gfxSharedReadLock::TYPE_MEMORY) {
return TexturedTileDescriptor(nullptr, mFrontBuffer->GetIPDLActor(),
mFrontBufferOnWhite ? MaybeTexture(mFrontBufferOnWhite->GetIPDLActor()) : MaybeTexture(null_t()),
+ mUpdateRegion,
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()),
+ mUpdateRegion,
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++) {
if (mRetainedTiles[i].IsPlaceholderTile()) continue;
mRetainedTiles[i].ReadLock();
}
}
void
@@ -868,19 +866,22 @@ ClientTiledLayerBuffer::GetSurfaceDescri
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);
+ mRetainedTiles[i].mUpdateRegion = nsIntRegion();
}
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
- tiles, mRetainedWidth, mRetainedHeight,
+ tiles,
+ mFirstTileX, mFirstTileY,
+ mRetainedWidth, mRetainedHeight,
mResolution, mFrameResolution.xScale,
mFrameResolution.yScale);
}
void
ClientTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
@@ -1131,16 +1132,19 @@ ClientTiledLayerBuffer::ValidateTile(Til
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
aTile.GetBackBuffer(offsetScaledDirtyRegion,
content, mode,
&createdTextureClient, extraPainted,
&backBufferOnWhite);
+ aTile.mUpdateRegion = offsetScaledDirtyRegion;
+ aTile.mUpdateRegion.OrWith(extraPainted);
+
extraPainted.MoveBy(aTileOrigin);
extraPainted.And(extraPainted, mNewValidRegion);
mPaintedRegion.Or(mPaintedRegion, extraPainted);
if (!backBuffer) {
NS_WARNING("Failed to allocate a tile TextureClient");
aTile.DiscardBackBuffer();
aTile.DiscardFrontBuffer();
--- a/gfx/layers/client/TiledContentClient.h
+++ b/gfx/layers/client/TiledContentClient.h
@@ -265,16 +265,17 @@ struct TileClient
RefPtr<TextureClient> mBuffer;
} mBackBuffer;
RefPtr<TextureClient> mBackBufferOnWhite;
RefPtr<TextureClient> mFrontBuffer;
RefPtr<TextureClient> mFrontBufferOnWhite;
RefPtr<gfxSharedReadLock> mBackLock;
RefPtr<gfxSharedReadLock> mFrontLock;
RefPtr<ClientLayerManager> mManager;
+ nsIntRegion mUpdateRegion;
CompositableClient* mCompositableClient;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
TimeStamp mLastUpdate;
#endif
nsIntRegion mInvalidFront;
nsIntRegion mInvalidBack;
nsExpirationState mExpirationState;
@@ -411,18 +412,16 @@ public:
std::numeric_limits<int32_t>::max())
{}
void PaintThebes(const nsIntRegion& aNewValidRegion,
const nsIntRegion& aPaintRegion,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);
- void ReadUnlock();
-
void ReadLock();
void Release();
void DiscardBuffers();
const CSSToParentLayerScale2D& GetFrameResolution() { return mFrameResolution; }
@@ -438,16 +437,25 @@ public:
nsIntRegion& aInvalidRegion,
const nsIntRegion& aOldValidRegion,
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData);
SurfaceDescriptorTiles GetSurfaceDescriptorTiles();
+ void SetResolution(float aResolution) {
+ if (mResolution == aResolution) {
+ return;
+ }
+
+ Update(nsIntRegion(), nsIntRegion());
+ mResolution = aResolution;
+ }
+
protected:
TileClient ValidateTile(TileClient aTile,
const nsIntPoint& aTileRect,
const nsIntRegion& dirtyRect);
void PostValidate(const nsIntRegion& aPaintRegion);
void UnlockTile(TileClient aTile);
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -321,16 +321,17 @@ class TextureHost
friend class AtomicRefCountedWithFinalize<TextureHost>;
public:
explicit TextureHost(TextureFlags aFlags);
protected:
virtual ~TextureHost();
public:
+
/**
* Factory method.
*/
static TemporaryRef<TextureHost> Create(const SurfaceDescriptor& aDesc,
ISurfaceAllocator* aDeallocator,
TextureFlags aFlags);
/**
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -24,382 +24,349 @@ class gfxReusableSurfaceWrapper;
namespace mozilla {
using namespace gfx;
namespace layers {
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);
}
}
}
TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
: ContentHost(aTextureInfo)
, mTiledBuffer(TiledLayerBufferComposite())
, mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
- , mOldTiledBuffer(TiledLayerBufferComposite())
- , mOldLowPrecisionTiledBuffer(TiledLayerBufferComposite())
- , mPendingUpload(false)
- , mPendingLowPrecisionUpload(false)
{
MOZ_COUNT_CTOR(TiledContentHost);
}
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
TiledContentHost::Attach(Layer* aLayer,
Compositor* aCompositor,
AttachFlags aFlags /* = NO_FLAGS */)
{
CompositableHost::Attach(aLayer, aCompositor, aFlags);
}
void
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);
}
bool
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 nsIntRegion& aUpdateRegion,
+ TextureHost* aNewTexture,
+ Compositor* aCompositor)
+{
+ aTexture = aNewTexture;
+ if (aTexture) {
+ if (aCompositor) {
+ aTexture->SetCompositor(aCompositor);
+ }
+
+ if (!aUpdateRegion.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.
+ aTexture->Updated(&aUpdateRegion);
+#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()
+ );
+
+ UseTileTexture(tile.mTextureHost,
+ tile.mTextureSource,
+ texturedDesc.updateRegion(),
+ textureHost,
+ aCompositor);
+
+ MaybeTexture onWhite = texturedDesc.textureOnWhite();
+ if (onWhite.type() == MaybeTexture::TPTextureParent) {
+ RefPtr<TextureHost> textureOnWhite = TextureHost::AsTextureHost(
+ onWhite.get_PTextureParent()
+ );
+ UseTileTexture(tile.mTextureHostOnWhite,
+ tile.mTextureSourceOnWhite,
+ texturedDesc.updateRegion(),
+ textureOnWhite,
+ aCompositor);
+ }
+
+ 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;
+ }
+ 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 (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
+ TileHost& tile = mRetainedTiles[i];
+ 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,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
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
// heavy and this helps mitigate that. When we reduce the opacity
// we also make sure to draw the background color behind the
// reduced-opacity tile so that content underneath doesn't show
// through.
// However, in cases where the background is transparent, or the layer
@@ -435,34 +402,21 @@ TiledContentHost::Composite(EffectChain&
// Render the low and high precision buffers.
RenderLayerBuffer(mLowPrecisionTiledBuffer,
lowPrecisionOpacityReduction < 1.0f ? &backgroundColor : nullptr,
aEffectChain, lowPrecisionOpacityReduction * aOpacity,
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,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion& aScreenRegion,
const IntPoint& aTextureOffset,
@@ -519,16 +473,17 @@ TiledContentHost::RenderTile(const TileH
mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, aOpacity, aTransform);
}
DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
if (aTile.mTextureHostOnWhite) {
flags |= DiagnosticFlags::COMPONENT_ALPHA;
}
mCompositor->DrawDiagnostics(flags,
aScreenRegion, aClipRect, aTransform, mFlashCounter);
+ aTile.ReadUnlockPrevious();
}
void
TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
const gfxRGBA* aBackgroundColor,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Filter& aFilter,
@@ -586,20 +541,20 @@ TiledContentHost::RenderLayerBuffer(Tile
int tileY = 0;
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
int32_t tileStartY = aLayerBuffer.GetTileStart(y, scaledTileSize.height);
int32_t h = scaledTileSize.height - tileStartY;
if (y + h > visibleRect.y + visibleRect.height) {
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);
tileDrawRegion.Sub(tileDrawRegion, maskRegion);
if (!tileDrawRegion.IsEmpty()) {
tileDrawRegion.ScaleRoundOut(resolution, resolution);
IntPoint tileOffset((x - tileStartX) * resolution,
--- a/gfx/layers/composite/TiledContentHost.h
+++ b/gfx/layers/composite/TiledContentHost.h
@@ -47,138 +47,134 @@ struct EffectChain;
class TileHost {
public:
// Constructs a placeholder TileHost. See the comments above
// TiledLayerBuffer for more information on what this is used for;
// 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.
TileHost(gfxSharedReadLock* aSharedLock,
TextureHost* aTextureHost,
TextureHost* aTextureHostOnWhite,
TextureSource* aSource,
TextureSource* aSourceOnWhite)
: mSharedLock(aSharedLock)
, mTextureHost(aTextureHost)
, mTextureHostOnWhite(aTextureHostOnWhite)
, mTextureSource(aSource)
, mTextureSourceOnWhite(aSourceOnWhite)
+ , x(-1)
+ , y(-1)
{}
TileHost(const TileHost& o) {
mTextureHost = o.mTextureHost;
mTextureHostOnWhite = o.mTextureHostOnWhite;
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) {
return *this;
}
mTextureHost = o.mTextureHost;
mTextureHostOnWhite = o.mTextureHostOnWhite;
mTextureSource = o.mTextureSource;
mTextureSourceOnWhite = o.mTextureSourceOnWhite;
mSharedLock = o.mSharedLock;
+ mPreviousSharedLock = o.mPreviousSharedLock;
+ x = o.x;
+ y = o.y;
return *this;
}
bool operator== (const TileHost& o) const {
return mTextureHost == o.mTextureHost;
}
bool operator!= (const TileHost& o) const {
return mTextureHost != o.mTextureHost;
}
bool IsPlaceholderTile() const { return mTextureHost == nullptr; }
void ReadUnlock() {
if (mSharedLock) {
mSharedLock->ReadUnlock();
+ mSharedLock = nullptr;
+ }
+ }
+
+ void ReadUnlockPrevious() {
+ if (mPreviousSharedLock) {
+ mPreviousSharedLock->ReadUnlock();
+ mPreviousSharedLock = nullptr;
}
}
void Dump(std::stringstream& aStream) {
aStream << "TileHost(...)"; // fill in as needed
}
void DumpTexture(std::stringstream& aStream) {
// TODO We should combine the OnWhite/OnBlack here an just output a single image.
CompositableHost::DumpTextureHost(aStream, mTextureHost);
}
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
: public TiledLayerBuffer<TiledLayerBufferComposite, TileHost>
{
friend class TiledLayerBuffer<TiledLayerBufferComposite, TileHost>;
public:
- typedef TiledLayerBuffer<TiledLayerBufferComposite, TileHost>::Iterator Iterator;
+ TiledLayerBufferComposite();
+ ~TiledLayerBufferComposite();
- TiledLayerBufferComposite();
- TiledLayerBufferComposite(ISurfaceAllocator* aAllocator,
- const SurfaceDescriptorTiles& aDescriptor,
- const nsIntRegion& aOldPaintedRegion,
- Compositor* aCompositor);
+ bool UseTiles(const SurfaceDescriptorTiles& aTileDescriptors,
+ Compositor* aCompositor,
+ ISurfaceAllocator* aAllocator);
+
+ void Clear();
TileHost GetPlaceholderTile() const { return TileHost(); }
// Stores the absolute resolution of the containing frame, calculated
// 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;
};
/**
* ContentHost for tiled PaintedLayers. Since tiled layers are special snow
* flakes, we have a unique update process. All the textures that back the
* tiles are added in the usual way, but Updated is called on the host side
* in response to a message that describes the transaction for every tile.
* Composition happens in the normal way.
@@ -228,21 +224,20 @@ public:
const nsIntRegion& GetValidRegion() const override
{
return mTiledBuffer.GetValidRegion();
}
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,
const SurfaceDescriptorTiles& aTiledDescriptor) override;
void Composite(EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
@@ -274,33 +269,29 @@ private:
EffectChain& aEffectChain,
float aOpacity,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
nsIntRegion aMaskRegion,
gfx::Matrix4x4 aTransform);
// Renders a single given tile.
- void RenderTile(const TileHost& aTile,
+ void RenderTile(TileHost& aTile,
const gfxRGBA* aBackgroundColor,
EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion& aScreenRegion,
const gfx::IntPoint& aTextureOffset,
const gfx::IntSize& aTextureBounds);
void EnsureTileStore() {}
TiledLayerBufferComposite mTiledBuffer;
TiledLayerBufferComposite mLowPrecisionTiledBuffer;
- TiledLayerBufferComposite mOldTiledBuffer;
- TiledLayerBufferComposite mOldLowPrecisionTiledBuffer;
- bool mPendingUpload;
- bool mPendingLowPrecisionUpload;
};
}
}
#endif
--- a/gfx/layers/ipc/LayersMessages.ipdlh
+++ b/gfx/layers/ipc/LayersMessages.ipdlh
@@ -310,31 +310,34 @@ union TileLock {
union MaybeTexture {
PTexture;
null_t;
};
struct TexturedTileDescriptor {
PTexture texture;
MaybeTexture textureOnWhite;
+ nsIntRegion updateRegion;
TileLock sharedLock;
};
struct PlaceholderTileDescriptor {
};
union TileDescriptor {
TexturedTileDescriptor;
PlaceholderTileDescriptor;
};
struct SurfaceDescriptorTiles {
nsIntRegion validRegion;
nsIntRegion paintedRegion;
TileDescriptor[] tiles;
+ int firstTileX;
+ int firstTileY;
int retainedWidth;
int retainedHeight;
float resolution;
float frameXResolution;
float frameYResolution;
};
struct OpUseTiledLayerBuffer {