--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -371,16 +371,17 @@ public:
* Returns if the container currently has an image.
* Can be called on any thread. This method takes mReentrantMonitor
* when accessing thread-shared state.
*/
bool HasCurrentImage();
struct OwningImage {
nsRefPtr<Image> mImage;
+ TimeStamp mTimeStamp;
};
/**
* Copy the current Image list to aImages.
* This has to add references since otherwise there are race conditions
* where the current image is destroyed before the caller can add
* a reference.
* Can be called on any thread.
* May return an empty list to indicate there is no current image.
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -98,17 +98,21 @@ CanvasClient2D::Update(gfx::IntSize aSiz
mBuffer->Unlock();
if (bufferCreated && !AddTextureClient(mBuffer)) {
mBuffer = nullptr;
return;
}
if (updated) {
- GetForwarder()->UseTexture(this, mBuffer);
+ nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
+ CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
+ t->mTextureClient = mBuffer;
+ t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mBuffer->GetSize());
+ GetForwarder()->UseTextures(this, textures);
mBuffer->SyncWithObject(GetForwarder()->GetSyncObject());
}
}
already_AddRefed<TextureClient>
CanvasClient2D::CreateTextureClientForCanvas(gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
TextureFlags aFlags,
@@ -375,17 +379,21 @@ CanvasClientSharedSurface::Update(gfx::I
}
}
mFront = newFront;
// Add the new TexClient.
MOZ_ALWAYS_TRUE( AddTextureClient(mFront) );
- forwarder->UseTexture(this, mFront);
+ nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
+ CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
+ t->mTextureClient = mFront;
+ t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize());
+ forwarder->UseTextures(this, textures);
}
void
CanvasClientSharedSurface::ClearSurfaces()
{
mFront = nullptr;
mShSurfClient = nullptr;
mReadbackClient = nullptr;
--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -379,17 +379,22 @@ ContentClientRemoteBuffer::Updated(const
aVisibleRegion,
aDidSelfCopy);
MOZ_ASSERT(mTextureClient);
if (mTextureClientOnWhite) {
mForwarder->UseComponentAlphaTextures(this, mTextureClient,
mTextureClientOnWhite);
} else {
- mForwarder->UseTexture(this, mTextureClient);
+ nsAutoTArray<CompositableForwarder::TimedTextureClient,1> textures;
+ CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
+ t->mTextureClient = mTextureClient;
+ IntSize size = mTextureClient->GetSize();
+ t->mPictureRect = nsIntRect(0, 0, size.width, size.height);
+ GetForwarder()->UseTextures(this, textures);
}
mForwarder->UpdateTextureRegion(this,
ThebesBufferData(BufferRect(),
BufferRotation()),
updatedRegion);
}
void
--- a/gfx/layers/client/ImageClient.cpp
+++ b/gfx/layers/client/ImageClient.cpp
@@ -108,150 +108,182 @@ TextureInfo ImageClientSingle::GetTextur
{
return TextureInfo(CompositableType::IMAGE);
}
void
ImageClientSingle::FlushAllImages(bool aExceptFront,
AsyncTransactionWaiter* aAsyncTransactionWaiter)
{
- if (!aExceptFront && mFrontBuffer) {
- RemoveTextureWithWaiter(mFrontBuffer, aAsyncTransactionWaiter);
- mFrontBuffer = nullptr;
+ if (!aExceptFront) {
+ for (auto& b : mBuffers) {
+ RemoveTextureWithWaiter(b.mTextureClient, aAsyncTransactionWaiter);
+ }
+ mBuffers.Clear();
}
}
bool
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
{
nsAutoTArray<ImageContainer::OwningImage,4> images;
uint32_t generationCounter;
aContainer->GetCurrentImages(&images, &generationCounter);
if (mLastUpdateGenerationCounter == generationCounter) {
return true;
}
mLastUpdateGenerationCounter = generationCounter;
- Image* image = images[0].mImage;
- // Don't try to update to an invalid image. We return true because the caller
- // would attempt to recreate the ImageClient otherwise, and that isn't going
- // to help.
- if (!image->IsValid()) {
+ for (int32_t i = images.Length() - 1; i >= 0; --i) {
+ if (!images[i].mImage->IsValid()) {
+ // Don't try to update to an invalid image.
+ images.RemoveElementAt(i);
+ }
+ }
+ if (images.IsEmpty()) {
+ // We return true because the caller would attempt to recreate the
+ // ImageClient otherwise, and that isn't going to help.
return true;
}
- RefPtr<TextureClient> texture = image->GetTextureClient(this);
+ nsTArray<Buffer> newBuffers;
+ nsAutoTArray<CompositableForwarder::TimedTextureClient,4> textures;
+
+ for (auto& img : images) {
+ Image* image = img.mImage;
+ RefPtr<TextureClient> texture = image->GetTextureClient(this);
+
+ for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
+ if (mBuffers[i].mImageSerial == image->GetSerial()) {
+ if (texture) {
+ MOZ_ASSERT(texture == mBuffers[i].mTextureClient);
+ } else {
+ texture = mBuffers[i].mTextureClient;
+ }
+ // Remove this element from mBuffers so mBuffers only contains
+ // images that aren't present in 'images'
+ mBuffers.RemoveElementAt(i);
+ }
+ }
+
+ if (!texture) {
+ // Slow path, we should not be hitting it very often and if we do it means
+ // we are using an Image class that is not backed by textureClient and we
+ // should fix it.
+ if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
+ PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
+ const PlanarYCbCrData* data = ycbcr->GetData();
+ if (!data) {
+ return false;
+ }
+ texture = TextureClient::CreateForYCbCr(GetForwarder(),
+ data->mYSize, data->mCbCrSize, data->mStereoMode,
+ TextureFlags::DEFAULT | mTextureFlags
+ );
+ if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
+ return false;
+ }
+ bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
+ MOZ_ASSERT(status);
+
+ texture->Unlock();
+ if (!status) {
+ return false;
+ }
+
+ } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
+ image->GetFormat() == ImageFormat::EGLIMAGE) {
+ gfx::IntSize size = image->GetSize();
- AutoRemoveTexture autoRemoveTexture(this);
- if (texture != mFrontBuffer) {
- autoRemoveTexture.mTexture = mFrontBuffer;
- mFrontBuffer = nullptr;
+ if (image->GetFormat() == ImageFormat::EGLIMAGE) {
+ EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
+ texture = new EGLImageTextureClient(GetForwarder(),
+ mTextureFlags,
+ typedImage,
+ size);
+#ifdef MOZ_WIDGET_ANDROID
+ } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
+ SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
+ const SurfaceTextureImage::Data* data = typedImage->GetData();
+ texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
+ data->mSurfTex, size,
+ data->mOriginPos);
+#endif
+ } else {
+ MOZ_ASSERT(false, "Bad ImageFormat.");
+ }
+ } else {
+ RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
+ MOZ_ASSERT(surface);
+ texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
+ gfx::BackendType::NONE, mTextureFlags);
+ if (!texture) {
+ return false;
+ }
+
+ MOZ_ASSERT(texture->CanExposeDrawTarget());
+
+ if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
+ return false;
+ }
+
+ {
+ // We must not keep a reference to the DrawTarget after it has been unlocked.
+ DrawTarget* dt = texture->BorrowDrawTarget();
+ if (!dt) {
+ gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
+ return false;
+ }
+ MOZ_ASSERT(surface.get());
+ dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
+ }
+
+ texture->Unlock();
+ }
+ }
+ if (!texture || !AddTextureClient(texture)) {
+ return false;
+ }
+
+
+ CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
+ t->mTextureClient = texture;
+ t->mTimeStamp = img.mTimeStamp;
+ t->mPictureRect = image->GetPictureRect();
+
+ Buffer* newBuf = newBuffers.AppendElement();
+ newBuf->mImageSerial = image->GetSerial();
+ newBuf->mTextureClient = texture;
+
+ aContainer->NotifyPaintedImage(image);
+ texture->SyncWithObject(GetForwarder()->GetSyncObject());
}
- if (!texture) {
- // Slow path, we should not be hitting it very often and if we do it means
- // we are using an Image class that is not backed by textureClient and we
- // should fix it.
- if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
- PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
- const PlanarYCbCrData* data = ycbcr->GetData();
- if (!data) {
- return false;
- }
- texture = TextureClient::CreateForYCbCr(GetForwarder(),
- data->mYSize, data->mCbCrSize, data->mStereoMode,
- TextureFlags::DEFAULT | mTextureFlags
- );
- if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
- return false;
- }
- bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
- MOZ_ASSERT(status);
-
- texture->Unlock();
- if (!status) {
- return false;
- }
-
- } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
- image->GetFormat() == ImageFormat::EGLIMAGE) {
- gfx::IntSize size = image->GetSize();
+ GetForwarder()->UseTextures(this, textures);
- if (image->GetFormat() == ImageFormat::EGLIMAGE) {
- EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
- texture = new EGLImageTextureClient(GetForwarder(),
- mTextureFlags,
- typedImage,
- size);
-#ifdef MOZ_WIDGET_ANDROID
- } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
- SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
- const SurfaceTextureImage::Data* data = typedImage->GetData();
- texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
- data->mSurfTex, size,
- data->mOriginPos);
-#endif
- } else {
- MOZ_ASSERT(false, "Bad ImageFormat.");
- }
- } else {
- RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
- MOZ_ASSERT(surface);
- texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
- gfx::BackendType::NONE, mTextureFlags);
- if (!texture) {
- return false;
- }
-
- MOZ_ASSERT(texture->CanExposeDrawTarget());
-
- if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
- return false;
- }
-
- {
- // We must not keep a reference to the DrawTarget after it has been unlocked.
- DrawTarget* dt = texture->BorrowDrawTarget();
- if (!dt) {
- gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
- return false;
- }
- MOZ_ASSERT(surface.get());
- dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
- }
-
- texture->Unlock();
- }
+ for (auto& b : mBuffers) {
+ RemoveTexture(b.mTextureClient);
}
- if (!texture || !AddTextureClient(texture)) {
- return false;
- }
-
- mFrontBuffer = texture;
- IntRect pictureRect = image->GetPictureRect();
- GetForwarder()->UseTexture(this, texture, &pictureRect);
-
- aContainer->NotifyPaintedImage(image);
- texture->SyncWithObject(GetForwarder()->GetSyncObject());
+ mBuffers.SwapElements(newBuffers);
return true;
}
bool
ImageClientSingle::AddTextureClient(TextureClient* aTexture)
{
MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
return CompositableClient::AddTextureClient(aTexture);
}
void
ImageClientSingle::OnDetach()
{
- mFrontBuffer = nullptr;
+ mBuffers.Clear();
}
ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
CompositableType aType)
: CompositableClient(aFwd, aFlags)
, mLayer(nullptr)
, mType(aType)
, mLastUpdateGenerationCounter(0)
--- a/gfx/layers/client/ImageClient.h
+++ b/gfx/layers/client/ImageClient.h
@@ -101,17 +101,21 @@ public:
virtual TextureInfo GetTextureInfo() const override;
virtual already_AddRefed<Image> CreateImage(ImageFormat aFormat) override;
virtual void FlushAllImages(bool aExceptFront,
AsyncTransactionWaiter* aAsyncTransactionWaiter) override;
protected:
- RefPtr<TextureClient> mFrontBuffer;
+ struct Buffer {
+ RefPtr<TextureClient> mTextureClient;
+ int32_t mImageSerial;
+ };
+ nsTArray<Buffer> mBuffers;
};
/**
* Image class to be used for async image uploads using the image bridge
* protocol.
* We store the ImageBridge id in the TextureClientIdentifier.
*/
class ImageClientBridge : public ImageClient
--- a/gfx/layers/ipc/CompositableForwarder.h
+++ b/gfx/layers/ipc/CompositableForwarder.h
@@ -123,26 +123,27 @@ public:
* Forcibly remove texture data from TextureClient
* This function needs to be called after a tansaction with Compositor.
*/
virtual void RemoveTexturesIfNecessary()
{
mTexturesToRemove.Clear();
}
+ struct TimedTextureClient {
+ TextureClient* mTextureClient;
+ TimeStamp mTimeStamp;
+ nsIntRect mPictureRect;
+ };
/**
- * Tell the CompositableHost on the compositor side what texture to use for
+ * Tell the CompositableHost on the compositor side what textures to use for
* the next composition.
- * If non-null, aPictureRect is the area of the texture which makes up the
- * image. That is, the area that should be composited. In texture space.
- * When aPictureRect is null, the entire area of the texture is used.
*/
- virtual void UseTexture(CompositableClient* aCompositable,
- TextureClient* aClient,
- const nsIntRect* aPictureRect = nullptr) = 0;
+ virtual void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) = 0;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) = 0;
virtual void SendPendingAsyncMessges() = 0;
void IdentifyTextureHost(const TextureFactoryIdentifier& aIdentifier);
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -99,32 +99,32 @@ struct CompositableTransaction
struct AutoEndTransaction {
explicit AutoEndTransaction(CompositableTransaction* aTxn) : mTxn(aTxn) {}
~AutoEndTransaction() { mTxn->End(); }
CompositableTransaction* mTxn;
};
void
-ImageBridgeChild::UseTexture(CompositableClient* aCompositable,
- TextureClient* aTexture,
- const gfx::IntRect* aPictureRect)
+ImageBridgeChild::UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures)
{
MOZ_ASSERT(aCompositable);
- MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
- MOZ_ASSERT(aTexture->GetIPDLActor());
+
+ nsAutoTArray<TimedTexture,4> textures;
- FenceHandle fence = aTexture->GetAcquireFenceHandle();
- IntRect pictureRect = aPictureRect ? *aPictureRect :
- IntRect(IntPoint(0, 0), IntSize(aTexture->GetSize()));
- nsAutoTArray<TimedTexture,1> textures;
- textures.AppendElement(TimedTexture(nullptr, aTexture->GetIPDLActor(),
- fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()),
- TimeStamp(), pictureRect));
+ for (auto& t : aTextures) {
+ MOZ_ASSERT(t.mTextureClient);
+ MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
+ FenceHandle fence = t.mTextureClient->GetAcquireFenceHandle();
+ textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
+ fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()),
+ t.mTimeStamp, t.mPictureRect));
+ }
mTxn->AddNoSwapEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
textures));
}
void
ImageBridgeChild::UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aTextureOnBlack,
TextureClient* aTextureOnWhite)
--- a/gfx/layers/ipc/ImageBridgeChild.h
+++ b/gfx/layers/ipc/ImageBridgeChild.h
@@ -206,21 +206,20 @@ public:
// CompositableForwarder
virtual void Connect(CompositableClient* aCompositable) override;
virtual bool IsImageBridgeChild() const override { return true; }
/**
- * See CompositableForwarder::UseTexture
+ * See CompositableForwarder::UseTextures
*/
- virtual void UseTexture(CompositableClient* aCompositable,
- TextureClient* aClient,
- const nsIntRect* aPictureRect = nullptr) override;
+ virtual void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) override;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) override;
#ifdef MOZ_WIDGET_GONK
virtual void UseOverlaySource(CompositableClient* aCompositable,
const OverlaySource& aOverlay,
const nsIntRect& aPictureRect) override;
#endif
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -345,41 +345,42 @@ ShadowLayerForwarder::UpdateTextureRegio
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aCompositable->GetIPDLActor());
mTxn->AddPaint(OpPaintTextureRegion(nullptr, aCompositable->GetIPDLActor(),
aThebesBufferData,
aUpdatedRegion));
}
void
-ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable,
- TextureClient* aTexture,
- const nsIntRect* aPictureRect)
+ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures)
{
MOZ_ASSERT(aCompositable);
- MOZ_ASSERT(aTexture);
MOZ_ASSERT(aCompositable->GetIPDLActor());
- MOZ_ASSERT(aTexture->GetIPDLActor());
+
+ nsAutoTArray<TimedTexture,4> textures;
- FenceHandle fence = aTexture->GetAcquireFenceHandle();
- IntRect pictureRect = aPictureRect ? *aPictureRect :
- IntRect(nsIntPoint(0, 0), IntSize(aTexture->GetSize()));
- nsAutoTArray<TimedTexture,1> textures;
- textures.AppendElement(TimedTexture(nullptr, aTexture->GetIPDLActor(),
- fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()),
- TimeStamp(), pictureRect));
+ for (auto& t : aTextures) {
+ MOZ_ASSERT(t.mTextureClient);
+ MOZ_ASSERT(t.mTextureClient->GetIPDLActor());
+ FenceHandle fence = t.mTextureClient->GetAcquireFenceHandle();
+ textures.AppendElement(TimedTexture(nullptr, t.mTextureClient->GetIPDLActor(),
+ fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()),
+ t.mTimeStamp, t.mPictureRect));
+ if ((t.mTextureClient->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD)
+ && t.mTextureClient->HasInternalBuffer()) {
+
+ // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
+ // race with updates on the main thread. In this case we want the transaction
+ // to be synchronous.
+ mTxn->MarkSyncTransaction();
+ }
+ }
mTxn->AddEdit(OpUseTexture(nullptr, aCompositable->GetIPDLActor(),
textures));
- if (aTexture->GetFlags() & TextureFlags::IMMEDIATE_UPLOAD
- && aTexture->HasInternalBuffer()) {
- // We use IMMEDIATE_UPLOAD when we want to be sure that the upload cannot
- // race with updates on the main thread. In this case we want the transaction
- // to be synchronous.
- mTxn->MarkSyncTransaction();
- }
}
void
ShadowLayerForwarder::UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aTextureOnBlack,
TextureClient* aTextureOnWhite)
{
MOZ_ASSERT(aCompositable);
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -224,21 +224,20 @@ public:
* Communicate to the compositor that aRegion in the texture identified by aLayer
* and aIdentifier has been updated to aThebesBuffer.
*/
virtual void UpdateTextureRegion(CompositableClient* aCompositable,
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) override;
/**
- * See CompositableForwarder::UseTexture
+ * See CompositableForwarder::UseTextures
*/
- virtual void UseTexture(CompositableClient* aCompositable,
- TextureClient* aClient,
- const nsIntRect* aPictureRect = nullptr) override;
+ virtual void UseTextures(CompositableClient* aCompositable,
+ const nsTArray<TimedTextureClient>& aTextures) override;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) override;
#ifdef MOZ_WIDGET_GONK
virtual void UseOverlaySource(CompositableClient* aCompositable,
const OverlaySource& aOverlay,
const nsIntRect& aPictureRect) override;
#endif