Bug 1143575. Make ImageClientSingle handle multiple textures. r=nical

--HG--
extra : commitid : IMpF8V8HNbk
extra : rebase_source : e7748b4daa61d031a092970c793edef38787f974
This commit is contained in:
Robert O'Callahan 2015-07-03 22:37:03 +12:00
parent 7f3db8a464
commit 6111862fcc
10 changed files with 191 additions and 141 deletions

View File

@ -376,6 +376,7 @@ public:
struct OwningImage {
nsRefPtr<Image> mImage;
TimeStamp mTimeStamp;
};
/**
* Copy the current Image list to aImages.

View File

@ -103,7 +103,11 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
}
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());
}
}
@ -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<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

View File

@ -384,7 +384,12 @@ ContentClientRemoteBuffer::Updated(const nsIntRegion& aRegionToDraw,
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(),

View File

@ -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<TextureClient> texture = image->GetTextureClient(this);
nsTArray<Buffer> newBuffers;
nsAutoTArray<CompositableForwarder::TimedTextureClient,4> textures;
AutoRemoveTexture autoRemoveTexture(this);
if (texture != mFrontBuffer) {
autoRemoveTexture.mTexture = mFrontBuffer;
mFrontBuffer = nullptr;
}
for (auto& img : images) {
Image* image = img.mImage;
RefPtr<TextureClient> 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<PlanarYCbCrImage*>(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<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";
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;
}
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<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();
}
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,

View File

@ -106,7 +106,11 @@ public:
AsyncTransactionWaiter* aAsyncTransactionWaiter) override;
protected:
RefPtr<TextureClient> mFrontBuffer;
struct Buffer {
RefPtr<TextureClient> mTextureClient;
int32_t mImageSerial;
};
nsTArray<Buffer> mBuffers;
};
/**

View File

@ -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<TimedTextureClient>& aTextures) = 0;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) = 0;

View File

@ -107,22 +107,22 @@ struct AutoEndTransaction {
};
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());
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));
nsAutoTArray<TimedTexture,4> 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));
}

View File

@ -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<TimedTextureClient>& aTextures) override;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) override;

View File

@ -350,31 +350,32 @@ ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable,
}
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());
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));
nsAutoTArray<TimedTexture,4> 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

View File

@ -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<TimedTextureClient>& aTextures) override;
virtual void UseComponentAlphaTextures(CompositableClient* aCompositable,
TextureClient* aClientOnBlack,
TextureClient* aClientOnWhite) override;