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

View File

@ -13,6 +13,7 @@
namespace mozilla {
namespace layers {
class AutoOpenSurface;
class ThebesLayer;
/**
@ -50,7 +51,8 @@ public:
};
ThebesLayerBuffer(BufferSizePolicy aBufferSizePolicy)
: mBufferRotation(0,0)
: mBufferProvider(nullptr)
, mBufferRotation(0,0)
, mBufferSizePolicy(aBufferSizePolicy)
{
MOZ_COUNT_CTOR(ThebesLayerBuffer);
@ -67,6 +69,7 @@ public:
void Clear()
{
mBuffer = nullptr;
mBufferProvider = nullptr;
mBufferRect.SetEmpty();
}
@ -172,13 +175,22 @@ protected:
}
/**
* Set the buffer only. This is intended to be used with the
* shadow-layer Open/CloseDescriptor interface, to ensure we don't
* accidentally touch a buffer when it's not mapped.
* Set the buffer provider only. This is used with surfaces that
* require explicit map/unmap, which |aProvider| is used to do on
* 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);
private:
bool BufferSizeOkFor(const nsIntSize& aSize)
{
return (aSize == mBufferRect.Size() ||
(SizedToVisibleBounds != mBufferSizePolicy &&
aSize < mBufferRect.Size()));
}
// Buffer helpers. Don't use mBuffer directly; instead use one of
// these helpers.
/**
* 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;
/**
* 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 */
nsIntRect mBufferRect;
/**

View File

@ -64,7 +64,7 @@ public:
* When BasicThebesLayerBuffer is used with layers that hold
* SurfaceDescriptor, this buffer only has a valid gfxASurface in
* 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
* underlying buffer attributes (rect, rotation) are affected by
* mapping/unmapping.
@ -72,13 +72,13 @@ public:
* These helpers just exist to provide more descriptive names of the
* map/unmap process.
*/
void MapBuffer(gfxASurface* aBuffer)
void ProvideBuffer(AutoOpenSurface* aProvider)
{
SetBuffer(aBuffer);
SetBufferProvider(aProvider);
}
void UnmapBuffer()
void RevokeBuffer()
{
SetBuffer(nullptr);
SetBufferProvider(nullptr);
}
private:

View File

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