From 6111862fccc94a2335b1b513680bd03dacae7960 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 3 Jul 2015 22:37:03 +1200 Subject: [PATCH] Bug 1143575. Make ImageClientSingle handle multiple textures. r=nical --HG-- extra : commitid : IMpF8V8HNbk extra : rebase_source : e7748b4daa61d031a092970c793edef38787f974 --- gfx/layers/ImageContainer.h | 1 + gfx/layers/client/CanvasClient.cpp | 12 +- gfx/layers/client/ContentClient.cpp | 7 +- gfx/layers/client/ImageClient.cpp | 214 ++++++++++++++----------- gfx/layers/client/ImageClient.h | 6 +- gfx/layers/ipc/CompositableForwarder.h | 15 +- gfx/layers/ipc/ImageBridgeChild.cpp | 24 +-- gfx/layers/ipc/ImageBridgeChild.h | 7 +- gfx/layers/ipc/ShadowLayers.cpp | 39 ++--- gfx/layers/ipc/ShadowLayers.h | 7 +- 10 files changed, 191 insertions(+), 141 deletions(-) diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index 21cbae7e9dad..d0613dffacc4 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -376,6 +376,7 @@ public: struct OwningImage { nsRefPtr mImage; + TimeStamp mTimeStamp; }; /** * Copy the current Image list to aImages. diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 272169610732..dbeeabfe95e6 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -103,7 +103,11 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) } if (updated) { - GetForwarder()->UseTexture(this, mBuffer); + nsAutoTArray 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()); } } @@ -380,7 +384,11 @@ CanvasClientSharedSurface::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) // Add the new TexClient. MOZ_ALWAYS_TRUE( AddTextureClient(mFront) ); - forwarder->UseTexture(this, mFront); + nsAutoTArray textures; + CompositableForwarder::TimedTextureClient* t = textures.AppendElement(); + t->mTextureClient = mFront; + t->mPictureRect = nsIntRect(nsIntPoint(0, 0), mFront->GetSize()); + forwarder->UseTextures(this, textures); } void diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index c424186f615b..d71b54745ddb 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -384,7 +384,12 @@ ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw, mForwarder->UseComponentAlphaTextures(this, mTextureClient, mTextureClientOnWhite); } else { - mForwarder->UseTexture(this, mTextureClient); + nsAutoTArray 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(), diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index fda830ca6471..934c270cdad0 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -113,9 +113,11 @@ 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(); } } @@ -131,107 +133,137 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag } 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 texture = image->GetTextureClient(this); + nsTArray newBuffers; + nsAutoTArray textures; - AutoRemoveTexture autoRemoveTexture(this); - if (texture != mFrontBuffer) { - autoRemoveTexture.mTexture = mFrontBuffer; - mFrontBuffer = nullptr; - } + for (auto& img : images) { + Image* image = img.mImage; + RefPtr texture = image->GetTextureClient(this); - 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(image); - const PlanarYCbCrData* data = ycbcr->GetData(); - if (!data) { - return false; + 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); } - 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(); - - if (image->GetFormat() == ImageFormat::EGLIMAGE) { - EGLImageImage* typedImage = static_cast(image); - texture = new EGLImageTextureClient(GetForwarder(), - mTextureFlags, - typedImage, - size); -#ifdef MOZ_WIDGET_ANDROID - } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { - SurfaceTextureImage* typedImage = static_cast(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 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"; + 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(image); + const PlanarYCbCrData* data = ycbcr->GetData(); + if (!data) { return false; } - MOZ_ASSERT(surface.get()); - dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); + 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(); + + if (image->GetFormat() == ImageFormat::EGLIMAGE) { + EGLImageImage* typedImage = static_cast(image); + texture = new EGLImageTextureClient(GetForwarder(), + mTextureFlags, + typedImage, + size); +#ifdef MOZ_WIDGET_ANDROID + } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) { + SurfaceTextureImage* typedImage = static_cast(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 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(); } - - texture->Unlock(); } - } - if (!texture || !AddTextureClient(texture)) { - return false; + 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()); } - mFrontBuffer = texture; - IntRect pictureRect = image->GetPictureRect(); - GetForwarder()->UseTexture(this, texture, &pictureRect); + GetForwarder()->UseTextures(this, textures); - aContainer->NotifyPaintedImage(image); - texture->SyncWithObject(GetForwarder()->GetSyncObject()); + for (auto& b : mBuffers) { + RemoveTexture(b.mTextureClient); + } + mBuffers.SwapElements(newBuffers); return true; } @@ -246,7 +278,7 @@ ImageClientSingle::AddTextureClient(TextureClient* aTexture) void ImageClientSingle::OnDetach() { - mFrontBuffer = nullptr; + mBuffers.Clear(); } ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags, diff --git a/gfx/layers/client/ImageClient.h b/gfx/layers/client/ImageClient.h index 8bf414ce5f66..0f6aafd7574e 100644 --- a/gfx/layers/client/ImageClient.h +++ b/gfx/layers/client/ImageClient.h @@ -106,7 +106,11 @@ public: AsyncTransactionWaiter* aAsyncTransactionWaiter) override; protected: - RefPtr mFrontBuffer; + struct Buffer { + RefPtr mTextureClient; + int32_t mImageSerial; + }; + nsTArray mBuffers; }; /** diff --git a/gfx/layers/ipc/CompositableForwarder.h b/gfx/layers/ipc/CompositableForwarder.h index 17fb36c50435..bc83f7f812fd 100644 --- a/gfx/layers/ipc/CompositableForwarder.h +++ b/gfx/layers/ipc/CompositableForwarder.h @@ -128,16 +128,17 @@ public: 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& aTextures) = 0; virtual void UseComponentAlphaTextures(CompositableClient* aCompositable, TextureClient* aClientOnBlack, TextureClient* aClientOnWhite) = 0; diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index 7649ce2cda46..fa6fa2ef6d8a 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -107,22 +107,22 @@ struct AutoEndTransaction { }; void -ImageBridgeChild::UseTexture(CompositableClient* aCompositable, - TextureClient* aTexture, - const gfx::IntRect* aPictureRect) +ImageBridgeChild::UseTextures(CompositableClient* aCompositable, + const nsTArray& aTextures) { MOZ_ASSERT(aCompositable); - MOZ_ASSERT(aTexture); MOZ_ASSERT(aCompositable->GetIPDLActor()); - MOZ_ASSERT(aTexture->GetIPDLActor()); - FenceHandle fence = aTexture->GetAcquireFenceHandle(); - IntRect pictureRect = aPictureRect ? *aPictureRect : - IntRect(IntPoint(0, 0), IntSize(aTexture->GetSize())); - nsAutoTArray textures; - textures.AppendElement(TimedTexture(nullptr, aTexture->GetIPDLActor(), - fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()), - TimeStamp(), pictureRect)); + nsAutoTArray textures; + + 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)); } diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 89b3dd4bdaf4..772e7685cf9b 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -217,11 +217,10 @@ public: 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& aTextures) override; virtual void UseComponentAlphaTextures(CompositableClient* aCompositable, TextureClient* aClientOnBlack, TextureClient* aClientOnWhite) override; diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index f4774e17bd20..3c9c6a26c333 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -350,31 +350,32 @@ ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable, } void -ShadowLayerForwarder::UseTexture(CompositableClient* aCompositable, - TextureClient* aTexture, - const nsIntRect* aPictureRect) +ShadowLayerForwarder::UseTextures(CompositableClient* aCompositable, + const nsTArray& aTextures) { MOZ_ASSERT(aCompositable); - MOZ_ASSERT(aTexture); MOZ_ASSERT(aCompositable->GetIPDLActor()); - MOZ_ASSERT(aTexture->GetIPDLActor()); - FenceHandle fence = aTexture->GetAcquireFenceHandle(); - IntRect pictureRect = aPictureRect ? *aPictureRect : - IntRect(nsIntPoint(0, 0), IntSize(aTexture->GetSize())); - nsAutoTArray textures; - textures.AppendElement(TimedTexture(nullptr, aTexture->GetIPDLActor(), - fence.IsValid() ? MaybeFence(fence) : MaybeFence(null_t()), - TimeStamp(), pictureRect)); + nsAutoTArray textures; + + 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 diff --git a/gfx/layers/ipc/ShadowLayers.h b/gfx/layers/ipc/ShadowLayers.h index 24b39ab9ea6e..42bf0d3eabe9 100644 --- a/gfx/layers/ipc/ShadowLayers.h +++ b/gfx/layers/ipc/ShadowLayers.h @@ -229,11 +229,10 @@ public: 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& aTextures) override; virtual void UseComponentAlphaTextures(CompositableClient* aCompositable, TextureClient* aClientOnBlack, TextureClient* aClientOnWhite) override;