--- a/gfx/layers/client/ContentClient.cpp
+++ b/gfx/layers/client/ContentClient.cpp
@@ -144,58 +144,55 @@ ContentClient::BeginPaint(PaintedLayer*
dest.mValidRegion);
if (result.mRegionToDraw.IsEmpty())
return result;
OpenMode lockMode = aFlags & PAINT_ASYNC ? OpenMode::OPEN_READ_ASYNC_WRITE
: OpenMode::OPEN_READ_WRITE;
- if (mBuffer) {
- if (mBuffer->Lock(lockMode)) {
- // Do not modify result.mRegionToDraw or result.mContentType after this call.
- // Do not modify the back buffer's bufferRect, bufferRotation, or didSelfCopy.
- FinalizeFrame(result.mRegionToDraw);
- } else {
- // Abandon everything and redraw it all. Ideally we'd reallocate and copy
- // the old to the new and then call FinalizeFrame on the new buffer so that
- // we only need to draw the latest bits, but we need a big refactor to support
- // that ordering.
- result.mRegionToDraw = dest.mNeededRegion;
- dest.mCanReuseBuffer = false;
- Clear();
- }
- }
-
// We need to disable rotation if we're going to be resampled when
// drawing, because we might sample across the rotation boundary.
// Also disable buffer rotation when using webrender.
bool canHaveRotation = gfxPlatform::BufferRotationEnabled() &&
!(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
!(aLayer->Manager()->AsWebRenderLayerManager());
bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
IntRect drawBounds = result.mRegionToDraw.GetBounds();
if (dest.mCanReuseBuffer) {
MOZ_ASSERT(mBuffer);
- if (!mBuffer->AdjustTo(dest.mBufferRect,
- drawBounds,
- canHaveRotation,
- canDrawRotated)) {
+ if (mBuffer->Lock(lockMode)) {
+ // Do not modify result.mRegionToDraw or result.mContentType after this call.
+ // Do not modify the back buffer's bufferRect, bufferRotation, or didSelfCopy.
+ FinalizeFrame(result.mRegionToDraw);
+
+ if (!mBuffer->AdjustTo(dest.mBufferRect,
+ drawBounds,
+ canHaveRotation,
+ canDrawRotated)) {
+ dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
+ dest.mCanReuseBuffer = false;
+ dest.mMustRemoveFrontBuffer = true;
+ mBuffer->Unlock();
+ }
+ } else {
dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
dest.mCanReuseBuffer = false;
+ dest.mMustRemoveFrontBuffer = true;
}
}
NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
"If we're resampling, we need to validate the entire buffer");
- // The buffer's not big enough, changed content, or we failed to unrotate it,
- // so we need to allocate a new one and prepare it for drawing
+ // We never had a buffer, the buffer wasn't big enough, the content changed
+ // types, or we failed to unrotate the buffer when requested. In any case,
+ // we need to allocate a new one and prepare it for drawing.
if (!dest.mCanReuseBuffer) {
uint32_t bufferFlags = 0;
if (dest.mBufferMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
bufferFlags |= BUFFER_COMPONENT_ALPHA;
}
RefPtr<RotatedBuffer> newBuffer = CreateBuffer(result.mContentType,
dest.mBufferRect,
@@ -204,39 +201,39 @@ ContentClient::BeginPaint(PaintedLayer*
if (!newBuffer) {
if (Factory::ReasonableSurfaceSize(IntSize(dest.mBufferRect.Width(), dest.mBufferRect.Height()))) {
gfxCriticalNote << "Failed buffer for "
<< dest.mBufferRect.x << ", "
<< dest.mBufferRect.y << ", "
<< dest.mBufferRect.Width() << ", "
<< dest.mBufferRect.Height();
}
- Clear();
return result;
}
if (!newBuffer->Lock(lockMode)) {
gfxCriticalNote << "Failed to lock new back buffer.";
- Clear();
return result;
}
- // If we have an existing back buffer, copy it into the new back buffer
- if (mBuffer) {
- newBuffer->UpdateDestinationFrom(*mBuffer, newBuffer->BufferRect());
+ // If we have an existing front buffer, copy it into the new back buffer
+ if (RefPtr<RotatedBuffer> frontBuffer = GetFrontBuffer()) {
+ if (frontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
+ newBuffer->UpdateDestinationFrom(*frontBuffer, newBuffer->BufferRect());
+ frontBuffer->Unlock();
+ } else {
+ gfxCriticalNote << "Failed to copy front buffer to back buffer.";
+ return result;
+ }
- // We are done with the old back buffer now and it is about to be
- // destroyed, so unlock it
- mBuffer->Unlock();
+ if (dest.mMustRemoveFrontBuffer) {
+ Clear();
+ }
}
- // Ensure our reference to the front buffer is released
- // as well as the old back buffer
- Clear();
-
mBuffer = newBuffer;
}
NS_ASSERTION(canHaveRotation || mBuffer->BufferRotation() == IntPoint(0,0),
"Rotation disabled, but we have nonzero rotation?");
nsIntRegion invalidate;
invalidate.Sub(aLayer->GetValidRegion(), dest.mBufferRect);
@@ -363,24 +360,27 @@ ContentClient::PrepareDrawTargetForPaint
ContentClient::BufferDecision
ContentClient::CalculateBufferForPaint(PaintedLayer* aLayer,
uint32_t aFlags)
{
gfxContentType layerContentType =
aLayer->CanUseOpaqueSurface() ? gfxContentType::COLOR :
gfxContentType::COLOR_ALPHA;
+ RefPtr<RotatedBuffer> frontBuffer = GetFrontBuffer();
+
SurfaceMode mode;
gfxContentType contentType;
IntRect destBufferRect;
nsIntRegion neededRegion;
nsIntRegion validRegion = aLayer->GetValidRegion();
bool canReuseBuffer = !!mBuffer;
bool canKeepBufferContents = true;
+ bool mustRemoveFrontBuffer = false;
while (true) {
mode = aLayer->GetSurfaceMode();
neededRegion = aLayer->GetVisibleRegion().ToUnknownRegion();
canReuseBuffer = canReuseBuffer && ValidBufferSize(mBufferSizePolicy,
mBuffer->BufferRect().Size(),
neededRegion.GetBounds().Size());
contentType = layerContentType;
@@ -392,18 +392,32 @@ ContentClient::CalculateBufferForPaint(P
} else if (neededRegion.GetBounds().Size() <= mBuffer->BufferRect().Size()) {
// The buffer's big enough but doesn't contain everything that's
// going to be visible. We'll move it.
destBufferRect = IntRect(neededRegion.GetBounds().TopLeft(), mBuffer->BufferRect().Size());
} else {
destBufferRect = neededRegion.GetBounds();
}
} else {
- // We won't be reusing the buffer. Compute a new rect.
- destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+ // We won't be reusing the buffer. Compute a new rect.
+ if (frontBuffer) {
+ // We must create a buffer that is the same size as the front buffer,
+ // or else we need to remove the front buffer
+ if (ValidBufferSize(mBufferSizePolicy,
+ frontBuffer->BufferRect().Size(),
+ neededRegion.GetBounds().Size())) {
+ destBufferRect = frontBuffer->BufferRect();
+ destBufferRect.MoveTo(neededRegion.GetBounds().TopLeft());
+ } else {
+ destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+ mustRemoveFrontBuffer = true;
+ }
+ } else {
+ destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
+ }
}
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
#if defined(MOZ_GFX_OPTIMIZE_MOBILE)
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
#else
if (!aLayer->GetParent() ||
!aLayer->GetParent()->SupportsComponentAlphaChildren() ||
@@ -428,21 +442,21 @@ ContentClient::CalculateBufferForPaint(P
// We need to validate the entire buffer, to make sure that only valid
// pixels are sampled.
neededRegion = destBufferRect;
}
// If we have an existing buffer, but the content type has changed or we
// have transitioned into/out of component alpha, then we need to recreate it.
- if (canKeepBufferContents &&
- mBuffer &&
- (contentType != mBuffer->GetContentType() ||
- (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mBuffer->HaveBufferOnWhite()))
- {
+ bool needsComponentAlpha = (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA);
+ bool changedSurfaceOrContent = frontBuffer &&
+ (contentType != frontBuffer->GetContentType() ||
+ needsComponentAlpha != frontBuffer->HaveBufferOnWhite());
+ if (canKeepBufferContents && changedSurfaceOrContent) {
// Restart the decision process; we won't re-enter since we guard on
// being able to keep the buffer contents.
canReuseBuffer = false;
canKeepBufferContents = false;
validRegion.SetEmpty();
continue;
}
@@ -455,29 +469,36 @@ ContentClient::CalculateBufferForPaint(P
BufferDecision dest;
dest.mNeededRegion = Move(neededRegion);
dest.mValidRegion = Move(validRegion);
dest.mBufferRect = destBufferRect;
dest.mBufferMode = mode;
dest.mBufferContentType = contentType;
dest.mCanReuseBuffer = canReuseBuffer;
dest.mCanKeepBufferContents = canKeepBufferContents;
+ dest.mMustRemoveFrontBuffer = mustRemoveFrontBuffer;
return dest;
}
bool
ContentClient::ValidBufferSize(BufferSizePolicy aPolicy,
const gfx::IntSize& aBufferSize,
const gfx::IntSize& aVisibleBoundsSize)
{
return (aVisibleBoundsSize == aBufferSize ||
(SizedToVisibleBounds != aPolicy &&
aVisibleBoundsSize < aBufferSize));
}
+RefPtr<RotatedBuffer>
+ContentClient::GetFrontBuffer() const
+{
+ return mBuffer;
+}
+
void
ContentClient::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{
aStream << aPrefix;
aStream << nsPrintfCString("ContentClient (0x%p)", this).get();
}
// We pass a null pointer for the ContentClient Forwarder argument, which means
@@ -826,18 +847,16 @@ ContentClientDoubleBuffered::SwapBuffers
mFrontAndBackBufferDiffer = true;
}
ContentClient::PaintState
ContentClientDoubleBuffered::BeginPaint(PaintedLayer* aLayer,
uint32_t aFlags)
{
- EnsureBackBufferIfFrontBuffer();
-
mIsNewBuffer = false;
if (!mFrontBuffer || !mBuffer) {
mFrontAndBackBufferDiffer = false;
}
if (mFrontAndBackBufferDiffer) {
if (mFrontBuffer->DidSelfCopy()) {
@@ -854,16 +873,22 @@ ContentClientDoubleBuffered::BeginPaint(
mBuffer->SetBufferRect(mFrontBuffer->BufferRect());
mBuffer->SetBufferRotation(mFrontBuffer->BufferRotation());
}
}
return ContentClient::BeginPaint(aLayer, aFlags);
}
+RefPtr<RotatedBuffer>
+ContentClientDoubleBuffered::GetFrontBuffer() const
+{
+ return mFrontBuffer;
+}
+
// Sync front/back buffers content
// After executing, the new back buffer has the same (interesting) pixels as
// the new front buffer, and mValidRegion et al. are correct wrt the new
// back buffer (i.e. as they were for the old back buffer)
void
ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
{
if (!mFrontAndBackBufferDiffer) {
@@ -902,21 +927,10 @@ ContentClientDoubleBuffered::FinalizeFra
}
if (mFrontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
mBuffer->UpdateDestinationFrom(*mFrontBuffer, updateRegion.GetBounds());
mFrontBuffer->Unlock();
}
}
-void
-ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
-{
- if (!mBuffer && mFrontBuffer) {
- mBuffer = CreateBufferInternal(mFrontBuffer->BufferRect(),
- mFrontBuffer->GetFormat(),
- mTextureFlags);
- MOZ_ASSERT(mBuffer);
- }
-}
-
} // namespace layers
} // namespace mozilla
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -188,30 +188,33 @@ protected:
struct BufferDecision {
nsIntRegion mNeededRegion;
nsIntRegion mValidRegion;
gfx::IntRect mBufferRect;
SurfaceMode mBufferMode;
gfxContentType mBufferContentType;
bool mCanReuseBuffer;
bool mCanKeepBufferContents;
+ bool mMustRemoveFrontBuffer;
};
/**
* Decide whether we can keep our current buffer and its contents,
* and return a struct containing the regions to paint, invalidate,
* the new buffer rect, surface mode, and content type.
*/
BufferDecision CalculateBufferForPaint(PaintedLayer* aLayer,
uint32_t aFlags);
static bool ValidBufferSize(BufferSizePolicy aPolicy,
const gfx::IntSize& aBufferSize,
const gfx::IntSize& aVisibleBoundsSize);
+ virtual RefPtr<RotatedBuffer> GetFrontBuffer() const;
+
/**
* Any actions that should be performed at the last moment before we begin
* rendering the next frame. I.e., after we calculate what we will draw,
* but before we rotate the buffer and possibly create new buffers.
* aRegionToDraw is the region which is guaranteed to be overwritten when
* drawing the next frame.
*/
virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) {}
@@ -352,26 +355,26 @@ public:
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
virtual void Clear() override;
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
virtual PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags) override;
+ virtual RefPtr<RotatedBuffer> GetFrontBuffer() const override;
+
virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
virtual TextureInfo GetTextureInfo() const override
{
return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
}
private:
- void EnsureBackBufferIfFrontBuffer();
-
RefPtr<RemoteRotatedBuffer> mFrontBuffer;
nsIntRegion mFrontUpdatedRegion;
bool mFrontAndBackBufferDiffer;
};
/**
* A single buffered ContentClientRemoteBuffer. We have a single
* TextureClient/Host which we update and then send a message to the