Bug 780330: Avoid mapping/unmapping buffers when we don't use them. r=mattwoodrow sr=roc

This commit is contained in:
Chris Jones 2012-09-12 03:41:34 -07:00
parent 80d98fd960
commit ffc89c8d34
4 changed files with 88 additions and 27 deletions

View File

@ -3,11 +3,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "ThebesLayerBuffer.h" #include "ThebesLayerBuffer.h"
#include "Layers.h" #include "Layers.h"
#include "gfxContext.h" #include "gfxContext.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
#include "gfxUtils.h" #include "gfxUtils.h"
#include "ipc/AutoOpenSurface.h"
#include "nsDeviceContext.h" #include "nsDeviceContext.h"
#include "sampler.h" #include "sampler.h"
@ -57,7 +60,7 @@ ThebesLayerBuffer::DrawBufferQuadrant(gfxContext* aTarget,
true); true);
gfxPoint quadrantTranslation(quadrantRect.x, quadrantRect.y); gfxPoint quadrantTranslation(quadrantRect.x, quadrantRect.y);
nsRefPtr<gfxPattern> pattern = new gfxPattern(mBuffer); nsRefPtr<gfxPattern> pattern = new gfxPattern(EnsureBuffer());
#ifdef MOZ_GFX_OPTIMIZE_MOBILE #ifdef MOZ_GFX_OPTIMIZE_MOBILE
gfxPattern::GraphicsFilter filter = gfxPattern::FILTER_NEAREST; gfxPattern::GraphicsFilter filter = gfxPattern::FILTER_NEAREST;
@ -113,7 +116,7 @@ ThebesLayerBuffer::DrawBufferWithRotation(gfxContext* aTarget, float aOpacity,
already_AddRefed<gfxContext> already_AddRefed<gfxContext>
ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds) ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds)
{ {
nsRefPtr<gfxContext> ctx = new gfxContext(mBuffer); nsRefPtr<gfxContext> ctx = new gfxContext(EnsureBuffer());
// Figure out which quadrant to draw in // Figure out which quadrant to draw in
int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x; int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
@ -127,6 +130,35 @@ ThebesLayerBuffer::GetContextForQuadrantUpdate(const nsIntRect& aBounds)
return ctx.forget(); return ctx.forget();
} }
gfxASurface::gfxContentType
ThebesLayerBuffer::BufferContentType()
{
return mBuffer ? mBuffer->GetContentType() : mBufferProvider->ContentType();
}
bool
ThebesLayerBuffer::BufferSizeOkFor(const nsIntSize& aSize)
{
return (aSize == mBufferRect.Size() ||
(SizedToVisibleBounds != mBufferSizePolicy &&
aSize < mBufferRect.Size()));
}
gfxASurface*
ThebesLayerBuffer::EnsureBuffer()
{
if (!mBuffer && mBufferProvider) {
mBuffer = mBufferProvider->Get();
}
return mBuffer;
}
bool
ThebesLayerBuffer::HaveBuffer()
{
return mBuffer || mBufferProvider;
}
static void static void
WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize) WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
{ {
@ -156,7 +188,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
while (true) { while (true) {
contentType = aContentType; contentType = aContentType;
neededRegion = aLayer->GetVisibleRegion(); neededRegion = aLayer->GetVisibleRegion();
canReuseBuffer = mBuffer && BufferSizeOkFor(neededRegion.GetBounds().Size()); canReuseBuffer = HaveBuffer() && BufferSizeOkFor(neededRegion.GetBounds().Size());
if (canReuseBuffer) { if (canReuseBuffer) {
if (mBufferRect.Contains(neededRegion.GetBounds())) { if (mBufferRect.Contains(neededRegion.GetBounds())) {
@ -184,7 +216,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
neededRegion = destBufferRect; neededRegion = destBufferRect;
} }
if (mBuffer && contentType != mBuffer->GetContentType()) { if (HaveBuffer() && contentType != BufferContentType()) {
// We're effectively clearing the valid region, so we need to draw // We're effectively clearing the valid region, so we need to draw
// the entire needed region now. // the entire needed region now.
result.mRegionToInvalidate = aLayer->GetValidRegion(); result.mRegionToInvalidate = aLayer->GetValidRegion();
@ -231,7 +263,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
if (mBufferRotation == nsIntPoint(0,0)) { if (mBufferRotation == nsIntPoint(0,0)) {
nsIntRect srcRect(nsIntPoint(0, 0), mBufferRect.Size()); nsIntRect srcRect(nsIntPoint(0, 0), mBufferRect.Size());
nsIntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft(); nsIntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft();
mBuffer->MovePixels(srcRect, dest); EnsureBuffer()->MovePixels(srcRect, dest);
result.mDidSelfCopy = true; result.mDidSelfCopy = true;
// Don't set destBuffer; we special-case self-copies, and // Don't set destBuffer; we special-case self-copies, and
// just did the necessary work above. // just did the necessary work above.
@ -269,7 +301,7 @@ ThebesLayerBuffer::BeginPaint(ThebesLayer* aLayer, ContentType aContentType,
bool isClear = mBuffer == nullptr; bool isClear = mBuffer == nullptr;
if (destBuffer) { if (destBuffer) {
if (mBuffer) { if (HaveBuffer()) {
// Copy the bits // Copy the bits
nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBuffer); nsRefPtr<gfxContext> tmpCtx = new gfxContext(destBuffer);
nsIntPoint offset = -destBufferRect.TopLeft(); nsIntPoint offset = -destBufferRect.TopLeft();

View File

@ -13,6 +13,7 @@
namespace mozilla { namespace mozilla {
namespace layers { namespace layers {
class AutoOpenSurface;
class ThebesLayer; class ThebesLayer;
/** /**
@ -50,7 +51,8 @@ public:
}; };
ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy) ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
: mBufferRotation(0,0) : mBufferProvider(nullptr)
, mBufferRotation(0,0)
, mBufferSizePolicy(aBufferSizePolicy) , mBufferSizePolicy(aBufferSizePolicy)
{ {
MOZ_COUNT_CTOR(ThebesLayerBuffer); MOZ_COUNT_CTOR(ThebesLayerBuffer);
@ -67,6 +69,7 @@ public:
void Clear() void Clear()
{ {
mBuffer = nullptr; mBuffer = nullptr;
mBufferProvider = nullptr;
mBufferRect.SetEmpty(); mBufferRect.SetEmpty();
} }
@ -172,13 +175,22 @@ protected:
} }
/** /**
* Set the buffer only. This is intended to be used with the * Set the buffer provider only. This is used with surfaces that
* shadow-layer Open/CloseDescriptor interface, to ensure we don't * require explicit map/unmap, which |aProvider| is used to do on
* accidentally touch a buffer when it's not mapped. * demand in this code.
*
* It's the caller's responsibility to ensure |aProvider| is valid
* for the duration of operations it requests of this
* ThebesLayerBuffer. It's also the caller's responsibility to
* unset the provider when inactive, by calling
* SetBufferProvider(nullptr).
*/ */
void SetBuffer(gfxASurface* aBuffer) void SetBufferProvider(AutoOpenSurface* aProvider)
{ {
mBuffer = aBuffer; mBufferProvider = aProvider;
if (!mBufferProvider) {
mBuffer = nullptr;
}
} }
/** /**
@ -189,14 +201,31 @@ protected:
GetContextForQuadrantUpdate(const nsIntRect& aBounds); GetContextForQuadrantUpdate(const nsIntRect& aBounds);
private: private:
bool BufferSizeOkFor(const nsIntSize& aSize) // Buffer helpers. Don't use mBuffer directly; instead use one of
{ // these helpers.
return (aSize == mBufferRect.Size() ||
(SizedToVisibleBounds != mBufferSizePolicy && /**
aSize < mBufferRect.Size())); * Return the buffer's content type. Requires a valid buffer or
} * buffer provider.
*/
gfxASurface::gfxContentType BufferContentType();
bool BufferSizeOkFor(const nsIntSize& aSize);
/**
* If the buffer hasn't been mapped, map it and return it.
*/
gfxASurface* EnsureBuffer();
/**
* True if we have a buffer where we can get it (but not necessarily
* mapped currently).
*/
bool HaveBuffer();
nsRefPtr<gfxASurface> mBuffer; nsRefPtr<gfxASurface> mBuffer;
/**
* This member is only set transiently. It's used to map mBuffer
* when we're using surfaces that require explicit map/unmap.
*/
AutoOpenSurface* mBufferProvider;
/** The area of the ThebesLayer that is covered by the buffer as a whole */ /** The area of the ThebesLayer that is covered by the buffer as a whole */
nsIntRect mBufferRect; nsIntRect mBufferRect;
/** /**

View File

@ -64,7 +64,7 @@ public:
* When BasicThebesLayerBuffer is used with layers that hold * When BasicThebesLayerBuffer is used with layers that hold
* SurfaceDescriptor, this buffer only has a valid gfxASurface in * SurfaceDescriptor, this buffer only has a valid gfxASurface in
* the scope of an AutoOpenSurface for that SurfaceDescriptor. That * the scope of an AutoOpenSurface for that SurfaceDescriptor. That
* is, it's sort of a "virtual buffer" that's only mapped an * is, it's sort of a "virtual buffer" that's only mapped and
* unmapped within the scope of AutoOpenSurface. None of the * unmapped within the scope of AutoOpenSurface. None of the
* underlying buffer attributes (rect, rotation) are affected by * underlying buffer attributes (rect, rotation) are affected by
* mapping/unmapping. * mapping/unmapping.
@ -72,13 +72,13 @@ public:
* These helpers just exist to provide more descriptive names of the * These helpers just exist to provide more descriptive names of the
* map/unmap process. * map/unmap process.
*/ */
void MapBuffer(gfxASurface* aBuffer) void ProvideBuffer(AutoOpenSurface* aProvider)
{ {
SetBuffer(aBuffer); SetBufferProvider(aProvider);
} }
void UnmapBuffer() void RevokeBuffer()
{ {
SetBuffer(nullptr); SetBufferProvider(nullptr);
} }
private: private:

View File

@ -248,13 +248,13 @@ struct NS_STACK_CLASS AutoBufferTracker {
mLayer->mBufferTracker = this; mLayer->mBufferTracker = this;
if (IsSurfaceDescriptorValid(mLayer->mBackBuffer)) { if (IsSurfaceDescriptorValid(mLayer->mBackBuffer)) {
mInitialBuffer.construct(OPEN_READ_WRITE, mLayer->mBackBuffer); mInitialBuffer.construct(OPEN_READ_WRITE, mLayer->mBackBuffer);
mLayer->mBuffer.MapBuffer(mInitialBuffer.ref().Get()); mLayer->mBuffer.ProvideBuffer(&mInitialBuffer.ref());
} }
} }
~AutoBufferTracker() { ~AutoBufferTracker() {
mLayer->mBufferTracker = nullptr; mLayer->mBufferTracker = nullptr;
mLayer->mBuffer.UnmapBuffer(); mLayer->mBuffer.RevokeBuffer();
// mInitialBuffer and mNewBuffer will clean up after themselves if // mInitialBuffer and mNewBuffer will clean up after themselves if
// they were constructed. // they were constructed.
} }
@ -597,11 +597,11 @@ BasicShadowThebesLayer::PaintThebes(gfxContext* aContext,
} }
AutoOpenSurface autoFrontBuffer(OPEN_READ_ONLY, mFrontBufferDescriptor); AutoOpenSurface autoFrontBuffer(OPEN_READ_ONLY, mFrontBufferDescriptor);
mFrontBuffer.MapBuffer(autoFrontBuffer.Get()); mFrontBuffer.ProvideBuffer(&autoFrontBuffer);
mFrontBuffer.DrawTo(this, aContext, GetEffectiveOpacity(), aMaskLayer); mFrontBuffer.DrawTo(this, aContext, GetEffectiveOpacity(), aMaskLayer);
mFrontBuffer.UnmapBuffer(); mFrontBuffer.RevokeBuffer();
} }
already_AddRefed<ThebesLayer> already_AddRefed<ThebesLayer>