Bug 809273 - Add code handling dual buffers in ThebesLayerBuffer. r=roc

This commit is contained in:
Matt Woodrow 2013-04-22 14:40:52 +12:00
parent 2a7f252e64
commit f3afacc43a
11 changed files with 380 additions and 100 deletions

View File

@ -34,6 +34,8 @@ const TextureFlags AllowRepeat = 0x8;
const TextureFlags NewTile = 0x10;
// The host is responsible for tidying up any shared resources.
const TextureFlags HostRelease = 0x20;
// The texture is part of a component-alpha pair
const TextureFlags ComponentAlpha = 0x40;
/**
* The kind of memory held by the texture client/host pair. This will

View File

@ -10,6 +10,7 @@
#include "Layers.h"
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "gfxTeeSurface.h"
#include "gfxUtils.h"
#include "ipc/AutoOpenSurface.h"
#include "nsDeviceContext.h"
@ -46,6 +47,7 @@ RotatedBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide) const
void
RotatedBuffer::DrawBufferQuadrant(gfxContext* aTarget,
XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfxASurface* aMask,
const gfxMatrix* aMaskTransform) const
@ -62,12 +64,23 @@ RotatedBuffer::DrawBufferQuadrant(gfxContext* aTarget,
nsRefPtr<gfxASurface> source;
if (mBuffer) {
source = mBuffer;
} else if (mDTBuffer) {
source = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDTBuffer);
if (aSource == BUFFER_BLACK) {
if (mBuffer) {
source = mBuffer;
} else if (mDTBuffer) {
source = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDTBuffer);
} else {
NS_RUNTIMEABORT("Can't draw a RotatedBuffer without any buffer!");
}
} else {
NS_RUNTIMEABORT("Can't draw a RotatedBuffer without any buffer!");
MOZ_ASSERT(aSource == BUFFER_WHITE);
if (mBufferOnWhite) {
source = mBufferOnWhite;
} else if (mDTBufferOnWhite) {
source = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDTBufferOnWhite);
} else {
NS_RUNTIMEABORT("Can't draw a RotatedBuffer without any buffer!");
}
}
@ -132,6 +145,7 @@ RotatedBuffer::DrawBufferQuadrant(gfxContext* aTarget,
void
RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const
@ -147,7 +161,13 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
gfx::Point quadrantTranslation(quadrantRect.x, quadrantRect.y);
RefPtr<SourceSurface> snapshot = mDTBuffer->Snapshot();
RefPtr<SourceSurface> snapshot;
if (aSource == BUFFER_BLACK) {
snapshot = mDTBuffer->Snapshot();
} else {
MOZ_ASSERT(aSource == BUFFER_WHITE);
snapshot = mDTBufferOnWhite->Snapshot();
}
// Transform from user -> buffer space.
Matrix transform;
@ -173,21 +193,23 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
}
void
RotatedBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
RotatedBuffer::DrawBufferWithRotation(gfxContext* aTarget, ContextSource aSource,
float aOpacity,
gfxASurface* aMask,
const gfxMatrix* aMaskTransform) const
{
PROFILER_LABEL("RotatedBuffer", "DrawBufferWithRotation");
// Draw four quadrants. We could use REPEAT_, but it's probably better
// not to, to be performance-safe.
DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
}
void
RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, float aOpacity,
RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, ContextSource aSource,
float aOpacity,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const
{
@ -195,10 +217,10 @@ RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, float aOpacity,
// See above, in Azure Repeat should always be a safe, even faster choice
// though! Particularly on D2D Repeat should be a lot faster, need to look
// into that. TODO[Bas]
DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aMask, aMaskTransform);
}
/* static */ bool
@ -237,7 +259,7 @@ ThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
gfxUtils::ClipToRegionSnapped(aTarget, aLayer->GetEffectiveVisibleRegion());
}
DrawBufferWithRotation(aTarget, aOpacity, aMask, aMaskTransform);
DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aMask, aMaskTransform);
aTarget->Restore();
} else {
RefPtr<DrawTarget> dt = aTarget->GetDrawTarget();
@ -258,21 +280,57 @@ ThebesLayerBuffer::DrawTo(ThebesLayer* aLayer,
gfxUtils::ClipToRegionSnapped(dt, aLayer->GetEffectiveVisibleRegion());
}
DrawBufferWithRotation(aTarget, aOpacity, aMask, aMaskTransform);
DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aMask, aMaskTransform);
aTarget->Restore();
}
}
static void
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
const nsIntPoint& aOffset, const gfxRGBA& aColor)
{
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
gfxUtils::ClipToRegion(ctx, aRegion);
ctx->SetColor(aColor);
ctx->Paint();
}
already_AddRefed<gfxContext>
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds)
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds, ContextSource aSource)
{
EnsureBuffer();
nsRefPtr<gfxContext> ctx;
if (mBuffer) {
ctx = new gfxContext(mBuffer);
if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
EnsureBufferOnWhite();
MOZ_ASSERT(mBuffer, "We don't support azure here yet");
gfxASurface* surfaces[2] = { mBuffer, mBufferOnWhite };
nsRefPtr<gfxTeeSurface> surf = new gfxTeeSurface(surfaces, ArrayLength(surfaces));
// XXX If the device offset is set on the individual surfaces instead of on
// the tee surface, we render in the wrong place. Why?
gfxPoint deviceOffset = mBuffer->GetDeviceOffset();
surfaces[0]->SetDeviceOffset(gfxPoint(0, 0));
surfaces[1]->SetDeviceOffset(gfxPoint(0, 0));
surf->SetDeviceOffset(deviceOffset);
surf->SetAllowUseAsSource(false);
ctx = new gfxContext(surf);
} else if (aSource == BUFFER_WHITE) {
EnsureBufferOnWhite();
if (mBufferOnWhite) {
ctx = new gfxContext(mBufferOnWhite);
} else {
ctx = new gfxContext(mDTBufferOnWhite);
}
} else {
ctx = new gfxContext(mDTBuffer);
// BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
if (mBuffer) {
ctx = new gfxContext(mBuffer);
} else {
ctx = new gfxContext(mDTBuffer);
}
}
// Figure out which quadrant to draw in
@ -330,12 +388,30 @@ ThebesLayerBuffer::EnsureBuffer()
}
}
void
ThebesLayerBuffer::EnsureBufferOnWhite()
{
if ((!mBufferOnWhite && !mDTBufferOnWhite) && mBufferProviderOnWhite) {
if (SupportsAzureContent()) {
mDTBufferOnWhite = mBufferProviderOnWhite->LockDrawTarget();
} else {
mBufferOnWhite = mBufferProviderOnWhite->LockSurface();
}
}
}
bool
ThebesLayerBuffer::HaveBuffer()
ThebesLayerBuffer::HaveBuffer() const
{
return mDTBuffer || mBuffer || mBufferProvider;
}
bool
ThebesLayerBuffer::HaveBufferOnWhite() const
{
return mDTBufferOnWhite || mBufferOnWhite || mBufferProviderOnWhite;
}
static void
WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
{
@ -370,12 +446,14 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
nsIntRegion validRegion = aLayer->GetValidRegion();
Layer::SurfaceMode mode;
ContentType contentType;
nsIntRegion neededRegion;
bool canReuseBuffer;
nsIntRect destBufferRect;
while (true) {
mode = aLayer->GetSurfaceMode();
contentType = aContentType;
neededRegion = aLayer->GetVisibleRegion();
canReuseBuffer = HaveBuffer() && BufferSizeOkFor(neededRegion.GetBounds().Size());
@ -396,18 +474,43 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
destBufferRect = ComputeBufferRect(neededRegion.GetBounds());
}
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
#if defined(MOZ_GFX_OPTIMIZE_MOBILE) || defined(MOZ_WIDGET_GONK)
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
#else
if (!aLayer->GetParent() ||
!aLayer->GetParent()->SupportsComponentAlphaChildren() ||
!aLayer->Manager()->IsCompositingCheap() ||
!aLayer->AsShadowableLayer() ||
!aLayer->AsShadowableLayer()->HasShadow() ||
SupportsAzureContent()) {
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
} else {
contentType = gfxASurface::CONTENT_COLOR;
}
#endif
}
if ((aFlags & PAINT_WILL_RESAMPLE) &&
(!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
neededRegion.GetNumRects() > 1)) {
// The area we add to neededRegion might not be painted opaquely
contentType = gfxASurface::CONTENT_COLOR_ALPHA;
if (mode == Layer::SURFACE_OPAQUE) {
contentType = gfxASurface::CONTENT_COLOR_ALPHA;
mode = Layer::SURFACE_SINGLE_CHANNEL_ALPHA;
}
// We need to validate the entire buffer, to make sure that only valid
// pixels are sampled
neededRegion = destBufferRect;
}
if (HaveBuffer() && contentType != BufferContentType()) {
// 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 (HaveBuffer() &&
(contentType != BufferContentType() ||
mode == Layer::SURFACE_COMPONENT_ALPHA) != (HaveBufferOnWhite())) {
// We're effectively clearing the valid region, so we need to draw
// the entire needed region now.
result.mRegionToInvalidate = aLayer->GetValidRegion();
@ -430,8 +533,13 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
nsRefPtr<gfxASurface> destBuffer;
nsRefPtr<gfxASurface> destBufferOnWhite;
RefPtr<DrawTarget> destDTBuffer;
RefPtr<DrawTarget> destDTBufferOnWhite;
uint32_t bufferFlags = canHaveRotation ? ALLOW_REPEAT : 0;
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
bufferFlags |= BUFFER_COMPONENT_ALPHA;
}
if (canReuseBuffer) {
EnsureBuffer();
nsIntRect keepArea;
@ -475,7 +583,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
if (SupportsAzureContent()) {
destDTBuffer = CreateDTBuffer(contentType, destBufferRect, bufferFlags);
} else {
destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags);
destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags, getter_AddRefs(destBufferOnWhite));
}
if (!destBuffer && !destDTBuffer)
return result;
@ -496,7 +604,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
if (SupportsAzureContent()) {
destDTBuffer = CreateDTBuffer(contentType, destBufferRect, bufferFlags);
} else {
destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags);
destBuffer = CreateBuffer(contentType, destBufferRect, bufferFlags, getter_AddRefs(destBufferOnWhite));
}
if (!destBuffer && !destDTBuffer)
return result;
@ -510,28 +618,40 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
bool isClear = !HaveBuffer();
if (destBuffer) {
if (!isClear) {
if (!isClear && (mode != Layer::SURFACE_COMPONENT_ALPHA || HaveBufferOnWhite())) {
// Copy the bits
nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBuffer);
nsIntPoint offset = -destBufferRect.TopLeft();
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->Translate(gfxPoint(offset.x, offset.y));
EnsureBuffer();
DrawBufferWithRotation(tmpCtx, 1.0, nullptr, nullptr);
DrawBufferWithRotation(tmpCtx, BUFFER_BLACK);
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
EnsureBufferOnWhite();
NS_ASSERTION(destBufferOnWhite, "Must have a white buffer!");
nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBufferOnWhite);
nsIntPoint offset = -destBufferRect.TopLeft();
tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
tmpCtx->Translate(gfxPoint(offset.x, offset.y));
DrawBufferWithRotation(tmpCtx, BUFFER_WHITE);
}
}
mBuffer = destBuffer.forget();
mBufferRect = destBufferRect;
mBufferOnWhite = destBufferOnWhite.forget();
mBufferRotation = nsIntPoint(0,0);
} else if (destDTBuffer) {
if (!isClear) {
if (!isClear && (mode != Layer::SURFACE_COMPONENT_ALPHA || HaveBufferOnWhite())) {
MOZ_ASSERT(mode != Layer::SURFACE_COMPONENT_ALPHA, "We don't support azure here yet");
// Copy the bits
nsIntPoint offset = -destBufferRect.TopLeft();
Matrix mat;
mat.Translate(offset.x, offset.y);
destDTBuffer->SetTransform(mat);
EnsureBuffer();
DrawBufferWithRotation(destDTBuffer, 1.0, nullptr, nullptr);
DrawBufferWithRotation(destDTBuffer, BUFFER_BLACK);
destDTBuffer->SetTransform(Matrix());
}
@ -546,9 +666,13 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
result.mContext = GetContextForQuadrantUpdate(drawBounds);
result.mContext = GetContextForQuadrantUpdate(drawBounds, BUFFER_BOTH);
if (contentType == gfxASurface::CONTENT_COLOR_ALPHA && !isClear) {
if (mode == Layer::SURFACE_COMPONENT_ALPHA) {
MOZ_ASSERT(mBuffer && mBufferOnWhite, "Must not be using azure!");
FillSurface(mBuffer, result.mRegionToDraw, result.mRegionToDraw.GetBounds().TopLeft(), gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(mBufferOnWhite, result.mRegionToDraw, result.mRegionToDraw.GetBounds().TopLeft(), gfxRGBA(1.0, 1.0, 1.0, 1.0));
} else if (contentType == gfxASurface::CONTENT_COLOR_ALPHA && !isClear) {
if (result.mContext->IsCairo()) {
gfxUtils::ClipToRegionSnapped(result.mContext, result.mRegionToDraw);
result.mContext->SetOperator(gfxContext::OPERATOR_CLEAR);

View File

@ -11,6 +11,7 @@
#include "nsRegion.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/gfx/2D.h"
#include "Layers.h"
namespace mozilla {
namespace layers {
@ -37,25 +38,39 @@ class RotatedBuffer {
public:
typedef gfxASurface::gfxContentType ContentType;
RotatedBuffer(gfxASurface* aBuffer, const nsIntRect& aBufferRect,
RotatedBuffer(gfxASurface* aBuffer, gfxASurface* aBufferOnWhite,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
: mBuffer(aBuffer)
, mBufferOnWhite(aBufferOnWhite)
, mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
{ }
RotatedBuffer(gfx::DrawTarget* aDTBuffer, const nsIntRect& aBufferRect,
RotatedBuffer(gfx::DrawTarget* aDTBuffer, gfx::DrawTarget* aDTBufferOnWhite,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
: mDTBuffer(aDTBuffer)
, mDTBufferOnWhite(aDTBufferOnWhite)
, mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
{ }
RotatedBuffer() { }
void DrawBufferWithRotation(gfxContext* aTarget, float aOpacity = 1.0,
/*
* Which buffer should be drawn to/read from.
*/
enum ContextSource {
BUFFER_BLACK, // The normal buffer, or buffer with black background when using component alpha.
BUFFER_WHITE, // The buffer with white background, only valid with component alpha.
BUFFER_BOTH // The combined black/white buffers, only valid for writing operations, not reading.
};
void DrawBufferWithRotation(gfxContext* aTarget, ContextSource aSource,
float aOpacity = 1.0,
gfxASurface* aMask = nullptr,
const gfxMatrix* aMaskTransform = nullptr) const;
void DrawBufferWithRotation(gfx::DrawTarget* aTarget, float aOpacity = 1.0,
void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
float aOpacity = 1.0,
gfx::SourceSurface* aMask = nullptr,
const gfx::Matrix* aMaskTransform = nullptr) const;
@ -67,6 +82,9 @@ public:
const nsIntRect& BufferRect() const { return mBufferRect; }
const nsIntPoint& BufferRotation() const { return mBufferRotation; }
virtual bool HaveBuffer() const { return mBuffer || mDTBuffer; }
virtual bool HaveBufferOnWhite() const { return mBufferOnWhite || mDTBufferOnWhite; }
protected:
enum XSide {
@ -83,16 +101,20 @@ protected:
* to adjust the coordinate space of the mask.
*/
void DrawBufferQuadrant(gfxContext* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfxASurface* aMask,
const gfxMatrix* aMaskTransform) const;
void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const;
nsRefPtr<gfxASurface> mBuffer;
nsRefPtr<gfxASurface> mBufferOnWhite;
RefPtr<gfx::DrawTarget> mDTBuffer;
RefPtr<gfx::DrawTarget> mDTBufferOnWhite;
/** The area of the ThebesLayer that is covered by the buffer as a whole */
nsIntRect mBufferRect;
/**
@ -130,6 +152,7 @@ public:
ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
: mBufferProvider(nullptr)
, mBufferProviderOnWhite(nullptr)
, mBufferSizePolicy(aBufferSizePolicy)
{
MOZ_COUNT_CTOR(ThebesLayerBuffer);
@ -146,8 +169,11 @@ public:
void Clear()
{
mBuffer = nullptr;
mBufferOnWhite = nullptr;
mDTBuffer = nullptr;
mDTBufferOnWhite = nullptr;
mBufferProvider = nullptr;
mBufferProviderOnWhite = nullptr;
mBufferRect.SetEmpty();
}
@ -195,7 +221,9 @@ public:
uint32_t aFlags);
enum {
ALLOW_REPEAT = 0x01
ALLOW_REPEAT = 0x01,
BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
// component alpha.
};
/**
* Return a new surface of |aSize| and |aType|.
@ -203,7 +231,7 @@ public:
* to allow repeat-mode, otherwise it should be in pad (clamp) mode
*/
virtual already_AddRefed<gfxASurface>
CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags) = 0;
CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, gfxASurface** aWhiteSurface) = 0;
virtual TemporaryRef<gfx::DrawTarget>
CreateDTBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags)
{ NS_RUNTIMEABORT("CreateDTBuffer not implemented on this platform!"); return nullptr; }
@ -216,6 +244,7 @@ public:
* Don't use it for anything else!
*/
gfxASurface* GetBuffer() { return mBuffer; }
gfxASurface* GetBufferOnWhite() { return mBufferOnWhite; }
/**
* Complete the drawing operation. The region to draw must have been
@ -238,6 +267,14 @@ protected:
return tmp.forget();
}
already_AddRefed<gfxASurface>
SetBufferOnWhite(gfxASurface* aBuffer)
{
nsRefPtr<gfxASurface> tmp = mBufferOnWhite.forget();
mBufferOnWhite = aBuffer;
return tmp.forget();
}
/**
* Set the texture client only. This is used with surfaces that
* require explicit lock/unlock, which |aClient| is used to do on
@ -261,13 +298,26 @@ protected:
mDTBuffer = nullptr;
}
}
void SetBufferProviderOnWhite(TextureClient* aClient)
{
// Only this buffer provider can give us a buffer. If we
// already have one, something has gone wrong.
MOZ_ASSERT(!aClient || (!mBufferOnWhite && !mDTBufferOnWhite));
mBufferProviderOnWhite = aClient;
if (!mBufferProviderOnWhite) {
mBufferOnWhite = nullptr;
mDTBufferOnWhite = nullptr;
}
}
/**
* Get a context at the specified resolution for updating |aBounds|,
* which must be contained within a single quadrant.
*/
already_AddRefed<gfxContext>
GetContextForQuadrantUpdate(const nsIntRect& aBounds);
GetContextForQuadrantUpdate(const nsIntRect& aBounds, ContextSource aSource);
static bool IsClippingCheap(gfxContext* aTarget, const nsIntRegion& aRegion);
@ -285,11 +335,13 @@ protected:
* If the buffer hasn't been mapped, map it.
*/
void EnsureBuffer();
void EnsureBufferOnWhite();
/**
* True if we have a buffer where we can get it (but not necessarily
* mapped currently).
*/
bool HaveBuffer();
virtual bool HaveBuffer() const;
virtual bool HaveBufferOnWhite() const;
/**
* These members are only set transiently. They're used to map mBuffer
@ -297,6 +349,7 @@ protected:
* may be used at a time.
*/
TextureClient* mBufferProvider;
TextureClient* mBufferProviderOnWhite;
BufferSizePolicy mBufferSizePolicy;
};

View File

@ -347,7 +347,7 @@ public:
protected:
virtual already_AddRefed<gfxASurface>
CreateBuffer(ContentType, const nsIntRect&, uint32_t)
CreateBuffer(ContentType, const nsIntRect&, uint32_t, gfxASurface**)
{
NS_RUNTIMEABORT("ShadowThebesLayer can't paint content");
return nullptr;

View File

@ -37,7 +37,8 @@ ContentClientBasic::ContentClientBasic(CompositableForwarder* aForwarder,
already_AddRefed<gfxASurface>
ContentClientBasic::CreateBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
uint32_t aFlags,
gfxASurface**)
{
nsRefPtr<gfxASurface> referenceSurface = GetBuffer();
if (!referenceSurface) {
@ -74,6 +75,7 @@ ContentClientRemote::DestroyBuffers()
MOZ_ASSERT(mTextureClient->GetAccessMode() == TextureClient::ACCESS_READ_WRITE);
mTextureClient = nullptr;
mTextureClientOnWhite = nullptr;
DestroyFrontBuffer();
@ -88,6 +90,9 @@ ContentClientRemote::BeginPaint()
if (mTextureClient) {
SetBufferProvider(mTextureClient);
}
if (mTextureClientOnWhite) {
SetBufferProviderOnWhite(mTextureClientOnWhite);
}
}
void
@ -96,15 +101,19 @@ ContentClientRemote::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.
SetBufferProvider(nullptr);
SetBufferProviderOnWhite(nullptr);
mOldTextures.Clear();
if (mTextureClient) {
mTextureClient->Unlock();
}
if (mTextureClientOnWhite) {
mTextureClientOnWhite->Unlock();
}
}
void
ContentClientRemote::BuildTextureClient(ContentType aType,
ContentClientRemote::BuildTextureClients(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
{
@ -115,15 +124,26 @@ ContentClientRemote::BuildTextureClient(ContentType aType,
if (mTextureClient) {
mOldTextures.AppendElement(mTextureClient);
if (mTextureClientOnWhite) {
mOldTextures.AppendElement(mTextureClientOnWhite);
}
DestroyBuffers();
}
mTextureInfo.mTextureFlags = aFlags | HostRelease;
mTextureClient = CreateTextureClient(TEXTURE_CONTENT);
if (aFlags & BUFFER_COMPONENT_ALPHA) {
mTextureClientOnWhite = CreateTextureClient(TEXTURE_CONTENT);
mTextureInfo.mTextureFlags |= ComponentAlpha;
}
mContentType = aType;
mSize = gfx::IntSize(aRect.width, aRect.height);
mTextureClient->EnsureAllocated(mSize, mContentType);
MOZ_ASSERT(IsSurfaceDescriptorValid(*mTextureClient->GetDescriptor()));
if (mTextureClientOnWhite) {
mTextureClientOnWhite->EnsureAllocated(mSize, mContentType);
MOZ_ASSERT(IsSurfaceDescriptorValid(*mTextureClientOnWhite->GetDescriptor()));
}
CreateFrontBufferAndNotify(aRect);
}
@ -133,7 +153,8 @@ ContentClientRemote::CreateDTBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
{
BuildTextureClient(aType, aRect, aFlags);
MOZ_ASSERT(!(aFlags & BUFFER_COMPONENT_ALPHA), "We don't support component alpha here!");
BuildTextureClients(aType, aRect, aFlags);
RefPtr<DrawTarget> ret = mTextureClient->LockDrawTarget();
return ret.forget();
@ -142,11 +163,15 @@ ContentClientRemote::CreateDTBuffer(ContentType aType,
already_AddRefed<gfxASurface>
ContentClientRemote::CreateBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags)
uint32_t aFlags,
gfxASurface** aWhiteSurface)
{
BuildTextureClient(aType, aRect, aFlags);
BuildTextureClients(aType, aRect, aFlags);
nsRefPtr<gfxASurface> ret = mTextureClient->LockSurface();
if (aFlags & BUFFER_COMPONENT_ALPHA) {
*aWhiteSurface = mTextureClientOnWhite->LockSurface();
}
return ret.forget();
}
@ -188,6 +213,9 @@ ContentClientRemote::Updated(const nsIntRegion& aRegionToDraw,
MOZ_ASSERT(mTextureClient);
mTextureClient->SetAccessMode(TextureClient::ACCESS_NONE);
if (mTextureClientOnWhite) {
mTextureClientOnWhite->SetAccessMode(TextureClient::ACCESS_NONE);
}
LockFrontBuffer();
mForwarder->UpdateTextureRegion(this,
ThebesBufferData(BufferRect(),
@ -199,25 +227,14 @@ void
ContentClientRemote::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);
}
void
ContentClientRemote::SetBackingBuffer(gfxASurface* aBuffer,
const nsIntRect& aRect,
const nsIntPoint& aRotation)
{
#ifdef DEBUG
gfxIntSize prevSize = gfxIntSize(BufferRect().width, BufferRect().height);
gfxIntSize newSize = aBuffer->GetSize();
NS_ABORT_IF_FALSE(newSize == prevSize,
"Swapped-in buffer size doesn't match old buffer's!");
#endif
nsRefPtr<gfxASurface> oldBuffer;
oldBuffer = SetBuffer(aBuffer, aRect, aRotation);
if (mTextureClientOnWhite) {
mTextureClientOnWhite->SetAccessMode(TextureClient::ACCESS_READ_WRITE);
}
}
ContentClientDoubleBuffered::~ContentClientDoubleBuffered()
@ -227,6 +244,11 @@ ContentClientDoubleBuffered::~ContentClientDoubleBuffered()
mTextureClient->SetDescriptor(SurfaceDescriptor());
mFrontClient->SetDescriptor(SurfaceDescriptor());
}
if (mTextureClientOnWhite) {
MOZ_ASSERT(mFrontClientOnWhite);
mTextureClientOnWhite->SetDescriptor(SurfaceDescriptor());
mFrontClientOnWhite->SetDescriptor(SurfaceDescriptor());
}
}
void
@ -238,10 +260,17 @@ ContentClientDoubleBuffered::CreateFrontBufferAndNotify(const nsIntRect& aBuffer
mFrontBufferRect = aBufferRect;
mFrontBufferRotation = nsIntPoint();
if (mTextureInfo.mTextureFlags & ComponentAlpha) {
mFrontClientOnWhite = CreateTextureClient(TEXTURE_CONTENT);
mFrontClientOnWhite->EnsureAllocated(mSize, mContentType);
}
mForwarder->CreatedDoubleBuffer(this,
*mFrontClient->GetDescriptor(),
*mTextureClient->GetDescriptor(),
mTextureInfo);
mTextureInfo,
mFrontClientOnWhite ? mFrontClientOnWhite->GetDescriptor() : nullptr,
mTextureClientOnWhite ? mTextureClientOnWhite->GetDescriptor() : nullptr);
}
void
@ -251,6 +280,7 @@ ContentClientDoubleBuffered::DestroyFrontBuffer()
MOZ_ASSERT(mFrontClient->GetAccessMode() != TextureClient::ACCESS_NONE);
mFrontClient = nullptr;
mFrontClientOnWhite = nullptr;
}
void
@ -258,6 +288,9 @@ ContentClientDoubleBuffered::LockFrontBuffer()
{
MOZ_ASSERT(mFrontClient);
mFrontClient->SetAccessMode(TextureClient::ACCESS_NONE);
if (mFrontClientOnWhite) {
mFrontClientOnWhite->SetAccessMode(TextureClient::ACCESS_NONE);
}
}
void
@ -269,6 +302,10 @@ ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
mTextureClient = mFrontClient;
mFrontClient = oldBack;
oldBack = mTextureClientOnWhite;
mTextureClientOnWhite = mFrontClientOnWhite;
mFrontClientOnWhite = oldBack;
nsIntRect oldBufferRect = mBufferRect;
mBufferRect = mFrontBufferRect;
mFrontBufferRect = oldBufferRect;
@ -279,6 +316,9 @@ ContentClientDoubleBuffered::SwapBuffers(const nsIntRegion& aFrontUpdatedRegion)
MOZ_ASSERT(mFrontClient);
mFrontClient->SetAccessMode(TextureClient::ACCESS_READ_ONLY);
if (mFrontClientOnWhite) {
mFrontClientOnWhite->SetAccessMode(TextureClient::ACCESS_READ_ONLY);
}
ContentClientRemote::SwapBuffers(aFrontUpdatedRegion);
}
@ -297,13 +337,19 @@ struct AutoTextureClient {
{
MOZ_ASSERT(!mTexture);
mTexture = aTexture;
return mTexture->LockSurface();
if (mTexture) {
return mTexture->LockSurface();
}
return nullptr;
}
DrawTarget* GetDrawTarget(TextureClient* aTexture)
{
MOZ_ASSERT(!mTexture);
mTexture = aTexture;
return mTexture->LockDrawTarget();
if (mTexture) {
return mTexture->LockDrawTarget();
}
return nullptr;
}
private:
TextureClient* mTexture;
@ -317,6 +363,8 @@ ContentClientDoubleBuffered::SyncFrontBufferToBackBuffer()
}
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 <x=%d,y=%d,w=%d,h=%d>",
this,
@ -355,13 +403,16 @@ ContentClientDoubleBuffered::SyncFrontBufferToBackBuffer()
}
AutoTextureClient autoTextureFront;
AutoTextureClient autoTextureFrontOnWhite;
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
RotatedBuffer frontBuffer(autoTextureFront.GetDrawTarget(mFrontClient),
autoTextureFrontOnWhite.GetDrawTarget(mFrontClientOnWhite),
mFrontBufferRect,
mFrontBufferRotation);
UpdateDestinationFrom(frontBuffer, updateRegion);
} else {
RotatedBuffer frontBuffer(autoTextureFront.GetSurface(mFrontClient),
autoTextureFrontOnWhite.GetSurface(mFrontClientOnWhite),
mFrontBufferRect,
mFrontBufferRotation);
UpdateDestinationFrom(frontBuffer, updateRegion);
@ -376,7 +427,7 @@ ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
const nsIntRegion& aUpdateRegion)
{
nsRefPtr<gfxContext> destCtx =
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds());
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK);
destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
@ -390,9 +441,32 @@ ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
}
aSource.DrawBufferWithRotation(destCtx->GetDrawTarget());
aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_BLACK);
} else {
aSource.DrawBufferWithRotation(destCtx);
aSource.DrawBufferWithRotation(destCtx, BUFFER_BLACK);
}
if (aSource.HaveBufferOnWhite()) {
MOZ_ASSERT(HaveBufferOnWhite());
nsRefPtr<gfxContext> destCtx =
GetContextForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE);
destCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
bool isClippingCheap = IsClippingCheap(destCtx, aUpdateRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destCtx, aUpdateRegion);
}
if (gfxPlatform::GetPlatform()->SupportsAzureContent()) {
MOZ_ASSERT(!destCtx->IsCairo());
if (destCtx->GetDrawTarget()->GetFormat() == FORMAT_B8G8R8A8) {
destCtx->GetDrawTarget()->ClearRect(Rect(0, 0, mFrontBufferRect.width, mFrontBufferRect.height));
}
aSource.DrawBufferWithRotation(destCtx->GetDrawTarget(), BUFFER_WHITE);
} else {
aSource.DrawBufferWithRotation(destCtx, BUFFER_WHITE);
}
}
}
@ -401,6 +475,9 @@ ContentClientSingleBuffered::~ContentClientSingleBuffered()
if (mTextureClient) {
mTextureClient->SetDescriptor(SurfaceDescriptor());
}
if (mTextureClientOnWhite) {
mTextureClientOnWhite->SetDescriptor(SurfaceDescriptor());
}
}
void
@ -408,7 +485,8 @@ ContentClientSingleBuffered::CreateFrontBufferAndNotify(const nsIntRect& aBuffer
{
mForwarder->CreatedSingleBuffer(this,
*mTextureClient->GetDescriptor(),
mTextureInfo);
mTextureInfo,
mTextureClientOnWhite ? mTextureClientOnWhite->GetDescriptor() : nullptr);
}
void
@ -428,6 +506,13 @@ ContentClientSingleBuffered::SyncFrontBufferToBackBuffer()
mBufferRect,
mBufferRotation);
backBuffer = GetBufferOnWhite();
if (!backBuffer && mTextureClientOnWhite) {
backBuffer = mTextureClientOnWhite->LockSurface();
}
oldBuffer = SetBufferOnWhite(backBuffer);
mIsNewBuffer = false;
mFrontAndBackBufferDiffer = false;
}

View File

@ -114,7 +114,8 @@ public:
virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags) MOZ_OVERRIDE;
uint32_t aFlags,
gfxASurface**) MOZ_OVERRIDE;
virtual TemporaryRef<gfx::DrawTarget>
CreateDTBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags);
@ -185,7 +186,8 @@ public:
virtual already_AddRefed<gfxASurface> CreateBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags) MOZ_OVERRIDE;
uint32_t aFlags,
gfxASurface** aWhiteSurface) MOZ_OVERRIDE;
virtual TemporaryRef<gfx::DrawTarget> CreateDTBuffer(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags) MOZ_OVERRIDE;
@ -203,21 +205,14 @@ public:
}
protected:
/**
* Swap out the old backing buffer for |aBuffer| and attributes.
*/
void SetBackingBuffer(gfxASurface* aBuffer,
const nsIntRect& aRect,
const nsIntPoint& aRotation);
virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy);
// create and configure mTextureClient
void BuildTextureClient(ContentType aType,
const nsIntRect& aRect,
uint32_t aFlags);
void BuildTextureClients(ContentType aType,
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).
@ -228,6 +223,7 @@ protected:
virtual void LockFrontBuffer() {}
RefPtr<TextureClient> mTextureClient;
RefPtr<TextureClient> mTextureClientOnWhite;
// keep a record of texture clients we have created and need to keep
// around, then unlock when we are done painting
nsTArray<RefPtr<TextureClient> > mOldTextures;
@ -270,20 +266,11 @@ protected:
virtual void LockFrontBuffer() MOZ_OVERRIDE;
private:
// The size policy doesn't really matter here; this constructor is
// intended to be used for creating temporaries
ContentClientDoubleBuffered(gfxASurface* aBuffer,
const nsIntRect& aRect,
const nsIntPoint& aRotation)
: ContentClientRemote(nullptr)
{
SetBuffer(aBuffer, aRect, aRotation);
}
void UpdateDestinationFrom(const RotatedBuffer& aSource,
const nsIntRegion& aUpdateRegion);
RefPtr<TextureClient> mFrontClient;
RefPtr<TextureClient> mFrontClientOnWhite;
nsIntRegion mFrontUpdatedRegion;
nsIntRect mFrontBufferRect;
nsIntPoint mFrontBufferRotation;

View File

@ -58,11 +58,14 @@ public:
*/
virtual void CreatedSingleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aDescriptor,
const TextureInfo& aTextureInfo) = 0;
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aDescriptorOnWhite = nullptr) = 0;
virtual void CreatedDoubleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aFrontDescriptor,
const SurfaceDescriptor& aBackDescriptor,
const TextureInfo& aTextureInfo) = 0;
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aFrontDescriptorOnWhite = nullptr,
const SurfaceDescriptor* aBackDescriptorOnWhite = nullptr) = 0;
/**
* Tell the compositor that a Compositable is killing its buffer(s),

View File

@ -255,13 +255,16 @@ public:
// thebes layers which don't support async updates.
virtual void CreatedSingleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aDescriptor,
const TextureInfo& aTextureInfo) MOZ_OVERRIDE {
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aDescriptorOnWhite = nullptr) MOZ_OVERRIDE {
NS_RUNTIMEABORT("should not be called");
}
virtual void CreatedDoubleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aFrontDescriptor,
const SurfaceDescriptor& aBackDescriptor,
const TextureInfo& aTextureInfo) MOZ_OVERRIDE {
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aFrontDescriptorOnWhite = nullptr,
const SurfaceDescriptor* aBackDescriptorOnWhite = nullptr) MOZ_OVERRIDE {
NS_RUNTIMEABORT("should not be called");
}
virtual void DestroyThebesBuffer(CompositableClient* aCompositable) MOZ_OVERRIDE {

View File

@ -683,7 +683,8 @@ ShadowLayerForwarder::Connect(CompositableClient* aCompositable)
void
ShadowLayerForwarder::CreatedSingleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aDescriptor,
const TextureInfo& aTextureInfo)
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aDescriptorOnWhite)
{
MOZ_ASSERT(aDescriptor.type() != SurfaceDescriptor::T__None &&
aDescriptor.type() != SurfaceDescriptor::Tnull_t);
@ -691,13 +692,21 @@ ShadowLayerForwarder::CreatedSingleBuffer(CompositableClient* aCompositable,
TextureFront,
aDescriptor,
aTextureInfo));
if (aDescriptorOnWhite) {
mTxn->AddEdit(OpCreatedTexture(nullptr, aCompositable->GetIPDLActor(),
TextureOnWhiteFront,
*aDescriptorOnWhite,
aTextureInfo));
}
}
void
ShadowLayerForwarder::CreatedDoubleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aFrontDescriptor,
const SurfaceDescriptor& aBackDescriptor,
const TextureInfo& aTextureInfo)
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aFrontDescriptorOnWhite,
const SurfaceDescriptor* aBackDescriptorOnWhite)
{
MOZ_ASSERT(aFrontDescriptor.type() != SurfaceDescriptor::T__None &&
aBackDescriptor.type() != SurfaceDescriptor::T__None &&
@ -711,6 +720,17 @@ ShadowLayerForwarder::CreatedDoubleBuffer(CompositableClient* aCompositable,
TextureBack,
aBackDescriptor,
aTextureInfo));
if (aFrontDescriptorOnWhite) {
MOZ_ASSERT(aBackDescriptorOnWhite);
mTxn->AddEdit(OpCreatedTexture(nullptr, aCompositable->GetIPDLActor(),
TextureOnWhiteFront,
*aFrontDescriptorOnWhite,
aTextureInfo));
mTxn->AddEdit(OpCreatedTexture(nullptr, aCompositable->GetIPDLActor(),
TextureOnWhiteBack,
*aBackDescriptorOnWhite,
aTextureInfo));
}
}
void

View File

@ -155,11 +155,14 @@ public:
virtual void CreatedSingleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aDescriptor,
const TextureInfo& aTextureInfo) MOZ_OVERRIDE;
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aDescriptorOnWhite = nullptr) MOZ_OVERRIDE;
virtual void CreatedDoubleBuffer(CompositableClient* aCompositable,
const SurfaceDescriptor& aFrontDescriptor,
const SurfaceDescriptor& aBackDescriptor,
const TextureInfo& aTextureInfo) MOZ_OVERRIDE;
const TextureInfo& aTextureInfo,
const SurfaceDescriptor* aFrontDescriptorOnWhite = nullptr,
const SurfaceDescriptor* aBackDescriptorOnWhite = nullptr) MOZ_OVERRIDE;
virtual void DestroyThebesBuffer(CompositableClient* aCompositable) MOZ_OVERRIDE;
/**

View File

@ -332,7 +332,7 @@ public:
// ThebesLayerBuffer interface
virtual already_AddRefed<gfxASurface>
CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags)
CreateBuffer(ContentType aType, const nsIntRect& aRect, uint32_t aFlags, gfxASurface**)
{
NS_ASSERTION(gfxASurface::CONTENT_ALPHA != aType,"ThebesBuffer has color");