mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
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:
parent
8c70dfad01
commit
181d4f159b
28
gfx/2d/2D.h
28
gfx/2d/2D.h
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -45,8 +45,7 @@ enum class CommandType : int8_t {
|
||||
SETTRANSFORM,
|
||||
SETPERMITSUBPIXELAA,
|
||||
FLUSH,
|
||||
BLUR,
|
||||
PADEDGES,
|
||||
BLUR
|
||||
};
|
||||
|
||||
class DrawingCommand
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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(); }
|
||||
|
@ -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',
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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"
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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',
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user