From b4aa3847a74f5085744f721c1da3e1b7c9937ece Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Mon, 23 Oct 2017 23:43:24 +0200 Subject: [PATCH] Backed out changeset 0c1485b37ae9 (bug 1409871) --- gfx/layers/RotatedBuffer.cpp | 267 ++++++++++++++++------------------- gfx/layers/RotatedBuffer.h | 10 -- 2 files changed, 123 insertions(+), 154 deletions(-) diff --git a/gfx/layers/RotatedBuffer.cpp b/gfx/layers/RotatedBuffer.cpp index 3fd99b509d88..2896b877b965 100644 --- a/gfx/layers/RotatedBuffer.cpp +++ b/gfx/layers/RotatedBuffer.cpp @@ -278,128 +278,6 @@ RotatedBuffer::UpdateDestinationFrom(const RotatedBuffer& aSource, } } -static void -WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize) -{ - if (*aRotationPoint < 0) { - *aRotationPoint += aSize; - } else if (*aRotationPoint >= aSize) { - *aRotationPoint -= aSize; - } -} - -static IntRect -ComputeBufferRect(const IntRect& aRequestedRect) -{ - IntRect rect(aRequestedRect); - // Set a minimum width to guarantee a minimum size of buffers we - // allocate (and work around problems on some platforms with smaller - // dimensions). 64 used to be the magic number needed to work around - // a rendering glitch on b2g (see bug 788411). Now that we don't support - // this device anymore we should be fine with 8 pixels as the minimum. - rect.SetWidth(std::max(aRequestedRect.Width(), 8)); - return rect; -} - -bool -RotatedBuffer::AdjustTo(const gfx::IntRect& aDestBufferRect, - const gfx::IntRect& aDrawBounds, - bool aCanHaveRotation, - bool aCanDrawRotated) -{ - IntRect keepArea; - if (keepArea.IntersectRect(aDestBufferRect, mBufferRect)) { - // Set mBufferRotation so that the pixels currently in mDTBuffer - // will still be rendered in the right place when mBufferRect - // changes to aDestBufferRect. - IntPoint newRotation = mBufferRotation + - (aDestBufferRect.TopLeft() - mBufferRect.TopLeft()); - WrapRotationAxis(&newRotation.x, mBufferRect.Width()); - WrapRotationAxis(&newRotation.y, mBufferRect.Height()); - NS_ASSERTION(gfx::IntRect(gfx::IntPoint(0,0), mBufferRect.Size()).Contains(newRotation), - "newRotation out of bounds"); - - int32_t xBoundary = aDestBufferRect.XMost() - newRotation.x; - int32_t yBoundary = aDestBufferRect.YMost() - newRotation.y; - bool drawWrapsBuffer = (aDrawBounds.x < xBoundary && xBoundary < aDrawBounds.XMost()) || - (aDrawBounds.y < yBoundary && yBoundary < aDrawBounds.YMost()); - - if ((drawWrapsBuffer && !aCanDrawRotated) || - (newRotation != IntPoint(0,0) && !aCanHaveRotation)) { - // The stuff we need to redraw will wrap around an edge of the - // buffer (and the caller doesn't know how to support that), so - // move the pixels we can keep into a position that lets us - // redraw in just one quadrant. - RefPtr dtBuffer = GetDTBuffer(); - RefPtr dtBufferOnWhite = GetDTBufferOnWhite(); - - if (mBufferRotation == IntPoint(0,0)) { - IntRect srcRect(IntPoint(0, 0), mBufferRect.Size()); - IntPoint dest = mBufferRect.TopLeft() - aDestBufferRect.TopLeft(); - - MOZ_ASSERT(dtBuffer && dtBuffer->IsValid()); - dtBuffer->CopyRect(srcRect, dest); - if (HaveBufferOnWhite()) { - MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid()); - dtBufferOnWhite->CopyRect(srcRect, dest); - } - - mDidSelfCopy = true; - mBufferRect = aDestBufferRect; - } else { - // With azure and a data surface perform an buffer unrotate - // (SelfCopy). - unsigned char* data; - IntSize size; - int32_t stride; - SurfaceFormat format; - - if (dtBuffer->LockBits(&data, &size, &stride, &format)) { - uint8_t bytesPerPixel = BytesPerPixel(format); - BufferUnrotate(data, - size.width * bytesPerPixel, - size.height, stride, - newRotation.x * bytesPerPixel, newRotation.y); - dtBuffer->ReleaseBits(data); - - if (HaveBufferOnWhite()) { - MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid()); - dtBufferOnWhite->LockBits(&data, &size, &stride, &format); - uint8_t bytesPerPixel = BytesPerPixel(format); - BufferUnrotate(data, - size.width * bytesPerPixel, - size.height, stride, - newRotation.x * bytesPerPixel, newRotation.y); - dtBufferOnWhite->ReleaseBits(data); - } - - // Buffer unrotate moves all the pixels - mDidSelfCopy = true; - mBufferRect = aDestBufferRect; - mBufferRotation = IntPoint(0, 0); - } - - if (!mDidSelfCopy) { - // We couldn't unrotate the buffer, so we need to create a - // new one and start from scratch - return false; - } - } - } else { - mBufferRect = aDestBufferRect; - mBufferRotation = newRotation; - } - } else { - // No pixels are going to be kept. The whole visible region - // will be redrawn, so we don't need to copy anything, so we don't - // set destBuffer. - mBufferRect = aDestBufferRect; - mBufferRotation = IntPoint(0,0); - } - - return true; -} - DrawTarget* RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds, ContextSource aSource, @@ -652,6 +530,29 @@ RotatedContentBuffer::HaveBufferOnWhite() const return mBufferProviderOnWhite || (mDTBufferOnWhite && mDTBufferOnWhite->IsValid()); } +static void +WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize) +{ + if (*aRotationPoint < 0) { + *aRotationPoint += aSize; + } else if (*aRotationPoint >= aSize) { + *aRotationPoint -= aSize; + } +} + +static IntRect +ComputeBufferRect(const IntRect& aRequestedRect) +{ + IntRect rect(aRequestedRect); + // Set a minimum width to guarantee a minimum size of buffers we + // allocate (and work around problems on some platforms with smaller + // dimensions). 64 used to be the magic number needed to work around + // a rendering glitch on b2g (see bug 788411). Now that we don't support + // this device anymore we should be fine with 8 pixels as the minimum. + rect.SetWidth(std::max(aRequestedRect.Width(), 8)); + return rect; +} + void RotatedContentBuffer::FlushBuffers() { @@ -668,6 +569,12 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer, uint32_t aFlags) { PaintState result; + // 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()); nsIntRegion validRegion = aLayer->GetValidRegion(); @@ -796,14 +703,6 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer, } } - // 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(); RefPtr destDTBuffer; RefPtr destDTBufferOnWhite; @@ -812,26 +711,106 @@ RotatedContentBuffer::BeginPaint(PaintedLayer* aLayer, bufferFlags |= BUFFER_COMPONENT_ALPHA; } if (canReuseBuffer) { - if (!EnsureBuffer() || - (HaveBufferOnWhite() && !EnsureBufferOnWhite())) { + if (!EnsureBuffer()) { return result; } + IntRect keepArea; + if (keepArea.IntersectRect(destBufferRect, mBufferRect)) { + // Set mBufferRotation so that the pixels currently in mDTBuffer + // will still be rendered in the right place when mBufferRect + // changes to destBufferRect. + IntPoint newRotation = mBufferRotation + + (destBufferRect.TopLeft() - mBufferRect.TopLeft()); + WrapRotationAxis(&newRotation.x, mBufferRect.Width()); + WrapRotationAxis(&newRotation.y, mBufferRect.Height()); + NS_ASSERTION(gfx::IntRect(gfx::IntPoint(0,0), mBufferRect.Size()).Contains(newRotation), + "newRotation out of bounds"); + int32_t xBoundary = destBufferRect.XMost() - newRotation.x; + int32_t yBoundary = destBufferRect.YMost() - newRotation.y; + bool drawWrapsBuffer = (drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) || + (drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()); + if ((drawWrapsBuffer && !(aFlags & PAINT_CAN_DRAW_ROTATED)) || + (newRotation != IntPoint(0,0) && !canHaveRotation)) { + // The stuff we need to redraw will wrap around an edge of the + // buffer (and the caller doesn't know how to support that), so + // move the pixels we can keep into a position that lets us + // redraw in just one quadrant. + if (mBufferRotation == IntPoint(0,0)) { + IntRect srcRect(IntPoint(0, 0), mBufferRect.Size()); + IntPoint dest = mBufferRect.TopLeft() - destBufferRect.TopLeft(); + MOZ_ASSERT(mDTBuffer && mDTBuffer->IsValid()); + mDTBuffer->CopyRect(srcRect, dest); + if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { + if (!EnsureBufferOnWhite()) { + return result; + } + MOZ_ASSERT(mDTBufferOnWhite && mDTBufferOnWhite->IsValid()); + mDTBufferOnWhite->CopyRect(srcRect, dest); + } + mDidSelfCopy = true; + // Don't set destBuffer; we special-case self-copies, and + // just did the necessary work above. + mBufferRect = destBufferRect; + } else { + // With azure and a data surface perform an buffer unrotate + // (SelfCopy). + unsigned char* data; + IntSize size; + int32_t stride; + SurfaceFormat format; - if (!AdjustTo(destBufferRect, - drawBounds, - canHaveRotation, - canDrawRotated)) { - destBufferRect = ComputeBufferRect(neededRegion.GetBounds()); - CreateBuffer(result.mContentType, destBufferRect, bufferFlags, - &destDTBuffer, &destDTBufferOnWhite); + if (mDTBuffer->LockBits(&data, &size, &stride, &format)) { + uint8_t bytesPerPixel = BytesPerPixel(format); + BufferUnrotate(data, + size.width * bytesPerPixel, + size.height, stride, + newRotation.x * bytesPerPixel, newRotation.y); + mDTBuffer->ReleaseBits(data); - if (!destDTBuffer || - (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) { - if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) { - gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height(); + if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) { + if (!EnsureBufferOnWhite()) { + return result; + } + MOZ_ASSERT(mDTBufferOnWhite && mDTBufferOnWhite->IsValid()); + mDTBufferOnWhite->LockBits(&data, &size, &stride, &format); + uint8_t bytesPerPixel = BytesPerPixel(format); + BufferUnrotate(data, + size.width * bytesPerPixel, + size.height, stride, + newRotation.x * bytesPerPixel, newRotation.y); + mDTBufferOnWhite->ReleaseBits(data); + } + + // Buffer unrotate moves all the pixels, note that + // we self copied for SyncBackToFrontBuffer + mDidSelfCopy = true; + mBufferRect = destBufferRect; + mBufferRotation = IntPoint(0, 0); + } + + if (!mDidSelfCopy) { + destBufferRect = ComputeBufferRect(neededRegion.GetBounds()); + CreateBuffer(result.mContentType, destBufferRect, bufferFlags, + &destDTBuffer, &destDTBufferOnWhite); + if (!destDTBuffer || + (!destDTBufferOnWhite && (bufferFlags & BUFFER_COMPONENT_ALPHA))) { + if (Factory::ReasonableSurfaceSize(IntSize(destBufferRect.Width(), destBufferRect.Height()))) { + gfxCriticalNote << "Failed 1 buffer db=" << hexa(destDTBuffer.get()) << " dw=" << hexa(destDTBufferOnWhite.get()) << " for " << destBufferRect.x << ", " << destBufferRect.y << ", " << destBufferRect.Width() << ", " << destBufferRect.Height(); + } + return result; + } + } } - return result; + } else { + mBufferRect = destBufferRect; + mBufferRotation = newRotation; } + } else { + // No pixels are going to be kept. The whole visible region + // will be redrawn, so we don't need to copy anything, so we don't + // set destBuffer. + mBufferRect = destBufferRect; + mBufferRotation = IntPoint(0,0); } } else { // The buffer's not big enough, so allocate a new one diff --git a/gfx/layers/RotatedBuffer.h b/gfx/layers/RotatedBuffer.h index 950913c8b2e2..897c0d8eb38a 100644 --- a/gfx/layers/RotatedBuffer.h +++ b/gfx/layers/RotatedBuffer.h @@ -121,16 +121,6 @@ public: void UpdateDestinationFrom(const RotatedBuffer& aSource, const nsIntRegion& aUpdateRegion); - /** - * Adjusts the buffer to be centered on the destination buffer rect, - * and ready to draw the specified bounds. Returns whether a new buffer - * needs to be created. - */ - bool AdjustTo(const gfx::IntRect& aDestBufferRect, - const gfx::IntRect& aDrawBounds, - bool aCanHaveRotation, - bool aCanDrawRotated); - /** * |BufferRect()| is the rect of device pixels that this * RotatedBuffer covers. That is what DrawBufferWithRotation()