From 598ae4efa7e892bfdd2b8c507c6667332a690c76 Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Thu, 28 Nov 2013 10:16:34 +1300 Subject: [PATCH] Bug 893301. Content clients. r=nical --- gfx/layers/CompositorTypes.h | 11 + gfx/layers/client/ClientThebesLayer.cpp | 12 + gfx/layers/client/ContentClient.cpp | 413 +++++++++++++++++++++++- gfx/layers/client/ContentClient.h | 161 ++++++++- gfx/layers/client/TextureClient.h | 8 +- 5 files changed, 599 insertions(+), 6 deletions(-) diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h index 7885568ef64d..8d0ca0475598 100644 --- a/gfx/layers/CompositorTypes.h +++ b/gfx/layers/CompositorTypes.h @@ -64,6 +64,12 @@ const TextureFlags TEXTURE_COPY_PREVIOUS = 1 << 24; // deallocation. // The default behaviour is to deallocate on the host side. const TextureFlags TEXTURE_DEALLOCATE_CLIENT = 1 << 25; +// The host side is responsible for deallocation, but that may not happen +// immediately after the client side requests it. Exactly when the texture is +// deallocated is up to the compositable. The texture must be deallocated by +// the time the compositable or texture host is destroyed. A texture may not +// have both TEXTURE_DEALLOCATE_CLIENT and TEXTURE_DEALLOCATE_DEFERRED flags. +const TextureFlags TEXTURE_DEALLOCATE_DEFERRED = 1 << 26; // After being shared ith the compositor side, an immutable texture is never // modified, it can only be read. It is safe to not Lock/Unlock immutable // textures. @@ -76,6 +82,9 @@ const TextureFlags TEXTURE_IMMEDIATE_UPLOAD = 1 << 28; // buffered pair, and so we can guarantee that the producer/consumer // won't be racing to access its contents. const TextureFlags TEXTURE_DOUBLE_BUFFERED = 1 << 29; +// We've previously tried a texture and it didn't work for some reason. If there +// is a fallback available, try that. +const TextureFlags TEXTURE_ALLOC_FALLBACK = 1 << 31; // the default flags const TextureFlags TEXTURE_FLAGS_DEFAULT = TEXTURE_FRONT; @@ -167,6 +176,8 @@ enum CompositableType BUFFER_TILED, // tiled thebes layer // the new compositable types COMPOSITABLE_IMAGE, // image with single buffering + COMPOSITABLE_CONTENT_SINGLE, // thebes layer interface, single buffering + COMPOSITABLE_CONTENT_DOUBLE, // thebes layer interface, double buffering BUFFER_COUNT }; diff --git a/gfx/layers/client/ClientThebesLayer.cpp b/gfx/layers/client/ClientThebesLayer.cpp index 7dadc3127682..23e971582ee2 100644 --- a/gfx/layers/client/ClientThebesLayer.cpp +++ b/gfx/layers/client/ClientThebesLayer.cpp @@ -106,6 +106,18 @@ ClientThebesLayer::RenderLayer() mContentClient->BeginPaint(); PaintThebes(); mContentClient->EndPaint(); + // It is very important that this is called after EndPaint, because destroying + // textures is a three stage process: + // 1. We are done with the buffer and move it to ContentClient::mOldTextures, + // that happens in DestroyBuffers which is may be called indirectly from + // PaintThebes. + // 2. The content client calls RemoveTextureClient on the texture clients in + // mOldTextures and forgets them. They then become invalid. The compositable + // client keeps a record of IDs. This happens in EndPaint. + // 3. An IPC message is sent to destroy the corresponding texture host. That + // happens from OnTransaction. + // It is important that these steps happen in order. + mContentClient->OnTransaction(); } void diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 8dfbaeaa2a09..e2b90c6fefbb 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -62,15 +62,22 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) } if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) { - return new ContentClientDoubleBuffered(aForwarder); + if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) { + return new ContentClientDoubleBuffered(aForwarder); + } else { + return new ContentClientDoubleBufferedNew(aForwarder); + } } #ifdef XP_MACOSX if (backend == LAYERS_OPENGL) { return new ContentClientIncremental(aForwarder); } #endif - return new ContentClientSingleBuffered(aForwarder); - + if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) { + return new ContentClientSingleBuffered(aForwarder); + } else { + return new ContentClientSingleBufferedNew(aForwarder); + } } // We pass a null pointer for the ContentClient Forwarder argument, which means @@ -97,6 +104,206 @@ ContentClientBasic::CreateBuffer(ContentType aType, ImageFormatToSurfaceFormat(format)); } +void +ContentClientRemoteBufferNew::DestroyBuffers() +{ + if (!mTextureClient) { + return; + } + MOZ_ASSERT(mTextureClient->GetAccessMode() == TextureClient::ACCESS_READ_WRITE); + + mOldTextures.AppendElement(mTextureClient); + mTextureClient = nullptr; + if (mTextureClientOnWhite) { + mOldTextures.AppendElement(mTextureClientOnWhite); + mTextureClientOnWhite = nullptr; + } + + DestroyFrontBuffer(); +} + +void +ContentClientRemoteBufferNew::BeginPaint() +{ + // XXX: So we might not have a DeprecatedTextureClient yet.. because it will + // only be created by CreateBuffer.. which will deliver a locked surface!. + if (mTextureClient) { + SetNewBufferProvider(mTextureClient); + } + if (mTextureClientOnWhite) { + SetNewBufferProviderOnWhite(mTextureClientOnWhite); + } +} + +void +ContentClientRemoteBufferNew::EndPaint() +{ + // XXX: We might still not have a texture client if PaintThebes + // decided we didn't need one yet because the region to draw was empty. + SetNewBufferProvider(nullptr); + SetNewBufferProviderOnWhite(nullptr); + for (size_t i = 0; i < mOldTextures.Length(); ++i) { + RemoveTextureClient(mOldTextures[i]); + } + mOldTextures.Clear(); + + if (mTextureClient) { + mTextureClient->Unlock(); + } + if (mTextureClientOnWhite) { + mTextureClientOnWhite->Unlock(); + } +} + +bool +ContentClientRemoteBufferNew::CreateAndAllocateTextureClient(RefPtr& aClient, + TextureFlags aFlags) +{ + aClient = CreateTextureClientForDrawing(mSurfaceFormat, + mTextureInfo.mTextureFlags | aFlags); + if (!aClient) { + return false; + } + + if (!aClient->AsTextureClientDrawTarget()->AllocateForSurface(mSize)) { + aClient = CreateTextureClientForDrawing(mSurfaceFormat, + mTextureInfo.mTextureFlags | TEXTURE_ALLOC_FALLBACK | aFlags); + if (!aClient) { + return false; + } + if (!aClient->AsTextureClientDrawTarget()->AllocateForSurface(mSize)) { + NS_WARNING("Could not allocate texture client"); + aClient = nullptr; + return false; + } + } + + NS_WARN_IF_FALSE(aClient->IsValid(), "Created an invalid texture client"); + return true; +} + +void +ContentClientRemoteBufferNew::BuildTextureClients(SurfaceFormat aFormat, + const nsIntRect& aRect, + uint32_t aFlags) +{ + // If we hit this assertion, then it might be due to an empty transaction + // followed by a real transaction. Our buffers should be created (but not + // painted in the empty transaction) and then painted (but not created) in the + // real transaction. That is kind of fragile, and this assert will catch + // circumstances where we screw that up, e.g., by unnecessarily recreating our + // buffers. + NS_ABORT_IF_FALSE(!mIsNewBuffer, + "Bad! Did we create a buffer twice without painting?"); + + mIsNewBuffer = true; + + DestroyBuffers(); + + mSurfaceFormat = aFormat; + mSize = gfx::IntSize(aRect.width, aRect.height); + mTextureInfo.mTextureFlags = (aFlags & ~TEXTURE_DEALLOCATE_CLIENT) | + TEXTURE_DEALLOCATE_DEFERRED; + + if (!CreateAndAllocateTextureClient(mTextureClient, TEXTURE_ON_BLACK) || + !AddTextureClient(mTextureClient)) { + AbortTextureClientCreation(); + return; + } + + if (aFlags & BUFFER_COMPONENT_ALPHA) { + if (!CreateAndAllocateTextureClient(mTextureClientOnWhite, TEXTURE_ON_WHITE) || + !AddTextureClient(mTextureClientOnWhite)) { + AbortTextureClientCreation(); + return; + } + mTextureInfo.mTextureFlags |= TEXTURE_COMPONENT_ALPHA; + } + + CreateFrontBuffer(aRect); +} + +void +ContentClientRemoteBufferNew::CreateBuffer(ContentType aType, + const nsIntRect& aRect, + uint32_t aFlags, + RefPtr* aBlackDT, + RefPtr* aWhiteDT) +{ + BuildTextureClients(gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aType), aRect, aFlags); + if (!mTextureClient) { + return; + } + + *aBlackDT = mTextureClient->AsTextureClientDrawTarget()->GetAsDrawTarget(); + if (aFlags & BUFFER_COMPONENT_ALPHA) { + *aWhiteDT = mTextureClientOnWhite->AsTextureClientDrawTarget()->GetAsDrawTarget(); + } +} + +nsIntRegion +ContentClientRemoteBufferNew::GetUpdatedRegion(const nsIntRegion& aRegionToDraw, + const nsIntRegion& aVisibleRegion, + bool aDidSelfCopy) +{ + nsIntRegion updatedRegion; + if (mIsNewBuffer || aDidSelfCopy) { + // A buffer reallocation clears both buffers. The front buffer has all the + // content by now, but the back buffer is still clear. Here, in effect, we + // are saying to copy all of the pixels of the front buffer to the back. + // Also when we self-copied in the buffer, the buffer space + // changes and some changed buffer content isn't reflected in the + // draw or invalidate region (on purpose!). When this happens, we + // need to read back the entire buffer too. + updatedRegion = aVisibleRegion; + mIsNewBuffer = false; + } else { + updatedRegion = aRegionToDraw; + } + + NS_ASSERTION(BufferRect().Contains(aRegionToDraw.GetBounds()), + "Update outside of buffer rect!"); + NS_ABORT_IF_FALSE(mTextureClient, "should have a back buffer by now"); + + return updatedRegion; +} + +void +ContentClientRemoteBufferNew::Updated(const nsIntRegion& aRegionToDraw, + const nsIntRegion& aVisibleRegion, + bool aDidSelfCopy) +{ + nsIntRegion updatedRegion = GetUpdatedRegion(aRegionToDraw, + aVisibleRegion, + aDidSelfCopy); + + MOZ_ASSERT(mTextureClient); + mTextureClient->SetAccessMode(TextureClient::ACCESS_NONE); + if (mTextureClientOnWhite) { + mTextureClientOnWhite->SetAccessMode(TextureClient::ACCESS_NONE); + } + LockFrontBuffer(); + mForwarder->UseTexture(this, mTextureClient); + mForwarder->UpdateTextureRegion(this, + ThebesBufferData(BufferRect(), + BufferRotation()), + updatedRegion); +} + +void +ContentClientRemoteBufferNew::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) +{ + MOZ_ASSERT(mTextureClient->GetAccessMode() == TextureClient::ACCESS_NONE); + MOZ_ASSERT(!mTextureClientOnWhite || mTextureClientOnWhite->GetAccessMode() == TextureClient::ACCESS_NONE); + MOZ_ASSERT(mTextureClient); + + mFrontAndBackBufferDiffer = true; + mTextureClient->SetAccessMode(TextureClient::ACCESS_READ_WRITE); + if (mTextureClientOnWhite) { + mTextureClientOnWhite->SetAccessMode(TextureClient::ACCESS_READ_WRITE); + } +} + void ContentClientRemoteBuffer::DestroyBuffers() { @@ -297,6 +504,178 @@ ContentClientRemoteBuffer::OnActorDestroy() mOldTextures[i]->OnActorDestroy(); } } + +void +ContentClientDoubleBufferedNew::CreateFrontBuffer(const nsIntRect& aBufferRect) +{ + if (!CreateAndAllocateTextureClient(mFrontClient, TEXTURE_ON_BLACK) || + !AddTextureClient(mFrontClient)) { + AbortTextureClientCreation(); + return; + } + if (mTextureInfo.mTextureFlags & TEXTURE_COMPONENT_ALPHA) { + if (!CreateAndAllocateTextureClient(mFrontClientOnWhite, TEXTURE_ON_WHITE) || + !AddTextureClient(mFrontClientOnWhite)) { + AbortTextureClientCreation(); + return; + } + } + + mFrontBufferRect = aBufferRect; + mFrontBufferRotation = nsIntPoint(); +} + +void +ContentClientDoubleBufferedNew::DestroyFrontBuffer() +{ + MOZ_ASSERT(mFrontClient); + MOZ_ASSERT(mFrontClient->GetAccessMode() != TextureClient::ACCESS_NONE); + + mOldTextures.AppendElement(mFrontClient); + mFrontClient = nullptr; + if (mFrontClientOnWhite) { + mOldTextures.AppendElement(mFrontClientOnWhite); + mFrontClientOnWhite = nullptr; + } +} + +void +ContentClientDoubleBufferedNew::LockFrontBuffer() +{ + MOZ_ASSERT(mFrontClient); + mFrontClient->SetAccessMode(TextureClient::ACCESS_NONE); + if (mFrontClientOnWhite) { + mFrontClientOnWhite->SetAccessMode(TextureClient::ACCESS_NONE); + } +} + +void +ContentClientDoubleBufferedNew::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) +{ + mFrontUpdatedRegion = aFrontUpdatedRegion; + + RefPtr oldBack = mTextureClient; + mTextureClient = mFrontClient; + mFrontClient = oldBack; + + oldBack = mTextureClientOnWhite; + mTextureClientOnWhite = mFrontClientOnWhite; + mFrontClientOnWhite = oldBack; + + nsIntRect oldBufferRect = mBufferRect; + mBufferRect = mFrontBufferRect; + mFrontBufferRect = oldBufferRect; + + nsIntPoint oldBufferRotation = mBufferRotation; + mBufferRotation = mFrontBufferRotation; + mFrontBufferRotation = oldBufferRotation; + + MOZ_ASSERT(mFrontClient); + mFrontClient->SetAccessMode(TextureClient::ACCESS_READ_ONLY); + if (mFrontClientOnWhite) { + mFrontClientOnWhite->SetAccessMode(TextureClient::ACCESS_READ_ONLY); + } + + ContentClientRemoteBufferNew::SwapBuffers(aFrontUpdatedRegion); +} + +void +ContentClientDoubleBufferedNew::SyncFrontBufferToBackBuffer() +{ + if (!mFrontAndBackBufferDiffer) { + return; + } + MOZ_ASSERT(mFrontClient); + MOZ_ASSERT(mFrontClient->GetAccessMode() == TextureClient::ACCESS_READ_ONLY); + MOZ_ASSERT(!mFrontClientOnWhite || + mFrontClientOnWhite->GetAccessMode() == TextureClient::ACCESS_READ_ONLY); + + MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back ", + this, + mFrontUpdatedRegion.GetBounds().x, + mFrontUpdatedRegion.GetBounds().y, + mFrontUpdatedRegion.GetBounds().width, + mFrontUpdatedRegion.GetBounds().height)); + + nsIntRegion updateRegion = mFrontUpdatedRegion; + + // This is a tricky trade off, we're going to get stuff out of our + // frontbuffer now, but the next PaintThebes might throw it all (or mostly) + // away if the visible region has changed. This is why in reality we want + // this code integrated with PaintThebes to always do the optimal thing. + + if (mDidSelfCopy) { + mDidSelfCopy = false; + // We can't easily draw our front buffer into us, since we're going to be + // copying stuff around anyway it's easiest if we just move our situation + // to non-rotated while we're at it. If this situation occurs we'll have + // hit a self-copy path in PaintThebes before as well anyway. + mBufferRect.MoveTo(mFrontBufferRect.TopLeft()); + mBufferRotation = nsIntPoint(); + updateRegion = mBufferRect; + } else { + mBufferRect = mFrontBufferRect; + mBufferRotation = mFrontBufferRotation; + } + + mIsNewBuffer = false; + mFrontAndBackBufferDiffer = false; + + // We need to ensure that we lock these two buffers in the same + // order as the compositor to prevent deadlocks. + if (!mFrontClient->Lock(OPEN_READ_ONLY)) { + return; + } + if (mFrontClientOnWhite && + !mFrontClientOnWhite->Lock(OPEN_READ_ONLY)) { + mFrontClient->Unlock(); + return; + } + RefPtr dt = + mFrontClient->AsTextureClientDrawTarget()->GetAsDrawTarget(); + RefPtr dtOnWhite = mFrontClientOnWhite + ? mFrontClientOnWhite->AsTextureClientDrawTarget()->GetAsDrawTarget() + : nullptr; + RotatedBuffer frontBuffer(dt, + dtOnWhite, + mFrontBufferRect, + mFrontBufferRotation); + UpdateDestinationFrom(frontBuffer, updateRegion); + mFrontClient->Unlock(); + if (mFrontClientOnWhite) { + mFrontClientOnWhite->Unlock(); + } +} + +void +ContentClientDoubleBufferedNew::UpdateDestinationFrom(const RotatedBuffer& aSource, + const nsIntRegion& aUpdateRegion) +{ + nsRefPtr destCtx = + GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK); + destCtx->SetOperator(gfxContext::OPERATOR_SOURCE); + + bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion); + if (isClippingCheap) { + gfxUtils::ClipToRegion(destCtx, aUpdateRegion); + } + + aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK, 1.0, OP_SOURCE); + + if (aSource.HaveBufferOnWhite()) { + MOZ_ASSERT(HaveBufferOnWhite()); + nsRefPtr destCtx = + GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE); + destCtx->SetOperator(gfxContext::OPERATOR_SOURCE); + + bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion); + if (isClippingCheap) { + gfxUtils::ClipToRegion(destCtx, aUpdateRegion); + } + + aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE, 1.0, OP_SOURCE); + } +} ContentClientDoubleBuffered::~ContentClientDoubleBuffered() { @@ -530,6 +909,34 @@ ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource, } } +void +ContentClientSingleBufferedNew::SyncFrontBufferToBackBuffer() +{ + if (!mFrontAndBackBufferDiffer) { + return; + } + + RefPtr backBuffer = GetDTBuffer(); + if (!backBuffer && mTextureClient) { + backBuffer = mTextureClient->AsTextureClientDrawTarget()->GetAsDrawTarget(); + } + + RefPtr oldBuffer; + oldBuffer = SetDTBuffer(backBuffer, + mBufferRect, + mBufferRotation); + + backBuffer = GetDTBufferOnWhite(); + if (!backBuffer && mTextureClientOnWhite) { + backBuffer = mTextureClientOnWhite->AsTextureClientDrawTarget()->GetAsDrawTarget(); + } + + oldBuffer = SetDTBufferOnWhite(backBuffer); + + mIsNewBuffer = false; + mFrontAndBackBufferDiffer = false; +} + ContentClientSingleBuffered::~ContentClientSingleBuffered() { if (mDeprecatedTextureClient) { diff --git a/gfx/layers/client/ContentClient.h b/gfx/layers/client/ContentClient.h index 8df768aed6f3..3801108acd0c 100644 --- a/gfx/layers/client/ContentClient.h +++ b/gfx/layers/client/ContentClient.h @@ -178,6 +178,109 @@ public: * If the size or type of our buffer(s) change(s), then we simply destroy and * create them. */ +// Version using new texture clients +class ContentClientRemoteBufferNew : public ContentClientRemote + , protected RotatedContentBuffer +{ + using RotatedContentBuffer::BufferRect; + using RotatedContentBuffer::BufferRotation; +public: + ContentClientRemoteBufferNew(CompositableForwarder* aForwarder) + : ContentClientRemote(aForwarder) + , RotatedContentBuffer(ContainsVisibleBounds) + , mIsNewBuffer(false) + , mFrontAndBackBufferDiffer(false) + , mSurfaceFormat(gfx::FORMAT_B8G8R8A8) + {} + + typedef RotatedContentBuffer::PaintState PaintState; + typedef RotatedContentBuffer::ContentType ContentType; + + virtual void Clear() { RotatedContentBuffer::Clear(); } + PaintState BeginPaintBuffer(ThebesLayer* aLayer, ContentType aContentType, + uint32_t aFlags) + { + return RotatedContentBuffer::BeginPaint(aLayer, aContentType, aFlags); + } + + /** + * Begin/End Paint map a gfxASurface from the texture client + * into the buffer of RotatedBuffer. The surface is only + * valid when the texture client is locked, so is mapped out + * of RotatedContentBuffer when we are done painting. + * None of the underlying buffer attributes (rect, rotation) + * are affected by mapping/unmapping. + */ + virtual void BeginPaint() MOZ_OVERRIDE; + virtual void EndPaint() MOZ_OVERRIDE; + + virtual void Updated(const nsIntRegion& aRegionToDraw, + const nsIntRegion& aVisibleRegion, + bool aDidSelfCopy); + + virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) MOZ_OVERRIDE; + + // Expose these protected methods from the superclass. + virtual const nsIntRect& BufferRect() const + { + return RotatedContentBuffer::BufferRect(); + } + virtual const nsIntPoint& BufferRotation() const + { + return RotatedContentBuffer::BufferRotation(); + } + + virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, + RefPtr* aBlackDT, RefPtr* aWhiteDT) MOZ_OVERRIDE; + + virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE + { + return mTextureInfo; + } + +protected: + void DestroyBuffers(); + + virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw, + const nsIntRegion& aVisibleRegion, + bool aDidSelfCopy); + + void BuildTextureClients(gfx::SurfaceFormat aFormat, + const nsIntRect& aRect, + uint32_t aFlags); + + // Create the front buffer for the ContentClient/Host pair if necessary + // and notify the compositor that we have created the buffer(s). + virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) = 0; + virtual void DestroyFrontBuffer() {} + // We're about to hand off to the compositor, if you've got a back buffer, + // lock it now. + virtual void LockFrontBuffer() {} + + bool CreateAndAllocateTextureClient(RefPtr& aClient, + TextureFlags aFlags = 0); + + virtual void AbortTextureClientCreation() + { + mTextureClient = nullptr; + mTextureClientOnWhite = nullptr; + mIsNewBuffer = false; + } + + RefPtr mTextureClient; + RefPtr mTextureClientOnWhite; + // keep a record of texture clients we have created and need to keep around + // (for RotatedBuffer to access), then unlock and remove them when we are done + // painting. + nsTArray > mOldTextures; + + TextureInfo mTextureInfo; + bool mIsNewBuffer; + bool mFrontAndBackBufferDiffer; + gfx::IntSize mSize; + gfx::SurfaceFormat mSurfaceFormat; +}; + class ContentClientRemoteBuffer : public ContentClientRemote , protected RotatedContentBuffer { @@ -233,8 +336,6 @@ public: virtual void CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, RefPtr* aBlackDT, RefPtr* aWhiteDT) MOZ_OVERRIDE; - void DestroyBuffers(); - virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE { return mTextureInfo; @@ -243,6 +344,8 @@ public: virtual void OnActorDestroy() MOZ_OVERRIDE; protected: + void DestroyBuffers(); + virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw, const nsIntRegion& aVisibleRegion, bool aDidSelfCopy); @@ -286,6 +389,44 @@ protected: * references. In response to the compositor's reply we swap our references * (in SwapBuffers). */ +class ContentClientDoubleBufferedNew : public ContentClientRemoteBufferNew +{ +public: + ContentClientDoubleBufferedNew(CompositableForwarder* aFwd) + : ContentClientRemoteBufferNew(aFwd) + { + mTextureInfo.mCompositableType = COMPOSITABLE_CONTENT_DOUBLE; + } + virtual ~ContentClientDoubleBufferedNew() {} + + virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) MOZ_OVERRIDE; + + virtual void SyncFrontBufferToBackBuffer() MOZ_OVERRIDE; + +protected: + virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) MOZ_OVERRIDE; + virtual void DestroyFrontBuffer() MOZ_OVERRIDE; + virtual void LockFrontBuffer() MOZ_OVERRIDE; + +private: + void UpdateDestinationFrom(const RotatedBuffer& aSource, + const nsIntRegion& aUpdateRegion); + + virtual void AbortTextureClientCreation() MOZ_OVERRIDE + { + mTextureClient = nullptr; + mTextureClientOnWhite = nullptr; + mFrontClient = nullptr; + mFrontClientOnWhite = nullptr; + } + + RefPtr mFrontClient; + RefPtr mFrontClientOnWhite; + nsIntRegion mFrontUpdatedRegion; + nsIntRect mFrontBufferRect; + nsIntPoint mFrontBufferRotation; +}; + class ContentClientDoubleBuffered : public ContentClientRemoteBuffer { public: @@ -326,6 +467,22 @@ private: * kind. We are free to modify the TextureClient once we receive reply from * the compositor. */ +class ContentClientSingleBufferedNew : public ContentClientRemoteBufferNew +{ +public: + ContentClientSingleBufferedNew(CompositableForwarder* aFwd) + : ContentClientRemoteBufferNew(aFwd) + { + mTextureInfo.mCompositableType = COMPOSITABLE_CONTENT_SINGLE; + } + virtual ~ContentClientSingleBufferedNew() {} + + virtual void SyncFrontBufferToBackBuffer() MOZ_OVERRIDE; + +protected: + virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) MOZ_OVERRIDE {} +}; + class ContentClientSingleBuffered : public ContentClientRemoteBuffer { public: diff --git a/gfx/layers/client/TextureClient.h b/gfx/layers/client/TextureClient.h index 9d09d1d36eb3..3eb7812bcdd6 100644 --- a/gfx/layers/client/TextureClient.h +++ b/gfx/layers/client/TextureClient.h @@ -279,6 +279,12 @@ public: virtual bool AllocateForSurface(gfx::IntSize aSize) MOZ_OVERRIDE; + // TextureClientDrawTarget + + virtual TextureClientDrawTarget* AsTextureClientDrawTarget() MOZ_OVERRIDE { return this; } + + virtual TemporaryRef GetAsDrawTarget() MOZ_OVERRIDE; + // TextureClientYCbCr virtual TextureClientYCbCr* AsTextureClientYCbCr() MOZ_OVERRIDE { return this; } @@ -289,7 +295,7 @@ public: gfx::IntSize aCbCrSize, StereoMode aStereoMode) MOZ_OVERRIDE; - gfx::SurfaceFormat GetFormat() const { return mFormat; } + virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; } // XXX - Bug 908196 - Make Allocate(uint32_t) and GetBufferSize() protected. // these two methods should only be called by methods of BufferTextureClient