Record buffer operations to a struct for replaying on paint thread (bug 1399692 part 6, r=bas)

This commit adds a CapturedBufferState which is used to record all the operations
that are necessary for preparing the buffers. The commands are then instantly
executed to preserve the same behavior, but in the following commit they will
be dispatched to the paint thread.

Note: RotatedBuffer's aren't thread safe and so a shallow copy needs to be made
for sending to the paint thread. This complicates the code for AdjustTo as it can
fail naturally and the buffer parameter changes are needed later in BeginPaint.
So the code for AdjustTo is split up a bit to accomodate that.

MozReview-Commit-ID: FwSwFay887o
This commit is contained in:
Ryan Hunt
2017-10-25 10:20:49 -04:00
parent f5da6dfc9f
commit a9762efedf
7 changed files with 288 additions and 115 deletions

View File

@@ -23,6 +23,7 @@
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/PaintThread.h"
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
#include "nsISupportsImpl.h" // for gfxContext::Release, etc
#include "nsIWidget.h" // for nsIWidget
@@ -146,9 +147,6 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
if (result.mRegionToDraw.IsEmpty())
return result;
OpenMode lockMode = aFlags & PAINT_ASYNC ? OpenMode::OPEN_READ_ASYNC_WRITE
: OpenMode::OPEN_READ_WRITE;
// 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.
@@ -156,24 +154,46 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
!(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
!(aLayer->Manager()->AsWebRenderLayerManager());
bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
bool asyncPaint = (aFlags & PAINT_ASYNC);
IntRect drawBounds = result.mRegionToDraw.GetBounds();
OpenMode lockMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC_WRITE
: OpenMode::OPEN_READ_WRITE;
if (dest.mCanReuseBuffer) {
MOZ_ASSERT(mBuffer);
if (mBuffer->Lock(lockMode)) {
// Do not modify result.mRegionToDraw or result.mContentType after this call.
FinalizeFrame(result.mRegionToDraw);
bool canReuseBuffer = false;
if (!mBuffer->AdjustTo(dest.mBufferRect,
drawBounds,
canHaveRotation,
canDrawRotated)) {
dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
dest.mCanReuseBuffer = false;
if (mBuffer->Lock(lockMode)) {
RefPtr<CapturedBufferState> bufferState = new CapturedBufferState();
// Do not modify result.mRegionToDraw or result.mContentType after this call.
FinalizeFrame(result.mRegionToDraw, bufferState);
auto newParameters = mBuffer->AdjustedParameters(dest.mBufferRect);
if ((!canHaveRotation && newParameters.IsRotated()) ||
(!canDrawRotated && newParameters.RectWrapsBuffer(drawBounds))) {
bufferState->mBufferUnrotate = Some(CapturedBufferState::Unrotate {
newParameters,
mBuffer->ShallowCopy(),
});
}
if (bufferState->PrepareBuffer()) {
if (bufferState->mBufferUnrotate) {
newParameters.SetUnrotated();
}
mBuffer->SetParameters(newParameters);
canReuseBuffer = true;
}
}
if (!canReuseBuffer) {
if (mBuffer->IsLocked()) {
mBuffer->Unlock();
}
} else {
dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
dest.mCanReuseBuffer = false;
}
@@ -213,10 +233,15 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
// If we have an existing front buffer, copy it into the new back buffer
if (RefPtr<RotatedBuffer> frontBuffer = GetFrontBuffer()) {
if (frontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
newBuffer->UpdateDestinationFrom(*frontBuffer, newBuffer->BufferRect());
frontBuffer->Unlock();
} else {
RefPtr<CapturedBufferState> bufferState = new CapturedBufferState();
bufferState->mBufferCopy = Some(CapturedBufferState::Copy {
frontBuffer->ShallowCopy(),
newBuffer->ShallowCopy(),
newBuffer->BufferRect(),
});
if (!bufferState->PrepareBuffer()) {
gfxCriticalNote << "Failed to copy front buffer to back buffer.";
return result;
}
@@ -851,7 +876,8 @@ ContentClientDoubleBuffered::GetFrontBuffer() const
// the new front buffer, and mValidRegion et al. are correct wrt the new
// back buffer (i.e. as they were for the old back buffer)
void
ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw,
CapturedBufferState* aPrepareState)
{
if (!mFrontAndBackBufferDiffer) {
MOZ_ASSERT(!mFrontBuffer || !mFrontBuffer->DidSelfCopy(),
@@ -898,10 +924,12 @@ ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
return;
}
if (mFrontBuffer->Lock(OpenMode::OPEN_READ_ONLY)) {
mBuffer->UpdateDestinationFrom(*mFrontBuffer, updateRegion.GetBounds());
mFrontBuffer->Unlock();
}
MOZ_ASSERT(!aPrepareState->mBufferCopy);
aPrepareState->mBufferCopy = Some(CapturedBufferState::Copy {
mFrontBuffer->ShallowCopy(),
mBuffer->ShallowCopy(),
updateRegion.GetBounds(),
});
}
} // namespace layers