Backed out 10 changesets (bug 1478815) for reftest failures on /reftests/layers/forced-bg-color-outside-visible-region.html. CLOSED TREE

Backed out changeset 7ae4c893867a (bug 1478815)
Backed out changeset b865a866fe5a (bug 1478815)
Backed out changeset 405ad3518218 (bug 1478815)
Backed out changeset 64cb50b227e0 (bug 1478815)
Backed out changeset 392a724d5acd (bug 1478815)
Backed out changeset 01110727f2e9 (bug 1478815)
Backed out changeset 56d967e03ee2 (bug 1478815)
Backed out changeset 082638a5c643 (bug 1478815)
Backed out changeset 3dc47f17fa44 (bug 1478815)
Backed out changeset 699c954992f8 (bug 1478815)

--HG--
rename : gfx/2d/BufferEdgePad.cpp => gfx/layers/BufferEdgePad.cpp
rename : gfx/2d/BufferEdgePad.h => gfx/layers/BufferEdgePad.h
rename : gfx/2d/BufferUnrotate.cpp => gfx/layers/BufferUnrotate.cpp
rename : gfx/2d/BufferUnrotate.h => gfx/layers/BufferUnrotate.h
This commit is contained in:
Brindusan Cristian 2018-08-07 20:57:27 +03:00
parent 8c70dfad01
commit 181d4f159b
39 changed files with 1551 additions and 918 deletions

View File

@ -34,8 +34,6 @@
#include "mozilla/DebugOnly.h"
#include "nsRegionFwd.h"
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
#ifndef MOZ_ENABLE_FREETYPE
#define MOZ_ENABLE_FREETYPE
@ -1298,16 +1296,6 @@ public:
*/
virtual void Blur(const AlphaBoxBlur& aBlur);
/**
* Performs an in-place edge padding operation.
*/
virtual void PadEdges(const IntRegion& aRegion);
/**
* Performs an in-place buffer unrotation operation.
*/
virtual bool Unrotate(IntPoint aRotation);
/**
* Create a SourceSurface optimized for use with this DrawTarget from
* existing bitmap data in memory.
@ -1547,7 +1535,6 @@ class DrawTargetCapture : public DrawTarget
public:
virtual bool IsCaptureDT() const override { return true; }
virtual bool IsEmpty() const = 0;
virtual void Dump() = 0;
};
@ -1633,18 +1620,6 @@ public:
static already_AddRefed<DrawTarget>
CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
/**
* Create a DrawTarget that captures the drawing commands to eventually be replayed
* onto the DrawTarget provided. An optional byte size can be provided as a limit
* for the CaptureCommandList. When the limit is reached, the CaptureCommandList
* will be replayed to the target and then cleared.
*
* @param aSize Size of the area this DT will capture.
* @param aFlushBytes The byte limit at which to flush the CaptureCommandList
*/
static already_AddRefed<DrawTargetCapture>
CreateCaptureDrawTargetForTarget(gfx::DrawTarget* aTarget, size_t aFlushBytes = 0);
/**
* Create a DrawTarget that captures the drawing commands and can be replayed
* onto a compatible DrawTarget afterwards.
@ -1779,9 +1754,6 @@ public:
static already_AddRefed<DrawTarget>
CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB);
static already_AddRefed<SourceSurface>
CreateDualSourceSurface(SourceSurface *sourceA, SourceSurface *sourceB);
/*
* This creates a new tiled DrawTarget. When a tiled drawtarget is used the
* drawing is distributed over number of tiles which may each hold an

View File

@ -11,19 +11,11 @@ namespace mozilla {
namespace gfx {
CaptureCommandList::~CaptureCommandList()
{
Clear();
}
void
CaptureCommandList::Clear()
{
for (iterator iter(*this); !iter.Done(); iter.Next()) {
DrawingCommand* cmd = iter.Get();
cmd->~DrawingCommand();
}
mLastCommand = nullptr;
mStorage.clear();
}
} // namespace gfx

View File

@ -64,21 +64,6 @@ public:
return Append<T>();
}
bool IsEmpty() const {
return mStorage.empty();
}
template <typename T>
bool BufferWillAlloc() const {
return mStorage.size() + sizeof(uint32_t) + sizeof(T) > mStorage.capacity();
}
size_t BufferCapacity() const {
return mStorage.capacity();
}
void Clear();
class iterator
{
public:

View File

@ -45,8 +45,7 @@ enum class CommandType : int8_t {
SETTRANSFORM,
SETPERMITSUBPIXELAA,
FLUSH,
BLUR,
PADEDGES,
BLUR
};
class DrawingCommand

View File

@ -1126,40 +1126,6 @@ private:
AlphaBoxBlur mBlur;
};
class PadEdgesCommand : public DrawingCommand
{
public:
explicit PadEdgesCommand(const IntRegion& aRegion)
: mRegion(aRegion)
{}
CommandType GetType() const override
{
return PadEdgesCommand::Type;
}
void CloneInto(CaptureCommandList* aList) override
{
CLONE_INTO(PadEdgesCommand)(IntRegion(mRegion));
}
void ExecuteOnDT(DrawTarget* aDT, const Matrix*) const override
{
aDT->PadEdges(mRegion);
}
void Log(TreeLog& aStream) const override
{
aStream << "[PADEDGES]";
}
static const bool AffectsSnapshot = true;
static const CommandType Type = CommandType::PADEDGES;
private:
IntRegion mRegion;
};
#undef CLONE_INTO
} // namespace gfx

View File

@ -7,13 +7,9 @@
#include "2D.h"
#include "Logging.h"
#include "PathHelpers.h"
#include "Tools.h"
#include "DrawTargetCapture.h"
#include "BufferEdgePad.h"
#include "BufferUnrotate.h"
#ifdef BUILD_ARM_NEON
#include "mozilla/arm.h"
#include "LuminanceNEON.h"
@ -292,32 +288,5 @@ DrawTarget::Blur(const AlphaBoxBlur& aBlur)
ReleaseBits(data);
}
void
DrawTarget::PadEdges(const IntRegion& aRegion)
{
PadDrawTargetOutFromRegion(this, aRegion);
}
bool
DrawTarget::Unrotate(IntPoint aRotation)
{
unsigned char* data;
IntSize size;
int32_t stride;
SurfaceFormat format;
if (LockBits(&data, &size, &stride, &format)) {
uint8_t bytesPerPixel = BytesPerPixel(format);
BufferUnrotate(data,
size.width * bytesPerPixel,
size.height, stride,
aRotation.x * bytesPerPixel,
aRotation.y);
ReleaseBits(data);
return true;
}
return false;
}
} // namespace gfx
} // namespace mozilla

View File

@ -23,27 +23,13 @@ DrawTargetCaptureImpl::~DrawTargetCaptureImpl()
}
}
DrawTargetCaptureImpl::DrawTargetCaptureImpl(gfx::DrawTarget* aTarget, size_t aFlushBytes)
: mSnapshot(nullptr),
mStride(0),
mSurfaceAllocationSize(0),
mFlushBytes(aFlushBytes)
{
mSize = aTarget->GetSize();
mFormat = aTarget->GetFormat();
SetPermitSubpixelAA(aTarget->GetPermitSubpixelAA());
mRefDT = aTarget;
}
DrawTargetCaptureImpl::DrawTargetCaptureImpl(BackendType aBackend,
const IntSize& aSize,
SurfaceFormat aFormat)
: mSize(aSize),
mSnapshot(nullptr),
mStride(0),
mSurfaceAllocationSize(0),
mFlushBytes(0)
mSurfaceAllocationSize(0)
{
RefPtr<DrawTarget> screenRefDT =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
@ -89,7 +75,6 @@ DrawTargetCaptureImpl::Init(const IntSize& aSize, DrawTarget* aRefDT)
void
DrawTargetCaptureImpl::InitForData(int32_t aStride, size_t aSurfaceAllocationSize)
{
MOZ_ASSERT(!mFlushBytes);
mStride = aStride;
mSurfaceAllocationSize = aSurfaceAllocationSize;
}
@ -358,12 +343,6 @@ DrawTargetCaptureImpl::Blur(const AlphaBoxBlur& aBlur)
AppendCommand(BlurCommand)(aBlur);
}
void
DrawTargetCaptureImpl::PadEdges(const IntRegion& aRegion)
{
AppendCommand(PadEdgesCommand)(aRegion);
}
void
DrawTargetCaptureImpl::ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform)
{
@ -412,12 +391,6 @@ DrawTargetCaptureImpl::CreateFilter(FilterType aType)
}
}
bool
DrawTargetCaptureImpl::IsEmpty() const
{
return mCommands.IsEmpty();
}
void
DrawTargetCaptureImpl::Dump()
{

View File

@ -24,7 +24,6 @@ class DrawTargetCaptureImpl : public DrawTargetCapture
friend class SourceSurfaceCapture;
public:
DrawTargetCaptureImpl(gfx::DrawTarget* aTarget, size_t aFlushBytes);
DrawTargetCaptureImpl(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat);
bool Init(const IntSize& aSize, DrawTarget* aRefDT);
@ -107,7 +106,6 @@ public:
bool aCopyBackground) override;
virtual void PopLayer() override;
virtual void Blur(const AlphaBoxBlur& aBlur) override;
virtual void PadEdges(const IntRegion& aRegion) override;
virtual void SetTransform(const Matrix &aTransform) override;
@ -149,7 +147,6 @@ public:
void ReplayToDrawTarget(DrawTarget* aDT, const Matrix& aTransform);
bool IsEmpty() const override;
void Dump() override;
protected:
@ -158,12 +155,6 @@ protected:
void MarkChanged();
private:
void FlushCommandBuffer()
{
ReplayToDrawTarget(mRefDT, Matrix());
mCommands.Clear();
}
// This storage system was used to minimize the amount of heap allocations
// that are required while recording. It should be noted there's no
// guarantees on the alignments of DrawingCommands allocated in this array.
@ -172,11 +163,6 @@ private:
if (T::AffectsSnapshot) {
MarkChanged();
}
if (mFlushBytes &&
mCommands.BufferWillAlloc<T>() &&
mCommands.BufferCapacity() > mFlushBytes) {
FlushCommandBuffer();
}
return mCommands.Append<T>();
}
template<typename T>
@ -184,11 +170,6 @@ private:
if (T::AffectsSnapshot) {
MarkChanged();
}
if (mFlushBytes &&
mCommands.BufferWillAlloc<T>() &&
mCommands.BufferCapacity() > mFlushBytes) {
FlushCommandBuffer();
}
return mCommands.ReuseOrAppend<T>();
}
@ -210,7 +191,6 @@ private:
std::vector<PushedLayer> mPushedLayers;
CaptureCommandList mCommands;
size_t mFlushBytes;
};
} // namespace gfx

View File

@ -125,13 +125,6 @@ DrawTargetDual::MaskSurface(const Pattern &aSource,
mB->MaskSurface(*source.mB, mask.mB, aOffset, aOptions);
}
void
DrawTargetDual::ClearRect(const Rect &aRect)
{
mA->FillRect(aRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
mB->FillRect(aRect, ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
}
void
DrawTargetDual::CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect,
const IntPoint &aDestination)

View File

@ -58,6 +58,7 @@ public:
FORWARD_FUNCTION1(PushClipRect, const Rect &, aRect)
FORWARD_FUNCTION(PopClip)
FORWARD_FUNCTION(PopLayer)
FORWARD_FUNCTION1(ClearRect, const Rect &, aRect)
virtual void SetTransform(const Matrix &aTransform) override {
mTransform = aTransform;
@ -86,8 +87,6 @@ public:
const Color &aColor, const Point &aOffset,
Float aSigma, CompositionOp aOp) override;
virtual void ClearRect(const Rect &aRect) override;
virtual void CopySurface(SourceSurface *aSurface, const IntRect &aSourceRect,
const IntPoint &aDestination) override;
@ -115,12 +114,6 @@ public:
const IntRect& aBounds = IntRect(),
bool aCopyBackground = false) override;
virtual bool Unrotate(IntPoint aRotation) override
{
return mA->Unrotate(aRotation) &&
mB->Unrotate(aRotation);
}
virtual already_AddRefed<SourceSurface>
CreateSourceSurfaceFromData(unsigned char *aData,
const IntSize &aSize,

View File

@ -387,28 +387,5 @@ DrawTargetTiled::PopLayer()
mPushedLayers.pop_back();
}
void
DrawTargetTiled::PadEdges(const IntRegion& aRegion)
{
for (size_t i = 0; i < mTiles.size(); i++) {
if (mTiles[i].mClippedOut) {
continue;
}
auto tileRect = RoundedOut(Rect(mTiles[i].mTileOrigin.x,
mTiles[i].mTileOrigin.y,
mTiles[i].mDrawTarget->GetSize().width,
mTiles[i].mDrawTarget->GetSize().height));
// We only need to pad edges on tiles that intersect the edge of the region
if (aRegion.Intersects(tileRect) && !aRegion.Contains(tileRect)) {
IntRegion padRegion = aRegion;
padRegion.MoveBy(-mTiles[i].mTileOrigin);
padRegion.AndWith(IntRect(0, 0, mTiles[i].mDrawTarget->GetSize().width, mTiles[i].mDrawTarget->GetSize().height));
mTiles[i].mDrawTarget->PadEdges(padRegion);
}
}
}
} // namespace gfx
} // namespace mozilla

View File

@ -124,7 +124,6 @@ public:
CompositionOp = CompositionOp::OP_OVER) override;
virtual void PopLayer() override;
virtual void PadEdges(const IntRegion& aRegion) override;
virtual void SetTransform(const Matrix &aTransform) override;

View File

@ -451,12 +451,6 @@ Factory::CreateRecordingDrawTarget(DrawEventRecorder *aRecorder, DrawTarget *aDT
return MakeAndAddRef<DrawTargetRecording>(aRecorder, aDT, aSize);
}
already_AddRefed<DrawTargetCapture>
Factory::CreateCaptureDrawTargetForTarget(gfx::DrawTarget* aTarget, size_t aFlushBytes)
{
return MakeAndAddRef<DrawTargetCaptureImpl>(aTarget, aFlushBytes);
}
already_AddRefed<DrawTargetCapture>
Factory::CreateCaptureDrawTarget(BackendType aBackend, const IntSize& aSize, SurfaceFormat aFormat)
{
@ -704,17 +698,6 @@ Factory::CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB)
return retVal.forget();
}
already_AddRefed<SourceSurface>
Factory::CreateDualSourceSurface(SourceSurface *sourceA, SourceSurface *sourceB)
{
MOZ_ASSERT(sourceA && sourceB);
RefPtr<SourceSurface> newSource =
new SourceSurfaceDual(sourceA, sourceB);
return newSource.forget();
}
#ifdef MOZ_ENABLE_FREETYPE
void

View File

@ -25,11 +25,6 @@ public:
, mB(aDTB->Snapshot())
{ }
SourceSurfaceDual(SourceSurface *aSourceA, SourceSurface *aSourceB)
: mA(aSourceA)
, mB(aSourceB)
{ }
virtual SurfaceType GetType() const override { return SurfaceType::DUAL_DT; }
virtual IntSize GetSize() const override { return mA->GetSize(); }
virtual SurfaceFormat GetFormat() const override { return mA->GetFormat(); }

View File

@ -162,8 +162,6 @@ elif CONFIG['CPU_ARCH'].startswith('mips'):
UNIFIED_SOURCES += [
'BezierUtils.cpp',
'Blur.cpp',
'BufferEdgePad.cpp',
'BufferUnrotate.cpp',
'CaptureCommandList.cpp',
'DataSourceSurface.cpp',
'DataSurfaceHelpers.cpp',

View File

@ -1,22 +1,15 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 "BufferEdgePad.h"
#include "2D.h" // for DrawTarget
#include "Point.h" // for IntSize
#include "Types.h" // for SurfaceFormat
#include "nsRegion.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
namespace mozilla {
namespace gfx {
namespace layers {
using namespace gfx;
void
PadDrawTargetOutFromRegion(DrawTarget* aDrawTarget, const nsIntRegion &aRegion)
PadDrawTargetOutFromRegion(RefPtr<DrawTarget> aDrawTarget, nsIntRegion &aRegion)
{
struct LockedBits {
uint8_t *data;
@ -96,5 +89,5 @@ PadDrawTargetOutFromRegion(DrawTarget* aDrawTarget, const nsIntRegion &aRegion)
}
}
} // namespace gfx
} // namespace layers
} // namespace mozilla

View File

@ -4,19 +4,18 @@
* 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/. */
#ifndef MOZILLA_GFX_BUFFER_EDGE_PAD_H
#define MOZILLA_GFX_BUFFER_EDGE_PAD_H
#ifndef MOZILLA_LAYERS_BUFFER_EDGE_PAD_H
#define MOZILLA_LAYERS_BUFFER_EDGE_PAD_H
#include "nsRegionFwd.h"
#include "mozilla/gfx/2D.h"
#include "nsRegion.h"
namespace mozilla {
namespace gfx {
namespace layers {
class DrawTarget;
void PadDrawTargetOutFromRegion(DrawTarget* aDrawTarget, const nsIntRegion &aRegion);
void PadDrawTargetOutFromRegion(RefPtr<gfx::DrawTarget> aDrawTarget, nsIntRegion &aRegion);
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_BUFFER_EDGE_PAD_H
#endif // MOZILLA_LAYERS_BUFFER_EDGE_PAD_H

View File

@ -11,9 +11,6 @@
#include <stdlib.h>
#include <string.h>
namespace mozilla {
namespace gfx {
void BufferUnrotate(uint8_t* aBuffer, int aByteWidth, int aHeight,
int aByteStride, int aXBoundary, int aYBoundary)
{
@ -66,5 +63,3 @@ void BufferUnrotate(uint8_t* aBuffer, int aByteWidth, int aHeight,
}
}
} // namespace gfx
} // namespace mozilla

View File

@ -4,18 +4,12 @@
* 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/. */
#ifndef MOZILLA_GFX_BUFFER_UNROTATE_H
#define MOZILLA_GFX_BUFFER_UNROTATE_H
#ifndef GFX_BUFFERUNROTATE_H
#define GFX_BUFFERUNROTATE_H
#include "mozilla/Types.h"
namespace mozilla {
namespace gfx {
void BufferUnrotate(uint8_t* aBuffer, int aByteWidth, int aHeight,
int aByteStride, int aXByteBoundary, int aYBoundary);
} // namespace gfx
} // namespace mozilla
#endif // MOZILLA_GFX_BUFFER_UNROTATE_H
#endif // GFX_BUFFERUNROTATE_H

View File

@ -51,10 +51,6 @@
#undef compress
#include "mozilla/Compression.h"
// Undo the damage done by X11
#ifdef Status
# undef Status
#endif
// Protocol buffer (generated automatically)
#include "protobuf/LayerScopePacket.pb.h"

View File

@ -12,6 +12,7 @@
#include "gfxPlatform.h"
#include "gfxPrefs.h"
#include "GeckoProfiler.h"
#include "mozilla/layers/BufferEdgePad.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/layers/SyncObject.h"
@ -33,6 +34,107 @@ namespace layers {
using namespace gfx;
bool
CapturedBufferState::Copy::CopyBuffer()
{
if (mSource->Lock(OpenMode::OPEN_READ_ONLY)) {
mDestination->UpdateDestinationFrom(*mSource, mBounds);
mSource->Unlock();
return true;
}
return false;
}
bool
CapturedBufferState::Unrotate::UnrotateBuffer()
{
return mBuffer->UnrotateBufferTo(mParameters);
}
bool
CapturedBufferState::PrepareBuffer()
{
return (!mBufferFinalize || mBufferFinalize->CopyBuffer()) &&
(!mBufferUnrotate || mBufferUnrotate->UnrotateBuffer()) &&
(!mBufferInitialize || mBufferInitialize->CopyBuffer());
}
bool
CapturedTiledPaintState::Copy::CopyBuffer()
{
RefPtr<gfx::SourceSurface> source = mSource->Snapshot();
// This operation requires the destination draw target to be untranslated,
// but the destination will have a transform from being part of a tiled draw
// target. However in this case, CopySurface ignores transforms so we don't
// need to do anything.
mDestination->CopySurface(source,
mSourceBounds,
mDestinationPoint);
return true;
}
void
CapturedTiledPaintState::Clear::ClearBuffer()
{
// See the comment in CopyBuffer for why we need to temporarily reset
// the transform of the draw target.
Matrix oldTransform = mTarget->GetTransform();
mTarget->SetTransform(Matrix());
if (mTargetOnWhite) {
mTargetOnWhite->SetTransform(Matrix());
for (auto iter = mDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
mTarget->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
mTargetOnWhite->FillRect(drawRect, ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
}
mTargetOnWhite->SetTransform(oldTransform);
} else {
for (auto iter = mDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
mTarget->ClearRect(drawRect);
}
}
mTarget->SetTransform(oldTransform);
}
void
CapturedTiledPaintState::EdgePad::EdgePadBuffer()
{
PadDrawTargetOutFromRegion(mTarget, mValidRegion);
}
void
CapturedTiledPaintState::PrePaint()
{
for (auto& copy : mCopies) {
copy.CopyBuffer();
}
for (auto& clear : mClears) {
clear.ClearBuffer();
}
}
void
CapturedTiledPaintState::Paint()
{
mTarget->DrawCapturedDT(mCapture, Matrix());
mTarget->Flush();
}
void
CapturedTiledPaintState::PostPaint()
{
if (mEdgePad) {
mEdgePad->EdgePadBuffer();
}
}
StaticAutoPtr<PaintThread> PaintThread::sSingleton;
StaticRefPtr<nsIThread> PaintThread::sThread;
PlatformThreadId PaintThread::sThreadId;
@ -190,25 +292,151 @@ PaintThread::UpdateRenderMode()
}
void
PaintThread::QueuePaintTask(PaintTask* aTask)
PaintThread::PrepareBuffer(CapturedBufferState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aTask);
if (gfxPrefs::LayersOMTPDumpCapture() && aTask->mCapture) {
aTask->mCapture->Dump();
}
MOZ_ASSERT(aState);
// If painting asynchronously, we need to acquire the compositor bridge which
// owns the underlying MessageChannel. Otherwise we leave it null and use
// synchronous dispatch.
RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
RefPtr<PaintTask> state(aTask);
RefPtr<CapturedBufferState> state(aState);
cbc->NotifyBeginAsyncPaint(state);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTask",
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PrepareBuffer",
[self, cbc, state]() -> void
{
self->AsyncPaintTask(cbc, state);
self->AsyncPrepareBuffer(cbc,
state);
});
#ifndef OMTP_FORCE_SYNC
sThread->Dispatch(task.forget());
#else
SyncRunnable::DispatchToThread(sThread, task);
#endif
}
void
PaintThread::AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
CapturedBufferState* aState)
{
AUTO_PROFILER_LABEL("PaintThread::AsyncPrepareBuffer", GRAPHICS);
MOZ_ASSERT(IsOnPaintThread());
MOZ_ASSERT(aState);
if (!aState->PrepareBuffer()) {
gfxCriticalNote << "Failed to prepare buffers on the paint thread.";
}
if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
// We need to dispatch this task to ourselves so it runs after
// AsyncEndLayer
DispatchEndLayerTransaction(aBridge);
}
}
void
PaintThread::PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
if (gfxPrefs::LayersOMTPDumpCapture() && aState->mCapture) {
aState->mCapture->Dump();
}
RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
RefPtr<CapturedPaintState> state(aState);
cbc->NotifyBeginAsyncPaint(state);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintContents",
[self, cbc, state, aCallback]() -> void
{
self->AsyncPaintContents(cbc,
state,
aCallback);
});
#ifndef OMTP_FORCE_SYNC
sThread->Dispatch(task.forget());
#else
SyncRunnable::DispatchToThread(sThread, task);
#endif
}
void
PaintThread::AsyncPaintContents(CompositorBridgeChild* aBridge,
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback)
{
AUTO_PROFILER_LABEL("PaintThread::AsyncPaintContents", GRAPHICS);
MOZ_ASSERT(IsOnPaintThread());
MOZ_ASSERT(aState);
DrawTarget* target = aState->mTargetDual;
DrawTargetCapture* capture = aState->mCapture;
Matrix oldTransform = target->GetTransform();
bool oldPermitsSubpixelAA = target->GetPermitSubpixelAA();
target->SetTransform(capture->GetTransform());
target->SetPermitSubpixelAA(capture->GetPermitSubpixelAA());
if (aCallback(aState)) {
// Draw all the things into the actual dest target.
target->DrawCapturedDT(capture, Matrix());
if (!mDrawTargetsToFlush.Contains(target)) {
mDrawTargetsToFlush.AppendElement(target);
}
if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
// This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
// gets destroyed on the main thread (See bug 1404742). This assumes (unflushed) target
// DrawTargets do not themselves hold on to UnscaledFonts.
NS_ReleaseOnMainThreadSystemGroup("CapturePaintState::DrawTargetCapture", aState->mCapture.forget());
}
}
target->SetTransform(oldTransform);
target->SetPermitSubpixelAA(oldPermitsSubpixelAA);
if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
// We need to dispatch this task to ourselves so it runs after
// AsyncEndLayer
DispatchEndLayerTransaction(aBridge);
}
}
void
PaintThread::PaintTiledContents(CapturedTiledPaintState* aState)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aState);
if (gfxPrefs::LayersOMTPDumpCapture() && aState->mCapture) {
aState->mCapture->Dump();
}
RefPtr<CompositorBridgeChild> cbc(CompositorBridgeChild::Get());
RefPtr<CapturedTiledPaintState> state(aState);
cbc->NotifyBeginAsyncPaint(state);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintTiledContents",
[self, cbc, state]() -> void
{
self->AsyncPaintTiledContents(cbc, state);
});
nsIEventTarget* paintThread = mPaintWorkers ?
@ -223,36 +451,34 @@ PaintThread::QueuePaintTask(PaintTask* aTask)
}
void
PaintThread::AsyncPaintTask(CompositorBridgeChild* aBridge,
PaintTask* aTask)
PaintThread::AsyncPaintTiledContents(CompositorBridgeChild* aBridge,
CapturedTiledPaintState* aState)
{
AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTask", GRAPHICS);
AUTO_PROFILER_LABEL("PaintThread::AsyncPaintTiledContents", GRAPHICS);
MOZ_ASSERT(IsOnPaintWorkerThread());
MOZ_ASSERT(aTask);
MOZ_ASSERT(aState);
gfx::DrawTargetCapture* capture = aTask->mCapture;
gfx::DrawTarget* target = aTask->mTarget;
target->DrawCapturedDT(capture, Matrix());
target->Flush();
aState->PrePaint();
aState->Paint();
aState->PostPaint();
if (gfxPrefs::LayersOMTPReleaseCaptureOnMainThread()) {
// This should ensure the capture drawtarget, which may hold on to UnscaledFont objects,
// gets destroyed on the main thread (See bug 1404742). This assumes (unflushed) target
// DrawTargets do not themselves hold on to UnscaledFonts.
NS_ReleaseOnMainThreadSystemGroup("PaintTask::DrawTargetCapture", aTask->mCapture.forget());
NS_ReleaseOnMainThreadSystemGroup("CapturePaintState::DrawTargetCapture", aState->mCapture.forget());
}
{
RefPtr<CompositorBridgeChild> cbc(aBridge);
RefPtr<PaintTask> Task(aTask);
RefPtr<CapturedTiledPaintState> state(aState);
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTaskFinished",
[self, cbc, Task]() -> void
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncPaintTiledContentsFinished",
[self, cbc, state]() -> void
{
self->AsyncPaintTaskFinished(cbc, Task);
self->AsyncPaintTiledContentsFinished(cbc, state);
});
#ifndef OMTP_FORCE_SYNC
@ -264,15 +490,34 @@ PaintThread::AsyncPaintTask(CompositorBridgeChild* aBridge,
}
void
PaintThread::AsyncPaintTaskFinished(CompositorBridgeChild* aBridge,
PaintTask* aTask)
PaintThread::AsyncPaintTiledContentsFinished(CompositorBridgeChild* aBridge,
CapturedTiledPaintState* aState)
{
MOZ_ASSERT(IsOnPaintThread());
if (aBridge->NotifyFinishedAsyncWorkerPaint(aTask)) {
if (aBridge->NotifyFinishedAsyncWorkerPaint(aState)) {
aBridge->NotifyFinishedAsyncEndLayerTransaction();
}
}
void
PaintThread::EndLayer()
{
MOZ_ASSERT(NS_IsMainThread());
RefPtr<PaintThread> self = this;
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::AsyncEndLayer",
[self]() -> void
{
self->AsyncEndLayer();
});
#ifndef OMTP_FORCE_SYNC
sThread->Dispatch(task.forget());
#else
SyncRunnable::DispatchToThread(sThread, task);
#endif
}
void
PaintThread::Dispatch(RefPtr<Runnable>& aRunnable)
{
@ -283,6 +528,21 @@ PaintThread::Dispatch(RefPtr<Runnable>& aRunnable)
#endif
}
void
PaintThread::AsyncEndLayer()
{
MOZ_ASSERT(IsOnPaintThread());
// Textureclient forces a flush once we "end paint", so
// users of this texture expect all the drawing to be complete.
// Force a flush now.
for (size_t i = 0; i < mDrawTargetsToFlush.Length(); i++) {
mDrawTargetsToFlush[i]->Flush();
}
mDrawTargetsToFlush.Clear();
}
void
PaintThread::EndLayerTransaction(SyncObjectClient* aSyncObject)
{

View File

@ -25,12 +25,224 @@ class DrawTargetCapture;
namespace layers {
// Holds the key parts from a RotatedBuffer::PaintState
// required to draw the captured paint state
class CapturedPaintState {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedPaintState)
public:
CapturedPaintState(nsIntRegion& aRegionToDraw,
gfx::DrawTarget* aTargetDual,
gfx::DrawTarget* aTarget,
gfx::DrawTarget* aTargetOnWhite,
const gfx::Matrix& aTargetTransform,
SurfaceMode aSurfaceMode,
gfxContentType aContentType)
: mRegionToDraw(aRegionToDraw)
, mTargetDual(aTargetDual)
, mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
, mTargetTransform(aTargetTransform)
, mSurfaceMode(aSurfaceMode)
, mContentType(aContentType)
{}
template<typename F>
void ForEachTextureClient(F aClosure) const
{
aClosure(mTextureClient);
if (mTextureClientOnWhite) {
aClosure(mTextureClientOnWhite);
}
}
void DropTextureClients()
{
mTextureClient = nullptr;
mTextureClientOnWhite = nullptr;
}
nsIntRegion mRegionToDraw;
RefPtr<TextureClient> mTextureClient;
RefPtr<TextureClient> mTextureClientOnWhite;
RefPtr<gfx::DrawTargetCapture> mCapture;
RefPtr<gfx::DrawTarget> mTargetDual;
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTarget> mTargetOnWhite;
gfx::Matrix mTargetTransform;
SurfaceMode mSurfaceMode;
gfxContentType mContentType;
protected:
virtual ~CapturedPaintState() {}
};
// Holds the key operations for a ContentClient to prepare
// its buffers for painting
class CapturedBufferState final {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedBufferState)
public:
struct Copy {
Copy(RefPtr<RotatedBuffer> aSource,
RefPtr<RotatedBuffer> aDestination,
gfx::IntRect aBounds)
: mSource(aSource)
, mDestination(aDestination)
, mBounds(aBounds)
{}
bool CopyBuffer();
RefPtr<RotatedBuffer> mSource;
RefPtr<RotatedBuffer> mDestination;
gfx::IntRect mBounds;
};
struct Unrotate {
Unrotate(RotatedBuffer::Parameters aParameters,
RefPtr<RotatedBuffer> aBuffer)
: mParameters(aParameters)
, mBuffer(aBuffer)
{}
bool UnrotateBuffer();
RotatedBuffer::Parameters mParameters;
RefPtr<RotatedBuffer> mBuffer;
};
/**
* Prepares the rotated buffers for painting by copying a previous frame
* into the buffer and/or unrotating the pixels and returns whether the
* operations were successful. If this fails a new buffer should be created
* for the frame.
*/
bool PrepareBuffer();
bool HasOperations() const
{
return mBufferFinalize || mBufferUnrotate || mBufferInitialize;
}
template<typename F>
void ForEachTextureClient(F aClosure) const
{
if (mBufferFinalize) {
if (TextureClient* source = mBufferFinalize->mSource->GetClient()) {
aClosure(source);
}
if (TextureClient* sourceOnWhite = mBufferFinalize->mSource->GetClientOnWhite()) {
aClosure(sourceOnWhite);
}
if (TextureClient* destination = mBufferFinalize->mDestination->GetClient()) {
aClosure(destination);
}
if (TextureClient* destinationOnWhite = mBufferFinalize->mDestination->GetClientOnWhite()) {
aClosure(destinationOnWhite);
}
}
if (mBufferUnrotate) {
if (TextureClient* client = mBufferUnrotate->mBuffer->GetClient()) {
aClosure(client);
}
if (TextureClient* clientOnWhite = mBufferUnrotate->mBuffer->GetClientOnWhite()) {
aClosure(clientOnWhite);
}
}
if (mBufferInitialize) {
if (TextureClient* source = mBufferInitialize->mSource->GetClient()) {
aClosure(source);
}
if (TextureClient* sourceOnWhite = mBufferInitialize->mSource->GetClientOnWhite()) {
aClosure(sourceOnWhite);
}
if (TextureClient* destination = mBufferInitialize->mDestination->GetClient()) {
aClosure(destination);
}
if (TextureClient* destinationOnWhite = mBufferInitialize->mDestination->GetClientOnWhite()) {
aClosure(destinationOnWhite);
}
}
}
void DropTextureClients()
{
mBufferFinalize = Nothing();
mBufferUnrotate = Nothing();
mBufferInitialize = Nothing();
}
Maybe<Copy> mBufferFinalize;
Maybe<Unrotate> mBufferUnrotate;
Maybe<Copy> mBufferInitialize;
protected:
~CapturedBufferState() {}
};
typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState* aPaintState);
// Holds the key operations needed to update a tiled content client on the
// paint thread.
class PaintTask {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaintTask)
class CapturedTiledPaintState {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CapturedTiledPaintState)
public:
PaintTask() {}
struct Copy {
Copy(RefPtr<gfx::DrawTarget> aSource,
RefPtr<gfx::DrawTarget> aDestination,
gfx::IntRect aSourceBounds,
gfx::IntPoint aDestinationPoint)
: mSource(aSource)
, mDestination(aDestination)
, mSourceBounds(aSourceBounds)
, mDestinationPoint(aDestinationPoint)
{}
bool CopyBuffer();
RefPtr<gfx::DrawTarget> mSource;
RefPtr<gfx::DrawTarget> mDestination;
gfx::IntRect mSourceBounds;
gfx::IntPoint mDestinationPoint;
};
struct Clear {
Clear(RefPtr<gfx::DrawTarget> aTarget,
RefPtr<gfx::DrawTarget> aTargetOnWhite,
nsIntRegion aDirtyRegion)
: mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
, mDirtyRegion(aDirtyRegion)
{}
void ClearBuffer();
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTarget> mTargetOnWhite;
nsIntRegion mDirtyRegion;
};
struct EdgePad {
EdgePad(RefPtr<gfx::DrawTarget> aTarget,
nsIntRegion&& aValidRegion)
: mTarget(aTarget)
, mValidRegion(aValidRegion)
{}
void EdgePadBuffer();
RefPtr<gfx::DrawTarget> mTarget;
nsIntRegion mValidRegion;
};
CapturedTiledPaintState()
{}
CapturedTiledPaintState(gfx::DrawTarget* aTarget,
gfx::DrawTargetCapture* aCapture)
: mTarget(aTarget)
, mCapture(aCapture)
{}
template<typename F>
void ForEachTextureClient(F aClosure) const
@ -45,12 +257,20 @@ public:
mClients.clear();
}
void PrePaint();
void Paint();
void PostPaint();
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTargetCapture> mCapture;
std::vector<Copy> mCopies;
std::vector<Clear> mClears;
Maybe<EdgePad> mEdgePad;
std::vector<RefPtr<TextureClient>> mClients;
protected:
virtual ~PaintTask() {}
virtual ~CapturedTiledPaintState() {}
};
class CompositorBridgeChild;
@ -70,7 +290,17 @@ public:
void UpdateRenderMode();
void QueuePaintTask(PaintTask* aTask);
void PrepareBuffer(CapturedBufferState* aState);
void PaintContents(CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
void PaintTiledContents(CapturedTiledPaintState* aState);
// Must be called on the main thread. Signifies that the current
// batch of CapturedPaintStates* for PaintContents have been recorded
// and the main thread is finished recording this layer.
void EndLayer();
// This allows external users to run code on the paint thread.
void Dispatch(RefPtr<Runnable>& aRunnable);
@ -100,11 +330,16 @@ private:
void InitOnPaintThread();
void InitPaintWorkers();
void AsyncPaintTask(CompositorBridgeChild* aBridge,
PaintTask* aTask);
void AsyncPaintTaskFinished(CompositorBridgeChild* aBridge,
PaintTask* aTask);
void AsyncPrepareBuffer(CompositorBridgeChild* aBridge,
CapturedBufferState* aState);
void AsyncPaintContents(CompositorBridgeChild* aBridge,
CapturedPaintState* aState,
PrepDrawTargetForPaintingCallback aCallback);
void AsyncPaintTiledContents(CompositorBridgeChild* aBridge,
CapturedTiledPaintState* aState);
void AsyncPaintTiledContentsFinished(CompositorBridgeChild* aBridge,
CapturedTiledPaintState* aState);
void AsyncEndLayer();
void AsyncEndLayerTransaction(CompositorBridgeChild* aBridge);
void DispatchEndLayerTransaction(CompositorBridgeChild* aBridge);
@ -114,6 +349,10 @@ private:
static PlatformThreadId sThreadId;
RefPtr<nsIThreadPool> mPaintWorkers;
// This shouldn't be very many elements, so a list should be fine.
// Should only be accessed on the paint thread.
nsTArray<RefPtr<gfx::DrawTarget>> mDrawTargetsToFlush;
};
} // namespace layers

View File

@ -9,6 +9,7 @@
#include <algorithm> // for max
#include "BasicImplData.h" // for BasicImplData
#include "BasicLayersImpl.h" // for ToData
#include "BufferUnrotate.h" // for BufferUnrotate
#include "GeckoProfiler.h" // for AUTO_PROFILER_LABEL
#include "Layers.h" // for PaintedLayer, Layer, etc
#include "gfxPlatform.h" // for gfxPlatform
@ -42,7 +43,9 @@ BorrowDrawTarget::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
MOZ_ASSERT(mLoanedDrawTarget);
MOZ_ASSERT(aReturned == mLoanedDrawTarget);
if (mLoanedDrawTarget) {
mLoanedDrawTarget->SetTransform(mLoanedTransform);
if (mSetTransform) {
mLoanedDrawTarget->SetTransform(mLoanedTransform);
}
mLoanedDrawTarget = nullptr;
}
aReturned = nullptr;
@ -76,23 +79,6 @@ RotatedBuffer::GetSourceRectangle(XSide aXSide, YSide aYSide) const
return result;
}
void
RotatedBuffer::BeginCapture()
{
RefPtr<gfx::DrawTarget> target = GetBufferTarget();
MOZ_ASSERT(!mCapture);
MOZ_ASSERT(target);
mCapture = Factory::CreateCaptureDrawTargetForTarget(target, gfxPrefs::LayersOMTPCaptureLimit());
}
RefPtr<gfx::DrawTargetCapture>
RotatedBuffer::EndCapture()
{
MOZ_ASSERT(mCapture);
return std::move(mCapture);
}
/**
* @param aXSide LEFT means we draw from the left side of the buffer (which
* is drawn on the right side of mBufferRect). RIGHT means we draw from
@ -106,6 +92,7 @@ RotatedBuffer::EndCapture()
void
RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
@ -122,7 +109,8 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
gfx::Point quadrantTranslation(quadrantRect.X(), quadrantRect.Y());
RefPtr<SourceSurface> snapshot = GetBufferSource();
MOZ_ASSERT(aSource != BUFFER_BOTH);
RefPtr<SourceSurface> snapshot = GetSourceSurface(aSource);
if (!snapshot) {
gfxCriticalError() << "Invalid snapshot in RotatedBuffer::DrawBufferQuadrant";
@ -189,7 +177,7 @@ RotatedBuffer::DrawBufferQuadrant(gfx::DrawTarget* aTarget,
}
void
RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget,
RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget, ContextSource aSource,
float aOpacity,
gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
@ -200,10 +188,10 @@ RotatedBuffer::DrawBufferWithRotation(gfx::DrawTarget *aTarget,
// See above, in Azure Repeat should always be a safe, even faster choice
// though! Particularly on D2D Repeat should be a lot faster, need to look
// into that. TODO[Bas]
DrawBufferQuadrant(aTarget, LEFT, TOP, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aOpacity, aOperator,aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, TOP, aSource, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, LEFT, BOTTOM, aSource, aOpacity, aOperator, aMask, aMaskTransform);
DrawBufferQuadrant(aTarget, RIGHT, BOTTOM, aSource, aOpacity, aOperator,aMask, aMaskTransform);
}
bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion)
@ -241,7 +229,7 @@ RotatedBuffer::DrawTo(PaintedLayer* aLayer,
clipped = true;
}
DrawBufferWithRotation(aTarget, aOpacity, aOp, aMask, aMaskTransform);
DrawBufferWithRotation(aTarget, BUFFER_BLACK, aOpacity, aOp, aMask, aMaskTransform);
if (clipped) {
aTarget->PopClip();
}
@ -253,18 +241,35 @@ RotatedBuffer::UpdateDestinationFrom(const RotatedBuffer& aSource,
{
DrawIterator iter;
while (DrawTarget* destDT =
BorrowDrawTargetForQuadrantUpdate(aUpdateRect, &iter)) {
BorrowDrawTargetForQuadrantUpdate(aUpdateRect, BUFFER_BLACK, &iter)) {
bool isClippingCheap = IsClippingCheap(destDT, iter.mDrawRegion);
if (isClippingCheap) {
gfxUtils::ClipToRegion(destDT, iter.mDrawRegion);
}
aSource.DrawBufferWithRotation(destDT, 1.0, CompositionOp::OP_SOURCE);
aSource.DrawBufferWithRotation(destDT, BUFFER_BLACK, 1.0, CompositionOp::OP_SOURCE);
if (isClippingCheap) {
destDT->PopClip();
}
ReturnDrawTarget(destDT);
}
if (aSource.HaveBufferOnWhite() && HaveBufferOnWhite()) {
DrawIterator whiteIter;
while (DrawTarget* destDT =
BorrowDrawTargetForQuadrantUpdate(aUpdateRect, 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();
}
ReturnDrawTarget(destDT);
}
}
}
static void
@ -326,18 +331,52 @@ RotatedBuffer::AdjustedParameters(const gfx::IntRect& aDestBufferRect) const
bool
RotatedBuffer::UnrotateBufferTo(const Parameters& aParameters)
{
RefPtr<gfx::DrawTarget> drawTarget = GetDrawTarget();
MOZ_ASSERT(drawTarget && drawTarget->IsValid());
RefPtr<gfx::DrawTarget> dtBuffer = GetDTBuffer();
RefPtr<gfx::DrawTarget> dtBufferOnWhite = GetDTBufferOnWhite();
if (mBufferRotation == IntPoint(0,0)) {
IntRect srcRect(IntPoint(0, 0), mBufferRect.Size());
IntPoint dest = mBufferRect.TopLeft() - aParameters.mBufferRect.TopLeft();
drawTarget->CopyRect(srcRect, dest);
return true;
MOZ_ASSERT(dtBuffer && dtBuffer->IsValid());
dtBuffer->CopyRect(srcRect, dest);
if (HaveBufferOnWhite()) {
MOZ_ASSERT(dtBufferOnWhite && dtBufferOnWhite->IsValid());
dtBufferOnWhite->CopyRect(srcRect, dest);
}
} else {
return drawTarget->Unrotate(aParameters.mBufferRotation);
// 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,
aParameters.mBufferRotation.x * bytesPerPixel,
aParameters.mBufferRotation.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,
aParameters.mBufferRotation.x * bytesPerPixel,
aParameters.mBufferRotation.y);
dtBufferOnWhite->ReleaseBits(data);
}
} else {
return false;
}
}
return true;
}
void
@ -356,7 +395,10 @@ RotatedBuffer::GetContentType() const
DrawTarget*
RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
DrawIterator* aIter)
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform,
Matrix* aOutMatrix)
{
IntRect bounds = aBounds;
if (aIter) {
@ -381,8 +423,19 @@ RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
bounds = aIter->mDrawRegion.GetBounds();
}
gfx::DrawTarget* dtBuffer = GetDTBuffer();
gfx::DrawTarget* dtBufferOnWhite = GetDTBufferOnWhite();
MOZ_ASSERT(!mLoanedDrawTarget, "draw target has been borrowed and not returned");
mLoanedDrawTarget = GetDrawTarget();
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;
@ -392,11 +445,18 @@ RotatedBuffer::BorrowDrawTargetForQuadrantUpdate(const IntRect& aBounds,
IntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
NS_ASSERTION(quadrantRect.Contains(bounds), "Messed up quadrants");
mLoanedTransform = mLoanedDrawTarget->GetTransform();
Matrix transform = Matrix(mLoanedTransform)
.PreTranslate(-quadrantRect.X(),
-quadrantRect.Y());
mLoanedDrawTarget->SetTransform(transform);
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;
}
@ -445,19 +505,6 @@ RemoteRotatedBuffer::Lock(OpenMode aMode)
}
}
if (mTargetOnWhite) {
mTargetDual = Factory::CreateDualDrawTarget(mTarget, mTargetOnWhite);
if (!mTargetDual || !mTargetDual->IsValid()) {
gfxCriticalNote << "Invalid dual draw target " << hexa(mTargetDual)
<< " in RemoteRotatedBuffer::Lock";
Unlock();
return false;
}
} else {
mTargetDual = mTarget;
}
return true;
}
@ -466,7 +513,6 @@ RemoteRotatedBuffer::Unlock()
{
mTarget = nullptr;
mTargetOnWhite = nullptr;
mTargetDual = nullptr;
if (mClient->IsLocked()) {
mClient->Unlock();
@ -493,10 +539,27 @@ RemoteRotatedBuffer::Clear()
mClientOnWhite = nullptr;
}
gfx::DrawTarget*
RemoteRotatedBuffer::GetBufferTarget() const
already_AddRefed<gfx::SourceSurface>
RemoteRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
return mTargetDual;
if (aSource == ContextSource::BUFFER_BLACK) {
return mTarget->Snapshot();
} else {
MOZ_ASSERT(aSource == ContextSource::BUFFER_WHITE);
return mTargetOnWhite->Snapshot();
}
}
gfx::DrawTarget*
RemoteRotatedBuffer::GetDTBuffer() const
{
return mTarget;
}
gfx::DrawTarget*
RemoteRotatedBuffer::GetDTBufferOnWhite() const
{
return mTargetOnWhite;
}
gfx::SurfaceFormat
@ -505,10 +568,27 @@ DrawTargetRotatedBuffer::GetFormat() const
return mTarget->GetFormat();
}
gfx::DrawTarget*
DrawTargetRotatedBuffer::GetBufferTarget() const
already_AddRefed<gfx::SourceSurface>
DrawTargetRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
return mTargetDual;
if (aSource == ContextSource::BUFFER_BLACK) {
return mTarget->Snapshot();
} else {
MOZ_ASSERT(aSource == ContextSource::BUFFER_WHITE);
return mTargetOnWhite->Snapshot();
}
}
gfx::DrawTarget*
DrawTargetRotatedBuffer::GetDTBuffer() const
{
return mTarget;
}
gfx::DrawTarget*
DrawTargetRotatedBuffer::GetDTBufferOnWhite() const
{
return mTargetOnWhite;
}
gfx::SurfaceFormat
@ -518,10 +598,18 @@ SourceRotatedBuffer::GetFormat() const
}
already_AddRefed<SourceSurface>
SourceRotatedBuffer::GetBufferSource() const
SourceRotatedBuffer::GetSourceSurface(ContextSource aSource) const
{
RefPtr<SourceSurface> sourceDual = mSourceDual;
return sourceDual.forget();
RefPtr<SourceSurface> surf;
if (aSource == BUFFER_BLACK) {
surf = mSource;
} else {
MOZ_ASSERT(aSource == BUFFER_WHITE);
surf = mSourceOnWhite;
}
MOZ_ASSERT(surf);
return surf.forget();
}
} // namespace layers

View File

@ -24,6 +24,7 @@ namespace mozilla {
namespace layers {
class PaintedLayer;
class CapturedBufferState;
class ContentClient;
// Mixin class for classes which need logic for loaning out a draw target.
@ -39,6 +40,11 @@ protected:
// 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;
};
/**
@ -65,44 +71,29 @@ public:
RotatedBuffer(const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: mCapture(nullptr)
, mBufferRect(aBufferRect)
: mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
, mDidSelfCopy(false)
{ }
RotatedBuffer()
: mCapture(nullptr)
, mDidSelfCopy(false)
: mDidSelfCopy(false)
{ }
/**
* Initializes the rotated buffer to begin capturing all drawing performed
* on it, to be eventually replayed. Callers must call EndCapture, or
* FlushCapture before the rotated buffer is destroyed.
/*
* Which buffer should be drawn to/read from.
*/
void BeginCapture();
/**
* Finishes a capture and returns it. The capture must be replayed to the
* buffer before it is presented or it will contain invalid contents.
*/
RefPtr<gfx::DrawTargetCapture> EndCapture();
/**
* Returns whether the RotatedBuffer is currently capturing all drawing
* performed on it, to be eventually replayed.
*/
bool IsCapturing() const
{
return !!mCapture;
}
enum ContextSource {
BUFFER_BLACK, // The normal buffer, or buffer with black background when using component alpha.
BUFFER_WHITE, // The buffer with white background, only valid with component alpha.
BUFFER_BOTH // The combined black/white buffers, only valid for writing operations, not reading.
};
/**
* Draws the contents of this rotated buffer into the specified draw target.
* It is the callers repsonsibility to ensure aTarget is flushed after calling
* this method.
*/
void DrawBufferWithRotation(gfx::DrawTarget* aTarget,
void DrawBufferWithRotation(gfx::DrawTarget* aTarget, ContextSource aSource,
float aOpacity = 1.0,
gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER,
gfx::SourceSurface* aMask = nullptr,
@ -159,7 +150,10 @@ public:
*/
gfx::DrawTarget*
BorrowDrawTargetForQuadrantUpdate(const gfx::IntRect& aBounds,
DrawIterator* aIter);
ContextSource aSource,
DrawIterator* aIter,
bool aSetTransform = true,
gfx::Matrix* aOutTransform = nullptr);
struct Parameters {
Parameters(const gfx::IntRect& aBufferRect,
@ -244,11 +238,10 @@ public:
virtual gfx::SurfaceFormat GetFormat() const = 0;
virtual already_AddRefed<gfx::SourceSurface> GetBufferSource() const
{
return GetBufferTarget()->Snapshot();
}
virtual gfx::DrawTarget* GetBufferTarget() const = 0;
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const = 0;
virtual gfx::DrawTarget* GetDTBuffer() const = 0;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const = 0;
virtual TextureClient* GetClient() const {
return nullptr;
@ -257,11 +250,15 @@ public:
return nullptr;
}
/**
* Creates a shallow copy of the rotated buffer with the same underlying
* texture clients and draw targets. Rotated buffers are not thread safe,
* so a copy needs to be sent for off main thread painting.
*/
virtual RefPtr<RotatedBuffer> ShallowCopy() const = 0;
protected:
virtual ~RotatedBuffer()
{
MOZ_ASSERT(!mCapture);
}
virtual ~RotatedBuffer() {}
enum XSide {
LEFT, RIGHT
@ -273,27 +270,18 @@ protected:
gfx::Rect GetSourceRectangle(XSide aXSide, YSide aYSide) const;
gfx::DrawTarget* GetDrawTarget() const
{
if (mCapture) {
return mCapture;
}
return GetBufferTarget();
}
/*
* If aMask is non-null, then it is used as an alpha mask for rendering this
* buffer. aMaskTransform must be non-null if aMask is non-null, and is used
* to adjust the coordinate space of the mask.
*/
void DrawBufferQuadrant(gfx::DrawTarget* aTarget, XSide aXSide, YSide aYSide,
ContextSource aSource,
float aOpacity,
gfx::CompositionOp aOperator,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform) const;
RefPtr<gfx::DrawTargetCapture> mCapture;
/** The area of the PaintedLayer that is covered by the buffer as a whole */
gfx::IntRect mBufferRect;
/**
@ -341,17 +329,28 @@ public:
virtual gfx::SurfaceFormat GetFormat() const override;
virtual gfx::DrawTarget* GetBufferTarget() const override;
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
virtual gfx::DrawTarget* GetDTBuffer() const override;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
virtual TextureClient* GetClient() const override { return mClient; }
virtual TextureClient* GetClientOnWhite() const override { return mClientOnWhite; }
virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
return new RemoteRotatedBuffer {
mClient, mClientOnWhite,
mTarget, mTargetOnWhite,
mBufferRect, mBufferRotation
};
}
void SyncWithObject(SyncObjectClient* aSyncObject);
void Clear();
private:
RemoteRotatedBuffer(TextureClient* aClient, TextureClient* aClientOnWhite,
gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite, gfx::DrawTarget* aTargetDual,
gfx::DrawTarget* aTarget, gfx::DrawTarget* aTargetOnWhite,
const gfx::IntRect& aBufferRect,
const gfx::IntPoint& aBufferRotation)
: RotatedBuffer(aBufferRect, aBufferRotation)
@ -359,7 +358,6 @@ private:
, mClientOnWhite(aClientOnWhite)
, mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
, mTargetDual(aTargetDual)
{ }
RefPtr<TextureClient> mClient;
@ -367,7 +365,6 @@ private:
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTarget> mTargetOnWhite;
RefPtr<gfx::DrawTarget> mTargetDual;
};
/**
@ -383,29 +380,32 @@ public:
: RotatedBuffer(aBufferRect, aBufferRotation)
, mTarget(aTarget)
, mTargetOnWhite(aTargetOnWhite)
{
if (mTargetOnWhite) {
mTargetDual = gfx::Factory::CreateDualDrawTarget(mTarget, mTargetOnWhite);
} else {
mTargetDual = mTarget;
}
}
{ }
virtual bool IsLocked() override { return false; }
virtual bool Lock(OpenMode aMode) override { return true; }
virtual void Unlock() override {}
virtual bool HaveBuffer() const override { return !!mTargetDual; }
virtual bool HaveBuffer() const override { return !!mTarget; }
virtual bool HaveBufferOnWhite() const override { return !!mTargetOnWhite; }
virtual gfx::SurfaceFormat GetFormat() const override;
virtual gfx::DrawTarget* GetBufferTarget() const override;
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
virtual gfx::DrawTarget* GetDTBuffer() const override;
virtual gfx::DrawTarget* GetDTBufferOnWhite() const override;
virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
return new DrawTargetRotatedBuffer {
mTarget, mTargetOnWhite,
mBufferRect, mBufferRotation
};
}
private:
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTarget> mTargetOnWhite;
RefPtr<gfx::DrawTarget> mTargetDual;
};
/**
@ -421,27 +421,29 @@ public:
: RotatedBuffer(aBufferRect, aBufferRotation)
, mSource(aSource)
, mSourceOnWhite(aSourceOnWhite)
{
mSourceDual = gfx::Factory::CreateDualSourceSurface(mSource, mSourceOnWhite);
}
{ }
virtual bool IsLocked() override { return false; }
virtual bool Lock(OpenMode aMode) override { return false; }
virtual void Unlock() override {}
virtual already_AddRefed<gfx::SourceSurface> GetBufferSource() const override;
virtual already_AddRefed<gfx::SourceSurface> GetSourceSurface(ContextSource aSource) const override;
virtual gfx::SurfaceFormat GetFormat() const override;
virtual bool HaveBuffer() const override { return !!mSourceDual; }
virtual bool HaveBuffer() const override { return !!mSource; }
virtual bool HaveBufferOnWhite() const override { return !!mSourceOnWhite; }
virtual gfx::DrawTarget* GetBufferTarget() const override { return nullptr; }
virtual gfx::DrawTarget* GetDTBuffer() const override { return nullptr; }
virtual gfx::DrawTarget* GetDTBufferOnWhite() const override { return nullptr; }
virtual RefPtr<RotatedBuffer> ShallowCopy() const override {
return nullptr;
}
private:
RefPtr<gfx::SourceSurface> mSource;
RefPtr<gfx::SourceSurface> mSourceOnWhite;
RefPtr<gfx::SourceSurface> mSourceDual;
};
} // namespace layers

View File

@ -8,7 +8,6 @@
#include <unordered_set>
#include "base/process_util.h"
#include "chrome/common/mach_ipc_mac.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
#include "mozilla/layers/CompositorThread.h"
@ -212,7 +211,7 @@ TextureSync::Shutdown()
void
TextureSync::UpdateTextureLocks(base::ProcessId aProcessId)
{
if (aProcessId == base::GetCurrentProcId()) {
if (aProcessId == getpid()) {
DispatchCheckTexturesForUnlock();
return;
}
@ -225,7 +224,7 @@ TextureSync::UpdateTextureLocks(base::ProcessId aProcessId)
bool
TextureSync::WaitForTextures(base::ProcessId aProcessId, const nsTArray<uint64_t>& textureIds)
{
if (aProcessId == base::GetCurrentProcId()) {
if (aProcessId == getpid()) {
bool success = WaitForTextureIdsToUnlock(aProcessId, MakeSpan<uint64_t>(textureIds));
if (!success) {
LOG_ERROR("Failed waiting for textures to unlock.\n");
@ -244,7 +243,7 @@ TextureSync::WaitForTextures(base::ProcessId aProcessId, const nsTArray<uint64_t
reqTextureIds[i] = textureIds[i];
}
req->pid = base::GetCurrentProcId();
req->pid = getpid();
bool dataWasSet = smsg.SetData(req, messageSize);
if (!dataWasSet) {

View File

@ -52,6 +52,23 @@ ClientPaintedLayer::EnsureContentClient()
return true;
}
bool
ClientPaintedLayer::CanRecordLayer(ReadbackProcessor* aReadback)
{
// If we don't have a paint thread, this is either not the content
// process or the pref is disabled.
if (!PaintThread::Get()) {
return false;
}
// Not supported yet
if (aReadback && UsedForReadback()) {
return false;
}
return true;
}
void
ClientPaintedLayer::UpdateContentClient(PaintState& aState)
{
@ -78,6 +95,7 @@ ClientPaintedLayer::UpdatePaintRegion(PaintState& aState)
if (!aState.mRegionToDraw.IsEmpty() && !ClientManager()->GetPaintedLayerCallback()) {
ClientManager()->SetTransactionIncomplete();
mContentClient->EndPaint(nullptr);
return false;
}
@ -90,17 +108,8 @@ ClientPaintedLayer::UpdatePaintRegion(PaintState& aState)
return true;
}
void
ClientPaintedLayer::FinishPaintState(PaintState& aState)
{
if (aState.mAsyncTask && !aState.mAsyncTask->mCapture->IsEmpty()) {
ClientManager()->SetQueuedAsyncPaints();
PaintThread::Get()->QueuePaintTask(aState.mAsyncTask);
}
}
uint32_t
ClientPaintedLayer::GetPaintFlags(ReadbackProcessor* aReadback)
ClientPaintedLayer::GetPaintFlags()
{
uint32_t flags = ContentClient::PAINT_CAN_DRAW_ROTATED;
#ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
@ -113,43 +122,34 @@ ClientPaintedLayer::GetPaintFlags(ReadbackProcessor* aReadback)
}
}
#endif
if ((!aReadback || !UsedForReadback()) && PaintThread::Get()) {
flags |= ContentClient::PAINT_ASYNC;
}
return flags;
}
void
ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
ClientPaintedLayer::PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
{
AUTO_PROFILER_LABEL("ClientPaintedLayer::RenderLayerWithReadback", GRAPHICS);
AUTO_PROFILER_LABEL("ClientPaintedLayer::PaintThebes", GRAPHICS);
NS_ASSERTION(ClientManager()->InDrawing(),
"Can only draw in drawing phase");
RenderMaskLayers(this);
if (!EnsureContentClient()) {
return;
}
nsTArray<ReadbackProcessor::Update> readbackUpdates;
nsIntRegion readbackRegion;
if (aReadback && UsedForReadback()) {
aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
}
uint32_t flags = GetPaintFlags(aReadback);
uint32_t flags = GetPaintFlags();
PaintState state = mContentClient->BeginPaint(this, flags);
if (!UpdatePaintRegion(state)) {
mContentClient->EndPaint(state, nullptr);
FinishPaintState(state);
return;
}
bool didUpdate = false;
RotatedBuffer::DrawIterator iter;
while (DrawTarget* target = mContentClient->BorrowDrawTargetForPainting(state, &iter)) {
if (!target || !target->IsValid()) {
if (target) {
mContentClient->ReturnDrawTarget(target);
}
continue;
}
SetAntialiasingFlags(this, target);
RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(target);
@ -168,14 +168,152 @@ ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
didUpdate = true;
}
mContentClient->EndPaint(state, &readbackUpdates);
FinishPaintState(state);
mContentClient->EndPaint(aReadbackUpdates);
if (didUpdate) {
UpdateContentClient(state);
}
}
class MOZ_RAII AutoQueuedAsyncPaint
{
public:
explicit AutoQueuedAsyncPaint(ClientLayerManager* aLayerManager)
: mLayerManager(aLayerManager)
, mQueuedAsyncPaints(false)
{ }
void Queue() { mQueuedAsyncPaints = true; }
~AutoQueuedAsyncPaint()
{
if (mQueuedAsyncPaints) {
mLayerManager->SetQueuedAsyncPaints();
}
}
private:
ClientLayerManager* mLayerManager;
bool mQueuedAsyncPaints;
};
/***
* If we can, let's paint this ClientPaintedLayer's contents off the main thread.
* The essential idea is that we ask the ContentClient for a DrawTarget and record
* the moz2d commands. On the Paint Thread, we replay those commands to the
* destination draw target. There are a couple of lifetime issues here though:
*
* 1) TextureClient owns the underlying buffer and DrawTarget. Because of this
* we have to keep the TextureClient and DrawTarget alive but trick the
* TextureClient into thinking it's already returned the DrawTarget
* since we iterate through different Rects to get DrawTargets*. If
* the TextureClient goes away, the DrawTarget and thus buffer can too.
* 2) When ContentClient::EndPaint happens, it flushes the DrawTarget. We have
* to Reflush on the Paint Thread
* 3) DrawTarget API is NOT thread safe. We get around this by recording
* on the main thread and painting on the paint thread. Logically,
* ClientLayerManager will force a flushed paint and block the main thread
* if we have another transaction. Thus we have a gap between when the main
* thread records, the paint thread paints, and we block the main thread
* from trying to paint again. The underlying API however is NOT thread safe.
* 4) We have both "sync" and "async" OMTP. Sync OMTP means we paint on the main thread
* but block the main thread while the paint thread paints. Async OMTP doesn't block
* the main thread. Sync OMTP is only meant to be used as a debugging tool.
*/
void
ClientPaintedLayer::PaintOffMainThread()
{
AutoQueuedAsyncPaint asyncPaints(ClientManager());
uint32_t flags = GetPaintFlags();
PaintState state = mContentClient->BeginPaint(this, flags | ContentClient::PAINT_ASYNC);
if (state.mBufferState && state.mBufferState->HasOperations()) {
PaintThread::Get()->PrepareBuffer(state.mBufferState);
asyncPaints.Queue();
}
if (!UpdatePaintRegion(state)) {
return;
}
bool didUpdate = false;
RotatedBuffer::DrawIterator iter;
// Debug Protip: Change to BorrowDrawTargetForPainting if using sync OMTP.
while (RefPtr<CapturedPaintState> captureState =
mContentClient->BorrowDrawTargetForRecording(state, &iter))
{
DrawTarget* target = captureState->mTargetDual;
if (!target || !target->IsValid()) {
if (target) {
mContentClient->ReturnDrawTarget(target);
}
continue;
}
RefPtr<DrawTargetCapture> captureDT =
Factory::CreateCaptureDrawTarget(target->GetBackendType(),
target->GetSize(),
target->GetFormat());
captureDT->SetTransform(captureState->mTargetTransform);
SetAntialiasingFlags(this, captureDT);
RefPtr<gfxContext> ctx = gfxContext::CreatePreservingTransformOrNull(captureDT);
MOZ_ASSERT(ctx); // already checked the target above
ClientManager()->GetPaintedLayerCallback()(this,
ctx,
iter.mDrawRegion,
iter.mDrawRegion,
state.mClip,
state.mRegionToInvalidate,
ClientManager()->GetPaintedLayerCallbackData());
ctx = nullptr;
captureState->mCapture = captureDT.forget();
PaintThread::Get()->PaintContents(captureState,
ContentClient::PrepareDrawTargetForPainting);
mContentClient->ReturnDrawTarget(target);
asyncPaints.Queue();
didUpdate = true;
}
PaintThread::Get()->EndLayer();
mContentClient->EndPaint(nullptr);
if (didUpdate) {
UpdateContentClient(state);
}
}
void
ClientPaintedLayer::RenderLayerWithReadback(ReadbackProcessor *aReadback)
{
RenderMaskLayers(this);
if (!EnsureContentClient()) {
return;
}
if (CanRecordLayer(aReadback)) {
PaintOffMainThread();
return;
}
nsTArray<ReadbackProcessor::Update> readbackUpdates;
nsIntRegion readbackRegion;
if (aReadback && UsedForReadback()) {
aReadback->GetPaintedLayerUpdates(this, &readbackUpdates);
}
PaintThebes(&readbackUpdates);
}
already_AddRefed<PaintedLayer>
ClientLayerManager::CreatePaintedLayer()
{

View File

@ -113,13 +113,15 @@ public:
}
protected:
void PaintThebes(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates);
void RecordThebes();
bool CanRecordLayer(ReadbackProcessor* aReadback);
bool HasMaskLayers();
bool EnsureContentClient();
uint32_t GetPaintFlags(ReadbackProcessor* aReadback);
uint32_t GetPaintFlags();
void UpdateContentClient(PaintState& aState);
bool UpdatePaintRegion(PaintState& aState);
void FinishPaintState(PaintState& aState);
void PaintOffMainThread();
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) override;

View File

@ -116,12 +116,9 @@ ContentClient::PaintState
ContentClient::BeginPaint(PaintedLayer* aLayer,
uint32_t aFlags)
{
BufferDecision dest = CalculateBufferForPaint(aLayer, aFlags);
bool asyncPaint = (aFlags & PAINT_ASYNC);
PaintState result;
result.mAsyncPaint = asyncPaint;
BufferDecision dest = CalculateBufferForPaint(aLayer, aFlags);
result.mContentType = dest.mBufferContentType;
if (!dest.mCanKeepBufferContents) {
@ -157,54 +154,26 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
!(aFlags & (PAINT_WILL_RESAMPLE | PAINT_NO_ROTATION)) &&
!(aLayer->Manager()->AsWebRenderLayerManager());
bool canDrawRotated = aFlags & PAINT_CAN_DRAW_ROTATED;
OpenMode readMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC
: OpenMode::OPEN_READ;
OpenMode writeMode = asyncPaint ? OpenMode::OPEN_READ_WRITE_ASYNC
: OpenMode::OPEN_READ_WRITE;
bool asyncPaint = (aFlags & PAINT_ASYNC);
IntRect drawBounds = result.mRegionToDraw.GetBounds();
OpenMode lockMode = asyncPaint ? OpenMode::OPEN_READ_WRITE_ASYNC
: OpenMode::OPEN_READ_WRITE;
if (asyncPaint) {
result.mAsyncTask = new PaintTask();
result.mBufferState = new CapturedBufferState();
}
// Try to acquire the back buffer, copy over contents if we are using a new buffer,
// and rotate or unrotate the buffer as necessary
if (mBuffer && dest.mCanReuseBuffer) {
if (mBuffer->Lock(writeMode)) {
auto newParameters = mBuffer->AdjustedParameters(dest.mBufferRect);
if (mBuffer) {
if (mBuffer->Lock(lockMode)) {
// Do not modify result.mRegionToDraw or result.mContentType after this call.
Maybe<CapturedBufferState::Copy> bufferFinalize =
FinalizeFrame(result.mRegionToDraw);
bool needsUnrotate = (!canHaveRotation && newParameters.IsRotated()) ||
(!canDrawRotated && newParameters.RectWrapsBuffer(drawBounds));
bool canUnrotate = !asyncPaint || mBuffer->BufferRotation() == IntPoint(0,0);
// Only begin a frame and copy over the previous frame if we don't need
// to unrotate, or we can try to unrotate it. This is to ensure that we
// don't have a paint task that depends on another paint task.
if (!needsUnrotate || canUnrotate) {
// If we're async painting then begin to capture draw commands
if (asyncPaint) {
mBuffer->BeginCapture();
}
// Do not modify result.mRegionToDraw or result.mContentType after this call.
FinalizeFrame(result);
}
// Try to rotate the buffer or unrotate it if we cannot be rotated
if (needsUnrotate) {
if (canUnrotate && mBuffer->UnrotateBufferTo(newParameters)) {
newParameters.SetUnrotated();
mBuffer->SetParameters(newParameters);
} else {
MOZ_ASSERT(!asyncPaint);
MOZ_ASSERT(GetFrontBuffer());
mBuffer->Unlock();
dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
dest.mCanReuseBuffer = false;
}
} else {
mBuffer->SetParameters(newParameters);
if (asyncPaint) {
result.mBufferState->mBufferFinalize = std::move(bufferFinalize);
} else if (bufferFinalize) {
bufferFinalize->CopyBuffer();
}
} else {
result.mRegionToDraw = dest.mNeededRegion;
@ -213,6 +182,55 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
}
}
if (dest.mCanReuseBuffer) {
MOZ_ASSERT(mBuffer);
bool canReuseBuffer = false;
auto newParameters = mBuffer->AdjustedParameters(dest.mBufferRect);
Maybe<CapturedBufferState::Unrotate> bufferUnrotate = Nothing();
if ((!canHaveRotation && newParameters.IsRotated()) ||
(!canDrawRotated && newParameters.RectWrapsBuffer(drawBounds))) {
bufferUnrotate = Some(CapturedBufferState::Unrotate {
newParameters,
mBuffer->ShallowCopy(),
});
}
// If we're async painting then return the buffer state to
// be dispatched to the paint thread, otherwise do it now
if (asyncPaint) {
// We cannot do a buffer unrotate if the buffer is already rotated
// and we're async painting as that may fail
if (!bufferUnrotate ||
mBuffer->BufferRotation() == IntPoint(0,0)) {
result.mBufferState->mBufferUnrotate = std::move(bufferUnrotate);
// We can then assume that preparing the buffer will always
// succeed and update our parameters unconditionally
if (result.mBufferState->mBufferUnrotate) {
newParameters.SetUnrotated();
}
mBuffer->SetParameters(newParameters);
canReuseBuffer = true;
}
} else {
if (!bufferUnrotate || bufferUnrotate->UnrotateBuffer()) {
if (bufferUnrotate) {
newParameters.SetUnrotated();
}
mBuffer->SetParameters(newParameters);
canReuseBuffer = true;
}
}
if (!canReuseBuffer) {
dest.mBufferRect = ComputeBufferRect(dest.mNeededRegion.GetBounds());
dest.mCanReuseBuffer = false;
}
}
MOZ_ASSERT(dest.mBufferRect.Contains(result.mRegionToDraw.GetBounds()));
NS_ASSERTION(!(aFlags & PAINT_WILL_RESAMPLE) || dest.mBufferRect == dest.mNeededRegion.GetBounds(),
@ -243,30 +261,39 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
return result;
}
if (!newBuffer->Lock(writeMode)) {
if (!newBuffer->Lock(lockMode)) {
gfxCriticalNote << "Failed to lock new back buffer.";
Clear();
return result;
}
if (asyncPaint) {
newBuffer->BeginCapture();
}
// If we have an existing front buffer, copy it into the new back buffer
RefPtr<RotatedBuffer> frontBuffer = GetFrontBuffer();
if (mBuffer) {
if (mBuffer->IsLocked()) {
mBuffer->Unlock();
}
if (frontBuffer && frontBuffer->Lock(readMode)) {
nsIntRegion updateRegion = newBuffer->BufferRect();
updateRegion.Sub(updateRegion, result.mRegionToDraw);
if (!updateRegion.IsEmpty()) {
newBuffer->UpdateDestinationFrom(*frontBuffer, updateRegion.GetBounds());
}
auto bufferInitialize = CapturedBufferState::Copy {
mBuffer->ShallowCopy(),
newBuffer->ShallowCopy(),
updateRegion.GetBounds(),
};
frontBuffer->Unlock();
} else {
result.mRegionToDraw = dest.mNeededRegion;
// If we're async painting then return the buffer state to
// be dispatched to the paint thread, otherwise do it now
if (asyncPaint) {
result.mBufferState->mBufferInitialize = Some(std::move(bufferInitialize));
} else {
if (!bufferInitialize.CopyBuffer()) {
gfxCriticalNote << "Failed to copy front buffer to back buffer.";
return result;
}
}
}
}
Clear();
@ -276,14 +303,6 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
NS_ASSERTION(canHaveRotation || mBuffer->BufferRotation() == IntPoint(0,0),
"Rotation disabled, but we have nonzero rotation?");
if (result.mAsyncPaint) {
result.mAsyncTask->mTarget = mBuffer->GetBufferTarget();
result.mAsyncTask->mClients.push_back(mBuffer->GetClient());
if (mBuffer->GetClientOnWhite()) {
result.mAsyncTask->mClients.push_back(mBuffer->GetClientOnWhite());
}
}
nsIntRegion invalidate;
invalidate.Sub(aLayer->GetValidRegion(), dest.mBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
@ -294,12 +313,22 @@ ContentClient::BeginPaint(PaintedLayer* aLayer,
return result;
}
void
ContentClient::EndPaint(PaintState& aPaintState, nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
DrawTarget*
ContentClient::BorrowDrawTargetForPainting(ContentClient::PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter /* = nullptr */)
{
if (aPaintState.mAsyncTask) {
aPaintState.mAsyncTask->mCapture = mBuffer->EndCapture();
RefPtr<CapturedPaintState> capturedState =
ContentClient::BorrowDrawTargetForRecording(aPaintState, aIter, true);
if (!capturedState) {
return nullptr;
}
if (!ContentClient::PrepareDrawTargetForPainting(capturedState)) {
return nullptr;
}
return capturedState->mTargetDual;
}
nsIntRegion
@ -323,37 +352,37 @@ ExpandDrawRegion(ContentClient::PaintState& aPaintState,
return *drawPtr;
}
DrawTarget*
ContentClient::BorrowDrawTargetForPainting(ContentClient::PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter /* = nullptr */)
RefPtr<CapturedPaintState>
ContentClient::BorrowDrawTargetForRecording(ContentClient::PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE || !mBuffer) {
return nullptr;
}
Matrix transform;
DrawTarget* result = mBuffer->BorrowDrawTargetForQuadrantUpdate(
aPaintState.mRegionToDraw.GetBounds(),
aIter);
if (!result || !result->IsValid()) {
if (result) {
mBuffer->ReturnDrawTarget(result);
}
RotatedBuffer::BUFFER_BOTH, aIter,
aSetTransform,
&transform);
if (!result) {
return nullptr;
}
nsIntRegion regionToDraw =
ExpandDrawRegion(aPaintState, aIter, result->GetBackendType());
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA ||
aPaintState.mContentType == gfxContentType::COLOR_ALPHA) {
// HaveBuffer() => we have an existing buffer that we must clear
for (auto iter = regionToDraw.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
result->ClearRect(Rect(rect.X(), rect.Y(), rect.Width(), rect.Height()));
}
}
return result;
RefPtr<CapturedPaintState> state =
new CapturedPaintState(regionToDraw,
result,
mBuffer->GetDTBuffer(),
mBuffer->GetDTBufferOnWhite(),
transform,
aPaintState.mMode,
aPaintState.mContentType);
return state;
}
void
@ -362,6 +391,40 @@ ContentClient::ReturnDrawTarget(gfx::DrawTarget*& aReturned)
mBuffer->ReturnDrawTarget(aReturned);
}
/*static */ bool
ContentClient::PrepareDrawTargetForPainting(CapturedPaintState* aState)
{
MOZ_ASSERT(aState);
RefPtr<DrawTarget> target = aState->mTarget;
RefPtr<DrawTarget> whiteTarget = aState->mTargetOnWhite;
if (aState->mSurfaceMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!target || !target->IsValid() ||
!whiteTarget || !whiteTarget->IsValid()) {
// This can happen in release builds if allocating one of the two buffers
// failed. This in turn can happen if unreasonably large textures are
// requested.
return false;
}
for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
target->FillRect(Rect(rect.X(), rect.Y(), rect.Width(), rect.Height()),
ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));
whiteTarget->FillRect(Rect(rect.X(), rect.Y(), rect.Width(), rect.Height()),
ColorPattern(Color(1.0, 1.0, 1.0, 1.0)));
}
} else if (aState->mContentType == gfxContentType::COLOR_ALPHA &&
target->IsValid()) {
// HaveBuffer() => we have an existing buffer that we must clear
for (auto iter = aState->mRegionToDraw.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& rect = iter.Get();
target->ClearRect(Rect(rect.X(), rect.Y(), rect.Width(), rect.Height()));
}
}
return true;
}
ContentClient::BufferDecision
ContentClient::CalculateBufferForPaint(PaintedLayer* aLayer,
uint32_t aFlags)
@ -539,6 +602,31 @@ ContentClientBasic::CreateBuffer(gfxContentType aType,
return new DrawTargetRotatedBuffer(drawTarget, nullptr, aRect, IntPoint(0,0));
}
RefPtr<CapturedPaintState>
ContentClientBasic::BorrowDrawTargetForRecording(ContentClient::PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform)
{
// BasicLayers does not yet support OMTP.
return nullptr;
}
RefPtr<CapturedPaintState>
ContentClientRemoteBuffer::BorrowDrawTargetForRecording(ContentClient::PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform)
{
RefPtr<CapturedPaintState> cps = ContentClient::BorrowDrawTargetForRecording(aPaintState, aIter, aSetTransform);
if (!cps) {
return nullptr;
}
RemoteRotatedBuffer* remoteBuffer = GetRemoteBuffer();
cps->mTextureClient = remoteBuffer->GetClient();
cps->mTextureClientOnWhite = remoteBuffer->GetClientOnWhite();
return cps.forget();
}
class RemoteBufferReadbackProcessor : public TextureReadbackSink
{
public:
@ -580,7 +668,7 @@ public:
dt->SetTransform(Matrix::Translation(offset.x, offset.y));
rotBuffer.DrawBufferWithRotation(dt);
rotBuffer.DrawBufferWithRotation(dt, RotatedBuffer::BUFFER_BLACK);
update.mLayer->GetSink()->EndUpdate(update.mUpdateRect + offset);
}
@ -596,7 +684,7 @@ private:
};
void
ContentClientRemoteBuffer::EndPaint(PaintState& aPaintState, nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
ContentClientRemoteBuffer::EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates)
{
MOZ_ASSERT(!mBuffer || !mBuffer->HaveBufferOnWhite() ||
!aReadbackUpdates || aReadbackUpdates->Length() == 0);
@ -616,7 +704,7 @@ ContentClientRemoteBuffer::EndPaint(PaintState& aPaintState, nsTArray<ReadbackPr
remoteBuffer->SyncWithObject(mForwarder->GetSyncObject());
}
ContentClient::EndPaint(aPaintState, aReadbackUpdates);
ContentClient::EndPaint(aReadbackUpdates);
}
RefPtr<RotatedBuffer>
@ -845,18 +933,18 @@ ContentClientDoubleBuffered::BeginPaint(PaintedLayer* aLayer,
// After executing, the new back buffer has the same (interesting) pixels as
// 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(PaintState& aPaintState)
Maybe<CapturedBufferState::Copy>
ContentClientDoubleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
{
if (!mFrontAndBackBufferDiffer) {
MOZ_ASSERT(!mFrontBuffer || !mFrontBuffer->DidSelfCopy(),
"If the front buffer did a self copy then our front and back buffer must be different.");
return;
return Nothing();
}
MOZ_ASSERT(mFrontBuffer && mBuffer);
if (!mFrontBuffer || !mBuffer) {
return;
return Nothing();
}
MOZ_LAYERS_LOG(("BasicShadowableThebes(%p): reading back <x=%d,y=%d,w=%d,h=%d>",
@ -876,27 +964,16 @@ ContentClientDoubleBuffered::FinalizeFrame(PaintState& aPaintState)
// No point in sync'ing what we are going to draw over anyway. And if there is
// nothing to sync at all, there is nothing to do and we can go home early.
updateRegion.Sub(updateRegion, aPaintState.mRegionToDraw);
updateRegion.Sub(updateRegion, aRegionToDraw);
if (updateRegion.IsEmpty()) {
return;
return Nothing();
}
OpenMode openMode = aPaintState.mAsyncPaint
? OpenMode::OPEN_READ_ASYNC
: OpenMode::OPEN_READ_ONLY;
if (mFrontBuffer->Lock(openMode)) {
mBuffer->UpdateDestinationFrom(*mFrontBuffer, updateRegion.GetBounds());
if (aPaintState.mAsyncPaint) {
aPaintState.mAsyncTask->mClients.push_back(mFrontBuffer->GetClient());
if (mFrontBuffer->GetClientOnWhite()) {
aPaintState.mAsyncTask->mClients.push_back(mFrontBuffer->GetClientOnWhite());
}
}
mFrontBuffer->Unlock();
}
return Some(CapturedBufferState::Copy {
mFrontBuffer->ShallowCopy(),
mBuffer->ShallowCopy(),
updateRegion.GetBounds(),
});
}
void

View File

@ -22,7 +22,7 @@
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/LayersTypes.h" // for TextureDumpMode
#include "mozilla/layers/TextureClient.h" // for TextureClient
#include "mozilla/layers/PaintThread.h" // for PaintTask
#include "mozilla/layers/PaintThread.h" // for CapturedBufferState
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/mozalloc.h" // for operator delete
#include "ReadbackProcessor.h" // For ReadbackProcessor::Update
@ -40,6 +40,10 @@ class DrawTarget;
namespace layers {
class PaintedLayer;
class CapturedPaintState;
class CapturedBufferState;
typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
/**
* A compositable client for PaintedLayers. These are different to Image/Canvas
@ -107,8 +111,6 @@ public:
, mMode(SurfaceMode::SURFACE_NONE)
, mClip(DrawRegionClip::NONE)
, mContentType(gfxContentType::SENTINEL)
, mAsyncPaint(false)
, mAsyncTask(nullptr)
{}
nsIntRegion mRegionToDraw;
@ -116,8 +118,7 @@ public:
SurfaceMode mMode;
DrawRegionClip mClip;
gfxContentType mContentType;
bool mAsyncPaint;
RefPtr<PaintTask> mAsyncTask;
RefPtr<CapturedBufferState> mBufferState;
};
enum {
@ -148,7 +149,7 @@ public:
* this.
*/
virtual PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags);
virtual void EndPaint(PaintState& aPaintState, nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr);
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) {}
/**
* Fetch a DrawTarget for rendering. The DrawTarget remains owned by
@ -169,8 +170,20 @@ public:
PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter = nullptr);
/**
* Borrow a draw target for recording. The required transform for correct painting
* is not applied to the returned DrawTarget by default, BUT it is
* required to be whenever drawing does happen.
*/
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(
PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform = false);
void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
static bool PrepareDrawTargetForPainting(CapturedPaintState*);
enum {
BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing with
// component alpha.
@ -206,12 +219,8 @@ protected:
* aRegionToDraw is the region which is guaranteed to be overwritten when
* drawing the next frame.
*/
virtual void FinalizeFrame(PaintState& aPaintState) {
}
virtual RefPtr<RotatedBuffer> GetFrontBuffer() const
{
return mBuffer;
virtual Maybe<CapturedBufferState::Copy> FinalizeFrame(const nsIntRegion& aRegionToDraw) {
return Nothing();
}
/**
@ -232,6 +241,10 @@ class ContentClientBasic final : public ContentClient
public:
explicit ContentClientBasic(gfx::BackendType aBackend);
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform) override;
void DrawTo(PaintedLayer* aLayer,
gfx::DrawTarget* aTarget,
float aOpacity,
@ -281,7 +294,11 @@ public:
bool aDumpHtml=false,
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
virtual void EndPaint(PaintState& aPaintState, nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform) override;
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
virtual void Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion);
@ -347,12 +364,7 @@ public:
virtual PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags) override;
virtual void FinalizeFrame(PaintState& aPaintState) override;
virtual RefPtr<RotatedBuffer> GetFrontBuffer() const override
{
return mFrontBuffer;
}
virtual Maybe<CapturedBufferState::Copy> FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
virtual TextureInfo GetTextureInfo() const override
{

View File

@ -8,6 +8,7 @@
#include "ClientTiledPaintedLayer.h"
#include "mozilla/layers/LayerMetricsWrapper.h"
#include "mozilla/layers/BufferEdgePad.h"
namespace mozilla {
@ -152,7 +153,7 @@ void ClientMultiTiledLayerBuffer::MaybeSyncTextures(const nsIntRegion& aPaintReg
// texture IDs that we need to ensure are unused by the GPU before we
// continue.
if (!aPaintRegion.IsEmpty()) {
MOZ_ASSERT(mPaintTasks.size() == 0);
MOZ_ASSERT(mPaintStates.size() == 0);
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
const TileCoordIntPoint tileCoord = aNewTiles.TileCoord(i);
@ -220,8 +221,7 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
MaybeSyncTextures(paintRegion, newTiles, scaledTileSize);
if (!paintRegion.IsEmpty()) {
MOZ_ASSERT(mPaintTasks.size() == 0);
MOZ_ASSERT(mPaintStates.size() == 0);
for (size_t i = 0; i < newTileCount; ++i) {
const TileCoordIntPoint tileCoord = newTiles.TileCoord(i);
@ -244,6 +244,13 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
}
if (!mPaintTiles.empty()) {
// Perform buffer copies and clears if we don't have the paint thread
if (!(aFlags & TilePaintFlags::Async)) {
for (const auto& state : mPaintStates) {
state->PrePaint();
}
}
// Create a tiled draw target
gfx::TileSet tileset;
for (size_t i = 0; i < mPaintTiles.size(); ++i) {
@ -268,10 +275,18 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
DrawRegionClip::DRAW, nsIntRegion(), mCallbackData);
ctx = nullptr;
// Edge padding allows us to avoid resampling artifacts
if (gfxPrefs::TileEdgePaddingEnabled() && mResolution == 1) {
drawTarget->PadEdges(newValidRegion);
// Dispatch to the paint thread or do any work left over
if (aFlags & TilePaintFlags::Async) {
for (const auto& state : mPaintStates) {
PaintThread::Get()->PaintTiledContents(state);
}
mManager->SetQueuedAsyncPaints();
} else {
for (const auto& state : mPaintStates) {
state->PostPaint();
}
}
mPaintStates.clear();
// Reset
mPaintTiles.clear();
@ -279,24 +294,6 @@ void ClientMultiTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
std::numeric_limits<int32_t>::max());
}
// Dispatch to the paint thread
if (aFlags & TilePaintFlags::Async) {
bool queuedTask = false;
for (const auto& state : mPaintTasks) {
if (!state->mCapture->IsEmpty()) {
PaintThread::Get()->QueuePaintTask(state);
queuedTask = true;
}
}
if (queuedTask) {
mManager->SetQueuedAsyncPaints();
}
mPaintTasks.clear();
}
for (uint32_t i = 0; i < mRetainedTiles.Length(); ++i) {
TileClient& tile = mRetainedTiles[i];
UnlockTile(tile);
@ -338,19 +335,21 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
nsIntRegion tileVisibleRegion = mNewValidRegion.MovedBy(-aTileOrigin);
tileVisibleRegion.ScaleRoundOut(mResolution, mResolution);
std::vector<CapturedTiledPaintState::Copy> asyncPaintCopies;
std::vector<RefPtr<TextureClient>> asyncPaintClients;
Maybe<AcquiredBackBuffer> backBuffer =
aTile.AcquireBackBuffer(mCompositableClient,
tileDirtyRegion,
tileVisibleRegion,
content,
mode,
aFlags);
if (!backBuffer) {
return false;
}
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
aTile.GetBackBuffer(mCompositableClient,
tileDirtyRegion,
tileVisibleRegion,
content, mode,
extraPainted,
aFlags,
&backBufferOnWhite,
&asyncPaintCopies,
&asyncPaintClients);
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
@ -371,34 +370,96 @@ ClientMultiTiledLayerBuffer::ValidateTile(TileClient& aTile,
// Mark the region we will be painting and the region we copied from the front buffer as
// needing to be uploaded to the compositor
aTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect);
aTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
// Add the region we copied from the front buffer into the painted region
extraPainted.MoveBy(aTileOrigin);
extraPainted.And(extraPainted, mNewValidRegion);
if (!backBuffer) {
return false;
}
// Get the targets to draw into, and create a dual target
// if we are using component alpha
RefPtr<DrawTarget> dt = backBuffer->BorrowDrawTarget();
RefPtr<DrawTarget> dtOnWhite;
if (backBufferOnWhite) {
dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
}
if (!dt || (backBufferOnWhite && !dtOnWhite)) {
aTile.DiscardBuffers();
return false;
}
RefPtr<DrawTarget> drawTarget;
if (dtOnWhite) {
drawTarget = Factory::CreateDualDrawTarget(dt, dtOnWhite);
} else {
drawTarget = dt;
}
// Create the paint operation that will be either dispatched to the paint
// thread, or executed synchronously
RefPtr<CapturedTiledPaintState> paintState = new CapturedTiledPaintState();
paintState->mCopies = std::move(asyncPaintCopies);
// We need to clear the dirty region of the tile before painting
// if we are painting non-opaque content
if (mode != SurfaceMode::SURFACE_OPAQUE) {
for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
backBuffer->mTarget->ClearRect(drawRect);
auto clear = CapturedTiledPaintState::Clear{
dt,
dtOnWhite,
tileDirtyRegion
};
paintState->mClears.push_back(clear);
}
// Only worry about padding when not doing low-res because it simplifies
// the math and the artifacts won't be noticable
// Edge padding prevents sampling artifacts when compositing.
if (gfxPrefs::TileEdgePaddingEnabled() && mResolution == 1) {
IntRect tileRect = IntRect(0, 0,
GetScaledTileSize().width,
GetScaledTileSize().height);
// We only need to pad out if the tile has area that's not valid
if (!tileVisibleRegion.Contains(tileRect)) {
tileVisibleRegion = tileVisibleRegion.Intersect(tileRect);
paintState->mEdgePad = Some(CapturedTiledPaintState::EdgePad{
drawTarget,
std::move(tileVisibleRegion),
});
}
}
paintState->mClients = std::move(asyncPaintClients);
paintState->mClients.push_back(backBuffer);
if (backBufferOnWhite) {
paintState->mClients.push_back(backBufferOnWhite);
}
gfx::Tile paintTile;
paintTile.mTileOrigin = gfx::IntPoint(aTileOrigin.x, aTileOrigin.y);
paintTile.mDrawTarget = backBuffer->mTarget;
mPaintTiles.push_back(paintTile);
if (aFlags & TilePaintFlags::Async) {
RefPtr<PaintTask> task = new PaintTask();
task->mCapture = backBuffer->mCapture;
task->mTarget = backBuffer->mBackBuffer;
task->mClients = std::move(backBuffer->mTextureClients);
mPaintTasks.push_back(task);
RefPtr<DrawTargetCapture> captureDT =
Factory::CreateCaptureDrawTarget(drawTarget->GetBackendType(),
drawTarget->GetSize(),
drawTarget->GetFormat());
paintTile.mDrawTarget = captureDT;
paintState->mTarget = drawTarget;
paintState->mCapture = captureDT;
} else {
MOZ_RELEASE_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
MOZ_RELEASE_ASSERT(backBuffer->mCapture == nullptr);
paintTile.mDrawTarget = drawTarget;
}
mPaintStates.push_back(paintState);
mPaintTiles.push_back(paintTile);
mTilingOrigin.x = std::min(mTilingOrigin.x, paintTile.mTileOrigin.x);
mTilingOrigin.y = std::min(mTilingOrigin.y, paintTile.mTileOrigin.y);

View File

@ -53,7 +53,7 @@ public:
BasicTiledLayerPaintData* aPaintData,
LayerManager::DrawPaintedLayerCallback aCallback,
void* aCallbackData) override;
void ResetPaintedAndValidState() override {
mValidRegion.SetEmpty();
mTiles.mSize.width = 0;
@ -122,7 +122,7 @@ private:
// Parameters that are collected during Update for a paint before they
// are either executed or replayed on the paint thread.
std::vector<gfx::Tile> mPaintTiles;
std::vector<RefPtr<PaintTask>> mPaintTasks;
std::vector<RefPtr<CapturedTiledPaintState>> mPaintStates;
/**
* While we're adding tiles, this is used to keep track of the position of

View File

@ -153,17 +153,22 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
nsIntRegion tileVisibleRegion = aNewValidRegion.MovedBy(-mTilingOrigin);
nsIntRegion tileDirtyRegion = paintRegion.MovedBy(-mTilingOrigin);
Maybe<AcquiredBackBuffer> backBuffer =
mTile.AcquireBackBuffer(mCompositableClient,
tileDirtyRegion,
tileVisibleRegion,
content,
mode,
aFlags);
std::vector<RefPtr<TextureClient>> paintClients;
std::vector<CapturedTiledPaintState::Copy> paintCopies;
std::vector<CapturedTiledPaintState::Clear> paintClears;
if (!backBuffer) {
return;
}
nsIntRegion extraPainted;
RefPtr<TextureClient> backBufferOnWhite;
RefPtr<TextureClient> backBuffer =
mTile.GetBackBuffer(mCompositableClient,
tileDirtyRegion,
tileVisibleRegion,
content, mode,
extraPainted,
aFlags,
&backBufferOnWhite,
&paintCopies,
&paintClients);
// Mark the area we need to paint in the back buffer as invalid in the
// front buffer as they will become out of sync.
@ -179,7 +184,20 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
// Mark the region we will be painting and the region we copied from the front buffer as
// needing to be uploaded to the compositor
mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(backBuffer->mUpdatedRect);
mTile.mUpdateRect = tileDirtyRegion.GetBounds().Union(extraPainted.GetBounds());
extraPainted.MoveBy(mTilingOrigin);
extraPainted.And(extraPainted, aNewValidRegion);
if (!backBuffer) {
return;
}
RefPtr<gfx::DrawTarget> dt = backBuffer->BorrowDrawTarget();
RefPtr<gfx::DrawTarget> dtOnWhite;
if (backBufferOnWhite) {
dtOnWhite = backBufferOnWhite->BorrowDrawTarget();
}
// If the old frontbuffer was discarded then attempt to copy what we
// can from it to the new backbuffer.
@ -188,45 +206,80 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
copyableRegion.And(aNewValidRegion, discardedValidRegion);
copyableRegion.SubOut(aDirtyRegion);
OpenMode readMode = asyncPaint ? OpenMode::OPEN_READ_ASYNC
: OpenMode::OPEN_READ;
DualTextureClientAutoLock discardedBuffer(discardedFrontBuffer, discardedFrontBufferOnWhite, readMode);
if (discardedBuffer.Succeeded()) {
RefPtr<gfx::SourceSurface> discardedSurface = discardedBuffer->Snapshot();
for (auto iter = copyableRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect src = iter.Get() - discardedValidRegion.GetBounds().TopLeft();
const gfx::IntPoint dest = iter.Get().TopLeft() - mTilingOrigin;
backBuffer->mTarget->CopySurface(discardedSurface, src, dest);
}
if (!mTile.CopyFromBuffer(discardedFrontBuffer,
discardedFrontBufferOnWhite,
discardedValidRegion.GetBounds().TopLeft(),
mTilingOrigin,
copyableRegion,
aFlags,
&paintCopies)) {
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
} else {
TILING_LOG("TILING %p: Region copied from discarded frontbuffer %s\n", &mPaintedLayer, Stringify(copyableRegion).c_str());
// We don't need to repaint valid content that was just copied.
paintRegion.SubOut(copyableRegion);
copyableRegion.MoveBy(-mTilingOrigin);
tileDirtyRegion.SubOut(copyableRegion);
} else {
gfxWarning() << "[Tiling:Client] Failed to aquire the discarded front buffer's draw target";
}
}
if (mode != SurfaceMode::SURFACE_OPAQUE) {
for (auto iter = tileDirtyRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::Rect drawRect(iter.Get().X(), iter.Get().Y(),
iter.Get().Width(), iter.Get().Height());
backBuffer->mTarget->ClearRect(drawRect);
auto clear = CapturedTiledPaintState::Clear{
dt,
dtOnWhite,
tileDirtyRegion,
};
if (asyncPaint) {
paintClears.push_back(clear);
} else {
clear.ClearBuffer();
}
}
// Paint into the target
{
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(backBuffer->mTarget);
if (dtOnWhite) {
dt = gfx::Factory::CreateDualDrawTarget(dt, dtOnWhite);
dtOnWhite = nullptr;
}
if (asyncPaint) {
// Create a capture draw target
RefPtr<gfx::DrawTargetCapture> captureDT =
gfx::Factory::CreateCaptureDrawTarget(dt->GetBackendType(),
dt->GetSize(),
dt->GetFormat());
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(captureDT);
if (!ctx) {
gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(backBuffer->mTarget);
gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt);
return;
}
ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
ctx = nullptr;
// Replay on the paint thread
RefPtr<CapturedTiledPaintState> capturedState =
new CapturedTiledPaintState(dt,
captureDT);
capturedState->mClients = std::move(paintClients);
capturedState->mClients.push_back(backBuffer);
if (backBufferOnWhite) {
capturedState->mClients.push_back(backBufferOnWhite);
}
capturedState->mCopies = std::move(paintCopies);
capturedState->mClears = std::move(paintClears);
PaintThread::Get()->PaintTiledContents(capturedState);
mManager->SetQueuedAsyncPaints();
} else {
MOZ_ASSERT(paintCopies.size() == 0);
MOZ_ASSERT(paintClears.size() == 0);
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
if (!ctx) {
gfxDevCrash(gfx::LogReason::InvalidContext) << "SingleTiledContextClient context problem " << gfx::hexa(dt);
return;
}
ctx->SetMatrix(ctx->CurrentMatrix().PreTranslate(-mTilingOrigin.x, -mTilingOrigin.y));
@ -234,24 +287,10 @@ ClientSingleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
aCallback(&mPaintedLayer, ctx, paintRegion, paintRegion, DrawRegionClip::DRAW, nsIntRegion(), aCallbackData);
}
if (asyncPaint) {
if (!backBuffer->mCapture->IsEmpty()) {
RefPtr<PaintTask> task = new PaintTask();
task->mCapture = backBuffer->mCapture;
task->mTarget = backBuffer->mBackBuffer;
task->mClients = std::move(backBuffer->mTextureClients);
PaintThread::Get()->QueuePaintTask(task);
mManager->SetQueuedAsyncPaints();
}
} else {
MOZ_ASSERT(backBuffer->mTarget == backBuffer->mBackBuffer);
MOZ_ASSERT(!backBuffer->mCapture);
}
// The new buffer is now validated, remove the dirty region from it.
mTile.mInvalidBack.SubOut(tileDirtyRegion);
backBuffer = Nothing();
dt = nullptr;
mTile.Flip();
UnlockTile(mTile);

View File

@ -829,80 +829,6 @@ private:
bool mSucceeded;
};
// Automatically locks and unlocks two texture clients, and exposes them as a
// a single draw target dual. Since texture locking is fallible, Succeeded()
// must be checked on the guard object before proceeding.
class MOZ_RAII DualTextureClientAutoLock
{
public:
DualTextureClientAutoLock(TextureClient* aTexture, TextureClient* aTextureOnWhite, OpenMode aMode)
: mTarget(nullptr)
, mTexture(aTexture)
, mTextureOnWhite(aTextureOnWhite)
{
if (!mTexture->Lock(aMode)) {
return;
}
mTarget = mTexture->BorrowDrawTarget();
if (!mTarget) {
mTexture->Unlock();
return;
}
if (!mTextureOnWhite) {
return;
}
if (!mTextureOnWhite->Lock(aMode)) {
mTarget = nullptr;
mTexture->Unlock();
return;
}
RefPtr<gfx::DrawTarget> targetOnWhite = mTextureOnWhite->BorrowDrawTarget();
if (!targetOnWhite) {
mTarget = nullptr;
mTexture->Unlock();
mTextureOnWhite->Unlock();
return;
}
mTarget = gfx::Factory::CreateDualDrawTarget(mTarget, targetOnWhite);
if (!mTarget) {
mTarget = nullptr;
mTexture->Unlock();
mTextureOnWhite->Unlock();
}
}
~DualTextureClientAutoLock()
{
if (Succeeded()) {
mTarget = nullptr;
mTexture->Unlock();
if (mTextureOnWhite) {
mTextureOnWhite->Unlock();
}
}
}
bool Succeeded() const { return !!mTarget; }
operator gfx::DrawTarget*() const { return mTarget; }
gfx::DrawTarget* operator->() const { return mTarget; }
RefPtr<gfx::DrawTarget> mTarget;
private:
RefPtr<TextureClient> mTexture;
RefPtr<TextureClient> mTextureOnWhite;
};
class KeepAlive
{
public:

View File

@ -429,13 +429,59 @@ TileClient::Flip()
mInvalidBack = invalidFront;
}
static bool
CopyFrontToBack(TextureClient* aFront,
TextureClient* aBack,
const gfx::IntRect& aRectToCopy,
TilePaintFlags aFlags,
std::vector<CapturedTiledPaintState::Copy>* aCopies,
std::vector<RefPtr<TextureClient>>* aClients)
{
bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC : OpenMode::OPEN_NONE;
TextureClientAutoLock frontLock(aFront, OpenMode::OPEN_READ | asyncFlags);
if (!frontLock.Succeeded()) {
return false;
}
if (!aBack->Lock(OpenMode::OPEN_READ_WRITE | asyncFlags)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock the tile's back buffer";
return false;
}
RefPtr<gfx::DrawTarget> backBuffer = aBack->BorrowDrawTarget();
if (!backBuffer) {
gfxWarning() << "[Tiling:Client] Failed to aquire the back buffer's draw target";
return false;
}
RefPtr<gfx::DrawTarget> frontBuffer = aFront->BorrowDrawTarget();
if (!frontBuffer) {
gfxWarning() << "[Tiling:Client] Failed to aquire the front buffer's draw target";
return false;
}
auto copy = CapturedTiledPaintState::Copy{
frontBuffer, backBuffer, aRectToCopy, aRectToCopy.TopLeft()
};
if (asyncPaint && aCopies) {
aClients->push_back(aFront);
aCopies->push_back(copy);
} else {
copy.CopyBuffer();
}
return true;
}
void
TileClient::ValidateFromFront(const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfx::DrawTarget* aBackBuffer,
TilePaintFlags aFlags,
IntRect* aCopiedRect,
std::vector<RefPtr<TextureClient>>* aClients)
TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
nsIntRegion& aAddPaintedRegion,
TilePaintFlags aFlags,
std::vector<CapturedTiledPaintState::Copy>* aCopies,
std::vector<RefPtr<TextureClient>>* aClients)
{
if (!mBackBuffer || !mFrontBuffer) {
return;
@ -457,7 +503,7 @@ TileClient::ValidateFromFront(const nsIntRegion& aDirtyRegion,
regionToCopy.Sub(regionToCopy, aDirtyRegion);
regionToCopy.And(regionToCopy, aVisibleRegion);
*aCopiedRect = regionToCopy.GetBounds();
aAddPaintedRegion = regionToCopy;
if (regionToCopy.IsEmpty()) {
// Just redraw it all.
@ -468,20 +514,14 @@ TileClient::ValidateFromFront(const nsIntRegion& aDirtyRegion,
// is unlikely that we'd save much by copying each individual rect of the
// region, but we can reevaluate this if it becomes an issue.
const IntRect rectToCopy = regionToCopy.GetBounds();
OpenMode readMode = !!(aFlags & TilePaintFlags::Async) ? OpenMode::OPEN_READ_ASYNC : OpenMode::OPEN_READ;
DualTextureClientAutoLock frontBuffer(mFrontBuffer, mFrontBufferOnWhite, readMode);
if (!frontBuffer.Succeeded()) {
if (!CopyFrontToBack(mFrontBuffer, mBackBuffer, rectToCopy, aFlags, aCopies, aClients)) {
return;
}
RefPtr<gfx::SourceSurface> frontSurface = frontBuffer->Snapshot();
aBackBuffer->CopySurface(frontSurface, rectToCopy, rectToCopy.TopLeft());
if (aFlags & TilePaintFlags::Async) {
aClients->push_back(mFrontBuffer);
if (mFrontBufferOnWhite) {
aClients->push_back(mFrontBufferOnWhite);
if (mBackBufferOnWhite) {
MOZ_ASSERT(mFrontBufferOnWhite);
if (!CopyFrontToBack(mFrontBufferOnWhite, mBackBufferOnWhite, rectToCopy, aFlags, aCopies, aClients)) {
return;
}
}
@ -544,6 +584,59 @@ TileClient::DiscardBackBuffer()
}
}
bool
TileClient::CopyFromBuffer(RefPtr<TextureClient> aBuffer,
RefPtr<TextureClient> aBufferOnWhite,
nsIntPoint aBufferOrigin,
nsIntPoint aTileOrigin,
const nsIntRegion& aRegion,
TilePaintFlags aFlags,
std::vector<CapturedTiledPaintState::Copy>* aCopies)
{
if (aRegion.IsEmpty()) {
return true;
}
bool asyncPaint = !!(aFlags & TilePaintFlags::Async);
auto CopyBuffer = [&aRegion, asyncPaint, &aCopies] (auto aSrc, auto aSrcOrigin, auto aDest, auto aDestOrigin) {
MOZ_ASSERT(aDest->IsLocked());
OpenMode asyncFlags = asyncPaint ? OpenMode::OPEN_ASYNC
: OpenMode::OPEN_NONE;
TextureClientAutoLock lock(aSrc, OpenMode::OPEN_READ | asyncFlags);
if (!lock.Succeeded()) {
return false;
}
RefPtr<gfx::DrawTarget> srcTarget = aSrc->BorrowDrawTarget();
RefPtr<gfx::DrawTarget> destTarget = aDest->BorrowDrawTarget();
if (!srcTarget || !destTarget) {
return false;
}
for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
const gfx::IntRect src = iter.Get() - aSrcOrigin;
const gfx::IntPoint dest = iter.Get().TopLeft() - aDestOrigin;
auto copy = CapturedTiledPaintState::Copy{
srcTarget, destTarget, src, dest
};
if (asyncPaint) {
aCopies->push_back(copy);
} else {
copy.CopyBuffer();
}
}
return true;
};
return CopyBuffer(aBuffer, aBufferOrigin, mBackBuffer, aTileOrigin) &&
(!aBufferOnWhite ||
!mBackBufferOnWhite ||
CopyBuffer(aBufferOnWhite, aBufferOrigin, mBackBufferOnWhite, aTileOrigin));
}
static already_AddRefed<TextureClient>
CreateBackBufferTexture(TextureClient* aCurrentTexture,
CompositableClient& aCompositable,
@ -597,17 +690,21 @@ TileClient::GetSyncTextureSerials(SurfaceMode aMode, nsTArray<uint64_t>& aSerial
}
}
Maybe<AcquiredBackBuffer>
TileClient::AcquireBackBuffer(CompositableClient& aCompositable,
const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfxContentType aContent,
SurfaceMode aMode,
TilePaintFlags aFlags)
TextureClient*
TileClient::GetBackBuffer(CompositableClient& aCompositable,
const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfxContentType aContent,
SurfaceMode aMode,
nsIntRegion& aAddPaintedRegion,
TilePaintFlags aFlags,
RefPtr<TextureClient>* aBackBufferOnWhite,
std::vector<CapturedTiledPaintState::Copy>* aCopies,
std::vector<RefPtr<TextureClient>>* aClients)
{
if (!mAllocator) {
gfxCriticalError() << "[TileClient] Missing TextureClientAllocator.";
return Nothing();
return nullptr;
}
if (aMode != SurfaceMode::SURFACE_COMPONENT_ALPHA) {
// It can happen that a component-alpha layer stops being on component alpha
@ -646,7 +743,7 @@ TileClient::AcquireBackBuffer(CompositableClient& aCompositable,
if (!mBackBuffer) {
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
return nullptr;
}
mInvalidBack = IntRect(IntPoint(), mBackBuffer->GetSize());
}
@ -659,85 +756,38 @@ TileClient::AcquireBackBuffer(CompositableClient& aCompositable,
if (!mBackBufferOnWhite) {
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
return nullptr;
}
mInvalidBack = IntRect(IntPoint(), mBackBufferOnWhite->GetSize());
}
}
ValidateBackBufferFromFront(aDirtyRegion, aVisibleRegion, aAddPaintedRegion, aFlags, aCopies, aClients);
}
// Lock the texture clients
OpenMode lockMode = aFlags & TilePaintFlags::Async ? OpenMode::OPEN_READ_WRITE_ASYNC
: OpenMode::OPEN_READ_WRITE;
if (!mBackBuffer->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (B)";
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
if (!mBackBuffer->IsLocked()) {
if (!mBackBuffer->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (B)";
DiscardBackBuffer();
DiscardFrontBuffer();
return nullptr;
}
}
if (mBackBufferOnWhite && !mBackBufferOnWhite->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (W)";
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
if (mBackBufferOnWhite && !mBackBufferOnWhite->IsLocked()) {
if (!mBackBufferOnWhite->Lock(lockMode)) {
gfxCriticalError() << "[Tiling:Client] Failed to lock a tile (W)";
DiscardBackBuffer();
DiscardFrontBuffer();
return nullptr;
}
}
// Borrow their draw targets
RefPtr<gfx::DrawTarget> backBuffer = mBackBuffer->BorrowDrawTarget();
RefPtr<gfx::DrawTarget> backBufferOnWhite = nullptr;
if (mBackBufferOnWhite) {
backBufferOnWhite = mBackBufferOnWhite->BorrowDrawTarget();
}
if (!backBuffer || (mBackBufferOnWhite && !backBufferOnWhite)) {
gfxCriticalError() << "[Tiling:Client] Failed to acquire draw targets for tile";
DiscardBackBuffer();
DiscardFrontBuffer();
return Nothing();
}
// Construct a dual target if necessary
RefPtr<DrawTarget> target;
if (backBufferOnWhite) {
backBuffer = Factory::CreateDualDrawTarget(backBuffer, backBufferOnWhite);
backBufferOnWhite = nullptr;
target = backBuffer;
} else {
target = backBuffer;
}
// Construct a capture draw target if necessary
RefPtr<DrawTargetCapture> capture;
if (aFlags & TilePaintFlags::Async) {
capture = Factory::CreateCaptureDrawTargetForTarget(target, gfxPrefs::LayersOMTPCaptureLimit());
target = capture;
}
// Gather texture clients
std::vector<RefPtr<TextureClient>> clients;
clients.push_back(RefPtr<TextureClient>(mBackBuffer));
if (mBackBufferOnWhite) {
clients.push_back(mBackBufferOnWhite);
}
// Copy from the front buerr to the back if necessary
IntRect updatedRect;
ValidateFromFront(aDirtyRegion,
aVisibleRegion,
target,
aFlags,
&updatedRect,
&clients);
return Some(AcquiredBackBuffer {
target,
capture,
backBuffer,
std::move(updatedRect),
std::move(clients),
});
*aBackBufferOnWhite = mBackBufferOnWhite;
return mBackBuffer;
}
TileDescriptor

View File

@ -16,7 +16,6 @@
#include "Units.h" // for CSSPoint
#include "gfxTypes.h"
#include "mozilla/Attributes.h" // for override
#include "mozilla/gfx/2D.h" // for gfx::Tile
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/ipc/Shmem.h" // for Shmem
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory
@ -51,33 +50,6 @@ enum class TilePaintFlags : uint8_t {
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TilePaintFlags)
struct AcquiredBackBuffer
{
AcquiredBackBuffer(gfx::DrawTarget* aTarget,
gfx::DrawTargetCapture* aCapture,
gfx::DrawTarget* aBackBuffer,
const gfx::IntRect& aUpdatedRect,
std::vector<RefPtr<TextureClient>>&& aTextureClients)
: mTarget(aTarget)
, mCapture(aCapture)
, mBackBuffer(aBackBuffer)
, mUpdatedRect(aUpdatedRect)
, mTextureClients(aTextureClients)
{}
AcquiredBackBuffer(const AcquiredBackBuffer&) = delete;
AcquiredBackBuffer& operator=(const AcquiredBackBuffer&) = delete;
AcquiredBackBuffer(AcquiredBackBuffer&&) = default;
AcquiredBackBuffer& operator=(AcquiredBackBuffer&&) = default;
RefPtr<gfx::DrawTarget> mTarget;
RefPtr<gfx::DrawTargetCapture> mCapture;
RefPtr<gfx::DrawTarget> mBackBuffer;
gfx::IntRect mUpdatedRect;
std::vector<RefPtr<TextureClient>> mTextureClients;
};
/**
* Represent a single tile in tiled buffer. The buffer keeps tiles,
* each tile keeps a reference to a texture client and a read-lock. This
@ -156,17 +128,32 @@ struct TileClient
*
* If nullptr is returned, aTextureClientOnWhite is undefined.
*/
Maybe<AcquiredBackBuffer> AcquireBackBuffer(CompositableClient&,
const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfxContentType aContent,
SurfaceMode aMode,
TilePaintFlags aFlags);
TextureClient* GetBackBuffer(CompositableClient&,
const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfxContentType aContent, SurfaceMode aMode,
nsIntRegion& aAddPaintedRegion,
TilePaintFlags aFlags,
RefPtr<TextureClient>* aTextureClientOnWhite,
std::vector<CapturedTiledPaintState::Copy>* aCopies,
std::vector<RefPtr<TextureClient>>* aClients);
void DiscardFrontBuffer();
void DiscardBackBuffer();
/*
* Copy aRegion from aBuffer and aBufferOnWhite positioned at aBufferOrigin
* into ourselves assuming we are positioned at aTileOrigin.
*/
bool CopyFromBuffer(RefPtr<TextureClient> aBuffer,
RefPtr<TextureClient> aBufferOnWhite,
nsIntPoint aBufferOrigin,
nsIntPoint aTileOrigin,
const nsIntRegion& aRegion,
TilePaintFlags aFlags,
std::vector<CapturedTiledPaintState::Copy>* aCopies);
/* We wrap the back buffer in a class that disallows assignment
* so that we can track when ever it changes so that we can update
* the expiry tracker for expiring the back buffers */
@ -199,12 +186,12 @@ private:
* Copies dirty pixels from the front buffer into the back buffer,
* and records the copied region in aAddPaintedRegion.
*/
void ValidateFromFront(const nsIntRegion& aDirtyRegion,
const nsIntRegion& aVisibleRegion,
gfx::DrawTarget* aBackBuffer,
TilePaintFlags aFlags,
gfx::IntRect* aCopiedRegion,
std::vector<RefPtr<TextureClient>>* aClients);
void ValidateBackBufferFromFront(const nsIntRegion &aDirtyRegion,
const nsIntRegion& aVisibleRegion,
nsIntRegion& aAddPaintedRegion,
TilePaintFlags aFlags,
std::vector<CapturedTiledPaintState::Copy>* aCopies,
std::vector<RefPtr<TextureClient>>* aClients);
};
/**

View File

@ -125,6 +125,7 @@ EXPORTS.mozilla.layers += [
'basic/MacIOSurfaceTextureHostBasic.h',
'basic/TextureHostBasic.h',
'BSPTree.h',
'BufferEdgePad.h',
'BufferTexture.h',
'CanvasRenderer.h',
'client/CanvasClient.h',
@ -353,7 +354,9 @@ UNIFIED_SOURCES += [
'basic/BasicPaintedLayer.cpp',
'basic/TextureHostBasic.cpp',
'BSPTree.cpp',
'BufferEdgePad.cpp',
'BufferTexture.cpp',
'BufferUnrotate.cpp',
'CanvasRenderer.cpp',
'client/CanvasClient.cpp',
'client/ClientCanvasLayer.cpp',

View File

@ -289,7 +289,7 @@ void nsRegion::SimplifyOutwardByArea(uint32_t aThreshold)
typedef void (*visit_fn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
void nsRegion::VisitEdges (visit_fn visit, void *closure) const
void nsRegion::VisitEdges (visit_fn visit, void *closure)
{
if (mBands.IsEmpty()) {
visit(closure, VisitSide::LEFT, mBounds.X(), mBounds.Y(), mBounds.X(), mBounds.YMost());
@ -310,7 +310,7 @@ void nsRegion::VisitEdges (visit_fn visit, void *closure) const
if (band != bandFinal) {
do {
const Band& topBand = *band;
Band& topBand = *band;
band++;
for (const Strip& strip : band->mStrips) {
@ -320,7 +320,7 @@ void nsRegion::VisitEdges (visit_fn visit, void *closure) const
if (band->top == topBand.bottom) {
// Two bands touching each other vertically.
const Band& bottomBand = *band;
Band& bottomBand = *band;
auto topStrip = std::begin(topBand.mStrips);
auto bottomStrip = std::begin(bottomBand.mStrips);

View File

@ -1913,7 +1913,7 @@ public:
* are the coordinates of the line. (x1 == x2) || (y1 == y2)
*/
typedef void(*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
void VisitEdges(visitFn, void *closure) const;
void VisitEdges(visitFn, void *closure);
nsCString ToString() const;
@ -2519,7 +2519,7 @@ public:
}
typedef void (*visitFn)(void *closure, VisitSide side, int x1, int y1, int x2, int y2);
void VisitEdges (visitFn visit, void *closure) const
void VisitEdges (visitFn visit, void *closure)
{
mImpl.VisitEdges (visit, closure);
}

View File

@ -634,7 +634,6 @@ private:
DECL_GFX_PREF(Once, "layers.mlgpu.enable-container-resizing", AdvancedLayersEnableContainerResizing, bool, true);
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
DECL_GFX_PREF(Once, "layers.omtp.capture-limit", LayersOMTPCaptureLimit, uint32_t, 25 * 1024 * 1024);
DECL_GFX_PREF(Live, "layers.omtp.dump-capture", LayersOMTPDumpCapture, bool, false);
DECL_GFX_PREF(Once, "layers.omtp.paint-workers", LayersOMTPPaintWorkers, int32_t, 1);
DECL_GFX_PREF(Live, "layers.omtp.release-capture-on-main-thread", LayersOMTPReleaseCaptureOnMainThread, bool, false);