Backed out changeset 0c763c30594d (bug 1409871)

This commit is contained in:
Sebastian Hengst
2017-10-23 23:44:09 +02:00
parent 66ebccfbb4
commit fb6a690cd5
4 changed files with 207 additions and 212 deletions

View File

@@ -35,20 +35,6 @@ using namespace gfx;
namespace layers {
void
BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
{
MOZ_ASSERT(mLoanedDrawTarget);
MOZ_ASSERT(aReturned == mLoanedDrawTarget);
if (mLoanedDrawTarget) {
if (mSetTransform) {
mLoanedDrawTarget->SetTransform(mLoanedTransform);
}
mLoanedDrawTarget = nullptr;
}
aReturned = nullptr;
}
IntRect
RotatedBuffer::GetQuadrantRectangle(XSide aXSide, YSide aYSide) const
{
@@ -196,124 +182,6 @@ RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, ContextSource aS
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aOperator,aMask, aMaskTransform);
}
bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion)
{
// Assume clipping is cheap if the draw target just has an integer
// translation, and the visible region is simple.
return !aTarget->GetTransform().HasNonIntegerTranslation() &&
aRegion.GetNumRects() <= 1;
}
void
RotatedBuffer::UpdateDestinationFrom(const RotatedBuffer& aSource,
const nsIntRegion& aUpdateRegion)
{
DrawIterator iter;
while (DrawTarget* destDT =
BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
}
aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
if (isClippingCheap) {
destDT->PopClip();
}
// Flush the destination before the sources become inaccessible (Unlock).
destDT->Flush();
ReturnDrawTarget(destDT);
}
if (aSource.HaveBufferOnWhite()) {
MOZ_ASSERT(HaveBufferOnWhite());
DrawIterator whiteIter;
while (DrawTarget* destDT =
BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
}
aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
if (isClippingCheap) {
destDT->PopClip();
}
// Flush the destination before the sources become inaccessible (Unlock).
destDT->Flush();
ReturnDrawTarget(destDT);
}
}
}
DrawTarget*
RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform,
Matrix* aOutMatrix)
{
IntRect bounds = aBounds;
if (aIter) {
// If an iterator was provided, then BeginPaint must have been run with
// PAINT_CAN_DRAW_ROTATED, and the draw region might cover multiple quadrants.
// Iterate over each of them, and return an appropriate buffer each time we find
// one that intersects the draw region. The iterator mCount value tracks which
// quadrants we have considered across multiple calls to this function.
aIter->mDrawRegion.SetEmpty();
while (aIter->mCount < 4) {
IntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
(aIter->mCount & 2) ? TOP : BOTTOM);
aIter->mDrawRegion.And(aBounds, quadrant);
aIter->mCount++;
if (!aIter->mDrawRegion.IsEmpty()) {
break;
}
}
if (aIter->mDrawRegion.IsEmpty()) {
return nullptr;
}
bounds = aIter->mDrawRegion.GetBounds();
}
gfx::DrawTarget* dtBuffer = GetDTBuffer();
gfx::DrawTarget* dtBufferOnWhite = GetDTBufferOnWhite();
MOZ_ASSERT(!mLoanedDrawTarget, "draw target has been borrowed and not returned");
if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
MOZ_ASSERT(dtBuffer && dtBuffer->IsValid() && dtBufferOnWhite && dtBufferOnWhite->IsValid());
mLoanedDrawTarget = Factory::CreateDualDrawTarget(dtBuffer, dtBufferOnWhite);
} else if (aSource == BUFFER_WHITE) {
mLoanedDrawTarget = dtBufferOnWhite;
} else {
// BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
mLoanedDrawTarget = dtBuffer;
}
// Figure out which quadrant to draw in
int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
XSide sideX = bounds.XMost() <= xBoundary ? RIGHT : LEFT;
YSide sideY = bounds.YMost() <= yBoundary ? BOTTOM : TOP;
IntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
NS_ASSERTION(quadrantRect.Contains(bounds), "Messed up quadrants");
if (aSetTransform) {
mLoanedTransform = mLoanedDrawTarget->GetTransform();
Matrix transform = Matrix(mLoanedTransform)
.PreTranslate(-quadrantRect.x,
-quadrantRect.y);
mLoanedDrawTarget->SetTransform(transform);
mSetTransform = true;
} else {
MOZ_ASSERT(aOutMatrix);
*aOutMatrix = Matrix::Translation(-quadrantRect.x, -quadrantRect.y);
mSetTransform = false;
}
return mLoanedDrawTarget;
}
already_AddRefed<SourceSurface>
SourceRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
@@ -329,6 +197,15 @@ SourceRotatedBuffer::GetSourceSurface(ContextSource aSource) const
return surf.forget();
}
/* static */ bool
RotatedContentBuffer::IsClippingCheap(DrawTarget* aTarget, const nsIntRegion& aRegion)
{
// Assume clipping is cheap if the draw target just has an integer
// translation, and the visible region is simple.
return !aTarget->GetTransform().HasNonIntegerTranslation() &&
aRegion.GetNumRects() <= 1;
}
void
RotatedContentBuffer::DrawTo(PaintedLayer* aLayer,
DrawTarget* aTarget,
@@ -366,6 +243,95 @@ RotatedContentBuffer::DrawTo(PaintedLayer* aLayer,
}
}
DrawTarget*
RotatedContentBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform,
Matrix* aOutMatrix)
{
IntRect bounds = aBounds;
if (aIter) {
// If an iterator was provided, then BeginPaint must have been run with
// PAINT_CAN_DRAW_ROTATED, and the draw region might cover multiple quadrants.
// Iterate over each of them, and return an appropriate buffer each time we find
// one that intersects the draw region. The iterator mCount value tracks which
// quadrants we have considered across multiple calls to this function.
aIter->mDrawRegion.SetEmpty();
while (aIter->mCount < 4) {
IntRect quadrant = GetQuadrantRectangle((aIter->mCount & 1) ? LEFT : RIGHT,
(aIter->mCount & 2) ? TOP : BOTTOM);
aIter->mDrawRegion.And(aBounds, quadrant);
aIter->mCount++;
if (!aIter->mDrawRegion.IsEmpty()) {
break;
}
}
if (aIter->mDrawRegion.IsEmpty()) {
return nullptr;
}
bounds = aIter->mDrawRegion.GetBounds();
}
if (!EnsureBuffer()) {
return nullptr;
}
MOZ_ASSERT(!mLoanedDrawTarget, "draw target has been borrowed and not returned");
if (aSource == BUFFER_BOTH && HaveBufferOnWhite()) {
if (!EnsureBufferOnWhite()) {
return nullptr;
}
MOZ_ASSERT(mDTBuffer && mDTBuffer->IsValid() && mDTBufferOnWhite && mDTBufferOnWhite->IsValid());
mLoanedDrawTarget = Factory::CreateDualDrawTarget(mDTBuffer, mDTBufferOnWhite);
} else if (aSource == BUFFER_WHITE) {
if (!EnsureBufferOnWhite()) {
return nullptr;
}
mLoanedDrawTarget = mDTBufferOnWhite;
} else {
// BUFFER_BLACK, or BUFFER_BOTH with a single buffer.
mLoanedDrawTarget = mDTBuffer;
}
// Figure out which quadrant to draw in
int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
XSide sideX = bounds.XMost() <= xBoundary ? RIGHT : LEFT;
YSide sideY = bounds.YMost() <= yBoundary ? BOTTOM : TOP;
IntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
NS_ASSERTION(quadrantRect.Contains(bounds), "Messed up quadrants");
if (aSetTransform) {
mLoanedTransform = mLoanedDrawTarget->GetTransform();
Matrix transform = Matrix(mLoanedTransform)
.PreTranslate(-quadrantRect.x,
-quadrantRect.y);
mLoanedDrawTarget->SetTransform(transform);
mSetTransform = true;
} else {
MOZ_ASSERT(aOutMatrix);
*aOutMatrix = Matrix::Translation(-quadrantRect.x, -quadrantRect.y);
mSetTransform = false;
}
return mLoanedDrawTarget;
}
void
BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
{
MOZ_ASSERT(mLoanedDrawTarget);
MOZ_ASSERT(aReturned == mLoanedDrawTarget);
if (mLoanedDrawTarget) {
if (mSetTransform) {
mLoanedDrawTarget->SetTransform(mLoanedTransform);
}
mLoanedDrawTarget = nullptr;
}
aReturned = nullptr;
}
gfxContentType
RotatedContentBuffer::BufferContentType()
{
@@ -782,9 +748,7 @@ RotatedContentBuffer::BorrowDrawTargetForRecording(PaintState& aPaintState,
DrawIterator* aIter,
bool aSetTransform)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE ||
!EnsureBuffer() ||
(HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
return nullptr;
}

View File

@@ -29,25 +29,6 @@ typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
class TextureClient;
class PaintedLayer;
// Mixin class for classes which need logic for loaning out a draw target.
// See comments on BorrowDrawTargetForQuadrantUpdate.
class BorrowDrawTarget
{
protected:
void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
// The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
// be used, we just keep a reference to ensure it is kept alive and so we can
// correctly restore state when it is returned.
RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
gfx::Matrix mLoanedTransform;
// This flag denotes whether or not a transform was already applied
// to mLoanedDrawTarget and thus needs to be reset to mLoanedTransform
// upon returning the drawtarget.
bool mSetTransform;
};
/**
* This is a cairo/Thebes surface, but with a literal twist. Scrolling
* causes the layer's visible region to move. We want to keep
@@ -63,8 +44,7 @@ protected:
* at row H-N on the screen.
* mBufferRotation.y would be N in this example.
*/
class RotatedBuffer : public BorrowDrawTarget
{
class RotatedBuffer {
public:
typedef gfxContentType ContentType;
@@ -78,18 +58,6 @@ public:
: mDidSelfCopy(false)
{ }
struct DrawIterator {
friend class RotatedBuffer;
DrawIterator()
: mCount(0)
{}
nsIntRegion mDrawRegion;
private:
uint32_t mCount;
};
/*
* Which buffer should be drawn to/read from.
*/
@@ -106,9 +74,6 @@ public:
gfx::SourceSurface* aMask = nullptr,
const gfx::Matrix* aMaskTransform = nullptr) const;
void UpdateDestinationFrom(const RotatedBuffer& aSource,
const nsIntRegion& aUpdateRegion);
/**
* |BufferRect()| is the rect of device pixels that this
* RotatedBuffer covers. That is what DrawBufferWithRotation()
@@ -124,9 +89,6 @@ public:
protected:
virtual gfx::DrawTarget* GetDTBuffer() const = 0;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;
enum XSide {
LEFT, RIGHT
};
@@ -149,27 +111,6 @@ protected:
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const;
/**
* Get a draw target at the specified resolution for updating |aBounds|,
* which must be contained within a single quadrant.
*
* The result should only be held temporarily by the caller (it will be kept
* alive by this). Once used it should be returned using ReturnDrawTarget.
* BorrowDrawTargetForQuadrantUpdate may not be called more than once without
* first calling ReturnDrawTarget.
*
* ReturnDrawTarget will by default restore the transform on the draw target.
* But it is the callers responsibility to restore the clip.
* The caller should flush the draw target, if necessary.
* If aSetTransform is false, the required transform will be set in aOutTransform.
*/
gfx::DrawTarget*
BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform = true,
gfx::Matrix* aOutTransform = nullptr);
/** The area of the PaintedLayer that is covered by the buffer as a whole */
gfx::IntRect mBufferRect;
/**
@@ -204,20 +145,36 @@ public:
virtual bool HaveBuffer() const { return !!mSource; }
virtual bool HaveBufferOnWhite() const { return !!mSourceOnWhite; }
protected:
virtual gfx::DrawTarget* GetDTBuffer() const { return nullptr; }
virtual gfx::DrawTarget* GetDTBufferOnWhite() const { return nullptr; }
private:
RefPtr<gfx::SourceSurface> mSource;
RefPtr<gfx::SourceSurface> mSourceOnWhite;
};
// Mixin class for classes which need logic for loaning out a draw target.
// See comments on BorrowDrawTargetForQuadrantUpdate.
class BorrowDrawTarget
{
protected:
void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
// The draw target loaned by BorrowDrawTargetForQuadrantUpdate. It should not
// be used, we just keep a reference to ensure it is kept alive and so we can
// correctly restore state when it is returned.
RefPtr<gfx::DrawTarget> mLoanedDrawTarget;
gfx::Matrix mLoanedTransform;
// This flag denotes whether or not a transform was already applied
// to mLoanedDrawTarget and thus needs to be reset to mLoanedTransform
// upon returning the drawtarget.
bool mSetTransform;
};
/**
* This class encapsulates the buffer used to retain PaintedLayer contents,
* i.e., the contents of the layer's GetVisibleRegion().
*/
class RotatedContentBuffer : public RotatedBuffer
, public BorrowDrawTarget
{
public:
typedef gfxContentType ContentType;
@@ -315,6 +272,18 @@ public:
PaintState BeginPaint(PaintedLayer* aLayer,
uint32_t aFlags);
struct DrawIterator {
friend class RotatedContentBuffer;
DrawIterator()
: mCount(0)
{}
nsIntRegion mDrawRegion;
private:
uint32_t mCount;
};
/**
* Fetch a DrawTarget for rendering. The DrawTarget remains owned by
* this. See notes on BorrowDrawTargetForQuadrantUpdate.
@@ -362,6 +331,14 @@ public:
CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) = 0;
/**
* Get the underlying buffer, if any. This is useful because we can pass
* in the buffer as the default "reference surface" if there is one.
* Don't use it for anything else!
*/
gfx::DrawTarget* GetDTBuffer() { return mDTBuffer; }
gfx::DrawTarget* GetDTBufferOnWhite() { return mDTBufferOnWhite; }
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const;
/**
@@ -402,6 +379,29 @@ protected:
}
}
/**
* Get a draw target at the specified resolution for updating |aBounds|,
* which must be contained within a single quadrant.
*
* The result should only be held temporarily by the caller (it will be kept
* alive by this). Once used it should be returned using ReturnDrawTarget.
* BorrowDrawTargetForQuadrantUpdate may not be called more than once without
* first calling ReturnDrawTarget.
*
* ReturnDrawTarget will by default restore the transform on the draw target.
* But it is the callers responsibility to restore the clip.
* The caller should flush the draw target, if necessary.
* If aSetTransform is false, the required transform will be set in aOutTransform.
*/
gfx::DrawTarget*
BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform = true,
gfx::Matrix* aOutTransform = nullptr);
static bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);
protected:
/**
* Return the buffer's content type. Requires a valid buffer or
@@ -418,14 +418,6 @@ protected:
// Flush our buffers if they are mapped.
void FlushBuffers();
/**
* Get the underlying buffer, if any. This is useful because we can pass
* in the buffer as the default "reference surface" if there is one.
* Don't use it for anything else!
*/
virtual gfx::DrawTarget* GetDTBuffer() const { return mDTBuffer; }
virtual gfx::DrawTarget* GetDTBufferOnWhite() const { return mDTBufferOnWhite; }
/**
* True if we have a buffer where we can get it (but not necessarily
* mapped currently).

View File

@@ -636,11 +636,6 @@ ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
return;
}
if (!EnsureBuffer() ||
(HaveBufferOnWhite() && !EnsureBufferOnWhite())) {
return;
}
// We need to ensure that we lock these two buffers in the same
// order as the compositor to prevent deadlocks.
TextureClientAutoLock frontLock(mFrontClient, OpenMode::OPEN_READ_ONLY);
@@ -686,5 +681,47 @@ ContentClientDoubleBuffered::EnsureBackBufferIfFrontBuffer()
}
}
void
ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
const nsIntRegion& aUpdateRegion)
{
DrawIterator iter;
while (DrawTarget* destDT =
BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_BLACK, &iter)) {
bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
}
aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
if (isClippingCheap) {
destDT->PopClip();
}
// Flush the destination before the sources become inaccessible (Unlock).
destDT->Flush();
ReturnDrawTargetToBuffer(destDT);
}
if (aSource.HaveBufferOnWhite()) {
MOZ_ASSERT(HaveBufferOnWhite());
DrawIterator whiteIter;
while (DrawTarget* destDT =
BorrowDrawTargetForQuadrantUpdate(aUpdateRegion.GetBounds(), BUFFER_WHITE, &whiteIter)) {
bool isClippingCheap = IsClippingCheap(destDT, whiteIter.mDrawRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destDT, whiteIter.mDrawRegion);
}
aSource.DrawBufferWithRotation(destDT, BUFFER_WHITE, 1.0, CompositionOp::OP_SOURCE);
if (isClippingCheap) {
destDT->PopClip();
}
// Flush the destination before the sources become inaccessible (Unlock).
destDT->Flush();
ReturnDrawTargetToBuffer(destDT);
}
}
}
} // namespace layers
} // namespace mozilla

View File

@@ -363,6 +363,8 @@ protected:
virtual void DestroyFrontBuffer() override;
private:
void UpdateDestinationFrom(const RotatedBuffer& aSource,
const nsIntRegion& aUpdateRegion);
virtual void AbortTextureClientCreation() override
{