Merge mozilla-central to autoland. on a CLOSED TREE

This commit is contained in:
Daniel Varga 2019-06-07 19:24:42 +03:00
commit 851bd2386e
86 changed files with 3495 additions and 516 deletions

View File

@ -1407,15 +1407,6 @@ bool CanvasRenderingContext2D::TrySharedTarget(
return false;
}
#ifdef XP_WIN
// Bug 1285271 - Disable shared buffer provider on Windows with D2D due to
// instability
if (gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() ==
BackendType::DIRECT2D1_1) {
return false;
}
#endif
RefPtr<LayerManager> layerManager =
LayerManagerFromCanvasElement(mCanvasElement);
@ -1620,19 +1611,13 @@ UniquePtr<uint8_t[]> CanvasRenderingContext2D::GetImageBuffer(
*aFormat = 0;
RefPtr<SourceSurface> snapshot;
if (mTarget) {
snapshot = mTarget->Snapshot();
} else if (mBufferProvider) {
snapshot = mBufferProvider->BorrowSnapshot();
} else {
EnsureTarget();
if (!IsTargetValid()) {
if (!mBufferProvider) {
if (!EnsureTarget()) {
return nullptr;
}
snapshot = mTarget->Snapshot();
}
RefPtr<SourceSurface> snapshot = mBufferProvider->BorrowSnapshot();
if (snapshot) {
RefPtr<DataSourceSurface> data = snapshot->GetDataSurface();
if (data && data->GetSize() == GetSize()) {
@ -1641,9 +1626,7 @@ UniquePtr<uint8_t[]> CanvasRenderingContext2D::GetImageBuffer(
}
}
if (!mTarget && mBufferProvider) {
mBufferProvider->ReturnSnapshot(snapshot.forget());
}
mBufferProvider->ReturnSnapshot(snapshot.forget());
return ret;
}
@ -1681,6 +1664,29 @@ CanvasRenderingContext2D::GetInputStream(const char* aMimeType,
aStream);
}
already_AddRefed<mozilla::gfx::SourceSurface>
CanvasRenderingContext2D::GetSurfaceSnapshot(gfxAlphaType* aOutAlphaType) {
if (!mBufferProvider) {
if (!EnsureTarget()) {
return nullptr;
}
}
RefPtr<SourceSurface> snapshot = mBufferProvider->BorrowSnapshot();
if (!snapshot) {
return nullptr;
}
RefPtr<DataSourceSurface> dataSurface = snapshot->GetDataSurface();
mBufferProvider->ReturnSnapshot(snapshot.forget());
if (aOutAlphaType) {
*aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
}
return dataSurface.forget();
}
SurfaceFormat CanvasRenderingContext2D::GetSurfaceFormat() const {
return mOpaque ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8;
}
@ -4929,27 +4935,21 @@ nsresult CanvasRenderingContext2D::GetImageDataArray(
return NS_OK;
}
RefPtr<DataSourceSurface> readback;
DataSourceSurface::MappedSurface rawData;
RefPtr<SourceSurface> snapshot;
if (!mTarget && mBufferProvider) {
snapshot = mBufferProvider->BorrowSnapshot();
} else {
EnsureTarget();
if (!IsTargetValid()) {
return NS_ERROR_FAILURE;
if (!mBufferProvider) {
if (!EnsureTarget()) {
return NS_ERROR_OUT_OF_MEMORY;
}
snapshot = mTarget->Snapshot();
}
if (snapshot) {
readback = snapshot->GetDataSurface();
RefPtr<SourceSurface> snapshot = mBufferProvider->BorrowSnapshot();
if (!snapshot) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (!mTarget && mBufferProvider) {
mBufferProvider->ReturnSnapshot(snapshot.forget());
}
RefPtr<DataSourceSurface> readback = snapshot->GetDataSurface();
mBufferProvider->ReturnSnapshot(snapshot.forget());
DataSourceSurface::MappedSurface rawData;
if (!readback || !readback->Map(DataSourceSurface::READ, &rawData)) {
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -409,13 +409,7 @@ class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
nsIInputStream** aStream) override;
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
gfxAlphaType* aOutAlphaType = nullptr) override {
EnsureTarget();
if (aOutAlphaType) {
*aOutAlphaType = (mOpaque ? gfxAlphaType::Opaque : gfxAlphaType::Premult);
}
return mTarget->Snapshot();
}
gfxAlphaType* aOutAlphaType = nullptr) override;
virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue) override;
bool GetIsOpaque() override { return mOpaque; }

View File

@ -8632,7 +8632,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType,
}
}
MOZ_DIAGNOSTIC_ASSERT(usage >= 0);
MOZ_ASSERT(usage >= 0);
if (!aForGetUsage) {
InitUsageForOrigin(aOrigin, usage);

View File

@ -61,6 +61,7 @@ struct ID3D11Texture2D;
struct ID3D11Device;
struct ID2D1Device;
struct ID2D1DeviceContext;
struct ID2D1Multithread;
struct IDWriteFactory;
struct IDWriteRenderingParams;
struct IDWriteFontFace;
@ -1871,6 +1872,17 @@ class GFX2D_API Factory {
static DrawEventRecorder* mRecorder;
};
class MOZ_RAII AutoSerializeWithMoz2D final {
public:
explicit AutoSerializeWithMoz2D(BackendType aBackendType);
~AutoSerializeWithMoz2D();
private:
#if defined(WIN32)
RefPtr<ID2D1Multithread> mMT;
#endif
};
} // namespace gfx
} // namespace mozilla

View File

@ -45,16 +45,12 @@ void DrawEventRecorderPrivate::StoreSourceSurfaceRecording(
}
void DrawEventRecorderFile::RecordEvent(const RecordedEvent& aEvent) {
WriteElement(mOutputStream, aEvent.mType);
aEvent.RecordToStream(mOutputStream);
Flush();
}
void DrawEventRecorderMemory::RecordEvent(const RecordedEvent& aEvent) {
WriteElement(mOutputStream, aEvent.mType);
aEvent.RecordToStream(mOutputStream);
}

View File

@ -85,23 +85,33 @@ class DataSourceSurfaceRecording : public DataSourceSurface {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DataSourceSurfaceRecording, override)
DataSourceSurfaceRecording(UniquePtr<uint8_t[]> aData, IntSize aSize,
int32_t aStride, SurfaceFormat aFormat)
int32_t aStride, SurfaceFormat aFormat,
DrawEventRecorderPrivate* aRecorder)
: mData(std::move(aData)),
mSize(aSize),
mStride(aStride),
mFormat(aFormat) {}
mFormat(aFormat),
mRecorder(aRecorder) {
mRecorder->RecordEvent(RecordedSourceSurfaceCreation(
ReferencePtr(this), mData.get(), mStride, mSize, mFormat));
mRecorder->AddStoredObject(this);
}
~DataSourceSurfaceRecording() {}
~DataSourceSurfaceRecording() {
mRecorder->RemoveStoredObject(this);
mRecorder->RecordEvent(
RecordedSourceSurfaceDestruction(ReferencePtr(this)));
}
static already_AddRefed<DataSourceSurface> Init(uint8_t* aData, IntSize aSize,
int32_t aStride,
SurfaceFormat aFormat) {
static already_AddRefed<DataSourceSurface> Init(
uint8_t* aData, IntSize aSize, int32_t aStride, SurfaceFormat aFormat,
DrawEventRecorderPrivate* aRecorder) {
// XXX: do we need to ensure any alignment here?
auto data = MakeUnique<uint8_t[]>(aStride * aSize.height);
if (data) {
memcpy(data.get(), aData, aStride * aSize.height);
RefPtr<DataSourceSurfaceRecording> surf = new DataSourceSurfaceRecording(
std::move(data), aSize, aStride, aFormat);
std::move(data), aSize, aStride, aFormat, aRecorder);
return surf.forget();
}
return nullptr;
@ -117,6 +127,7 @@ class DataSourceSurfaceRecording : public DataSourceSurface {
IntSize mSize;
int32_t mStride;
SurfaceFormat mFormat;
RefPtr<DrawEventRecorderPrivate> mRecorder;
};
class GradientStopsRecording : public GradientStops {
@ -368,7 +379,13 @@ already_AddRefed<SourceSurface> DrawTargetRecording::IntoLuminanceSource(
return retSurf.forget();
}
void DrawTargetRecording::DetachAllSnapshots() {}
void DrawTargetRecording::Flush() {
mRecorder->RecordEvent(RecordedFlush(this));
}
void DrawTargetRecording::DetachAllSnapshots() {
mRecorder->RecordEvent(RecordedDetachAllSnapshots(this));
}
void DrawTargetRecording::DrawSurface(SourceSurface* aSurface,
const Rect& aDest, const Rect& aSource,
@ -480,16 +497,9 @@ DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char* aData,
const IntSize& aSize,
int32_t aStride,
SurfaceFormat aFormat) const {
RefPtr<SourceSurface> surf =
DataSourceSurfaceRecording::Init(aData, aSize, aStride, aFormat);
RefPtr<SourceSurface> retSurf =
new SourceSurfaceRecording(aSize, aFormat, mRecorder);
mRecorder->RecordEvent(
RecordedSourceSurfaceCreation(retSurf, aData, aStride, aSize, aFormat));
return retSurf.forget();
RefPtr<SourceSurface> surf = DataSourceSurfaceRecording::Init(
aData, aSize, aStride, aFormat, mRecorder);
return surf.forget();
}
already_AddRefed<SourceSurface> DrawTargetRecording::OptimizeSourceSurface(

View File

@ -37,11 +37,7 @@ class DrawTargetRecording : public DrawTarget {
virtual IntSize GetSize() const override { return mSize; }
/* Ensure that the DrawTarget backend has flushed all drawing operations to
* this draw target. This must be called before using the backing surface of
* this draw target outside of GFX 2D code.
*/
virtual void Flush() override { mFinalDT->Flush(); }
virtual void Flush() override;
virtual void FlushItem(const IntRect& aBounds) override;

View File

@ -738,6 +738,30 @@ FT_Error Factory::LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex,
}
#endif
AutoSerializeWithMoz2D::AutoSerializeWithMoz2D(BackendType aBackendType) {
#ifdef WIN32
// We use a multi-threaded ID2D1Factory1, so that makes the calls through the
// Direct2D API thread-safe. However, if the Moz2D objects are using Direct3D
// resources we need to make sure that calls through the Direct3D or DXGI API
// use the Direct2D synchronization. It's possible that this should be pushed
// down into the TextureD3D11 objects, so that we always use this.
if (aBackendType == BackendType::DIRECT2D1_1 ||
aBackendType == BackendType::DIRECT2D) {
D2DFactory()->QueryInterface(
static_cast<ID2D1Multithread**>(getter_AddRefs(mMT)));
mMT->Enter();
}
#endif
}
AutoSerializeWithMoz2D::~AutoSerializeWithMoz2D() {
#ifdef WIN32
if (mMT) {
mMT->Leave();
}
#endif
};
#ifdef WIN32
already_AddRefed<DrawTarget> Factory::CreateDrawTargetForD3D11Texture(
ID3D11Texture2D* aTexture, SurfaceFormat aFormat) {

View File

@ -69,7 +69,7 @@ bool InlineTranslator::TranslateRecording(char* aData, size_t aLen) {
while (reader.good()) {
bool success = RecordedEvent::DoWithEvent(
reader, static_cast<RecordedEvent::EventType>(eventType),
[&](RecordedEvent* recordedEvent) {
[&](RecordedEvent* recordedEvent) -> bool {
// Make sure that the whole event was read from the stream
// successfully.
if (!reader.good()) {

View File

@ -126,13 +126,13 @@ class InlineTranslator : public Translator {
mNativeFontResources.Put(aKey, aScaledFontResouce);
}
void RemoveDrawTarget(ReferencePtr aRefPtr) final {
void RemoveDrawTarget(ReferencePtr aRefPtr) override {
mDrawTargets.Remove(aRefPtr);
}
void RemovePath(ReferencePtr aRefPtr) final { mPaths.Remove(aRefPtr); }
void RemoveSourceSurface(ReferencePtr aRefPtr) final {
void RemoveSourceSurface(ReferencePtr aRefPtr) override {
mSourceSurfaces.Remove(aRefPtr);
}
@ -154,7 +154,7 @@ class InlineTranslator : public Translator {
already_AddRefed<DrawTarget> CreateDrawTarget(
ReferencePtr aRefPtr, const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) final;
gfx::SurfaceFormat aFormat) override;
mozilla::gfx::DrawTarget* GetReferenceDrawTarget() final { return mBaseDT; }

View File

@ -135,7 +135,8 @@ enum class LogReason : int {
NativeFontResourceNotFound,
UnscaledFontNotFound,
ScaledFontNotFound,
InvalidLayerType,
InvalidLayerType, // 40
PlayEventFailed,
// End
MustBeLessThanThis = 101,
};

View File

@ -123,7 +123,7 @@ inline void AcuteArcToBezier(T* aSink, const Point& aOrigin,
template <typename T>
void ArcToBezier(T* aSink, const Point& aOrigin, const Size& aRadius,
float aStartAngle, float aEndAngle, bool aAntiClockwise,
float aRotation = 0.0f) {
float aRotation = 0.0f, const Matrix& aTransform = Matrix()) {
Float sweepDirection = aAntiClockwise ? -1.0f : 1.0f;
// Calculate the total arc we're going to sweep.
@ -148,6 +148,7 @@ void ArcToBezier(T* aSink, const Point& aOrigin, const Size& aRadius,
transform *= Matrix::Rotation(aRotation);
}
transform.PostTranslate(aOrigin);
transform *= aTransform;
aSink->LineTo(transform.TransformPoint(currentStartOffset));
while (arcSweepLeft > 0) {

View File

@ -11,55 +11,183 @@
namespace mozilla {
namespace gfx {
#define NEXT_PARAMS(_type) \
const _type params = *reinterpret_cast<const _type*>(nextByte); \
nextByte += sizeof(_type);
using namespace std;
bool PathOps::StreamToSink(PathSink& aPathSink) const {
if (mPathData.empty()) {
return true;
}
const uint8_t* nextByte = mPathData.data();
const uint8_t* end = nextByte + mPathData.size();
while (nextByte < end) {
const OpType opType = *reinterpret_cast<const OpType*>(nextByte);
nextByte += sizeof(OpType);
switch (opType) {
case OpType::OP_MOVETO: {
NEXT_PARAMS(Point)
aPathSink.MoveTo(params);
break;
}
case OpType::OP_LINETO: {
NEXT_PARAMS(Point)
aPathSink.LineTo(params);
break;
}
case OpType::OP_BEZIERTO: {
NEXT_PARAMS(ThreePoints)
aPathSink.BezierTo(params.p1, params.p2, params.p3);
break;
}
case OpType::OP_QUADRATICBEZIERTO: {
NEXT_PARAMS(TwoPoints)
aPathSink.QuadraticBezierTo(params.p1, params.p2);
break;
}
case OpType::OP_ARC: {
NEXT_PARAMS(ArcParams)
aPathSink.Arc(params.origin, params.radius, params.startAngle,
params.endAngle, params.antiClockwise);
break;
}
case OpType::OP_CLOSE:
aPathSink.Close();
break;
default:
return false;
}
}
return true;
}
PathOps PathOps::TransformedCopy(const Matrix& aTransform) const {
PathOps newPathOps;
const uint8_t* nextByte = mPathData.data();
const uint8_t* end = nextByte + mPathData.size();
while (nextByte < end) {
const OpType opType = *reinterpret_cast<const OpType*>(nextByte);
nextByte += sizeof(OpType);
switch (opType) {
case OpType::OP_MOVETO: {
NEXT_PARAMS(Point)
newPathOps.MoveTo(aTransform.TransformPoint(params));
break;
}
case OpType::OP_LINETO: {
NEXT_PARAMS(Point)
newPathOps.LineTo(aTransform.TransformPoint(params));
break;
}
case OpType::OP_BEZIERTO: {
NEXT_PARAMS(ThreePoints)
newPathOps.BezierTo(aTransform.TransformPoint(params.p1),
aTransform.TransformPoint(params.p2),
aTransform.TransformPoint(params.p3));
break;
}
case OpType::OP_QUADRATICBEZIERTO: {
NEXT_PARAMS(TwoPoints)
newPathOps.QuadraticBezierTo(aTransform.TransformPoint(params.p1),
aTransform.TransformPoint(params.p2));
break;
}
case OpType::OP_ARC: {
NEXT_PARAMS(ArcParams)
ArcToBezier(&newPathOps, params.origin,
gfx::Size(params.radius, params.radius), params.startAngle,
params.endAngle, params.antiClockwise, 0.0f, aTransform);
break;
}
case OpType::OP_CLOSE:
newPathOps.Close();
break;
default:
MOZ_CRASH("We control mOpTypes, so this should never happen.");
}
}
return newPathOps;
}
#undef NEXT_PARAMS
size_t PathOps::NumberOfOps() const {
size_t size = 0;
const uint8_t* nextByte = mPathData.data();
const uint8_t* end = nextByte + mPathData.size();
while (nextByte < end) {
size++;
const OpType opType = *reinterpret_cast<const OpType*>(nextByte);
nextByte += sizeof(OpType);
switch (opType) {
case OpType::OP_MOVETO:
nextByte += sizeof(Point);
break;
case OpType::OP_LINETO:
nextByte += sizeof(Point);
break;
case OpType::OP_BEZIERTO:
nextByte += sizeof(ThreePoints);
break;
case OpType::OP_QUADRATICBEZIERTO:
nextByte += sizeof(TwoPoints);
break;
case OpType::OP_ARC:
nextByte += sizeof(ArcParams);
break;
case OpType::OP_CLOSE:
break;
default:
MOZ_CRASH("We control mOpTypes, so this should never happen.");
}
}
return size;
}
void PathBuilderRecording::MoveTo(const Point& aPoint) {
PathOp op;
op.mType = PathOp::OP_MOVETO;
op.mP1 = aPoint;
mPathOps.push_back(op);
mPathOps.MoveTo(aPoint);
mPathBuilder->MoveTo(aPoint);
}
void PathBuilderRecording::LineTo(const Point& aPoint) {
PathOp op;
op.mType = PathOp::OP_LINETO;
op.mP1 = aPoint;
mPathOps.push_back(op);
mPathOps.LineTo(aPoint);
mPathBuilder->LineTo(aPoint);
}
void PathBuilderRecording::BezierTo(const Point& aCP1, const Point& aCP2,
const Point& aCP3) {
PathOp op;
op.mType = PathOp::OP_BEZIERTO;
op.mP1 = aCP1;
op.mP2 = aCP2;
op.mP3 = aCP3;
mPathOps.push_back(op);
mPathOps.BezierTo(aCP1, aCP2, aCP3);
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
}
void PathBuilderRecording::QuadraticBezierTo(const Point& aCP1,
const Point& aCP2) {
PathOp op;
op.mType = PathOp::OP_QUADRATICBEZIERTO;
op.mP1 = aCP1;
op.mP2 = aCP2;
mPathOps.push_back(op);
mPathOps.QuadraticBezierTo(aCP1, aCP2);
mPathBuilder->QuadraticBezierTo(aCP1, aCP2);
}
void PathBuilderRecording::Close() {
PathOp op;
op.mType = PathOp::OP_CLOSE;
mPathOps.push_back(op);
mPathOps.Close();
mPathBuilder->Close();
}
void PathBuilderRecording::Arc(const Point& aOrigin, float aRadius,
float aStartAngle, float aEndAngle,
bool aAntiClockwise) {
mPathOps.Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
mPathBuilder->Arc(aOrigin, aRadius, aStartAngle, aEndAngle, aAntiClockwise);
}
already_AddRefed<Path> PathBuilderRecording::Finish() {
RefPtr<Path> path = mPathBuilder->Finish();
return MakeAndAddRef<PathRecording>(path, mPathOps, mFillRule, mCurrentPoint, mBeginPoint);
return MakeAndAddRef<PathRecording>(path, std::move(mPathOps), mFillRule,
mCurrentPoint, mBeginPoint);
}
PathRecording::~PathRecording() {
@ -73,8 +201,7 @@ already_AddRefed<PathBuilder> PathRecording::CopyToBuilder(
FillRule aFillRule) const {
RefPtr<PathBuilder> pathBuilder = mPath->CopyToBuilder(aFillRule);
RefPtr<PathBuilderRecording> recording =
new PathBuilderRecording(pathBuilder, aFillRule);
recording->mPathOps = mPathOps;
new PathBuilderRecording(pathBuilder, mPathOps, aFillRule);
recording->SetCurrentPoint(mCurrentPoint);
recording->SetBeginPoint(mBeginPoint);
return recording.forget();
@ -84,24 +211,8 @@ already_AddRefed<PathBuilder> PathRecording::TransformedCopyToBuilder(
const Matrix& aTransform, FillRule aFillRule) const {
RefPtr<PathBuilder> pathBuilder =
mPath->TransformedCopyToBuilder(aTransform, aFillRule);
RefPtr<PathBuilderRecording> recording =
new PathBuilderRecording(pathBuilder, aFillRule);
typedef std::vector<PathOp> pathOpVec;
for (pathOpVec::const_iterator iter = mPathOps.begin();
iter != mPathOps.end(); iter++) {
PathOp newPathOp;
newPathOp.mType = iter->mType;
if (sPointCount[newPathOp.mType] >= 1) {
newPathOp.mP1 = aTransform.TransformPoint(iter->mP1);
}
if (sPointCount[newPathOp.mType] >= 2) {
newPathOp.mP2 = aTransform.TransformPoint(iter->mP2);
}
if (sPointCount[newPathOp.mType] >= 3) {
newPathOp.mP3 = aTransform.TransformPoint(iter->mP3);
}
recording->mPathOps.push_back(newPathOp);
}
RefPtr<PathBuilderRecording> recording = new PathBuilderRecording(
pathBuilder, mPathOps.TransformedCopy(aTransform), aFillRule);
recording->SetCurrentPoint(aTransform.TransformPoint(mCurrentPoint));
recording->SetBeginPoint(aTransform.TransformPoint(mBeginPoint));

View File

@ -12,123 +12,218 @@
#include <ostream>
#include "PathHelpers.h"
#include "RecordingTypes.h"
namespace mozilla {
namespace gfx {
class PathOps {
public:
PathOps() {}
template <class S>
explicit PathOps(S& aStream);
PathOps(PathOps&& aOther) : mPathData(std::move(aOther.mPathData)) {}
PathOps(const PathOps& aOther) : mPathData(aOther.mPathData) {}
PathOps& operator=(PathOps&& aOther) {
mPathData = std::move(aOther.mPathData);
return *this;
}
template <class S>
void Record(S& aStream) const;
bool StreamToSink(PathSink& aPathSink) const;
PathOps TransformedCopy(const Matrix& aTransform) const;
size_t NumberOfOps() const;
void MoveTo(const Point& aPoint) { AppendPathOp(OpType::OP_MOVETO, aPoint); }
void LineTo(const Point& aPoint) { AppendPathOp(OpType::OP_LINETO, aPoint); }
void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) {
AppendPathOp(OpType::OP_BEZIERTO, ThreePoints{aCP1, aCP2, aCP3});
}
void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) {
AppendPathOp(OpType::OP_QUADRATICBEZIERTO, TwoPoints{aCP1, aCP2});
}
void Arc(const Point& aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise) {
AppendPathOp(OpType::OP_ARC, ArcParams{aOrigin, aRadius, aStartAngle,
aEndAngle, aAntiClockwise});
}
void Close() {
size_t oldSize = mPathData.size();
mPathData.resize(oldSize + sizeof(OpType));
*reinterpret_cast<OpType*>(mPathData.data() + oldSize) = OpType::OP_CLOSE;
}
private:
void operator=(const PathOps&) = delete; // assign using std::move()!
enum class OpType : uint32_t {
OP_MOVETO = 0,
OP_LINETO,
OP_BEZIERTO,
OP_QUADRATICBEZIERTO,
OP_ARC,
OP_CLOSE,
OP_INVALID
};
template <typename T>
void AppendPathOp(const OpType& aOpType, const T& aOpParams) {
size_t oldSize = mPathData.size();
mPathData.resize(oldSize + sizeof(OpType) + sizeof(T));
memcpy(mPathData.data() + oldSize, &aOpType, sizeof(OpType));
oldSize += sizeof(OpType);
memcpy(mPathData.data() + oldSize, &aOpParams, sizeof(T));
}
struct TwoPoints {
Point p1;
Point p2;
};
struct ThreePoints {
Point p1;
Point p2;
Point p3;
};
struct ArcParams {
Point origin;
float radius;
float startAngle;
float endAngle;
bool antiClockwise;
};
std::vector<uint8_t> mPathData;
};
template <class S>
PathOps::PathOps(S& aStream) {
ReadVector(aStream, mPathData);
}
template <class S>
inline void PathOps::Record(S& aStream) const {
WriteVector(aStream, mPathData);
}
class PathRecording;
class DrawEventRecorderPrivate;
class PathBuilderRecording : public PathBuilder {
class PathBuilderRecording final : public PathBuilder {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathBuilderRecording, override)
PathBuilderRecording(PathBuilder* aBuilder, FillRule aFillRule)
: mPathBuilder(aBuilder), mFillRule(aFillRule) {}
PathBuilderRecording(PathBuilder* aBuilder, const PathOps& aPathOps,
FillRule aFillRule)
: mPathBuilder(aBuilder), mFillRule(aFillRule), mPathOps(aPathOps) {}
/* Move the current point in the path, any figure currently being drawn will
* be considered closed during fill operations, however when stroking the
* closing line segment will not be drawn.
*/
virtual void MoveTo(const Point& aPoint) override;
void MoveTo(const Point& aPoint) final;
/* Add a linesegment to the current figure */
virtual void LineTo(const Point& aPoint) override;
void LineTo(const Point& aPoint) final;
/* Add a cubic bezier curve to the current figure */
virtual void BezierTo(const Point& aCP1, const Point& aCP2,
const Point& aCP3) override;
void BezierTo(const Point& aCP1, const Point& aCP2, const Point& aCP3) final;
/* Add a quadratic bezier curve to the current figure */
virtual void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) override;
void QuadraticBezierTo(const Point& aCP1, const Point& aCP2) final;
/* Close the current figure, this will essentially generate a line segment
* from the current point to the starting point for the current figure
*/
virtual void Close() override;
void Close() final;
/* Add an arc to the current figure */
virtual void Arc(const Point& aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise) override {
ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle,
aAntiClockwise);
}
void Arc(const Point& aOrigin, float aRadius, float aStartAngle,
float aEndAngle, bool aAntiClockwise) final;
/* Point the current subpath is at - or where the next subpath will start
* if there is no active subpath.
*/
virtual Point CurrentPoint() const override {
Point CurrentPoint() const final {
return mPathBuilder->CurrentPoint();
}
virtual Point BeginPoint() const override {
Point BeginPoint() const final {
return mPathBuilder->BeginPoint();
}
virtual void SetCurrentPoint(const Point& aPoint) override {
void SetCurrentPoint(const Point& aPoint) final {
mPathBuilder->SetCurrentPoint(aPoint);
}
virtual void SetBeginPoint(const Point& aPoint) override {
void SetBeginPoint(const Point& aPoint) final {
mPathBuilder->SetBeginPoint(aPoint);
}
virtual already_AddRefed<Path> Finish() override;
already_AddRefed<Path> Finish() final;
virtual BackendType GetBackendType() const override {
return BackendType::RECORDING;
}
BackendType GetBackendType() const final { return BackendType::RECORDING; }
private:
friend class PathRecording;
RefPtr<PathBuilder> mPathBuilder;
FillRule mFillRule;
std::vector<PathOp> mPathOps;
PathOps mPathOps;
};
class PathRecording : public Path {
class PathRecording final : public Path {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(PathRecording, override)
PathRecording(Path* aPath, const std::vector<PathOp> aOps, FillRule aFillRule,
PathRecording(Path* aPath, PathOps&& aOps, FillRule aFillRule,
const Point& aCurrentPoint, const Point& aBeginPoint)
: mPath(aPath), mPathOps(aOps), mFillRule(aFillRule),
: mPath(aPath), mPathOps(std::move(aOps)), mFillRule(aFillRule),
mCurrentPoint(aCurrentPoint), mBeginPoint(aBeginPoint) {}
~PathRecording();
virtual BackendType GetBackendType() const override {
return BackendType::RECORDING;
}
virtual already_AddRefed<PathBuilder> CopyToBuilder(
FillRule aFillRule) const override;
virtual already_AddRefed<PathBuilder> TransformedCopyToBuilder(
const Matrix& aTransform, FillRule aFillRule) const override;
virtual bool ContainsPoint(const Point& aPoint,
const Matrix& aTransform) const override {
BackendType GetBackendType() const final { return BackendType::RECORDING; }
already_AddRefed<PathBuilder> CopyToBuilder(FillRule aFillRule) const final;
already_AddRefed<PathBuilder> TransformedCopyToBuilder(
const Matrix& aTransform, FillRule aFillRule) const final;
bool ContainsPoint(const Point& aPoint,
const Matrix& aTransform) const final {
return mPath->ContainsPoint(aPoint, aTransform);
}
virtual bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions,
const Point& aPoint,
const Matrix& aTransform) const override {
bool StrokeContainsPoint(const StrokeOptions& aStrokeOptions,
const Point& aPoint,
const Matrix& aTransform) const final {
return mPath->StrokeContainsPoint(aStrokeOptions, aPoint, aTransform);
}
virtual Rect GetBounds(const Matrix& aTransform = Matrix()) const override {
Rect GetBounds(const Matrix& aTransform = Matrix()) const final {
return mPath->GetBounds(aTransform);
}
virtual Rect GetStrokedBounds(
const StrokeOptions& aStrokeOptions,
const Matrix& aTransform = Matrix()) const override {
Rect GetStrokedBounds(const StrokeOptions& aStrokeOptions,
const Matrix& aTransform = Matrix()) const final {
return mPath->GetStrokedBounds(aStrokeOptions, aTransform);
}
virtual void StreamToSink(PathSink* aSink) const override {
mPath->StreamToSink(aSink);
}
void StreamToSink(PathSink* aSink) const final { mPath->StreamToSink(aSink); }
virtual FillRule GetFillRule() const override { return mFillRule; }
void StorePath(std::ostream& aStream) const;
static void ReadPathToBuilder(std::istream& aStream, PathBuilder* aBuilder);
FillRule GetFillRule() const final { return mFillRule; }
private:
friend class DrawTargetWrapAndRecord;
@ -136,7 +231,7 @@ class PathRecording : public Path {
friend class RecordedPathCreation;
RefPtr<Path> mPath;
std::vector<PathOp> mPathOps;
PathOps mPathOps;
FillRule mFillRule;
Point mCurrentPoint;
Point mBeginPoint;

View File

@ -19,14 +19,18 @@ namespace gfx {
using namespace std;
RecordedEvent* RecordedEvent::LoadEventFromStream(std::istream& aStream,
EventType aType) {
return LoadEvent(aStream, aType);
/* static */
bool RecordedEvent::DoWithEventFromStream(
EventStream& aStream, EventType aType,
const std::function<bool(RecordedEvent*)>& aAction) {
return DoWithEvent(aStream, aType, aAction);
}
RecordedEvent* RecordedEvent::LoadEventFromStream(EventStream& aStream,
EventType aType) {
return LoadEvent(aStream, aType);
/* static */
bool RecordedEvent::DoWithEventFromStream(
EventRingBuffer& aStream, EventType aType,
const std::function<bool(RecordedEvent*)>& aAction) {
return DoWithEvent(aStream, aType, aAction);
}
string RecordedEvent::GetEventName(EventType aType) {

View File

@ -13,12 +13,11 @@
#include <cstring>
#include <vector>
#include "RecordingTypes.h"
namespace mozilla {
namespace gfx {
struct PathOp;
class PathRecording;
const uint32_t kMagicInt = 0xc001feed;
// A change in major revision means a change in event binary format, causing
@ -169,6 +168,71 @@ struct MemWriter {
char* mPtr;
};
// This is a simple interface for an EventRingBuffer, so we can use it in the
// RecordedEvent reading and writing machinery.
class EventRingBuffer {
public:
/**
* Templated RecordEvent function so that when we have enough contiguous
* space we can record into the buffer quickly using MemWriter.
*
* @param aRecordedEvent the event to record
*/
template <class RE>
void RecordEvent(const RE* aRecordedEvent) {
SizeCollector size;
WriteElement(size, aRecordedEvent->GetType());
aRecordedEvent->Record(size);
if (size.mTotalSize > mAvailable) {
WaitForAndRecalculateAvailableSpace();
}
if (size.mTotalSize <= mAvailable) {
MemWriter writer(mBufPos);
WriteElement(writer, aRecordedEvent->GetType());
aRecordedEvent->Record(writer);
UpdateWriteTotalsBy(size.mTotalSize);
} else {
WriteElement(*this, aRecordedEvent->GetType());
aRecordedEvent->Record(*this);
}
}
/**
* Simple write function required by WriteElement.
*
* @param aData the data to be written to the buffer
* @param aSize the number of chars to write
*/
virtual void write(const char* const aData, const size_t aSize) = 0;
/**
* Simple read function required by ReadElement.
*
* @param aOut the pointer to read into
* @param aSize the number of chars to read
*/
virtual void read(char* const aOut, const size_t aSize) = 0;
virtual bool good() const = 0;
protected:
/**
* Wait until space is available for writing and then set mBufPos and
* mAvailable.
*/
virtual bool WaitForAndRecalculateAvailableSpace() = 0;
/**
* Update write count, mBufPos and mAvailable.
*
* @param aCount number of bytes written
*/
virtual void UpdateWriteTotalsBy(uint32_t aCount) = 0;
char* mBufPos = nullptr;
uint32_t mAvailable = 0;
};
struct MemStream {
char* mData;
size_t mLength;
@ -199,6 +263,7 @@ class EventStream {
public:
virtual void write(const char* aData, size_t aSize) = 0;
virtual void read(char* aOut, size_t aSize) = 0;
virtual bool good() = 0;
};
class RecordedEvent {
@ -249,9 +314,10 @@ class RecordedEvent {
UNSCALEDFONTDESTRUCTION,
INTOLUMINANCE,
EXTERNALSURFACECREATION,
FLUSH,
DETACHALLSNAPSHOTS,
LAST,
};
static const uint32_t kTotalEventTypes =
RecordedEvent::FILTERNODESETINPUT + 1;
virtual ~RecordedEvent() = default;
@ -272,6 +338,7 @@ class RecordedEvent {
virtual void RecordToStream(std::ostream& aStream) const = 0;
virtual void RecordToStream(EventStream& aStream) const = 0;
virtual void RecordToStream(EventRingBuffer& aStream) const = 0;
virtual void RecordToStream(MemStream& aStream) const = 0;
virtual void OutputSimpleEventInfo(std::stringstream& aStringStream) const {}
@ -290,25 +357,20 @@ class RecordedEvent {
virtual std::string GetName() const = 0;
virtual ReferencePtr GetObjectRef() const = 0;
virtual ReferencePtr GetDestinedDT() { return nullptr; }
void OutputSimplePatternInfo(const PatternStorage& aStorage,
std::stringstream& aOutput) const;
template <class S>
static RecordedEvent* LoadEvent(S& aStream, EventType aType);
static RecordedEvent* LoadEventFromStream(std::istream& aStream,
EventType aType);
static RecordedEvent* LoadEventFromStream(EventStream& aStream,
EventType aType);
// An alternative to LoadEvent that avoids a heap allocation for the event.
// This accepts a callable `f' that will take a RecordedEvent* as a single
// parameter
template <class S, class F>
static bool DoWithEvent(S& aStream, EventType aType, F f);
static bool DoWithEvent(S& aStream, EventType aType,
const std::function<bool(RecordedEvent*)>& aAction);
static bool DoWithEventFromStream(
EventStream& aStream, EventType aType,
const std::function<bool(RecordedEvent*)>& aAction);
static bool DoWithEventFromStream(
EventRingBuffer& aStream, EventType aType,
const std::function<bool(RecordedEvent*)>& aAction);
EventType GetType() const { return (EventType)mType; }
@ -329,6 +391,35 @@ class RecordedEvent {
std::vector<Float> mDashPatternStorage;
};
template <class Derived>
class RecordedEventDerived : public RecordedEvent {
using RecordedEvent::RecordedEvent;
public:
void RecordToStream(std::ostream& aStream) const override {
WriteElement(aStream, this->mType);
static_cast<const Derived*>(this)->Record(aStream);
}
void RecordToStream(EventStream& aStream) const override {
WriteElement(aStream, this->mType);
static_cast<const Derived*>(this)->Record(aStream);
}
void RecordToStream(EventRingBuffer& aStream) const final {
aStream.RecordEvent(static_cast<const Derived*>(this));
}
void RecordToStream(MemStream& aStream) const override {
SizeCollector size;
WriteElement(size, this->mType);
static_cast<const Derived*>(this)->Record(size);
aStream.Resize(aStream.mLength + size.mTotalSize);
MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
WriteElement(writer, this->mType);
static_cast<const Derived*>(this)->Record(writer);
}
};
} // namespace gfx
} // namespace mozilla

View File

@ -20,26 +20,6 @@
namespace mozilla {
namespace gfx {
template <class Derived>
class RecordedEventDerived : public RecordedEvent {
using RecordedEvent::RecordedEvent;
public:
void RecordToStream(std::ostream& aStream) const override {
static_cast<const Derived*>(this)->Record(aStream);
}
void RecordToStream(EventStream& aStream) const override {
static_cast<const Derived*>(this)->Record(aStream);
}
void RecordToStream(MemStream& aStream) const override {
SizeCollector size;
static_cast<const Derived*>(this)->Record(size);
aStream.Resize(aStream.mLength + size.mTotalSize);
MemWriter writer(aStream.mData + aStream.mLength - size.mTotalSize);
static_cast<const Derived*>(this)->Record(writer);
}
};
template <class Derived>
class RecordedDrawingEvent : public RecordedEventDerived<Derived> {
public:
@ -54,8 +34,6 @@ class RecordedDrawingEvent : public RecordedEventDerived<Derived> {
template <class S>
void Record(S& aStream) const;
ReferencePtr GetObjectRef() const override;
ReferencePtr mDT;
};
@ -82,7 +60,6 @@ class RecordedDrawTargetCreation
std::stringstream& aStringStream) const override;
std::string GetName() const override { return "DrawTarget Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
ReferencePtr mRefPtr;
BackendType mBackendType;
@ -113,7 +90,6 @@ class RecordedDrawTargetDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "DrawTarget Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
ReferencePtr mRefPtr;
@ -144,7 +120,6 @@ class RecordedCreateSimilarDrawTarget
std::stringstream& aStringStream) const override;
std::string GetName() const override { return "CreateSimilarDrawTarget"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
ReferencePtr mRefPtr;
IntSize mSize;
@ -177,7 +152,6 @@ class RecordedCreateClippedDrawTarget
std::stringstream& aStringStream) const override;
std::string GetName() const override { return "CreateClippedDrawTarget"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
ReferencePtr mRefPtr;
IntSize mMaxSize;
@ -219,7 +193,6 @@ class RecordedCreateDrawTargetForFilter
std::string GetName() const override {
return "CreateSimilarDrawTargetForFilter";
}
ReferencePtr GetObjectRef() const override { return mRefPtr; }
ReferencePtr mRefPtr;
IntSize mMaxSize;
@ -836,7 +809,6 @@ class RecordedDrawFilter : public RecordedDrawingEvent<RecordedDrawFilter> {
class RecordedPathCreation : public RecordedEventDerived<RecordedPathCreation> {
public:
MOZ_IMPLICIT RecordedPathCreation(PathRecording* aPath);
~RecordedPathCreation();
bool PlayEvent(Translator* aTranslator) const override;
@ -845,14 +817,14 @@ class RecordedPathCreation : public RecordedEventDerived<RecordedPathCreation> {
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "Path Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
ReferencePtr mRefPtr;
FillRule mFillRule;
std::vector<PathOp> mPathOps;
RefPtr<PathRecording> mPath;
UniquePtr<PathOps> mPathOps;
template <class S>
MOZ_IMPLICIT RecordedPathCreation(S& aStream);
@ -871,7 +843,6 @@ class RecordedPathDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "Path Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -905,7 +876,6 @@ class RecordedSourceSurfaceCreation
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "SourceSurface Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -934,7 +904,6 @@ class RecordedSourceSurfaceDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "SourceSurface Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -964,7 +933,6 @@ class RecordedExternalSurfaceCreation
virtual std::string GetName() const {
return "SourceSurfaceSharedData Creation";
}
virtual ReferencePtr GetObjectRef() const { return mRefPtr; }
private:
friend class RecordedEvent;
@ -993,7 +961,6 @@ class RecordedFilterNodeCreation
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "FilterNode Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1018,7 +985,6 @@ class RecordedFilterNodeDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "FilterNode Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1050,7 +1016,6 @@ class RecordedGradientStopsCreation
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "GradientStops Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1078,7 +1043,6 @@ class RecordedGradientStopsDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "GradientStops Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1089,6 +1053,48 @@ class RecordedGradientStopsDestruction
MOZ_IMPLICIT RecordedGradientStopsDestruction(S& aStream);
};
class RecordedFlush : public RecordedDrawingEvent<RecordedFlush> {
public:
explicit RecordedFlush(DrawTarget* aDT) : RecordedDrawingEvent(FLUSH, aDT) {}
bool PlayEvent(Translator* aTranslator) const final;
template <class S>
void Record(S& aStream) const;
virtual void OutputSimpleEventInfo(
std::stringstream& aStringStream) const override;
virtual std::string GetName() const override { return "Flush"; }
private:
friend class RecordedEvent;
template <class S>
MOZ_IMPLICIT RecordedFlush(S& aStream);
};
class RecordedDetachAllSnapshots
: public RecordedDrawingEvent<RecordedDetachAllSnapshots> {
public:
explicit RecordedDetachAllSnapshots(DrawTarget* aDT)
: RecordedDrawingEvent(DETACHALLSNAPSHOTS, aDT) {}
bool PlayEvent(Translator* aTranslator) const final;
template <class S>
void Record(S& aStream) const;
virtual void OutputSimpleEventInfo(
std::stringstream& aStringStream) const override;
virtual std::string GetName() const override { return "DetachAllSnapshots"; }
private:
friend class RecordedEvent;
template <class S>
MOZ_IMPLICIT RecordedDetachAllSnapshots(S& aStream);
};
class RecordedSnapshot : public RecordedEventDerived<RecordedSnapshot> {
public:
RecordedSnapshot(ReferencePtr aRefPtr, DrawTarget* aDT)
@ -1101,7 +1107,6 @@ class RecordedSnapshot : public RecordedEventDerived<RecordedSnapshot> {
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "Snapshot"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1131,7 +1136,6 @@ class RecordedIntoLuminanceSource
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "IntoLuminanceSource"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1173,7 +1177,6 @@ class RecordedFontData : public RecordedEventDerived<RecordedFontData> {
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "Font Data"; }
ReferencePtr GetObjectRef() const override { return nullptr; };
void SetFontData(const uint8_t* aData, uint32_t aSize, uint32_t aIndex);
@ -1220,7 +1223,6 @@ class RecordedFontDescriptor
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "Font Desc"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1264,7 +1266,6 @@ class RecordedUnscaledFontCreation
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "UnscaledFont Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
void SetFontInstanceData(const uint8_t* aData, uint32_t aSize);
@ -1292,7 +1293,6 @@ class RecordedUnscaledFontDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "UnscaledFont Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1331,7 +1331,6 @@ class RecordedScaledFontCreation
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "ScaledFont Creation"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
void SetFontInstanceData(const uint8_t* aData, uint32_t aSize,
const FontVariation* aVariations,
@ -1363,7 +1362,6 @@ class RecordedScaledFontDestruction
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "ScaledFont Destruction"; }
ReferencePtr GetObjectRef() const override { return mRefPtr; }
private:
friend class RecordedEvent;
@ -1454,7 +1452,6 @@ class RecordedFilterNodeSetAttribute
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "SetAttribute"; }
ReferencePtr GetObjectRef() const override { return mNode; }
private:
friend class RecordedEvent;
@ -1494,7 +1491,6 @@ class RecordedFilterNodeSetInput
void OutputSimpleEventInfo(std::stringstream& aStringStream) const override;
std::string GetName() const override { return "SetInput"; }
ReferencePtr GetObjectRef() const override { return mNode; }
private:
friend class RecordedEvent;
@ -1735,11 +1731,6 @@ void RecordedDrawingEvent<T>::Record(S& aStream) const {
WriteElement(aStream, mDT);
}
template <class T>
ReferencePtr RecordedDrawingEvent<T>::GetObjectRef() const {
return mDT;
}
inline bool RecordedDrawTargetCreation::PlayEvent(
Translator* aTranslator) const {
RefPtr<DrawTarget> newDT =
@ -2677,36 +2668,13 @@ inline RecordedPathCreation::RecordedPathCreation(PathRecording* aPath)
: RecordedEventDerived(PATHCREATION),
mRefPtr(aPath),
mFillRule(aPath->mFillRule),
mPathOps(aPath->mPathOps) {}
inline RecordedPathCreation::~RecordedPathCreation() {}
mPath(aPath) {}
inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const {
RefPtr<PathBuilder> builder =
aTranslator->GetReferenceDrawTarget()->CreatePathBuilder(mFillRule);
for (size_t i = 0; i < mPathOps.size(); i++) {
const PathOp& op = mPathOps[i];
switch (op.mType) {
case PathOp::OP_MOVETO:
builder->MoveTo(op.mP1);
break;
case PathOp::OP_LINETO:
builder->LineTo(op.mP1);
break;
case PathOp::OP_BEZIERTO:
builder->BezierTo(op.mP1, op.mP2, op.mP3);
break;
case PathOp::OP_QUADRATICBEZIERTO:
builder->QuadraticBezierTo(op.mP1, op.mP2);
break;
case PathOp::OP_ARC:
MOZ_ASSERT_UNREACHABLE("Recordings should not contain arc operations");
break;
case PathOp::OP_CLOSE:
builder->Close();
break;
}
if (!mPathOps->StreamToSink(*builder)) {
return false;
}
RefPtr<Path> path = builder->Finish();
@ -2717,54 +2685,24 @@ inline bool RecordedPathCreation::PlayEvent(Translator* aTranslator) const {
template <class S>
void RecordedPathCreation::Record(S& aStream) const {
WriteElement(aStream, mRefPtr);
WriteElement(aStream, uint64_t(mPathOps.size()));
WriteElement(aStream, mFillRule);
typedef std::vector<PathOp> pathOpVec;
for (pathOpVec::const_iterator iter = mPathOps.begin();
iter != mPathOps.end(); iter++) {
WriteElement(aStream, iter->mType);
if (sPointCount[iter->mType] >= 1) {
WriteElement(aStream, iter->mP1);
}
if (sPointCount[iter->mType] >= 2) {
WriteElement(aStream, iter->mP2);
}
if (sPointCount[iter->mType] >= 3) {
WriteElement(aStream, iter->mP3);
}
}
mPath->mPathOps.Record(aStream);
}
template <class S>
RecordedPathCreation::RecordedPathCreation(S& aStream)
: RecordedEventDerived(PATHCREATION) {
uint64_t size;
ReadElement(aStream, mRefPtr);
ReadElement(aStream, size);
ReadElement(aStream, mFillRule);
for (uint64_t i = 0; i < size; i++) {
PathOp newPathOp;
ReadElement(aStream, newPathOp.mType);
if (sPointCount[newPathOp.mType] >= 1) {
ReadElement(aStream, newPathOp.mP1);
}
if (sPointCount[newPathOp.mType] >= 2) {
ReadElement(aStream, newPathOp.mP2);
}
if (sPointCount[newPathOp.mType] >= 3) {
ReadElement(aStream, newPathOp.mP3);
}
mPathOps.push_back(newPathOp);
}
mPathOps = MakeUnique<PathOps>(aStream);
}
inline void RecordedPathCreation::OutputSimpleEventInfo(
std::stringstream& aStringStream) const {
aStringStream << "[" << mRefPtr
<< "] Path created (OpCount: " << mPathOps.size() << ")";
size_t numberOfOps =
mPath ? mPath->mPathOps.NumberOfOps() : mPathOps->NumberOfOps();
aStringStream << "[" << mRefPtr << "] Path created (OpCount: " << numberOfOps
<< ")";
}
inline bool RecordedPathDestruction::PlayEvent(Translator* aTranslator) const {
aTranslator->RemovePath(mRefPtr);
@ -2812,9 +2750,10 @@ void RecordedSourceSurfaceCreation::Record(S& aStream) const {
WriteElement(aStream, mSize);
WriteElement(aStream, mFormat);
MOZ_ASSERT(mData);
for (int y = 0; y < mSize.height; y++) {
aStream.write((const char*)mData + y * mStride,
BytesPerPixel(mFormat) * mSize.width);
size_t dataFormatWidth = BytesPerPixel(mFormat) * mSize.width;
const char* endSrc = (const char*)(mData + (mSize.height * mStride));
for (const char* src = (const char*)mData; src < endSrc; src += mStride) {
aStream.write(src, dataFormatWidth);
}
}
@ -3039,6 +2978,45 @@ inline void RecordedIntoLuminanceSource::OutputSimpleEventInfo(
<< ")";
}
inline bool RecordedFlush::PlayEvent(Translator* aTranslator) const {
aTranslator->LookupDrawTarget(mDT)->Flush();
return true;
}
template <class S>
void RecordedFlush::Record(S& aStream) const {
RecordedDrawingEvent::Record(aStream);
}
template <class S>
RecordedFlush::RecordedFlush(S& aStream)
: RecordedDrawingEvent(FLUSH, aStream) {}
inline void RecordedFlush::OutputSimpleEventInfo(
std::stringstream& aStringStream) const {
aStringStream << "[" << mDT << "] Flush";
}
inline bool RecordedDetachAllSnapshots::PlayEvent(
Translator* aTranslator) const {
aTranslator->LookupDrawTarget(mDT)->DetachAllSnapshots();
return true;
}
template <class S>
void RecordedDetachAllSnapshots::Record(S& aStream) const {
RecordedDrawingEvent::Record(aStream);
}
template <class S>
RecordedDetachAllSnapshots::RecordedDetachAllSnapshots(S& aStream)
: RecordedDrawingEvent(DETACHALLSNAPSHOTS, aStream) {}
inline void RecordedDetachAllSnapshots::OutputSimpleEventInfo(
std::stringstream& aStringStream) const {
aStringStream << "[" << mDT << "] DetachAllSnapshots";
}
inline bool RecordedSnapshot::PlayEvent(Translator* aTranslator) const {
RefPtr<SourceSurface> src = aTranslator->LookupDrawTarget(mDT)->Snapshot();
aTranslator->AddSourceSurface(mRefPtr, src);
@ -3480,10 +3458,6 @@ inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo(
aStringStream << ")";
}
#define LOAD_EVENT_TYPE(_typeenum, _class) \
case _typeenum: \
return new _class(aStream)
#define FOR_EACH_EVENT(f) \
f(DRAWTARGETCREATION, RecordedDrawTargetCreation); \
f(DRAWTARGETDESTRUCTION, RecordedDrawTargetDestruction); \
@ -3529,25 +3503,20 @@ inline void RecordedFilterNodeSetInput::OutputSimpleEventInfo(
f(UNSCALEDFONTCREATION, RecordedUnscaledFontCreation); \
f(UNSCALEDFONTDESTRUCTION, RecordedUnscaledFontDestruction); \
f(INTOLUMINANCE, RecordedIntoLuminanceSource); \
f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation);
template <class S>
RecordedEvent* RecordedEvent::LoadEvent(S& aStream, EventType aType) {
switch (aType) {
FOR_EACH_EVENT(LOAD_EVENT_TYPE)
default:
return nullptr;
}
}
f(EXTERNALSURFACECREATION, RecordedExternalSurfaceCreation); \
f(FLUSH, RecordedFlush); \
f(DETACHALLSNAPSHOTS, RecordedDetachAllSnapshots);
#define DO_WITH_EVENT_TYPE(_typeenum, _class) \
case _typeenum: { \
auto e = _class(aStream); \
return f(&e); \
return aAction(&e); \
}
template <class S, class F>
bool RecordedEvent::DoWithEvent(S& aStream, EventType aType, F f) {
template <class S>
bool RecordedEvent::DoWithEvent(
S& aStream, EventType aType,
const std::function<bool(RecordedEvent*)>& aAction) {
switch (aType) {
FOR_EACH_EVENT(DO_WITH_EVENT_TYPE)
default:

View File

@ -8,6 +8,7 @@
#define MOZILLA_GFX_RECORDINGTYPES_H_
#include <ostream>
#include <vector>
namespace mozilla {
namespace gfx {
@ -27,9 +28,29 @@ void WriteElement(S& aStream, const T& aElement) {
ElementStreamFormat<S, T>::Write(aStream, aElement);
}
template <class S, class T>
void WriteVector(S& aStream, const std::vector<T>& aVector) {
size_t size = aVector.size();
WriteElement(aStream, size);
if (size) {
aStream.write(reinterpret_cast<const char*>(aVector.data()),
sizeof(T) * size);
}
}
template <class S, class T>
void ReadElement(S& aStream, T& aElement) {
ElementStreamFormat<S, T>::Read(aStream, aElement);
}
template <class S, class T>
void ReadVector(S& aStream, std::vector<T>& aVector) {
size_t size;
ReadElement(aStream, size);
if (size) {
aVector.resize(size);
aStream.read(reinterpret_cast<char*>(aVector.data()), sizeof(T) * size);
} else {
aVector.clear();
}
}
} // namespace gfx
} // namespace mozilla

View File

@ -50,7 +50,8 @@ class gfxVarReceiver;
_(UseOMTP, bool, false) \
_(AllowD3D11KeyedMutex, bool, false) \
_(SystemTextQuality, int32_t, 5 /* CLEARTYPE_QUALITY */) \
_(LayersWindowRecordingPath, nsCString, nsCString())
_(LayersWindowRecordingPath, nsCString, nsCString()) \
_(RemoteCanvasEnabled, bool, false) \
/* Add new entries above this line. */

View File

@ -205,7 +205,11 @@ mozilla::ipc::IPCResult GPUParent::RecvInit(
#if defined(XP_WIN)
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
DeviceManagerDx::Get()->CreateCompositorDevices();
if (DeviceManagerDx::Get()->CreateCompositorDevices() &&
gfxVars::RemoteCanvasEnabled()) {
MOZ_ALWAYS_TRUE(DeviceManagerDx::Get()->CreateCanvasDevice());
MOZ_ALWAYS_TRUE(Factory::EnsureDWriteFactory());
}
}
if (gfxVars::UseWebRender()) {
DeviceManagerDx::Get()->CreateDirectCompositionDevice();

View File

@ -0,0 +1,455 @@
/* -*- 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 "CanvasDrawEventRecorder.h"
#include <string.h>
namespace mozilla {
namespace layers {
static const int32_t kCheckpointEventType = -1;
static const uint32_t kMaxSpinCount = 200;
// TODO: These timeouts are long because failure in the middle of writing or
// reading an event is probably going to be fatal to the GPU process. What we
// really need to know is whether the other process has died.
static const TimeDuration kWriterTimeout = TimeDuration::FromMilliseconds(1000);
static const TimeDuration kReaderTimeout = TimeDuration::FromMilliseconds(5000);
static const uint32_t kCacheLineSize = 64;
static const uint32_t kStreamSize = 64 * 1024;
static const uint32_t kShmemSize = kStreamSize + (2 * kCacheLineSize);
static_assert((static_cast<uint64_t>(UINT32_MAX) + 1) % kStreamSize == 0,
"kStreamSize must be a power of two.");
bool CanvasEventRingBuffer::InitWriter(
base::ProcessId aOtherPid, ipc::SharedMemoryBasic::Handle* aReadHandle,
CrossProcessSemaphoreHandle* aReaderSem,
CrossProcessSemaphoreHandle* aWriterSem,
const std::function<void()>& aResumeReaderCallback) {
mSharedMemory = MakeAndAddRef<ipc::SharedMemoryBasic>();
if (NS_WARN_IF(!mSharedMemory->Create(kShmemSize)) ||
NS_WARN_IF(!mSharedMemory->Map(kShmemSize))) {
return false;
}
if (NS_WARN_IF(!mSharedMemory->ShareToProcess(aOtherPid, aReadHandle))) {
return false;
}
mSharedMemory->CloseHandle();
mBuf = static_cast<char*>(mSharedMemory->memory());
mBufPos = mBuf;
mAvailable = kStreamSize;
static_assert(sizeof(ReadFooter) <= kCacheLineSize,
"ReadFooter must fit in kCacheLineSize.");
mRead = reinterpret_cast<ReadFooter*>(mBuf + kStreamSize);
mRead->count = 0;
mRead->returnCount = 0;
mRead->state = State::Processing;
static_assert(sizeof(WriteFooter) <= kCacheLineSize,
"WriteFooter must fit in kCacheLineSize.");
mWrite = reinterpret_cast<WriteFooter*>(mBuf + kStreamSize + kCacheLineSize);
mWrite->count = 0;
mWrite->returnCount = 0;
mWrite->requiredDifference = 0;
mWrite->state = State::Processing;
mReaderSemaphore.reset(
CrossProcessSemaphore::Create("SharedMemoryStreamParent", 0));
*aReaderSem = mReaderSemaphore->ShareToProcess(aOtherPid);
mReaderSemaphore->CloseHandle();
mWriterSemaphore.reset(
CrossProcessSemaphore::Create("SharedMemoryStreamChild", 0));
*aWriterSem = mWriterSemaphore->ShareToProcess(aOtherPid);
mWriterSemaphore->CloseHandle();
mResumeReaderCallback = aResumeReaderCallback;
mGood = true;
return true;
}
bool CanvasEventRingBuffer::InitReader(
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem) {
mSharedMemory = MakeAndAddRef<ipc::SharedMemoryBasic>();
if (NS_WARN_IF(!mSharedMemory->SetHandle(
aReadHandle, ipc::SharedMemory::RightsReadWrite)) ||
NS_WARN_IF(!mSharedMemory->Map(kShmemSize))) {
return false;
}
mSharedMemory->CloseHandle();
mBuf = static_cast<char*>(mSharedMemory->memory());
mRead = reinterpret_cast<ReadFooter*>(mBuf + kStreamSize);
mWrite = reinterpret_cast<WriteFooter*>(mBuf + kStreamSize + kCacheLineSize);
mReaderSemaphore.reset(CrossProcessSemaphore::Create(aReaderSem));
mReaderSemaphore->CloseHandle();
mWriterSemaphore.reset(CrossProcessSemaphore::Create(aWriterSem));
mWriterSemaphore->CloseHandle();
mGood = true;
return true;
}
bool CanvasEventRingBuffer::WaitForAndRecalculateAvailableSpace() {
uint32_t bufPos = mOurCount % kStreamSize;
uint32_t maxToWrite = kStreamSize - bufPos;
mAvailable = std::min(maxToWrite, WaitForBytesToWrite());
if (!mAvailable) {
mGood = false;
mBufPos = nullptr;
return false;
}
mBufPos = mBuf + bufPos;
return true;
}
void CanvasEventRingBuffer::write(const char* const aData, const size_t aSize) {
const char* curDestPtr = aData;
size_t remainingToWrite = aSize;
if (remainingToWrite > mAvailable) {
if (!WaitForAndRecalculateAvailableSpace()) {
return;
}
}
if (remainingToWrite <= mAvailable) {
memcpy(mBufPos, curDestPtr, remainingToWrite);
UpdateWriteTotalsBy(remainingToWrite);
return;
}
do {
memcpy(mBufPos, curDestPtr, mAvailable);
IncrementWriteCountBy(mAvailable);
curDestPtr += mAvailable;
remainingToWrite -= mAvailable;
if (!WaitForAndRecalculateAvailableSpace()) {
return;
}
} while (remainingToWrite > mAvailable);
memcpy(mBufPos, curDestPtr, remainingToWrite);
UpdateWriteTotalsBy(remainingToWrite);
}
void CanvasEventRingBuffer::IncrementWriteCountBy(uint32_t aCount) {
mOurCount += aCount;
mWrite->count = mOurCount;
if (mRead->state != State::Processing) {
CheckAndSignalReader();
}
}
void CanvasEventRingBuffer::UpdateWriteTotalsBy(uint32_t aCount) {
IncrementWriteCountBy(aCount);
mBufPos += aCount;
mAvailable -= aCount;
}
bool CanvasEventRingBuffer::WaitForAndRecalculateAvailableData() {
uint32_t bufPos = mOurCount % kStreamSize;
uint32_t maxToRead = kStreamSize - bufPos;
mAvailable = std::min(maxToRead, WaitForBytesToRead());
if (!mAvailable) {
mGood = false;
mBufPos = nullptr;
return false;
}
mBufPos = mBuf + bufPos;
return true;
}
void CanvasEventRingBuffer::read(char* const aOut, const size_t aSize) {
char* curSrcPtr = aOut;
size_t remainingToRead = aSize;
if (remainingToRead > mAvailable) {
if (!WaitForAndRecalculateAvailableData()) {
return;
}
}
if (remainingToRead <= mAvailable) {
memcpy(curSrcPtr, mBufPos, remainingToRead);
UpdateReadTotalsBy(remainingToRead);
return;
}
do {
memcpy(curSrcPtr, mBufPos, mAvailable);
IncrementReadCountBy(mAvailable);
curSrcPtr += mAvailable;
remainingToRead -= mAvailable;
if (!WaitForAndRecalculateAvailableData()) {
return;
}
} while (remainingToRead > mAvailable);
memcpy(curSrcPtr, mBufPos, remainingToRead);
UpdateReadTotalsBy(remainingToRead);
}
void CanvasEventRingBuffer::IncrementReadCountBy(uint32_t aCount) {
mOurCount += aCount;
mRead->count = mOurCount;
if (mWrite->state != State::Processing) {
CheckAndSignalWriter();
}
}
void CanvasEventRingBuffer::UpdateReadTotalsBy(uint32_t aCount) {
IncrementReadCountBy(aCount);
mBufPos += aCount;
mAvailable -= aCount;
}
void CanvasEventRingBuffer::CheckAndSignalReader() {
do {
switch (mRead->state) {
case State::Processing:
return;
case State::AboutToWait:
// The reader is making a decision about whether to wait. So, we must
// wait until it has decided to avoid races.
continue;
case State::Waiting:
if (mRead->count != mOurCount) {
// We have to use compareExchange here because the reader can change
// from Waiting to Stopped.
if (mRead->state.compareExchange(State::Waiting, State::Processing)) {
mReaderSemaphore->Signal();
return;
}
MOZ_ASSERT(mRead->state == State::Stopped);
continue;
}
return;
case State::Stopped:
if (mRead->count != mOurCount) {
mRead->state = State::Processing;
mResumeReaderCallback();
}
return;
default:
MOZ_ASSERT_UNREACHABLE("Invalid waiting state.");
return;
}
} while (true);
}
bool CanvasEventRingBuffer::HasDataToRead() {
return (mWrite->count != mOurCount);
}
bool CanvasEventRingBuffer::StopIfEmpty() {
// Double-check that the writer isn't waiting.
CheckAndSignalWriter();
mRead->state = State::AboutToWait;
if (HasDataToRead()) {
mRead->state = State::Processing;
return false;
}
mRead->state = State::Stopped;
return true;
}
bool CanvasEventRingBuffer::WaitForDataToRead(TimeDuration aTimeout) {
uint32_t spinCount = kMaxSpinCount;
do {
if (HasDataToRead()) {
return true;
}
} while (--spinCount != 0);
// Double-check that the writer isn't waiting.
CheckAndSignalWriter();
mRead->state = State::AboutToWait;
if (HasDataToRead()) {
mRead->state = State::Processing;
return true;
}
mRead->state = State::Waiting;
if (!mReaderSemaphore->Wait(Some(aTimeout))) {
// We have to use compareExchange here because the writer can change our
// state if we are waiting.
if (!mRead->state.compareExchange(State::Waiting, State::Stopped)) {
MOZ_RELEASE_ASSERT(HasDataToRead());
MOZ_RELEASE_ASSERT(mRead->state == State::Processing);
// The writer has just signaled us, so consume it before returning
MOZ_ALWAYS_TRUE(mReaderSemaphore->Wait());
return true;
}
return false;
}
MOZ_RELEASE_ASSERT(HasDataToRead());
return true;
}
int32_t CanvasEventRingBuffer::ReadNextEvent() {
int32_t nextEvent;
ReadElement(*this, nextEvent);
while (nextEvent == kCheckpointEventType) {
ReadElement(*this, nextEvent);
}
return nextEvent;
}
uint32_t CanvasEventRingBuffer::CreateCheckpoint() {
WriteElement(*this, kCheckpointEventType);
return mOurCount;
}
bool CanvasEventRingBuffer::WaitForCheckpoint(uint32_t aCheckpoint,
TimeDuration aTimeout) {
return WaitForReadCount(aCheckpoint, aTimeout);
}
void CanvasEventRingBuffer::CheckAndSignalWriter() {
do {
switch (mWrite->state) {
case State::Processing:
return;
case State::AboutToWait:
// The writer is making a decision about whether to wait. So, we must
// wait until it has decided to avoid races.
continue;
case State::Waiting:
if (mWrite->count - mOurCount <= mWrite->requiredDifference) {
mWrite->state = State::Processing;
mWriterSemaphore->Signal();
}
return;
default:
MOZ_ASSERT_UNREACHABLE("Invalid waiting state.");
return;
}
} while (true);
}
bool CanvasEventRingBuffer::WaitForReadCount(uint32_t aReadCount,
TimeDuration aTimeout) {
uint32_t requiredDifference = mOurCount - aReadCount;
uint32_t spinCount = kMaxSpinCount;
do {
if (mOurCount - mRead->count <= requiredDifference) {
return true;
}
} while (--spinCount != 0);
// Double-check that the reader isn't waiting.
CheckAndSignalReader();
mWrite->state = State::AboutToWait;
if (mOurCount - mRead->count <= requiredDifference) {
mWrite->state = State::Processing;
return true;
}
mWrite->requiredDifference = requiredDifference;
mWrite->state = State::Waiting;
uint32_t lastReadCount = mRead->count;
while (!mWriterSemaphore->Wait(Some(aTimeout))) {
if (NS_WARN_IF(mRead->count == lastReadCount)) {
return false;
}
lastReadCount = mRead->count;
}
MOZ_ASSERT(mOurCount - mRead->count <= requiredDifference);
return true;
}
uint32_t CanvasEventRingBuffer::WaitForBytesToWrite() {
uint32_t streamFullReadCount = mOurCount - kStreamSize;
if (!WaitForReadCount(streamFullReadCount + 1, kWriterTimeout)) {
mGood = false;
return 0;
}
return mRead->count - streamFullReadCount;
}
uint32_t CanvasEventRingBuffer::WaitForBytesToRead() {
if (!WaitForDataToRead(kReaderTimeout)) {
return 0;
}
return mWrite->count - mOurCount;
}
void CanvasEventRingBuffer::ReturnWrite(const char* aData, size_t aSize) {
uint32_t writeCount = mRead->returnCount;
uint32_t bufPos = writeCount % kStreamSize;
uint32_t bufRemaining = kStreamSize - bufPos;
uint32_t availableToWrite =
std::min(bufRemaining, (mWrite->returnCount + kStreamSize - writeCount));
while (availableToWrite < aSize) {
if (availableToWrite) {
memcpy(mBuf + bufPos, aData, availableToWrite);
writeCount += availableToWrite;
mRead->returnCount = writeCount;
bufPos = writeCount % kStreamSize;
bufRemaining = kStreamSize - bufPos;
aData += availableToWrite;
aSize -= availableToWrite;
}
availableToWrite = std::min(
bufRemaining, (mWrite->returnCount + kStreamSize - writeCount));
}
memcpy(mBuf + bufPos, aData, aSize);
writeCount += aSize;
mRead->returnCount = writeCount;
}
void CanvasEventRingBuffer::ReturnRead(char* aOut, size_t aSize) {
uint32_t readCount = mWrite->returnCount;
uint32_t bufPos = readCount % kStreamSize;
uint32_t bufRemaining = kStreamSize - bufPos;
uint32_t availableToRead =
std::min(bufRemaining, (mRead->returnCount - readCount));
while (availableToRead < aSize) {
if (availableToRead) {
memcpy(aOut, mBuf + bufPos, availableToRead);
readCount += availableToRead;
mWrite->returnCount = readCount;
bufPos = readCount % kStreamSize;
bufRemaining = kStreamSize - bufPos;
aOut += availableToRead;
aSize -= availableToRead;
} else {
// Double-check that the reader isn't waiting.
CheckAndSignalReader();
}
availableToRead = std::min(bufRemaining, (mRead->returnCount - readCount));
}
memcpy(aOut, mBuf + bufPos, aSize);
readCount += aSize;
mWrite->returnCount = readCount;
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,232 @@
/* -*- 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/. */
#ifndef mozilla_layers_CanvasDrawEventRecorder_h
#define mozilla_layers_CanvasDrawEventRecorder_h
#include "mozilla/gfx/DrawEventRecorder.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/ipc/SharedMemoryBasic.h"
namespace mozilla {
namespace layers {
class CanvasEventRingBuffer final : public gfx::EventRingBuffer {
public:
CanvasEventRingBuffer() {}
/**
* Initialize the write side of a CanvasEventRingBuffer returning handles to
* the shared memory for the buffer and the two semaphores for waiting in the
* reader and the writer.
*
* @param aOtherPid process ID to share the handles to
* @param aReadHandle handle to the shared memory for the buffer
* @param aReaderSem reading blocked semaphore
* @param aWriterSem writing blocked semaphore
* @param aResumeReaderCallback callback to start the reader when it is has
* stopped
* @returns true if initialization succeeds
*/
bool InitWriter(base::ProcessId aOtherPid,
ipc::SharedMemoryBasic::Handle* aReadHandle,
CrossProcessSemaphoreHandle* aReaderSem,
CrossProcessSemaphoreHandle* aWriterSem,
const std::function<void()>& aResumeReaderCallback);
/**
* Initialize the read side of a CanvasEventRingBuffer.
*
* @param aReadHandle handle to the shared memory for the buffer
* @param aReaderSem reading blocked semaphore
* @param aWriterSem writing blocked semaphore
* @returns true if initialization succeeds
*/
bool InitReader(const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem);
bool good() const final { return mGood; }
void write(const char* const aData, const size_t aSize) final;
bool HasDataToRead();
/*
* This will put the reader into a stopped state if there is no more data to
* read. If this returns false the caller is responsible for continuing
* translation at a later point. If it returns false the writer will start the
* translation again when more data is written.
*
* @returns true if stopped
*/
bool StopIfEmpty();
/*
* Waits for the given TimeDuration for data to become available.
*
* @returns true if data is available to read.
*/
bool WaitForDataToRead(TimeDuration aTimeout);
int32_t ReadNextEvent();
void read(char* const aOut, const size_t aSize) final;
/**
* Writes a checkpoint event to the buffer.
*
* @returns the write count after the checkpoint has been written
*/
uint32_t CreateCheckpoint();
/**
* Waits until the given checkpoint has been read from the buffer.
*
* @params aCheckpoint the checkpoint to wait for
* @params aTimeout duration to wait while reader is not active
* @returns true if the checkpoint was reached, false if the read count has
* not changed in the aTimeout duration.
*/
bool WaitForCheckpoint(uint32_t aCheckpoint, TimeDuration aTimeout);
/**
* Used to send data back to the writer. This is done through the same shared
* memory so the writer must wait and read the response after it has submitted
* the event that uses this.
*
* @param aData the data to be written back to the writer
* @param aSize the number of chars to write
*/
void ReturnWrite(const char* aData, size_t aSize);
/**
* Used to read data sent back from the reader via ReturnWrite. This is done
* through the same shared memory so the writer must wait until all expected
* data is read before writing new events to the buffer.
*
* @param aOut the pointer to read into
* @param aSize the number of chars to read
*/
void ReturnRead(char* aOut, size_t aSize);
protected:
bool WaitForAndRecalculateAvailableSpace() final;
void UpdateWriteTotalsBy(uint32_t aCount) final;
private:
enum class State : uint32_t {
Processing,
/**
* This is the important state to make sure the other side signals or starts
* us as soon as data or space is available. We set AboutToWait first and
* then re-check the condition. If we went straight to Waiting or Stopped
* then in between the last check and setting the state, the other side
* could have used all available data or space and never have signaled us
* because it didn't know we were about to wait, causing a deadlock.
* While we are in this state, the other side must wait until we resolve the
* AboutToWait state to one of the other states and then signal or start us
* if it needs to.
*/
AboutToWait,
Waiting,
Stopped
};
struct ReadFooter {
Atomic<uint32_t, ReleaseAcquire> count;
Atomic<uint32_t, ReleaseAcquire> returnCount;
Atomic<State, ReleaseAcquire> state;
};
struct WriteFooter {
Atomic<uint32_t, ReleaseAcquire> count;
Atomic<uint32_t, ReleaseAcquire> returnCount;
Atomic<uint32_t, ReleaseAcquire> requiredDifference;
Atomic<State, ReleaseAcquire> state;
};
CanvasEventRingBuffer(const CanvasEventRingBuffer&) = delete;
void operator=(const CanvasEventRingBuffer&) = delete;
void IncrementWriteCountBy(uint32_t aCount);
bool WaitForReadCount(uint32_t aReadCount, TimeDuration aTimeout);
bool WaitForAndRecalculateAvailableData();
void UpdateReadTotalsBy(uint32_t aCount);
void IncrementReadCountBy(uint32_t aCount);
void CheckAndSignalReader();
void CheckAndSignalWriter();
uint32_t WaitForBytesToWrite();
uint32_t WaitForBytesToRead();
RefPtr<ipc::SharedMemoryBasic> mSharedMemory;
UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
std::function<void()> mResumeReaderCallback;
char* mBuf = nullptr;
uint32_t mOurCount = 0;
WriteFooter* mWrite = nullptr;
ReadFooter* mRead = nullptr;
bool mGood = false;
};
class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final)
explicit CanvasDrawEventRecorder(){};
bool Init(base::ProcessId aOtherPid, ipc::SharedMemoryBasic::Handle* aHandle,
CrossProcessSemaphoreHandle* aReaderSem,
CrossProcessSemaphoreHandle* aWriterSem,
const std::function<void()>& aResumeReaderCallback) {
return mOutputStream.InitWriter(aOtherPid, aHandle, aReaderSem, aWriterSem,
aResumeReaderCallback);
}
void RecordEvent(const gfx::RecordedEvent& aEvent) final {
if (!mOutputStream.good()) {
return;
}
aEvent.RecordToStream(mOutputStream);
}
void Flush() final {}
void ReturnRead(char* aOut, size_t aSize) {
mOutputStream.ReturnRead(aOut, aSize);
}
uint32_t CreateCheckpoint() { return mOutputStream.CreateCheckpoint(); }
/**
* Waits until the given checkpoint has been read by the translator.
*
* @params aCheckpoint the checkpoint to wait for
* @params aTimeout duration to wait while translator is not actively reading
* @returns true if the checkpoint was reached, false if the translator has
* not been active in the aTimeout duration.
*/
bool WaitForCheckpoint(uint32_t aCheckpoint, TimeDuration aTimeout) {
return mOutputStream.WaitForCheckpoint(aCheckpoint, aTimeout);
}
private:
CanvasEventRingBuffer mOutputStream;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_CanvasDrawEventRecorder_h

View File

@ -0,0 +1,245 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#include "CanvasTranslator.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "RecordedCanvasEventImpl.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerDx.h"
# include "mozilla/layers/TextureD3D11.h"
#endif
namespace mozilla {
namespace layers {
// When in a transaction we wait for a short time because we're expecting more
// events from the content process. We don't want to wait for too long in case
// other content processes are waiting for events to process.
static const TimeDuration kReadEventTimeout = TimeDuration::FromMilliseconds(5);
static TextureData* CreateTextureData(TextureType aTextureType,
const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) {
TextureData* textureData = nullptr;
switch (aTextureType) {
#ifdef XP_WIN
case TextureType::D3D11: {
RefPtr<ID3D11Device> device =
gfx::DeviceManagerDx::Get()->GetCanvasDevice();
MOZ_RELEASE_ASSERT(device, "Failed to get a device for canvas drawing.");
textureData =
D3D11TextureData::Create(aSize, aFormat, ALLOC_CLEAR_BUFFER, device);
break;
}
#endif
default:
MOZ_CRASH("Unsupported TextureType for CanvasTranslator.");
}
if (!textureData) {
MOZ_CRASH("Failed to create TextureData.");
}
return textureData;
}
/* static */
UniquePtr<CanvasTranslator> CanvasTranslator::Create(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem) {
TextureData* textureData = CreateTextureData(aTextureType, gfx::IntSize(1, 1),
gfx::SurfaceFormat::B8G8R8A8);
textureData->Lock(OpenMode::OPEN_READ_WRITE);
RefPtr<gfx::DrawTarget> dt = textureData->BorrowDrawTarget();
return UniquePtr<CanvasTranslator>(new CanvasTranslator(
aTextureType, textureData, dt, aReadHandle, aReaderSem, aWriterSem));
}
CanvasTranslator::CanvasTranslator(
const TextureType& aTextureType, TextureData* aTextureData,
gfx::DrawTarget* aDT, const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem)
: gfx::InlineTranslator(aDT),
mTextureType(aTextureType),
mReferenceTextureData(aTextureData) {
mStream.InitReader(aReadHandle, aReaderSem, aWriterSem);
}
CanvasTranslator::~CanvasTranslator() { mReferenceTextureData->Unlock(); }
bool CanvasTranslator::TranslateRecording() {
int32_t eventType = mStream.ReadNextEvent();
while (mStream.good()) {
bool success = RecordedEvent::DoWithEventFromStream(
mStream, static_cast<RecordedEvent::EventType>(eventType),
[&](RecordedEvent* recordedEvent) -> bool {
// Make sure that the whole event was read from the stream.
if (!mStream.good()) {
return false;
}
return recordedEvent->PlayEvent(this);
});
if (!success && !HandleExtensionEvent(eventType)) {
gfxDevCrash(gfx::LogReason::PlayEventFailed)
<< "Failed to play canvas event type: " << eventType;
mIsValid = false;
return true;
}
if (!mIsInTransaction) {
return mStream.StopIfEmpty();
}
if (!mStream.HasDataToRead()) {
// We're going to wait for the next event, so take the opportunity to
// flush the rendering.
Flush();
if (!mStream.WaitForDataToRead(kReadEventTimeout)) {
return true;
}
}
eventType = mStream.ReadNextEvent();
}
mIsValid = false;
return true;
}
#define READ_AND_PLAY_CANVAS_EVENT_TYPE(_typeenum, _class) \
case _typeenum: { \
auto e = _class(mStream); \
if (!mStream.good()) { \
return false; \
} \
return e.PlayCanvasEvent(this); \
}
bool CanvasTranslator::HandleExtensionEvent(int32_t aType) {
// This is where we handle extensions to the Moz2D Recording events to handle
// canvas specific things.
switch (aType) {
FOR_EACH_CANVAS_EVENT(READ_AND_PLAY_CANVAS_EVENT_TYPE)
default:
return false;
}
}
void CanvasTranslator::BeginTransaction() { mIsInTransaction = true; }
void CanvasTranslator::Flush() {
#if defined(XP_WIN)
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
GetReferenceDrawTarget()->GetBackendType());
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetCanvasDevice();
RefPtr<ID3D11DeviceContext> deviceContext;
device->GetImmediateContext(getter_AddRefs(deviceContext));
deviceContext->Flush();
#endif
}
void CanvasTranslator::EndTransaction() {
Flush();
mIsInTransaction = false;
}
void CanvasTranslator::AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr,
TextureData* aTextureData) {
UniquePtr<SurfaceDescriptor> descriptor = MakeUnique<SurfaceDescriptor>();
if (!aTextureData->Serialize(*descriptor)) {
MOZ_CRASH("Failed to serialize");
}
MonitorAutoLock lock(mSurfaceDescriptorsMonitor);
mSurfaceDescriptors[aRefPtr] = std::move(descriptor);
mSurfaceDescriptorsMonitor.Notify();
}
already_AddRefed<gfx::DrawTarget> CanvasTranslator::CreateDrawTarget(
gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) {
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
GetReferenceDrawTarget()->GetBackendType());
TextureData* textureData = CreateTextureData(mTextureType, aSize, aFormat);
textureData->Lock(OpenMode::OPEN_READ_WRITE);
mTextureDatas[aRefPtr] = UniquePtr<TextureData>(textureData);
AddSurfaceDescriptor(aRefPtr, textureData);
RefPtr<gfx::DrawTarget> dt = textureData->BorrowDrawTarget();
AddDrawTarget(aRefPtr, dt);
return dt.forget();
}
void CanvasTranslator::RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) {
InlineTranslator::RemoveDrawTarget(aDrawTarget);
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
GetReferenceDrawTarget()->GetBackendType());
mTextureDatas.erase(aDrawTarget);
}
TextureData* CanvasTranslator::LookupTextureData(
gfx::ReferencePtr aDrawTarget) {
TextureMap::const_iterator result = mTextureDatas.find(aDrawTarget);
if (result == mTextureDatas.end()) {
return nullptr;
}
return result->second.get();
}
UniquePtr<SurfaceDescriptor> CanvasTranslator::WaitForSurfaceDescriptor(
gfx::ReferencePtr aDrawTarget) {
MonitorAutoLock lock(mSurfaceDescriptorsMonitor);
DescriptorMap::iterator result;
while ((result = mSurfaceDescriptors.find(aDrawTarget)) ==
mSurfaceDescriptors.end()) {
mSurfaceDescriptorsMonitor.Wait();
}
UniquePtr<SurfaceDescriptor> descriptor = std::move(result->second);
mSurfaceDescriptors.erase(aDrawTarget);
return descriptor;
}
gfx::DataSourceSurface* CanvasTranslator::LookupDataSurface(
gfx::ReferencePtr aRefPtr) {
return mDataSurfaces.GetWeak(aRefPtr);
}
void CanvasTranslator::AddDataSurface(
gfx::ReferencePtr aRefPtr, RefPtr<gfx::DataSourceSurface>&& aSurface) {
mDataSurfaces.Put(aRefPtr, aSurface);
}
void CanvasTranslator::RemoveDataSurface(gfx::ReferencePtr aRefPtr) {
mDataSurfaces.Remove(aRefPtr);
}
void CanvasTranslator::SetPreparedMap(
gfx::ReferencePtr aSurface,
UniquePtr<gfx::DataSourceSurface::ScopedMap> aMap) {
mMappedSurface = aSurface;
mPreparedMap = std::move(aMap);
}
UniquePtr<gfx::DataSourceSurface::ScopedMap> CanvasTranslator::GetPreparedMap(
gfx::ReferencePtr aSurface) {
MOZ_RELEASE_ASSERT(mMappedSurface == aSurface,
"aSurface must match previously stored surface.");
mMappedSurface = nullptr;
return std::move(mPreparedMap);
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,216 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_CanvasTranslator_h
#define mozilla_layers_CanvasTranslator_h
#include <unordered_map>
#include <vector>
#include "mozilla/gfx/InlineTranslator.h"
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/Monitor.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace layers {
class TextureData;
class CanvasTranslator final : public gfx::InlineTranslator {
public:
/**
* Create a canvas translator for a particular TextureType, which translates
* events from a CanvasEventRingBuffer.
*
* @param aTextureType the TextureType the translator will create
* @param aReadHandle handle to the shared memory for the
* CanvasEventRingBuffer
* @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer
* @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer
* @returns the new CanvasTranslator
*/
static UniquePtr<CanvasTranslator> Create(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem);
~CanvasTranslator();
bool IsValid() { return mIsValid; }
/**
* Translates events until no more are available or the end of a transaction
* If this returns false the caller of this is responsible for re-calling
* this function.
*
* @returns true if all events are processed and false otherwise.
*/
bool TranslateRecording();
/**
* Marks the beginning of rendering for a transaction. While in a transaction
* the translator will wait for a short time for events before returning.
* When not in a transaction the translator will only translate one event at a
* time.
*/
void BeginTransaction();
/**
* Marks the end of a transaction.
*/
void EndTransaction();
/**
* Flushes canvas drawing, for example to a device.
*/
void Flush();
/**
* Used to send data back to the writer. This is done through the same shared
* memory so the writer must wait and read the response after it has submitted
* the event that uses this.
*
* @param aData the data to be written back to the writer
* @param aSize the number of chars to write
*/
void ReturnWrite(const char* aData, size_t aSize) {
mStream.ReturnWrite(aData, aSize);
}
/**
* Used during playback of events to create DrawTargets. For the
* CanvasTranslator this means creating TextureDatas and getting the
* DrawTargets from those.
*
* @param aRefPtr the key to store the created DrawTarget against
* @param aSize the size of the DrawTarget
* @param aFormat the surface format for the DrawTarget
* @returns the new DrawTarget
*/
already_AddRefed<gfx::DrawTarget> CreateDrawTarget(
gfx::ReferencePtr aRefPtr, const gfx::IntSize& aSize,
gfx::SurfaceFormat aFormat) final;
/**
* Get the TextureData associated with a DrawTarget from another process.
*
* @param aDrawTarget the key used to find the TextureData
* @returns the TextureData found
*/
TextureData* LookupTextureData(gfx::ReferencePtr aDrawTarget);
/**
* Waits for the SurfaceDescriptor associated with a DrawTarget from another
* process to be created and then returns it.
*
* @param aDrawTarget the key used to find the TextureData
* @returns the SurfaceDescriptor found
*/
UniquePtr<SurfaceDescriptor> WaitForSurfaceDescriptor(
gfx::ReferencePtr aDrawTarget);
/**
* Removes the DrawTarget and other objects associated with a DrawTarget from
* another process.
*
* @param aDrawTarget the key to the objects to remove
*/
void RemoveDrawTarget(gfx::ReferencePtr aDrawTarget) final;
/**
* Removes the SourceSurface and other objects associated with a SourceSurface
* from another process.
*
* @param aRefPtr the key to the objects to remove
*/
void RemoveSourceSurface(gfx::ReferencePtr aRefPtr) final {
RemoveDataSurface(aRefPtr);
InlineTranslator::RemoveSourceSurface(aRefPtr);
}
/**
* Gets the cached DataSourceSurface, if it exists, associated with a
* SourceSurface from another process.
*
* @param aRefPtr the key used to find the DataSourceSurface
* @returns the DataSourceSurface or nullptr if not found
*/
gfx::DataSourceSurface* LookupDataSurface(gfx::ReferencePtr aRefPtr);
/**
* Used to cache the DataSourceSurface from a SourceSurface associated with a
* SourceSurface from another process. This is to improve performance if we
* require the data for that SourceSurface.
*
* @param aRefPtr the key used to store the DataSourceSurface
* @param aSurface the DataSourceSurface to store
*/
void AddDataSurface(gfx::ReferencePtr aRefPtr,
RefPtr<gfx::DataSourceSurface>&& aSurface);
/**
* Gets the cached DataSourceSurface, if it exists, associated with a
* SourceSurface from another process.
*
* @param aRefPtr the key used to find the DataSourceSurface
* @returns the DataSourceSurface or nullptr if not found
*/
void RemoveDataSurface(gfx::ReferencePtr aRefPtr);
/**
* Sets a ScopedMap, to be used in a later event.
*
* @param aSurface the associated surface in the other process
* @param aMap the ScopedMap to store
*/
void SetPreparedMap(gfx::ReferencePtr aSurface,
UniquePtr<gfx::DataSourceSurface::ScopedMap> aMap);
/**
* Gets the ScopedMap stored using SetPreparedMap.
*
* @param aSurface must match the surface from the SetPreparedMap call
* @returns the ScopedMap if aSurface matches otherwise nullptr
*/
UniquePtr<gfx::DataSourceSurface::ScopedMap> GetPreparedMap(
gfx::ReferencePtr aSurface);
private:
CanvasTranslator(const TextureType& aTextureType, TextureData* aTextureData,
gfx::DrawTarget* aDrawTarget,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem);
void AddSurfaceDescriptor(gfx::ReferencePtr aRefPtr,
TextureData* atextureData);
bool HandleExtensionEvent(int32_t aType);
CanvasEventRingBuffer mStream;
TextureType mTextureType = TextureType::Unknown;
UniquePtr<TextureData> mReferenceTextureData;
typedef std::unordered_map<void*, UniquePtr<TextureData>> TextureMap;
TextureMap mTextureDatas;
nsRefPtrHashtable<nsPtrHashKey<void>, gfx::DataSourceSurface> mDataSurfaces;
gfx::ReferencePtr mMappedSurface;
UniquePtr<gfx::DataSourceSurface::ScopedMap> mPreparedMap;
typedef std::unordered_map<void*, UniquePtr<SurfaceDescriptor>> DescriptorMap;
DescriptorMap mSurfaceDescriptors;
Monitor mSurfaceDescriptorsMonitor{
"CanvasTranslator::mSurfaceDescriptorsMonitor"};
bool mIsValid = true;
bool mIsInTransaction = false;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_CanvasTranslator_h

View File

@ -155,6 +155,16 @@ enum class LayersBackend : int8_t {
LAYERS_LAST
};
enum class TextureType : int8_t {
Unknown = 0,
D3D11,
DIB,
X11,
MacIOSurface,
AndroidNativeWindow,
Last
};
enum class BufferMode : int8_t { BUFFER_NONE, BUFFERED };
enum class DrawRegionClip : int8_t { DRAW, NONE };

View File

@ -10,6 +10,7 @@
#include "mozilla/layers/ShadowLayers.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/StaticPrefs.h"
#include "pratom.h"
#include "gfxPlatform.h"
@ -103,6 +104,21 @@ PersistentBufferProviderShared::Create(gfx::IntSize aSize,
return nullptr;
}
if (!StaticPrefs::PersistentBufferProviderSharedEnabled()) {
return nullptr;
}
#ifdef XP_WIN
// Bug 1285271 - Disable shared buffer provider on Windows with D2D due to
// instability, unless we are remoting the canvas drawing to the GPU process.
if (gfxPlatform::GetPlatform()->GetPreferredCanvasBackend() ==
BackendType::DIRECT2D1_1 &&
!TextureData::IsRemote(aKnowsCompositor->GetCompositorBackendType(),
BackendSelector::Canvas)) {
return nullptr;
}
#endif
RefPtr<TextureClient> texture = TextureClient::CreateForDrawing(
aKnowsCompositor, aFormat, aSize, BackendSelector::Canvas,
TextureFlags::DEFAULT | TextureFlags::NON_BLOCKING_READ_LOCK,
@ -332,18 +348,23 @@ PersistentBufferProviderShared::BorrowDrawTarget(
return nullptr;
}
mDrawTarget = tex->BorrowDrawTarget();
if (mBack != previousBackBuffer && !aPersistedRect.IsEmpty()) {
TextureClient* previous = GetTexture(previousBackBuffer);
if (previous && previous->Lock(OpenMode::OPEN_READ)) {
DebugOnly<bool> success =
previous->CopyToTextureClient(tex, &aPersistedRect, nullptr);
MOZ_ASSERT(success);
if (mPreviousSnapshot) {
mDrawTarget->CopySurface(mPreviousSnapshot, aPersistedRect,
gfx::IntPoint(0, 0));
} else {
TextureClient* previous = GetTexture(previousBackBuffer);
if (previous && previous->Lock(OpenMode::OPEN_READ)) {
DebugOnly<bool> success =
previous->CopyToTextureClient(tex, &aPersistedRect, nullptr);
MOZ_ASSERT(success);
previous->Unlock();
previous->Unlock();
}
}
}
mDrawTarget = tex->BorrowDrawTarget();
mPreviousSnapshot = nullptr;
if (mDrawTarget) {
// This is simply to ensure the DrawTarget gets initialized, and will detect
@ -366,12 +387,23 @@ bool PersistentBufferProviderShared::ReturnDrawTarget(
// Can't change the current front buffer while its snapshot is borrowed!
MOZ_ASSERT(!mSnapshot);
mDrawTarget = nullptr;
dt = nullptr;
TextureClient* back = GetTexture(mBack);
MOZ_ASSERT(back);
// If our TextureClients have internal synchronization then, if locks are
// needed for reading and writing, this can cause locking issues with the
// compositor. To prevent this we take a snapshot when the DrawTarget is
// returned, so this can be used when our own BorrowSnapshot is called and
// also for copying to the next TextureClient. Using this snapshot outside of
// the locks is safe, because the TextureClient calls DetachAllSnapshots on
// its DrawTarget when we Unlock below.
if (back->HasSynchronization()) {
mPreviousSnapshot = back->BorrowSnapshot();
}
mDrawTarget = nullptr;
dt = nullptr;
if (back) {
back->Unlock();
mFront = mBack;
@ -393,7 +425,17 @@ TextureClient* PersistentBufferProviderShared::GetTextureClient() {
already_AddRefed<gfx::SourceSurface>
PersistentBufferProviderShared::BorrowSnapshot() {
MOZ_ASSERT(!mDrawTarget);
if (mPreviousSnapshot) {
mSnapshot = mPreviousSnapshot;
return do_AddRef(mSnapshot);
}
if (mDrawTarget) {
auto back = GetTexture(mBack);
MOZ_ASSERT(back && back->IsLocked());
mSnapshot = back->BorrowSnapshot();
return do_AddRef(mSnapshot);
}
auto front = GetTexture(mFront);
if (!front || front->IsLocked()) {
@ -405,17 +447,9 @@ PersistentBufferProviderShared::BorrowSnapshot() {
return nullptr;
}
RefPtr<DrawTarget> dt = front->BorrowDrawTarget();
mSnapshot = front->BorrowSnapshot();
if (!dt) {
front->Unlock();
return nullptr;
}
mSnapshot = dt->Snapshot();
RefPtr<SourceSurface> snapshot = mSnapshot;
return snapshot.forget();
return do_AddRef(mSnapshot);
}
void PersistentBufferProviderShared::ReturnSnapshot(
@ -426,6 +460,10 @@ void PersistentBufferProviderShared::ReturnSnapshot(
mSnapshot = nullptr;
snapshot = nullptr;
if (mPreviousSnapshot || mDrawTarget) {
return;
}
auto front = GetTexture(mFront);
if (front) {
front->Unlock();
@ -461,6 +499,7 @@ void PersistentBufferProviderShared::ClearCachedResources() {
void PersistentBufferProviderShared::Destroy() {
mSnapshot = nullptr;
mPreviousSnapshot = nullptr;
mDrawTarget = nullptr;
for (auto& mTexture : mTextures) {

View File

@ -180,6 +180,7 @@ class PersistentBufferProviderShared : public PersistentBufferProvider,
RefPtr<gfx::DrawTarget> mDrawTarget;
RefPtr<gfx::SourceSurface> mSnapshot;
RefPtr<gfx::SourceSurface> mPreviousSnapshot;
};
struct AutoReturnSnapshot final {

View File

@ -6,6 +6,7 @@
#include "mozilla/layers/ProfilerScreenshots.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/TimeStamp.h"
#include "GeckoProfiler.h"
@ -16,6 +17,7 @@
#endif
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::layers;
ProfilerScreenshots::ProfilerScreenshots()

View File

@ -11,6 +11,9 @@
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TimeStamp.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
#include "mozilla/gfx/Point.h"
@ -84,19 +87,19 @@ class ProfilerScreenshots final {
* Returns null if the limit is reached.
* Can be called on any thread.
*/
already_AddRefed<DataSourceSurface> TakeNextSurface();
already_AddRefed<gfx::DataSourceSurface> TakeNextSurface();
/**
* Return aSurface back into the mAvailableSurfaces pool. Can be called on
* any thread.
*/
void ReturnSurface(DataSourceSurface* aSurface);
void ReturnSurface(gfx::DataSourceSurface* aSurface);
// The thread on which encoding happens.
nsCOMPtr<nsIThread> mThread;
// An array of surfaces ready to be recycled. Can be accessed from multiple
// threads, protected by mMutex.
nsTArray<RefPtr<DataSourceSurface>> mAvailableSurfaces;
nsTArray<RefPtr<gfx::DataSourceSurface>> mAvailableSurfaces;
// Protects mAvailableSurfaces.
Mutex mMutex;
// The total number of surfaces created. If encoding is fast enough to happen

View File

@ -0,0 +1,384 @@
/* -*- 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/. */
#ifndef mozilla_layers_RecordedCanvasEventImpl_h
#define mozilla_layers_RecordedCanvasEventImpl_h
#include "mozilla/gfx/RecordedEvent.h"
#include "mozilla/gfx/RecordingTypes.h"
#include "mozilla/layers/CanvasTranslator.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/TextureClient.h"
namespace mozilla {
namespace layers {
using gfx::DrawTarget;
using gfx::IntSize;
using gfx::RecordedEvent;
using gfx::RecordedEventDerived;
using EventType = gfx::RecordedEvent::EventType;
using gfx::ReadElement;
using gfx::ReferencePtr;
using gfx::SurfaceFormat;
using gfx::WriteElement;
using ipc::SharedMemoryBasic;
const EventType CANVAS_BEGIN_TRANSACTION = EventType::LAST;
const EventType CANVAS_END_TRANSACTION = EventType(EventType::LAST + 1);
const EventType CANVAS_FLUSH = EventType(EventType::LAST + 2);
const EventType TEXTURE_LOCK = EventType(EventType::LAST + 3);
const EventType TEXTURE_UNLOCK = EventType(EventType::LAST + 4);
const EventType CACHE_DATA_SURFACE = EventType(EventType::LAST + 5);
const EventType PREPARE_DATA_FOR_SURFACE = EventType(EventType::LAST + 6);
const EventType GET_DATA_FOR_SURFACE = EventType(EventType::LAST + 7);
class RecordedCanvasBeginTransaction final
: public RecordedEventDerived<RecordedCanvasBeginTransaction> {
public:
RecordedCanvasBeginTransaction()
: RecordedEventDerived(CANVAS_BEGIN_TRANSACTION) {}
template <class S>
MOZ_IMPLICIT RecordedCanvasBeginTransaction(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedCanvasBeginTransaction"; }
};
inline bool RecordedCanvasBeginTransaction::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
aTranslator->BeginTransaction();
return true;
}
template <class S>
void RecordedCanvasBeginTransaction::Record(S& aStream) const {}
template <class S>
RecordedCanvasBeginTransaction::RecordedCanvasBeginTransaction(S& aStream)
: RecordedEventDerived(CANVAS_BEGIN_TRANSACTION) {}
class RecordedCanvasEndTransaction final
: public RecordedEventDerived<RecordedCanvasEndTransaction> {
public:
RecordedCanvasEndTransaction()
: RecordedEventDerived(CANVAS_END_TRANSACTION) {}
template <class S>
MOZ_IMPLICIT RecordedCanvasEndTransaction(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedCanvasEndTransaction"; }
};
inline bool RecordedCanvasEndTransaction::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
aTranslator->EndTransaction();
return true;
}
template <class S>
void RecordedCanvasEndTransaction::Record(S& aStream) const {}
template <class S>
RecordedCanvasEndTransaction::RecordedCanvasEndTransaction(S& aStream)
: RecordedEventDerived(CANVAS_END_TRANSACTION) {}
class RecordedCanvasFlush final
: public RecordedEventDerived<RecordedCanvasFlush> {
public:
RecordedCanvasFlush() : RecordedEventDerived(CANVAS_FLUSH) {}
template <class S>
MOZ_IMPLICIT RecordedCanvasFlush(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedCanvasFlush"; }
};
inline bool RecordedCanvasFlush::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
aTranslator->Flush();
return true;
}
template <class S>
void RecordedCanvasFlush::Record(S& aStream) const {}
template <class S>
RecordedCanvasFlush::RecordedCanvasFlush(S& aStream)
: RecordedEventDerived(CANVAS_FLUSH) {}
class RecordedTextureLock final
: public RecordedEventDerived<RecordedTextureLock> {
public:
RecordedTextureLock(DrawTarget* aDT, const OpenMode aMode)
: RecordedEventDerived(TEXTURE_LOCK), mDT(aDT), mMode(aMode) {}
template <class S>
MOZ_IMPLICIT RecordedTextureLock(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "TextureLock"; }
private:
ReferencePtr mDT;
OpenMode mMode;
};
inline bool RecordedTextureLock::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
TextureData* textureData = aTranslator->LookupTextureData(mDT);
if (!textureData) {
return false;
}
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
aTranslator->GetReferenceDrawTarget()->GetBackendType());
textureData->Lock(mMode);
return true;
}
template <class S>
void RecordedTextureLock::Record(S& aStream) const {
WriteElement(aStream, mDT);
WriteElement(aStream, mMode);
}
template <class S>
RecordedTextureLock::RecordedTextureLock(S& aStream)
: RecordedEventDerived(TEXTURE_LOCK) {
ReadElement(aStream, mDT);
ReadElement(aStream, mMode);
}
class RecordedTextureUnlock final
: public RecordedEventDerived<RecordedTextureUnlock> {
public:
explicit RecordedTextureUnlock(DrawTarget* aDT)
: RecordedEventDerived(TEXTURE_UNLOCK), mDT(aDT) {}
template <class S>
MOZ_IMPLICIT RecordedTextureUnlock(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "TextureUnlock"; }
private:
ReferencePtr mDT;
};
inline bool RecordedTextureUnlock::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
TextureData* textureData = aTranslator->LookupTextureData(mDT);
if (!textureData) {
return false;
}
gfx::AutoSerializeWithMoz2D serializeWithMoz2D(
aTranslator->GetReferenceDrawTarget()->GetBackendType());
textureData->Unlock();
return true;
}
template <class S>
void RecordedTextureUnlock::Record(S& aStream) const {
WriteElement(aStream, mDT);
}
template <class S>
RecordedTextureUnlock::RecordedTextureUnlock(S& aStream)
: RecordedEventDerived(TEXTURE_UNLOCK) {
ReadElement(aStream, mDT);
}
class RecordedCacheDataSurface final
: public RecordedEventDerived<RecordedCacheDataSurface> {
public:
explicit RecordedCacheDataSurface(gfx::SourceSurface* aSurface)
: RecordedEventDerived(CACHE_DATA_SURFACE), mSurface(aSurface) {}
template <class S>
MOZ_IMPLICIT RecordedCacheDataSurface(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedCacheDataSurface"; }
private:
ReferencePtr mSurface;
};
inline bool RecordedCacheDataSurface::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
RefPtr<gfx::SourceSurface> surface =
aTranslator->LookupSourceSurface(mSurface);
RefPtr<gfx::DataSourceSurface> dataSurface = surface->GetDataSurface();
aTranslator->AddDataSurface(mSurface, std::move(dataSurface));
return true;
}
template <class S>
void RecordedCacheDataSurface::Record(S& aStream) const {
WriteElement(aStream, mSurface);
}
template <class S>
RecordedCacheDataSurface::RecordedCacheDataSurface(S& aStream)
: RecordedEventDerived(CACHE_DATA_SURFACE) {
ReadElement(aStream, mSurface);
}
class RecordedPrepareDataForSurface final
: public RecordedEventDerived<RecordedPrepareDataForSurface> {
public:
explicit RecordedPrepareDataForSurface(const gfx::SourceSurface* aSurface)
: RecordedEventDerived(PREPARE_DATA_FOR_SURFACE), mSurface(aSurface) {}
template <class S>
MOZ_IMPLICIT RecordedPrepareDataForSurface(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedPrepareDataForSurface"; }
private:
ReferencePtr mSurface;
};
inline bool RecordedPrepareDataForSurface::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
RefPtr<gfx::DataSourceSurface> dataSurface =
aTranslator->LookupDataSurface(mSurface);
if (!dataSurface) {
RefPtr<gfx::SourceSurface> surface =
aTranslator->LookupSourceSurface(mSurface);
if (!surface) {
return false;
}
dataSurface = surface->GetDataSurface();
if (!dataSurface) {
return false;
}
}
auto preparedMap = MakeUnique<gfx::DataSourceSurface::ScopedMap>(
dataSurface, gfx::DataSourceSurface::READ);
aTranslator->SetPreparedMap(mSurface, std::move(preparedMap));
return true;
}
template <class S>
void RecordedPrepareDataForSurface::Record(S& aStream) const {
WriteElement(aStream, mSurface);
}
template <class S>
RecordedPrepareDataForSurface::RecordedPrepareDataForSurface(S& aStream)
: RecordedEventDerived(PREPARE_DATA_FOR_SURFACE) {
ReadElement(aStream, mSurface);
}
class RecordedGetDataForSurface final
: public RecordedEventDerived<RecordedGetDataForSurface> {
public:
explicit RecordedGetDataForSurface(const gfx::SourceSurface* aSurface)
: RecordedEventDerived(GET_DATA_FOR_SURFACE), mSurface(aSurface) {}
template <class S>
MOZ_IMPLICIT RecordedGetDataForSurface(S& aStream);
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const;
template <class S>
void Record(S& aStream) const;
std::string GetName() const final { return "RecordedGetDataForSurface"; }
private:
ReferencePtr mSurface;
};
inline bool RecordedGetDataForSurface::PlayCanvasEvent(
CanvasTranslator* aTranslator) const {
RefPtr<gfx::SourceSurface> surface =
aTranslator->LookupSourceSurface(mSurface);
if (!surface) {
return false;
}
UniquePtr<gfx::DataSourceSurface::ScopedMap> map =
aTranslator->GetPreparedMap(mSurface);
gfx::IntSize ssSize = surface->GetSize();
size_t dataFormatWidth = ssSize.width * BytesPerPixel(surface->GetFormat());
int32_t srcStride = map->GetStride();
char* src = reinterpret_cast<char*>(map->GetData());
char* endSrc = src + (ssSize.height * srcStride);
while (src < endSrc) {
aTranslator->ReturnWrite(src, dataFormatWidth);
src += srcStride;
}
return true;
}
template <class S>
void RecordedGetDataForSurface::Record(S& aStream) const {
WriteElement(aStream, mSurface);
}
template <class S>
RecordedGetDataForSurface::RecordedGetDataForSurface(S& aStream)
: RecordedEventDerived(GET_DATA_FOR_SURFACE) {
ReadElement(aStream, mSurface);
}
#define FOR_EACH_CANVAS_EVENT(f) \
f(CANVAS_BEGIN_TRANSACTION, RecordedCanvasBeginTransaction); \
f(CANVAS_END_TRANSACTION, RecordedCanvasEndTransaction); \
f(CANVAS_FLUSH, RecordedCanvasFlush); \
f(TEXTURE_LOCK, RecordedTextureLock); \
f(TEXTURE_UNLOCK, RecordedTextureUnlock); \
f(CACHE_DATA_SURFACE, RecordedCacheDataSurface); \
f(PREPARE_DATA_FOR_SURFACE, RecordedPrepareDataForSurface); \
f(GET_DATA_FOR_SURFACE, RecordedGetDataForSurface);
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_RecordedCanvasEventImpl_h

View File

@ -18,6 +18,7 @@
#include "mozilla/layers/APZInputBridge.h" // for APZInputBridge
#include "mozilla/layers/APZTestData.h" // for APZTestData
#include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager
#include "mozilla/layers/LayerAttributes.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/KeyboardMap.h" // for KeyboardMap
#include "mozilla/layers/TouchCounter.h" // for TouchCounter

View File

@ -19,6 +19,7 @@
#include "mozilla/gfx/ssse3-scaler.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/SSE.h"
#include "mozilla/StaticPrefs.h"
#include "gfxPlatform.h"
#include "gfxUtils.h"
#include "YCbCrUtils.h"

View File

@ -665,6 +665,8 @@ void ClientLayerManager::ForwardTransaction(bool aScheduleComposite) {
AUTO_PROFILER_TRACING("Paint", "ForwardTransaction", GRAPHICS);
TimeStamp start = TimeStamp::Now();
GetCompositorBridgeChild()->EndCanvasTransaction();
// Skip the synchronization for buffer since we also skip the painting during
// device-reset status. With OMTP, we have to wait for async paints
// before we synchronize and it's done on the paint thread.
@ -862,8 +864,7 @@ ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize,
// because the canvas will most likely be flattened into a thebes layer
// instead of being sent to the compositor, in which case rendering into
// shared memory is wasteful.
if (IsCompositingCheap() &&
StaticPrefs::PersistentBufferProviderSharedEnabled()) {
if (IsCompositingCheap()) {
RefPtr<PersistentBufferProvider> provider =
PersistentBufferProviderShared::Create(aSize, aFormat,
AsShadowForwarder());

View File

@ -9,6 +9,7 @@
#include "Layers.h" // for Layer, etc
#include "gfx2DGlue.h"
#include "gfxPlatform.h" // for gfxPlatform
#include "MainThreadUtils.h"
#include "mozilla/Atomics.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/SystemGroup.h"
@ -19,6 +20,7 @@
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/PaintThread.h"
#include "mozilla/layers/TextureClientRecycleAllocator.h"
#include "mozilla/layers/TextureRecorded.h"
#include "mozilla/Mutex.h"
#include "nsDebug.h" // for NS_ASSERTION, NS_WARNING, etc
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
@ -235,6 +237,159 @@ class TextureChild final : PTextureChild {
friend void DeallocateTextureClient(TextureDeallocParams params);
};
static inline gfx::BackendType
BackendTypeForBackendSelector(LayersBackend aLayersBackend, BackendSelector aSelector)
{
switch (aSelector) {
case BackendSelector::Canvas:
return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
case BackendSelector::Content:
return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend);
default:
MOZ_ASSERT_UNREACHABLE("Unknown backend selector");
return gfx::BackendType::NONE;
}
};
static TextureType
GetTextureType(gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
LayersBackend aLayersBackend, gfx::BackendType aBackendType,
int32_t aMaxTextureSize, TextureAllocationFlags aAllocFlags)
{
#ifdef XP_WIN
if ((aLayersBackend == LayersBackend::LAYERS_D3D11 ||
aLayersBackend == LayersBackend::LAYERS_WR) &&
(aBackendType == gfx::BackendType::DIRECT2D ||
aBackendType == gfx::BackendType::DIRECT2D1_1 ||
(!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) &&
DeviceManagerDx::Get()->GetContentDevice())) &&
aSize.width <= aMaxTextureSize &&
aSize.height <= aMaxTextureSize &&
!(aAllocFlags & ALLOC_UPDATE_FROM_SURFACE)) {
return TextureType::D3D11;
}
if (aLayersBackend != LayersBackend::LAYERS_WR &&
aFormat == SurfaceFormat::B8G8R8X8 &&
aBackendType == gfx::BackendType::CAIRO &&
NS_IsMainThread()) {
return TextureType::DIB;
}
#endif
#ifdef MOZ_X11
gfxSurfaceType type =
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
if (aLayersBackend == LayersBackend::LAYERS_BASIC &&
aBackendType == gfx::BackendType::CAIRO &&
type == gfxSurfaceType::Xlib) {
return TextureType::X11;
}
if (aLayersBackend == LayersBackend::LAYERS_OPENGL &&
type == gfxSurfaceType::Xlib &&
aFormat != SurfaceFormat::A8 &&
gl::sGLXLibrary.UseTextureFromPixmap()) {
return TextureType::X11;
}
#endif
#ifdef XP_MACOSX
if (StaticPrefs::UseIOSurfaceTextures()) {
return TextureType::MacIOSurface;
}
#endif
#ifdef MOZ_WIDGET_ANDROID
if (StaticPrefs::UseSurfaceTextureTextures()) {
return TextureType::AndroidNativeWindow;
}
#endif
return TextureType::Unknown;
}
static bool
ShouldRemoteTextureType(TextureType aTextureType, BackendSelector aSelector)
{
if (!XRE_IsContentProcess()) {
return false;
}
if (aSelector != BackendSelector::Canvas || !gfxVars::RemoteCanvasEnabled()) {
return false;
}
switch (aTextureType) {
case TextureType::D3D11:
return true;
default:
return false;
}
}
/* static */
TextureData*
TextureData::Create(TextureForwarder* aAllocator, gfx::SurfaceFormat aFormat,
gfx::IntSize aSize, LayersBackend aLayersBackend,
int32_t aMaxTextureSize, BackendSelector aSelector,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags)
{
gfx::BackendType moz2DBackend =
BackendTypeForBackendSelector(aLayersBackend, aSelector);
TextureType textureType = GetTextureType(aFormat, aSize, aLayersBackend,
moz2DBackend, aMaxTextureSize,
aAllocFlags);
if (ShouldRemoteTextureType(textureType, aSelector)) {
RefPtr<CanvasChild> canvasChild = aAllocator->GetCanvasChild();
if (canvasChild) {
return new RecordedTextureData(canvasChild.forget(), aSize, aFormat,
textureType);
}
}
switch(textureType) {
#ifdef XP_WIN
case TextureType::D3D11:
return D3D11TextureData::Create(aSize, aFormat, aAllocFlags);
case TextureType::DIB:
return DIBTextureData::Create(aSize, aFormat, aAllocator);
#endif
#ifdef MOZ_X11
case TextureType::X11:
return X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
#endif
#ifdef XP_MACOSX
case TextureType::MacIOSurface:
return MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend);
#endif
#ifdef MOZ_WIDGET_ANDROID
case TextureType::AndroidNativeWindow:
return AndroidNativeWindowTextureData::Create(aSize, aFormat);
#endif
default:
return nullptr;
}
}
/* static */
bool
TextureData::IsRemote(LayersBackend aLayersBackend, BackendSelector aSelector)
{
gfx::BackendType moz2DBackend =
BackendTypeForBackendSelector(aLayersBackend, aSelector);
TextureType textureType =
GetTextureType(gfx::SurfaceFormat::UNKNOWN, gfx::IntSize(1,1),
aLayersBackend, moz2DBackend, INT32_MAX,
TextureAllocationFlags::ALLOC_DEFAULT);
return ShouldRemoteTextureType(textureType, aSelector);
}
static void DestroyTextureData(TextureData* aTextureData,
LayersIPCChannel* aAllocator, bool aDeallocate,
bool aMainThreadOnly) {
@ -686,6 +841,17 @@ gfx::DrawTarget* TextureClient::BorrowDrawTarget() {
return mBorrowedDrawTarget;
}
already_AddRefed<gfx::SourceSurface> TextureClient::BorrowSnapshot() {
MOZ_ASSERT(mIsLocked);
RefPtr<gfx::SourceSurface> surface = mData->BorrowSnapshot();
if (!surface) {
surface = BorrowDrawTarget()->Snapshot();
}
return surface.forget();
}
bool TextureClient::BorrowMappedData(MappedTextureData& aMap) {
MOZ_ASSERT(IsValid());
@ -996,19 +1162,6 @@ bool TextureClient::InitIPDLActor(KnowsCompositor* aKnowsCompositor) {
PTextureChild* TextureClient::GetIPDLActor() { return mActor; }
static inline gfx::BackendType BackendTypeForBackendSelector(
LayersBackend aLayersBackend, BackendSelector aSelector) {
switch (aSelector) {
case BackendSelector::Canvas:
return gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
case BackendSelector::Content:
return gfxPlatform::GetPlatform()->GetContentBackendFor(aLayersBackend);
default:
MOZ_ASSERT_UNREACHABLE("Unknown backend selector");
return gfx::BackendType::NONE;
}
};
// static
already_AddRefed<TextureClient> TextureClient::CreateForDrawing(
KnowsCompositor* aAllocator, gfx::SurfaceFormat aFormat, gfx::IntSize aSize,
@ -1043,53 +1196,9 @@ already_AddRefed<TextureClient> TextureClient::CreateForDrawing(
return nullptr;
}
TextureData* data = nullptr;
#ifdef XP_WIN
if ((aLayersBackend == LayersBackend::LAYERS_D3D11 ||
aLayersBackend == LayersBackend::LAYERS_WR) &&
(moz2DBackend == gfx::BackendType::DIRECT2D ||
moz2DBackend == gfx::BackendType::DIRECT2D1_1 ||
(!!(aAllocFlags & ALLOC_FOR_OUT_OF_BAND_CONTENT) &&
DeviceManagerDx::Get()->GetContentDevice())) &&
aSize.width <= aMaxTextureSize && aSize.height <= aMaxTextureSize &&
!(aAllocFlags & ALLOC_UPDATE_FROM_SURFACE)) {
data = D3D11TextureData::Create(aSize, aFormat, aAllocFlags);
}
if (aLayersBackend != LayersBackend::LAYERS_WR && !data &&
aFormat == SurfaceFormat::B8G8R8X8 &&
moz2DBackend == gfx::BackendType::CAIRO && NS_IsMainThread()) {
data = DIBTextureData::Create(aSize, aFormat, aAllocator);
}
#endif
#ifdef MOZ_X11
gfxSurfaceType type =
gfxPlatform::GetPlatform()->ScreenReferenceSurface()->GetType();
if (!data && aLayersBackend == LayersBackend::LAYERS_BASIC &&
moz2DBackend == gfx::BackendType::CAIRO && type == gfxSurfaceType::Xlib) {
data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
}
if (!data && aLayersBackend == LayersBackend::LAYERS_OPENGL &&
type == gfxSurfaceType::Xlib && aFormat != SurfaceFormat::A8 &&
gl::sGLXLibrary.UseTextureFromPixmap()) {
data = X11TextureData::Create(aSize, aFormat, aTextureFlags, aAllocator);
}
#endif
#ifdef XP_MACOSX
if (!data && StaticPrefs::UseIOSurfaceTextures()) {
data = MacIOSurfaceTextureData::Create(aSize, aFormat, moz2DBackend);
}
#endif
#ifdef MOZ_WIDGET_ANDROID
if (!data && StaticPrefs::UseSurfaceTextureTextures()) {
data = AndroidNativeWindowTextureData::Create(aSize, aFormat);
}
#endif
TextureData* data =
TextureData::Create(aAllocator, aFormat, aSize, aLayersBackend,
aMaxTextureSize, aSelector, aTextureFlags, aAllocFlags);
if (data) {
return MakeAndAddRef<TextureClient>(data, aTextureFlags, aAllocator);

View File

@ -245,7 +245,16 @@ class TextureData {
canConcurrentlyReadLock(true) {}
};
TextureData() { MOZ_COUNT_CTOR(TextureData); }
static TextureData* Create(TextureForwarder* aAllocator,
gfx::SurfaceFormat aFormat,
gfx::IntSize aSize,
LayersBackend aLayersBackend,
int32_t aMaxTextureSize,
BackendSelector aSelector,
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags);
static bool IsRemote(LayersBackend aLayersBackend, BackendSelector aSelector);
virtual ~TextureData() { MOZ_COUNT_DTOR(TextureData); }
@ -259,6 +268,10 @@ class TextureData {
return nullptr;
}
virtual already_AddRefed<gfx::SourceSurface> BorrowSnapshot() {
return nullptr;
}
virtual bool BorrowMappedData(MappedTextureData&) { return false; }
virtual bool BorrowMappedYCbCrData(MappedYCbCrTextureData&) { return false; }
@ -300,6 +313,9 @@ class TextureData {
virtual BufferTextureData* AsBufferTextureData() { return nullptr; }
virtual GPUVideoTextureData* AsGPUVideoTextureData() { return nullptr; }
protected:
TextureData() { MOZ_COUNT_CTOR(TextureData); }
};
/**
@ -430,6 +446,8 @@ class TextureClient : public AtomicRefCountedWithFinalize<TextureClient> {
*/
gfx::DrawTarget* BorrowDrawTarget();
already_AddRefed<gfx::SourceSurface> BorrowSnapshot();
/**
* Similar to BorrowDrawTarget but provides direct access to the texture's
* bits instead of a DrawTarget.

View File

@ -0,0 +1,110 @@
/* -*- 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 "TextureRecorded.h"
#include "RecordedCanvasEventImpl.h"
namespace mozilla {
namespace layers {
class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SourceSurfaceCanvasRecording, final)
SourceSurfaceCanvasRecording(RefPtr<gfx::SourceSurface>& aRecordedSuface,
RefPtr<CanvasChild>& aCanvasChild)
: mRecordedSurface(aRecordedSuface), mCanvasChild(aCanvasChild) {}
gfx::SurfaceType GetType() const final { return mRecordedSurface->GetType(); }
gfx::IntSize GetSize() const final { return mRecordedSurface->GetSize(); }
gfx::SurfaceFormat GetFormat() const final {
return mRecordedSurface->GetFormat();
}
already_AddRefed<gfx::DataSourceSurface> GetDataSurface() final {
if (!mDataSourceSurface) {
mDataSourceSurface = mCanvasChild->GetDataSurface(mRecordedSurface);
}
return do_AddRef(mDataSourceSurface);
}
RefPtr<gfx::SourceSurface> mRecordedSurface;
RefPtr<CanvasChild> mCanvasChild;
RefPtr<gfx::DataSourceSurface> mDataSourceSurface;
};
RecordedTextureData::RecordedTextureData(
already_AddRefed<CanvasChild> aCanvasChild, gfx::IntSize aSize,
gfx::SurfaceFormat aFormat, TextureType aTextureType)
: mCanvasChild(aCanvasChild), mSize(aSize), mFormat(aFormat) {
mCanvasChild->EnsureRecorder(aTextureType);
}
RecordedTextureData::~RecordedTextureData() {}
void RecordedTextureData::FillInfo(TextureData::Info& aInfo) const {
aInfo.size = mSize;
aInfo.format = mFormat;
aInfo.supportsMoz2D = true;
aInfo.hasIntermediateBuffer = false;
aInfo.hasSynchronization = true;
}
bool RecordedTextureData::Lock(OpenMode aMode) {
mCanvasChild->EnsureBeginTransaction();
if (!mDT) {
mDT = mCanvasChild->CreateDrawTarget(mSize, mFormat);
// We lock the TextureData when we create it to get the remote DrawTarget.
mCanvasChild->OnTextureWriteLock();
return true;
}
mCanvasChild->RecordEvent(RecordedTextureLock(mDT.get(), aMode));
if (aMode & OpenMode::OPEN_WRITE) {
mCanvasChild->OnTextureWriteLock();
mSnapshot = nullptr;
}
return true;
}
void RecordedTextureData::Unlock() {
mCanvasChild->RecordEvent(RecordedTextureUnlock(mDT.get()));
}
already_AddRefed<gfx::DrawTarget> RecordedTextureData::BorrowDrawTarget() {
return do_AddRef(mDT);
}
already_AddRefed<gfx::SourceSurface> RecordedTextureData::BorrowSnapshot() {
MOZ_ASSERT(mDT);
mSnapshot = mDT->Snapshot();
return MakeAndAddRef<SourceSurfaceCanvasRecording>(mSnapshot, mCanvasChild);
}
void RecordedTextureData::Deallocate(LayersIPCChannel* aAllocator) {}
bool RecordedTextureData::Serialize(SurfaceDescriptor& aDescriptor) {
SurfaceDescriptorRecorded descriptor;
descriptor.drawTarget() = reinterpret_cast<uintptr_t>(mDT.get());
aDescriptor = std::move(descriptor);
return true;
}
void RecordedTextureData::OnForwardedToHost() {
mCanvasChild->OnTextureForwarded();
if (mSnapshot && mCanvasChild->ShouldCacheDataSurface()) {
mCanvasChild->RecordEvent(RecordedCacheDataSurface(mSnapshot.get()));
}
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,53 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_TextureRecorded_h
#define mozilla_layers_TextureRecorded_h
#include "TextureClient.h"
#include "mozilla/layers/CanvasChild.h"
namespace mozilla {
namespace layers {
class RecordedTextureData final : public TextureData {
public:
RecordedTextureData(already_AddRefed<CanvasChild> aCanvasChild,
gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
TextureType aTextureType);
void FillInfo(TextureData::Info& aInfo) const final;
bool Lock(OpenMode aMode) final;
void Unlock() final;
already_AddRefed<gfx::DrawTarget> BorrowDrawTarget() final;
already_AddRefed<gfx::SourceSurface> BorrowSnapshot() final;
void Deallocate(LayersIPCChannel* aAllocator) final;
bool Serialize(SurfaceDescriptor& aDescriptor) final;
void OnForwardedToHost() final;
private:
DISALLOW_COPY_AND_ASSIGN(RecordedTextureData);
~RecordedTextureData() override;
RefPtr<CanvasChild> mCanvasChild;
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
RefPtr<gfx::DrawTarget> mDT;
RefPtr<gfx::SourceSurface> mSnapshot;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_TextureRecorded_h

View File

@ -11,6 +11,7 @@
#include "Effects.h" // for EffectMask, Effect, etc
#include "gfxUtils.h"
#include "ImageHost.h" // for ImageHostBuffered, etc
#include "Layers.h"
#include "TiledContentHost.h" // for TiledContentHost
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor

View File

@ -10,7 +10,9 @@
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/layers/Compositor.h"
#include "mozilla/layers/ProfilerScreenshots.h"
#include "mozilla/layers/TextureHost.h"
#include "mozilla/gfx/Point.h"
#include "nsTArray.h"

View File

@ -12,6 +12,7 @@
namespace mozilla {
namespace layers {
class Compositor;
class CompositorScreenshotGrabberImpl;
/**

View File

@ -216,6 +216,16 @@ already_AddRefed<TextureHost> TextureHost::Create(
result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
break;
#endif
case SurfaceDescriptor::TSurfaceDescriptorRecorded: {
const SurfaceDescriptorRecorded& desc =
aDesc.get_SurfaceDescriptorRecorded();
UniquePtr<SurfaceDescriptor> realDesc =
aDeallocator->AsCompositorBridgeParentBase()
->LookupSurfaceDescriptorForClientDrawTarget(desc.drawTarget());
result = TextureHost::Create(*realDesc, aReadLock, aDeallocator, aBackend,
aFlags, aExternalImageId);
return result.forget();
}
default:
MOZ_CRASH("GFX: Unsupported Surface type host");
}

View File

@ -15,6 +15,7 @@
// clang-format on
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
#include "mozilla/layers/PTextureParent.h"
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
#ifdef XP_DARWIN
# include "mozilla/layers/TextureSync.h" // for TextureSync

View File

@ -11,6 +11,7 @@
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/gfx/StackArray.h"
#include "mozilla/layers/DiagnosticsD3D11.h"
#include "mozilla/layers/HelpersD3D11.h"
#include "mozilla/layers/LayerMLGPU.h"
#include "mozilla/layers/MemoryReportingMLGPU.h"
#include "mozilla/layers/ShaderDefinitionsMLGPU.h"
@ -18,6 +19,7 @@
#include "mozilla/widget/CompositorWidget.h"
#include "mozilla/widget/WinCompositorWidget.h"
#include "MLGShaders.h"
#include "LayersLogging.h"
#include "TextureD3D11.h"
#include "gfxConfig.h"
#include "mozilla/StaticPrefs.h"

View File

@ -13,11 +13,13 @@
#include "gfxContext.h"
#include "mozilla/StaticPrefs.h"
#include "gfxWindowsPlatform.h"
#include "MainThreadUtils.h"
#include "mozilla/gfx/DataSurfaceHelpers.h"
#include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/Telemetry.h"
#include "mozilla/webrender/RenderD3D11TextureHostOGL.h"
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/webrender/WebRenderAPI.h"
@ -726,7 +728,8 @@ already_AddRefed<TextureHost> CreateTextureHostD3D11(
}
already_AddRefed<DrawTarget> D3D11TextureData::BorrowDrawTarget() {
MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread());
MOZ_ASSERT(NS_IsMainThread() || PaintThread::IsOnPaintThread() ||
NS_IsInCanvasThread());
if (!mDrawTarget && mTexture) {
// This may return a null DrawTarget

View File

@ -0,0 +1,150 @@
/* -*- 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 "CanvasChild.h"
#include "MainThreadUtils.h"
#include "mozilla/gfx/DrawTargetRecording.h"
#include "mozilla/gfx/Tools.h"
#include "mozilla/layers/CanvasDrawEventRecorder.h"
#include "RecordedCanvasEventImpl.h"
namespace mozilla {
namespace layers {
static const TimeDuration kLockWaitTimeout =
TimeDuration::FromMilliseconds(100);
static const TimeDuration kGetDataTimeout = TimeDuration::FromMilliseconds(500);
CanvasChild::CanvasChild(Endpoint<PCanvasChild>&& aEndpoint) {
aEndpoint.Bind(this);
mCanSend = true;
}
CanvasChild::~CanvasChild() {}
void CanvasChild::EnsureRecorder(TextureType aTextureType) {
if (!mRecorder) {
MOZ_ASSERT(mTextureType == TextureType::Unknown);
mTextureType = aTextureType;
mRecorder = MakeAndAddRef<CanvasDrawEventRecorder>();
SharedMemoryBasic::Handle handle;
CrossProcessSemaphoreHandle readerSem;
CrossProcessSemaphoreHandle writerSem;
RefPtr<CanvasChild> thisRef = this;
mRecorder->Init(OtherPid(), &handle, &readerSem, &writerSem,
[cc = std::move(thisRef)] { cc->ResumeTranslation(); });
if (mCanSend) {
Unused << SendCreateTranslator(mTextureType, handle, readerSem,
writerSem);
}
}
MOZ_RELEASE_ASSERT(mTextureType == aTextureType,
"We only support one remote TextureType currently.");
}
void CanvasChild::ActorDestroy(ActorDestroyReason aWhy) {
mCanSend = false;
// Explicitly drop our reference to the recorder, because it holds a reference
// to us via the ResumeTranslation callback.
mRecorder = nullptr;
}
void CanvasChild::ResumeTranslation() {
if (mCanSend) {
SendResumeTranslation();
}
}
void CanvasChild::Destroy() { Close(); }
void CanvasChild::OnTextureWriteLock() {
mHasOutstandingWriteLock = true;
mLastWriteLockCheckpoint = mRecorder->CreateCheckpoint();
}
void CanvasChild::OnTextureForwarded() {
if (mHasOutstandingWriteLock) {
mRecorder->RecordEvent(RecordedCanvasFlush());
if (!mRecorder->WaitForCheckpoint(mLastWriteLockCheckpoint,
kLockWaitTimeout)) {
gfxWarning() << "Timed out waiting for last write lock to be processed.";
}
mHasOutstandingWriteLock = false;
}
}
void CanvasChild::EnsureBeginTransaction() {
if (!mIsInTransaction) {
mRecorder->RecordEvent(RecordedCanvasBeginTransaction());
mIsInTransaction = true;
}
}
void CanvasChild::EndTransaction() {
if (mIsInTransaction) {
mRecorder->RecordEvent(RecordedCanvasEndTransaction());
mIsInTransaction = false;
}
++mTransactionsSinceGetDataSurface;
}
already_AddRefed<gfx::DrawTarget> CanvasChild::CreateDrawTarget(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
MOZ_ASSERT(mRecorder);
RefPtr<gfx::DrawTarget> dummyDt = gfx::Factory::CreateDrawTarget(
gfx::BackendType::SKIA, gfx::IntSize(1, 1), aFormat);
RefPtr<gfx::DrawTarget> dt =
MakeAndAddRef<gfx::DrawTargetRecording>(mRecorder, dummyDt, aSize);
return dt.forget();
}
void CanvasChild::RecordEvent(const gfx::RecordedEvent& aEvent) {
mRecorder->RecordEvent(aEvent);
}
already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
const gfx::SourceSurface* aSurface) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aSurface);
mTransactionsSinceGetDataSurface = 0;
EnsureBeginTransaction();
mRecorder->RecordEvent(RecordedPrepareDataForSurface(aSurface));
uint32_t checkpoint = mRecorder->CreateCheckpoint();
gfx::IntSize ssSize = aSurface->GetSize();
gfx::SurfaceFormat ssFormat = aSurface->GetFormat();
size_t dataFormatWidth = ssSize.width * BytesPerPixel(ssFormat);
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateDataSourceSurfaceWithStride(ssSize, ssFormat,
dataFormatWidth);
if (!dataSurface) {
gfxWarning() << "Failed to create DataSourceSurface.";
return nullptr;
}
gfx::DataSourceSurface::ScopedMap map(dataSurface,
gfx::DataSourceSurface::READ_WRITE);
char* dest = reinterpret_cast<char*>(map.GetData());
if (!mRecorder->WaitForCheckpoint(checkpoint, kGetDataTimeout)) {
gfxWarning() << "Timed out preparing data for DataSourceSurface.";
return dataSurface.forget();
}
mRecorder->RecordEvent(RecordedGetDataForSurface(aSurface));
mRecorder->ReturnRead(dest, ssSize.height * dataFormatWidth);
return dataSurface.forget();
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,117 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_CanvasChild_h
#define mozilla_layers_CanvasChild_h
#include "mozilla/gfx/RecordedEvent.h"
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/layers/PCanvasChild.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "nsRefPtrHashtable.h"
#include "nsTArray.h"
namespace mozilla {
namespace gfx {
class SourceSurface;
}
namespace layers {
class CanvasDrawEventRecorder;
class CanvasChild final : public PCanvasChild {
public:
NS_INLINE_DECL_REFCOUNTING(CanvasChild)
explicit CanvasChild(Endpoint<PCanvasChild>&& aEndpoint);
/**
* Ensures that the DrawEventRecorder has been created.
*
* @params aTextureType the TextureType to create in the CanvasTranslator.
*/
void EnsureRecorder(TextureType aTextureType);
/**
* Send a messsage to our CanvasParent to resume translation.
*/
void ResumeTranslation();
/**
* Clean up IPDL actor.
*/
void Destroy();
/**
* Called when a RecordedTextureData is write locked.
*/
void OnTextureWriteLock();
/**
* Called when a RecordedTextureData is forwarded to the compositor.
*/
void OnTextureForwarded();
/**
* @returns true if we should be caching data surfaces in the GPU process.
*/
bool ShouldCacheDataSurface() const {
return mTransactionsSinceGetDataSurface < kCacheDataSurfaceThreshold;
}
/**
* Ensures that we have sent a begin transaction event, since the last
* end transaction.
*/
void EnsureBeginTransaction();
/**
* Send an end transaction event to indicate the end of events for this frame.
*/
void EndTransaction();
/**
* Create a DrawTargetRecording for a canvas texture.
* @param aSize size for the DrawTarget
* @param aFormat SurfaceFormat for the DrawTarget
* @returns newly created DrawTargetRecording
*/
already_AddRefed<gfx::DrawTarget> CreateDrawTarget(
gfx::IntSize aSize, gfx::SurfaceFormat aFormat);
/**
* Record an event for processing by the CanvasParent's CanvasTranslator.
* @param aEvent the event to record
*/
void RecordEvent(const gfx::RecordedEvent& aEvent);
already_AddRefed<gfx::DataSourceSurface> GetDataSurface(
const gfx::SourceSurface* aSurface);
protected:
void ActorDestroy(ActorDestroyReason aWhy) final;
private:
DISALLOW_COPY_AND_ASSIGN(CanvasChild);
~CanvasChild() final;
static const uint32_t kCacheDataSurfaceThreshold = 10;
RefPtr<CanvasDrawEventRecorder> mRecorder;
TextureType mTextureType = TextureType::Unknown;
uint32_t mLastWriteLockCheckpoint = 0;
uint32_t mTransactionsSinceGetDataSurface = kCacheDataSurfaceThreshold;
bool mCanSend = false;
bool mIsInTransaction = false;
bool mHasOutstandingWriteLock = false;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_CanvasChild_h

View File

@ -0,0 +1,159 @@
/* -*- 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 "CanvasParent.h"
#include "base/thread.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/layers/TextureClient.h"
#include "mozilla/SharedThreadPool.h"
#include "prsystem.h"
#if defined(XP_WIN)
# include "mozilla/gfx/DeviceManagerDx.h"
# include "mozilla/layers/DeviceAttachmentsD3D11.h"
#endif
bool NS_IsInCanvasThread() {
return mozilla::layers::CanvasParent::IsInCanvasThread();
}
namespace mozilla {
namespace layers {
static base::Thread* sCanvasThread = nullptr;
static StaticRefPtr<nsIThreadPool> sCanvasWorkers;
static bool sShuttingDown = false;
static MessageLoop* CanvasPlaybackLoop() {
if (!sCanvasThread && !sShuttingDown) {
MOZ_ASSERT(NS_IsInCompositorThread());
base::Thread* canvasThread = new base::Thread("Canvas");
if (canvasThread->Start()) {
sCanvasThread = canvasThread;
}
}
return sCanvasThread ? sCanvasThread->message_loop() : nullptr;
}
/* static */
already_AddRefed<CanvasParent> CanvasParent::Create(
ipc::Endpoint<PCanvasParent>&& aEndpoint) {
MOZ_ASSERT(NS_IsInCompositorThread());
if (sShuttingDown) {
return nullptr;
}
RefPtr<CanvasParent> canvasParent = new CanvasParent();
if (CanvasPlaybackLoop()->IsAcceptingTasks()) {
RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PCanvasParent>&&>(
"CanvasParent::Bind", canvasParent, &CanvasParent::Bind,
std::move(aEndpoint));
CanvasPlaybackLoop()->PostTask(runnable.forget());
}
return do_AddRef(canvasParent);
}
/* static */ bool CanvasParent::IsInCanvasThread() {
return (sCanvasWorkers && sCanvasWorkers->IsOnCurrentThread()) ||
(sCanvasThread &&
sCanvasThread->thread_id() == PlatformThread::CurrentId());
}
static already_AddRefed<nsIThreadPool> GetCanvasWorkers() {
if (!sCanvasWorkers && !sShuttingDown) {
// Given that the canvas workers are receiving instructions from content
// processes, it probably doesn't make sense to have more than half the
// number of processors doing canvas drawing. We set the lower limit to 2,
// so that even on single processor systems, if there is more than one
// window with canvas drawing, the OS can manage the load between them.
uint32_t threadLimit = std::max(2, PR_GetNumberOfProcessors() / 2);
sCanvasWorkers =
SharedThreadPool::Get(NS_LITERAL_CSTRING("CanvasWorkers"), threadLimit);
}
return do_AddRef(sCanvasWorkers);
}
/* static */ void CanvasParent::Shutdown() {
sShuttingDown = true;
if (sCanvasThread) {
sCanvasThread->Stop();
delete sCanvasThread;
sCanvasThread = nullptr;
}
if (sCanvasWorkers) {
sCanvasWorkers->Shutdown();
sCanvasWorkers = nullptr;
}
}
CanvasParent::CanvasParent() {}
CanvasParent::~CanvasParent() {}
void CanvasParent::Bind(Endpoint<PCanvasParent>&& aEndpoint) {
if (!aEndpoint.Bind(this)) {
return;
}
mSelfRef = this;
}
mozilla::ipc::IPCResult CanvasParent::RecvCreateTranslator(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem) {
mTranslator = CanvasTranslator::Create(aTextureType, aReadHandle, aReaderSem,
aWriterSem);
return RecvResumeTranslation();
}
ipc::IPCResult CanvasParent::RecvResumeTranslation() {
MOZ_ASSERT(mTranslator);
if (!mTranslator->IsValid()) {
return IPC_FAIL(this, "Canvas Translation failed.");
}
PostStartTranslationTask(nsIThread::DISPATCH_NORMAL);
return IPC_OK();
}
void CanvasParent::PostStartTranslationTask(uint32_t aDispatchFlags) {
if (sShuttingDown) {
return;
}
RefPtr<nsIThreadPool> canvasWorkers = GetCanvasWorkers();
RefPtr<Runnable> runnable = NewRunnableMethod(
"CanvasParent::StartTranslation", this, &CanvasParent::StartTranslation);
canvasWorkers->Dispatch(runnable.forget(), aDispatchFlags);
}
void CanvasParent::StartTranslation() {
if (!mTranslator->TranslateRecording()) {
PostStartTranslationTask(nsIThread::DISPATCH_AT_END);
}
}
UniquePtr<SurfaceDescriptor>
CanvasParent::LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget) {
return mTranslator->WaitForSurfaceDescriptor(
reinterpret_cast<void*>(aDrawTarget));
}
void CanvasParent::DeallocPCanvasParent() { mSelfRef = nullptr; }
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,97 @@
/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_CanvasParent_h
#define mozilla_layers_CanvasParent_h
#include "mozilla/ipc/CrossProcessSemaphore.h"
#include "mozilla/layers/CanvasTranslator.h"
#include "mozilla/layers/PCanvasParent.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace layers {
class TextureData;
class CanvasParent final : public PCanvasParent {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CanvasParent)
friend class PProtocolParent;
/**
* Create a CanvasParent and bind it to the given endpoint on the
* CanvasPlaybackLoop.
*
* @params aEndpoint the endpoint to bind to
* @returns the new CanvasParent
*/
static already_AddRefed<CanvasParent> Create(
Endpoint<PCanvasParent>&& aEndpoint);
static bool IsInCanvasThread();
/**
* Shutdown the canvas thread.
*/
static void Shutdown();
/**
* Create a canvas translator for a particular TextureType, which translates
* events from a CanvasEventRingBuffer.
*
* @param aTextureType the TextureType the translator will create
* @param aReadHandle handle to the shared memory for the
* CanvasEventRingBuffer
* @param aReaderSem reading blocked semaphore for the CanvasEventRingBuffer
* @param aWriterSem writing blocked semaphore for the CanvasEventRingBuffer
*/
ipc::IPCResult RecvCreateTranslator(
const TextureType& aTextureType,
const ipc::SharedMemoryBasic::Handle& aReadHandle,
const CrossProcessSemaphoreHandle& aReaderSem,
const CrossProcessSemaphoreHandle& aWriterSem);
/**
* Used to tell the CanvasTranslator to start translating again after it has
* stopped due to a timeout waiting for events.
*/
ipc::IPCResult RecvResumeTranslation();
void ActorDestroy(ActorDestroyReason why) final {}
void DeallocPCanvasParent();
/**
* Used by the compositor thread to get the SurfaceDescriptor associated with
* the DrawTarget from another process.
*
* @param aDrawTarget the key to find the TextureData
* @returns the SurfaceDescriptor associated with the key
*/
UniquePtr<SurfaceDescriptor> LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget);
private:
CanvasParent();
~CanvasParent() final;
DISALLOW_COPY_AND_ASSIGN(CanvasParent);
void Bind(Endpoint<PCanvasParent>&& aEndpoint);
void PostStartTranslationTask(uint32_t aDispatchFlags);
void StartTranslation();
RefPtr<CanvasParent> mSelfRef;
UniquePtr<CanvasTranslator> mTranslator;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_CanvasParent_h

View File

@ -18,6 +18,7 @@
#include "mozilla/layers/APZChild.h"
#include "mozilla/layers/IAPZCTreeManager.h"
#include "mozilla/layers/APZCTreeManagerChild.h"
#include "mozilla/layers/CanvasChild.h"
#include "mozilla/layers/LayerTransactionChild.h"
#include "mozilla/layers/PaintThread.h"
#include "mozilla/layers/PLayerTransactionChild.h"
@ -117,6 +118,10 @@ void CompositorBridgeChild::AfterDestroy() {
mActorDestroyed = true;
}
if (mCanvasChild) {
mCanvasChild->Destroy();
}
if (sCompositorBridge == this) {
sCompositorBridge = nullptr;
}
@ -245,6 +250,18 @@ void CompositorBridgeChild::InitForContent(uint32_t aNamespace) {
mCanSend = true;
mIdNamespace = aNamespace;
if (gfx::gfxVars::RemoteCanvasEnabled()) {
ipc::Endpoint<PCanvasParent> parentEndpoint;
ipc::Endpoint<PCanvasChild> childEndpoint;
nsresult rv = PCanvas::CreateEndpoints(OtherPid(), base::GetCurrentProcId(),
&parentEndpoint, &childEndpoint);
if (NS_SUCCEEDED(rv)) {
Unused << SendInitPCanvasParent(std::move(parentEndpoint));
mCanvasChild = new CanvasChild(std::move(childEndpoint));
}
}
sCompositorBridge = this;
}
@ -918,6 +935,16 @@ PTextureChild* CompositorBridgeChild::CreateTexture(
LayersId{0} /* FIXME? */, aSerial, aExternalImageId);
}
already_AddRefed<CanvasChild> CompositorBridgeChild::GetCanvasChild() {
return do_AddRef(mCanvasChild);
}
void CompositorBridgeChild::EndCanvasTransaction() {
if (mCanvasChild) {
mCanvasChild->EndTransaction();
}
}
bool CompositorBridgeChild::AllocUnsafeShmem(
size_t aSize, ipc::SharedMemory::SharedMemoryType aType,
ipc::Shmem* aShmem) {

View File

@ -41,6 +41,7 @@ using mozilla::dom::BrowserChild;
class IAPZCTreeManager;
class APZCTreeManagerChild;
class CanvasChild;
class ClientLayerManager;
class CompositorBridgeParent;
class CompositorManagerChild;
@ -122,6 +123,10 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
wr::MaybeExternalImageId& aExternalImageId,
nsIEventTarget* aTarget) override;
already_AddRefed<CanvasChild> GetCanvasChild() final;
void EndCanvasTransaction();
/**
* Request that the parent tell us when graphics are ready on GPU.
* When we get that message, we bounce it to the BrowserParent via
@ -391,6 +396,8 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
uintptr_t mSlowFlushCount;
uintptr_t mTotalFlushCount;
RefPtr<CanvasChild> mCanvasChild;
};
} // namespace layers

View File

@ -1871,7 +1871,7 @@ Maybe<TimeStamp> CompositorBridgeParent::GetTestingTimeStamp() const {
return mTestTime;
}
static void EraseLayerState(LayersId aId) {
void EraseLayerState(LayersId aId) {
RefPtr<APZUpdater> apz;
{ // scope lock
@ -2189,8 +2189,8 @@ void CompositorBridgeParent::InvalidateRemoteLayers() {
});
}
static void UpdateIndirectTree(LayersId aId, Layer* aRoot,
const TargetConfig& aTargetConfig) {
void UpdateIndirectTree(LayersId aId, Layer* aRoot,
const TargetConfig& aTargetConfig) {
MonitorAutoLock lock(*sIndirectLayerTreesLock);
sIndirectLayerTrees[aId].mRoot = aRoot;
sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig;
@ -2283,6 +2283,11 @@ bool CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) {
return TextureHost::DestroyIPDLActor(actor);
}
mozilla::ipc::IPCResult CompositorBridgeParent::RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) {
MOZ_CRASH("PCanvasParent shouldn't be created via CompositorBridgeParent.");
}
bool CompositorBridgeParent::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}

View File

@ -85,6 +85,7 @@ class PAPZParent;
class ContentCompositorBridgeParent;
class CompositorThreadHolder;
class InProcessCompositorSession;
class TextureData;
class WebRenderBridgeParent;
struct ScopedLayerTreeRegistration {
@ -188,6 +189,11 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
virtual bool IsRemote() const { return false; }
virtual UniquePtr<SurfaceDescriptor>
LookupSurfaceDescriptorForClientDrawTarget(const uintptr_t aDrawTarget) {
MOZ_CRASH("Should only be called on ContentCompositorBridgeParent.");
}
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) {
MOZ_CRASH();
@ -265,6 +271,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
const uint32_t& startIndex, nsTArray<float>* intervals) = 0;
virtual mozilla::ipc::IPCResult RecvCheckContentOnlyTDR(
const uint32_t& sequenceNum, bool* isContentOnlyTDR) = 0;
virtual mozilla::ipc::IPCResult RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) = 0;
bool mCanSend;
@ -388,6 +396,9 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
const wr::MaybeExternalImageId& aExternalImageId) override;
bool DeallocPTextureParent(PTextureParent* actor) override;
mozilla::ipc::IPCResult RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) final;
bool IsSameProcess() const override;
void NotifyWebRenderContextPurge();

View File

@ -7,6 +7,7 @@
#include "MainThreadUtils.h"
#include "nsThreadUtils.h"
#include "CompositorBridgeParent.h"
#include "mozilla/layers/CanvasParent.h"
#include "mozilla/layers/CompositorManagerParent.h"
#include "mozilla/layers/ImageBridgeParent.h"
#include "mozilla/media/MediaSystemResourceService.h"
@ -127,6 +128,7 @@ void CompositorThreadHolder::Shutdown() {
gfx::ReleaseVRManagerParentSingleton();
MediaSystemResourceService::Shutdown();
CompositorManagerParent::Shutdown();
CanvasParent::Shutdown();
sCompositorThreadHolder = nullptr;

View File

@ -13,6 +13,7 @@
#include "base/message_loop.h" // for MessageLoop
#include "base/task.h" // for CancelableTask, etc
#include "base/thread.h" // for Thread
#include "gfxUtils.h"
#ifdef XP_WIN
# include "mozilla/gfx/DeviceManagerDx.h" // for DeviceManagerDx
#endif
@ -21,6 +22,7 @@
#include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent
#include "mozilla/layers/APZUpdater.h" // for APZUpdater
#include "mozilla/layers/AsyncCompositionManager.h"
#include "mozilla/layers/CanvasParent.h"
#include "mozilla/layers/CompositorOptions.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/LayerManagerComposite.h"
@ -35,7 +37,10 @@
#include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop
#include "mozilla/Unused.h"
#include "mozilla/StaticPtr.h"
#include "gfxUtils.h"
#include "mozilla/Telemetry.h"
#ifdef MOZ_GECKO_PROFILER
# include "ProfilerMarkerPayload.h"
#endif
using namespace std;
@ -306,12 +311,12 @@ mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvCheckContentOnlyTDR(
const uint32_t& sequenceNum, bool* isContentOnlyTDR) {
*isContentOnlyTDR = false;
#ifdef XP_WIN
ContentDeviceData compositor;
gfx::ContentDeviceData compositor;
DeviceManagerDx* dm = DeviceManagerDx::Get();
gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
// Check that the D3D11 device sequence numbers match.
D3D11DeviceStatus status;
gfx::D3D11DeviceStatus status;
dm->ExportDeviceInfo(&status);
if (sequenceNum == status.sequenceNumber() && !dm->HasDeviceReset()) {
@ -610,6 +615,22 @@ bool ContentCompositorBridgeParent::DeallocPTextureParent(
return TextureHost::DestroyIPDLActor(actor);
}
mozilla::ipc::IPCResult ContentCompositorBridgeParent::RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) {
MOZ_RELEASE_ASSERT(!mCanvasParent,
"Canvas Parent should only be created once per "
"CrossProcessCompositorBridgeParent.");
mCanvasParent = CanvasParent::Create(std::move(aEndpoint));
return IPC_OK();
}
UniquePtr<SurfaceDescriptor>
ContentCompositorBridgeParent::LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget) {
return mCanvasParent->LookupSurfaceDescriptorForClientDrawTarget(aDrawTarget);
}
bool ContentCompositorBridgeParent::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}

View File

@ -9,10 +9,12 @@
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/UniquePtr.h"
namespace mozilla {
namespace layers {
class CanvasParent;
class CompositorOptions;
/**
@ -153,6 +155,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
bool DeallocPTextureParent(PTextureParent* actor) override;
mozilla::ipc::IPCResult RecvInitPCanvasParent(
Endpoint<PCanvasParent>&& aEndpoint) final;
bool IsSameProcess() const override;
PCompositorWidgetParent* AllocPCompositorWidgetParent(
@ -188,6 +193,9 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
bool IsRemote() const override { return true; }
UniquePtr<SurfaceDescriptor> LookupSurfaceDescriptorForClientDrawTarget(
const uintptr_t aDrawTarget) final;
private:
// Private destructor, to discourage deletion outside of Release():
virtual ~ContentCompositorBridgeParent();
@ -203,6 +211,8 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
// transaction is received
bool mNotifyAfterRemotePaint;
bool mDestroyCalled;
RefPtr<CanvasParent> mCanvasParent;
};
} // namespace layers

View File

@ -20,6 +20,7 @@
#include "mozilla/ReentrantMonitor.h" // for ReentrantMonitor, etc
#include "mozilla/ipc/MessageChannel.h" // for MessageChannel, etc
#include "mozilla/ipc/Transport.h" // for Transport
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/AsyncCanvasRenderer.h"
#include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager

View File

@ -82,6 +82,13 @@ struct ParamTraits<mozilla::layers::LayersBackend>
mozilla::layers::LayersBackend::LAYERS_NONE,
mozilla::layers::LayersBackend::LAYERS_LAST> {};
template <>
struct ParamTraits<mozilla::layers::TextureType>
: public ContiguousEnumSerializer<
mozilla::layers::TextureType,
mozilla::layers::TextureType::Unknown,
mozilla::layers::TextureType::Last> {};
template <>
struct ParamTraits<mozilla::layers::ScaleMode>
: public ContiguousEnumSerializerInclusive<

View File

@ -133,6 +133,10 @@ struct SurfaceDescriptorShared
Handle handle;
};
struct SurfaceDescriptorRecorded {
uintptr_t drawTarget;
};
union SurfaceDescriptor {
SurfaceDescriptorBuffer;
SurfaceDescriptorDIB;
@ -145,6 +149,7 @@ union SurfaceDescriptor {
SurfaceDescriptorMacIOSurface;
SurfaceDescriptorSharedGLTexture;
SurfaceDescriptorGPUVideo;
SurfaceDescriptorRecorded;
null_t;
};

View File

@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et : */
/* 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/. */
using mozilla::CrossProcessSemaphoreHandle from "mozilla/ipc/CrossProcessSemaphore.h";
using mozilla::layers::TextureType from "mozilla/layers/LayersTypes.h";
using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
namespace mozilla {
namespace layers {
/**
* PCanvas is the IPDL for recorded Canvas drawing.
*/
sync protocol PCanvas {
parent:
/**
* Create a CanvasTranslator for a particular TextureType, which translates
* events from a CanvasEventRingBuffer. aReadHandle is the shared memory
* handle for the ring buffer. aReaderSem and aWriterSem are handles for the
* semaphores to handle waiting on either side.
*/
async CreateTranslator(TextureType aTextureType, Handle aReadHandle,
CrossProcessSemaphoreHandle aReaderSem,
CrossProcessSemaphoreHandle aWriterSem);
/**
* Used to tell the CanvasTranslator to start translating again after it has
* stopped due to a timeout waiting for events.
*/
async ResumeTranslation();
};
} // layers
} // mozilla

View File

@ -11,6 +11,7 @@ include PlatformWidgetTypes;
include protocol PAPZ;
include protocol PAPZCTreeManager;
include protocol PBrowser;
include protocol PCanvas;
include protocol PCompositorManager;
include protocol PCompositorWidget;
include protocol PLayerTransaction;
@ -255,6 +256,8 @@ parent:
async PTexture(SurfaceDescriptor aSharedData, ReadLockDescriptor aReadLock, LayersBackend aBackend, TextureFlags aTextureFlags, LayersId id, uint64_t aSerial, MaybeExternalImageId aExternalImageId);
async InitPCanvasParent(Endpoint<PCanvasParent> aEndpoint);
sync SyncWithCompositor();
// The pipelineId is the same as the layersId

View File

@ -19,6 +19,7 @@ namespace ipc {
class IShmemAllocator;
}
namespace layers {
class CanvasChild;
/**
* An abstract interface for classes that implement the autogenerated
@ -78,6 +79,11 @@ class TextureForwarder : public LayersIPCChannel {
LayersBackend aLayersBackend, TextureFlags aFlags, uint64_t aSerial,
wr::MaybeExternalImageId& aExternalImageId,
nsIEventTarget* aTarget = nullptr) = 0;
/**
* Returns the CanvasChild for this TextureForwarder.
*/
virtual already_AddRefed<CanvasChild> GetCanvasChild() { return nullptr; };
};
} // namespace layers

View File

@ -7,11 +7,13 @@
#if defined(MOZ_WIDGET_ANDROID)
# include "apz/src/APZCTreeManager.h"
# include "mozilla/layers/AsyncCompositionManager.h"
#endif
#include "mozilla/layers/Compositor.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/UiCompositorControllerMessageTypes.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/Move.h"
#include "mozilla/Unused.h"

View File

@ -130,7 +130,9 @@ EXPORTS.mozilla.layers += [
'basic/TextureHostBasic.h',
'BSPTree.h',
'BufferTexture.h',
'CanvasDrawEventRecorder.h',
'CanvasRenderer.h',
'CanvasTranslator.h',
'client/CanvasClient.h',
'client/CompositableClient.h',
'client/ContentClient.h',
@ -142,6 +144,7 @@ EXPORTS.mozilla.layers += [
'client/TextureClientPool.h',
'client/TextureClientRecycleAllocator.h',
'client/TextureClientSharedSurface.h',
'client/TextureRecorded.h',
'client/TiledContentClient.h',
'composite/AsyncCompositionManager.h',
'composite/CanvasLayerComposite.h',
@ -176,6 +179,8 @@ EXPORTS.mozilla.layers += [
'ipc/APZCTreeManagerParent.h',
'ipc/APZInputBridgeChild.h',
'ipc/APZInputBridgeParent.h',
'ipc/CanvasChild.h',
'ipc/CanvasParent.h',
'ipc/CompositableForwarder.h',
'ipc/CompositableTransactionParent.h',
'ipc/CompositorBridgeChild.h',
@ -371,7 +376,9 @@ UNIFIED_SOURCES += [
'basic/TextureHostBasic.cpp',
'BSPTree.cpp',
'BufferTexture.cpp',
'CanvasDrawEventRecorder.cpp',
'CanvasRenderer.cpp',
'CanvasTranslator.cpp',
'client/CanvasClient.cpp',
'client/ClientCanvasLayer.cpp',
'client/ClientCanvasRenderer.cpp',
@ -391,6 +398,7 @@ UNIFIED_SOURCES += [
'client/TextureClientPool.cpp',
'client/TextureClientRecycleAllocator.cpp',
'client/TextureClientSharedSurface.cpp',
'client/TextureRecorded.cpp',
'client/TiledContentClient.cpp',
'composite/AsyncCompositionManager.cpp',
'composite/CanvasLayerComposite.cpp',
@ -424,6 +432,8 @@ UNIFIED_SOURCES += [
'ipc/APZCTreeManagerParent.cpp',
'ipc/APZInputBridgeChild.cpp',
'ipc/APZInputBridgeParent.cpp',
'ipc/CanvasChild.cpp',
'ipc/CanvasParent.cpp',
'ipc/CompositableTransactionParent.cpp',
'ipc/CompositorBench.cpp',
'ipc/CompositorBridgeChild.cpp',
@ -540,6 +550,7 @@ IPDL_SOURCES += [
'ipc/PAPZ.ipdl',
'ipc/PAPZCTreeManager.ipdl',
'ipc/PAPZInputBridge.ipdl',
'ipc/PCanvas.ipdl',
'ipc/PCompositorBridge.ipdl',
'ipc/PCompositorManager.ipdl',
'ipc/PImageBridge.ipdl',

View File

@ -7,6 +7,7 @@
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h"
namespace mozilla {
namespace layers {

View File

@ -12,6 +12,7 @@
#include "CompositableHost.h" // for CompositableHost, ImageCompositeNotificationInfo
#include "GLContextProvider.h"
#include "Layers.h"
#include "mozilla/layers/CompositableTransactionParent.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/CompositorVsyncSchedulerOwner.h"

View File

@ -12,6 +12,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/AnimationHelper.h"
#include "mozilla/layers/ClipManager.h"
#include "mozilla/layers/ImageClient.h"
#include "mozilla/layers/RenderRootStateManager.h"

View File

@ -245,6 +245,8 @@ bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
}
}
GetCompositorBridgeChild()->EndCanvasTransaction();
AutoTArray<RenderRootUpdates, wr::kRenderRootCount> renderRootUpdates;
for (auto& stateManager : mStateManagers) {
auto renderRoot = stateManager.GetRenderRoot();
@ -428,6 +430,8 @@ void WebRenderLayerManager::EndTransactionWithoutLayer(
}
}
GetCompositorBridgeChild()->EndCanvasTransaction();
{
AUTO_PROFILER_TRACING("Paint", "ForwardDPTransaction", GRAPHICS);
InfallibleTArray<RenderRootDisplayListData> renderRootDLs;
@ -734,14 +738,13 @@ WebRenderLayerManager::CreatePersistentBufferProvider(
// initialized with WebRender to reduce memory usage.
gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
if (StaticPrefs::PersistentBufferProviderSharedEnabled()) {
RefPtr<PersistentBufferProvider> provider =
PersistentBufferProviderShared::Create(aSize, aFormat,
AsKnowsCompositor());
if (provider) {
return provider.forget();
}
RefPtr<PersistentBufferProvider> provider =
PersistentBufferProviderShared::Create(aSize, aFormat,
AsKnowsCompositor());
if (provider) {
return provider.forget();
}
return LayerManager::CreatePersistentBufferProvider(aSize, aFormat);
}

View File

@ -267,6 +267,44 @@ bool DeviceManagerDx::CreateVRDevice() {
return true;
}
bool DeviceManagerDx::CreateCanvasDevice() {
MOZ_ASSERT(ProcessOwnsCompositor());
if (mCanvasDevice) {
return true;
}
if (!LoadD3D11()) {
return false;
}
RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
if (!adapter) {
NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
return false;
}
UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
HRESULT hr;
if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr,
mCanvasDevice)) {
gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
return false;
}
if (FAILED(hr) || !mCanvasDevice) {
NS_WARNING("Failed to acquire a D3D11 device for Canvas");
return false;
}
if (XRE_IsGPUProcess()) {
Factory::SetDirect3D11Device(mCanvasDevice);
}
return true;
}
void DeviceManagerDx::CreateDirectCompositionDevice() {
if (!gfxVars::UseWebRenderDCompWin()) {
return;
@ -866,6 +904,7 @@ void DeviceManagerDx::ResetDevices() {
mMLGDevice = nullptr;
mCompositorDevice = nullptr;
mContentDevice = nullptr;
mCanvasDevice = nullptr;
mImageDevice = nullptr;
mDeviceStatus = Nothing();
mDeviceResetReason = Nothing();
@ -888,6 +927,7 @@ bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
bool createCompositorDevice = !!mCompositorDevice;
bool createContentDevice = !!mContentDevice;
bool createCanvasDevice = !!mCanvasDevice;
ResetDevices();
@ -898,6 +938,9 @@ bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
if (createContentDevice) {
CreateContentDevices();
}
if (createCanvasDevice) {
CreateCanvasDevice();
}
return true;
}
@ -986,7 +1029,8 @@ bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) {
mDeviceLock.AssertCurrentThreadOwns();
if (DidDeviceReset(mCompositorDevice, aOutReason) ||
DidDeviceReset(mContentDevice, aOutReason)) {
DidDeviceReset(mContentDevice, aOutReason) ||
DidDeviceReset(mCanvasDevice, aOutReason)) {
return true;
}
@ -1069,6 +1113,14 @@ RefPtr<ID3D11Device> DeviceManagerDx::GetVRDevice() {
return mVRDevice;
}
RefPtr<ID3D11Device> DeviceManagerDx::GetCanvasDevice() {
MutexAutoLock lock(mDeviceLock);
if (!mCanvasDevice) {
CreateCanvasDevice();
}
return mCanvasDevice;
}
RefPtr<IDCompositionDevice> DeviceManagerDx::GetDirectCompositionDevice() {
MutexAutoLock lock(mDeviceLock);
return mDirectCompositionDevice;

View File

@ -19,6 +19,7 @@
#include <windows.h>
#include <objbase.h>
#include <d3d11.h>
#include <dxgi.h>
#include <dxgi1_6.h>
@ -56,6 +57,7 @@ class DeviceManagerDx final {
RefPtr<ID3D11Device> GetCompositorDevice();
RefPtr<ID3D11Device> GetContentDevice();
RefPtr<ID3D11Device> GetCanvasDevice();
RefPtr<ID3D11Device> GetImageDevice();
RefPtr<IDCompositionDevice> GetDirectCompositionDevice();
RefPtr<ID3D11Device> GetVRDevice();
@ -88,6 +90,7 @@ class DeviceManagerDx final {
bool CreateCompositorDevices();
void CreateContentDevices();
void CreateDirectCompositionDevice();
bool CreateCanvasDevice();
void GetCompositorDevices(
RefPtr<ID3D11Device>* aOutDevice,
@ -165,6 +168,7 @@ class DeviceManagerDx final {
RefPtr<IDXGIAdapter1> mAdapter;
RefPtr<ID3D11Device> mCompositorDevice;
RefPtr<ID3D11Device> mContentDevice;
RefPtr<ID3D11Device> mCanvasDevice;
RefPtr<ID3D11Device> mImageDevice;
RefPtr<ID3D11Device> mVRDevice;
RefPtr<ID3D11Device> mDecoderDevice;

View File

@ -2423,6 +2423,9 @@ void gfxPlatform::InitAcceleration() {
VideoDecodingFailedChangedCallback,
"media.hardware-video-decoding.failed");
InitGPUProcessPrefs();
gfxVars::SetRemoteCanvasEnabled(StaticPrefs::CanvasRemote() &&
gfxConfig::IsEnabled(Feature::GPU_PROCESS));
}
}
@ -3394,6 +3397,8 @@ void gfxPlatform::NotifyGPUProcessDisabled() {
NS_LITERAL_CSTRING("FEATURE_FAILURE_GPU_PROCESS_DISABLED"));
gfxVars::SetUseWebRender(false);
}
gfxVars::SetRemoteCanvasEnabled(false);
}
void gfxPlatform::FetchAndImportContentDeviceData() {

View File

@ -18,6 +18,7 @@
#include "mozilla/layers/SyncObject.h"
#include "mozilla/layers/WebRenderCompositionRecorder.h"
#include "mozilla/Range.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "GLTypes.h"

View File

@ -3750,7 +3750,7 @@ nsDocumentViewer::GetCurrentPrintSettings(
NS_IMETHODIMP
nsDocumentViewer::Cancel() {
NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
return mPrintJob->Cancelled();
return mPrintJob->Cancel();
}
NS_IMETHODIMP

View File

@ -7435,7 +7435,7 @@ nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas,
RefPtr<DrawTarget>& aTarget) {
SurfaceFromElementResult result;
nsIntSize size = aOffscreenCanvas->GetWidthHeight();
IntSize size = aOffscreenCanvas->GetWidthHeight();
result.mSourceSurface =
aOffscreenCanvas->GetSurfaceSnapshot(&result.mAlphaType);
@ -7447,10 +7447,12 @@ nsLayoutUtils::SurfaceFromOffscreenCanvas(OffscreenCanvas* aOffscreenCanvas,
RefPtr<DrawTarget> ref =
aTarget ? aTarget
: gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(
IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
if (dt) {
result.mSourceSurface = dt->Snapshot();
if (ref->CanCreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8)) {
RefPtr<DrawTarget> dt =
ref->CreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8);
if (dt) {
result.mSourceSurface = dt->Snapshot();
}
}
} else if (aTarget) {
RefPtr<SourceSurface> opt =
@ -7618,10 +7620,12 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
RefPtr<DrawTarget> ref =
aTarget ? aTarget
: gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<DrawTarget> dt = ref->CreateSimilarDrawTarget(
IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8);
if (dt) {
result.mSourceSurface = dt->Snapshot();
if (ref->CanCreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8)) {
RefPtr<DrawTarget> dt =
ref->CreateSimilarDrawTarget(size, SurfaceFormat::B8G8R8A8);
if (dt) {
result.mSourceSurface = dt->Snapshot();
}
}
} else if (aTarget) {
RefPtr<SourceSurface> opt =

View File

@ -11,8 +11,6 @@ namespace layout {
void DrawEventRecorderPRFileDesc::RecordEvent(
const gfx::RecordedEvent& aEvent) {
WriteElement(mOutputStream, aEvent.GetType());
aEvent.RecordToStream(mOutputStream);
Flush();

View File

@ -105,7 +105,7 @@ class PRFileDescStream final : public mozilla::gfx::EventStream {
mGood = res >= 0 && (static_cast<size_t>(res) == aSize);
}
bool good() { return mGood; }
bool good() final { return mGood; }
private:
size_t AvailableBufferSpace() { return kBufferSize - mBufferPos; }

View File

@ -46,15 +46,18 @@ bool PrintTranslator::TranslateRecording(PRFileDescStream& aRecording) {
int32_t eventType;
ReadElement(aRecording, eventType);
while (aRecording.good()) {
UniquePtr<RecordedEvent> recordedEvent(RecordedEvent::LoadEventFromStream(
aRecording, static_cast<RecordedEvent::EventType>(eventType)));
bool success = RecordedEvent::DoWithEventFromStream(
aRecording, static_cast<RecordedEvent::EventType>(eventType),
[&](RecordedEvent* recordedEvent) -> bool {
// Make sure that the whole event was read from the stream.
if (!aRecording.good()) {
return false;
}
// Make sure that the whole event was read from the stream successfully.
if (!aRecording.good() || !recordedEvent) {
return false;
}
return recordedEvent->PlayEvent(this);
});
if (!recordedEvent->PlayEvent(this)) {
if (!success) {
return false;
}

View File

@ -451,16 +451,12 @@ static void MapContentToWebShells(const UniquePtr<nsPrintObject>& aRootPO,
}
/**
* Recursively builds the static clone document tree.
* XXXjwatt - uh, CreateStaticClone already takes care of recursively creating
* subdocs (in-process, at least). nsPrintObject::Init creating a static clone
* for subdocs is...broken, surely.
* The outparam aDocList returns a (depth first) flat list of all the
* nsPrintObjects created.
*/
static void BuildDocTree(BrowsingContext* aBrowsingContext,
const UniquePtr<nsPrintObject>& aPO,
nsTArray<nsPrintObject*>* aDocList) {
static void BuildNestedPrintObjects(BrowsingContext* aBrowsingContext,
const UniquePtr<nsPrintObject>& aPO,
nsTArray<nsPrintObject*>* aDocList) {
MOZ_ASSERT(aBrowsingContext, "Pointer is null!");
MOZ_ASSERT(aDocList, "Pointer is null!");
MOZ_ASSERT(aPO, "Pointer is null!");
@ -472,15 +468,14 @@ static void BuildDocTree(BrowsingContext* aBrowsingContext,
continue;
}
auto childPO = MakeUnique<nsPrintObject>();
childPO->mParent = aPO.get();
nsresult rv = childPO->Init(childBC->GetDocShell(), window->GetExtantDoc(),
aPO->mPrintPreview);
nsresult rv = childPO->InitAsNestedObject(
childBC->GetDocShell(), window->GetExtantDoc(), aPO.get());
if (NS_FAILED(rv)) {
MOZ_ASSERT_UNREACHABLE("Init failed?");
}
aPO->mKids.AppendElement(std::move(childPO));
aDocList->AppendElement(aPO->mKids.LastElement().get());
BuildDocTree(childBC, aPO->mKids.LastElement(), aDocList);
BuildNestedPrintObjects(childBC, aPO->mKids.LastElement(), aDocList);
}
}
@ -645,7 +640,7 @@ bool nsPrintJob::CheckBeforeDestroy() {
}
//-------------------------------------------------------
nsresult nsPrintJob::Cancelled() {
nsresult nsPrintJob::Cancel() {
if (mPrt && mPrt->mPrintSettings) {
return mPrt->mPrintSettings->SetIsCancelled(true);
}
@ -840,7 +835,8 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
nsAutoScriptBlocker scriptBlocker;
printData->mPrintObject = MakeUnique<nsPrintObject>();
rv = printData->mPrintObject->Init(docShell, aSourceDoc, aIsPrintPreview);
rv = printData->mPrintObject->InitAsRootObject(docShell, aSourceDoc,
aIsPrintPreview);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(
@ -851,10 +847,9 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
printData->mPrintObject->mFrameType =
printData->mIsParentAFrameSet ? eFrameSet : eDoc;
// Builds the static clone doc tree and the "tree" of PrintObjects
BuildDocTree(nsDocShell::Cast(printData->mPrintObject->mDocShell)
->GetBrowsingContext(),
printData->mPrintObject, &printData->mPrintDocList);
BuildNestedPrintObjects(nsDocShell::Cast(printData->mPrintObject->mDocShell)
->GetBrowsingContext(),
printData->mPrintObject, &printData->mPrintDocList);
}
// The nsAutoScriptBlocker above will now have been destroyed, which may

View File

@ -209,7 +209,7 @@ class nsPrintJob final : public nsIObserver,
eDocTitleDefault aDefType);
bool CheckBeforeDestroy();
nsresult Cancelled();
nsresult Cancel();
mozilla::PresShell* GetPrintPreviewPresShell() {
return mPrtPreview->mPrintObject->mPresShell;

View File

@ -38,7 +38,6 @@ nsPrintObject::nsPrintObject()
mDontPrint(true),
mPrintAsIs(false),
mInvisible(false),
mPrintPreview(false),
mDidCreateDocShell(false),
mShrinkRatio(1.0),
mZoomRatio(1.0) {
@ -60,16 +59,16 @@ nsPrintObject::~nsPrintObject() {
}
//------------------------------------------------------------------
nsresult nsPrintObject::Init(nsIDocShell* aDocShell, Document* aDoc,
bool aPrintPreview) {
nsresult nsPrintObject::InitAsRootObject(nsIDocShell* aDocShell, Document* aDoc,
bool aForPrintPreview) {
NS_ENSURE_STATE(aDocShell);
NS_ENSURE_STATE(aDoc);
mPrintPreview = aPrintPreview;
if (mPrintPreview || mParent) {
if (aForPrintPreview) {
mDocShell = aDocShell;
} else {
mTreeOwner = do_GetInterface(aDocShell);
// When doing an actual print, we create a BrowsingContext/nsDocShell that
// is detached from any browser window or tab.
// Create a new BrowsingContext to create our DocShell in.
RefPtr<BrowsingContext> bc = BrowsingContext::Create(
@ -85,31 +84,38 @@ nsresult nsPrintObject::Init(nsIDocShell* aDocShell, Document* aDoc,
mDidCreateDocShell = true;
MOZ_ASSERT(mDocShell->ItemType() == aDocShell->ItemType());
mTreeOwner = do_GetInterface(aDocShell);
mDocShell->SetTreeOwner(mTreeOwner);
}
NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
// Keep the document related to this docshell alive
nsCOMPtr<Document> dummy = do_GetInterface(mDocShell);
mozilla::Unused << dummy;
nsCOMPtr<nsIContentViewer> viewer;
mDocShell->GetContentViewer(getter_AddRefs(viewer));
NS_ENSURE_STATE(viewer);
if (mParent) {
nsCOMPtr<nsPIDOMWindowOuter> window = aDoc->GetWindow();
if (window) {
mContent = window->GetFrameElementInternal();
}
mDocument = aDoc;
return NS_OK;
// Make sure nsDocShell::EnsureContentViewer() is called:
mozilla::Unused << nsDocShell::Cast(mDocShell)->GetDocument();
}
mDocument = aDoc->CreateStaticClone(mDocShell);
NS_ENSURE_STATE(mDocument);
nsCOMPtr<nsIContentViewer> viewer;
mDocShell->GetContentViewer(getter_AddRefs(viewer));
NS_ENSURE_STATE(viewer);
viewer->SetDocument(mDocument);
return NS_OK;
}
nsresult nsPrintObject::InitAsNestedObject(nsIDocShell* aDocShell,
Document* aDoc,
nsPrintObject* aParent) {
NS_ENSURE_STATE(aDocShell);
NS_ENSURE_STATE(aDoc);
mParent = aParent;
mDocShell = aDocShell;
mDocument = aDoc;
nsCOMPtr<nsPIDOMWindowOuter> window = aDoc->GetWindow();
mContent = window->GetFrameElementInternal();
return NS_OK;
}

View File

@ -33,9 +33,12 @@ class nsPrintObject {
nsPrintObject();
~nsPrintObject(); // non-virtual
// Methods
nsresult Init(nsIDocShell* aDocShell, mozilla::dom::Document* aDoc,
bool aPrintPreview);
nsresult InitAsRootObject(nsIDocShell* aDocShell,
mozilla::dom::Document* aDoc,
bool aForPrintPreview);
nsresult InitAsNestedObject(nsIDocShell* aDocShell,
mozilla::dom::Document* aDoc,
nsPrintObject* aParent);
bool IsPrintable() { return !mDontPrint; }
void DestroyPresentation();
@ -58,7 +61,6 @@ class nsPrintObject {
bool mDontPrint;
bool mPrintAsIs;
bool mInvisible; // Indicates PO is set to not visible by CSS
bool mPrintPreview;
bool mDidCreateDocShell;
float mShrinkRatio;
float mZoomRatio;

View File

@ -2525,6 +2525,13 @@ VARCACHE_PREF(
RelaxedAtomicInt32, 0x7fff
)
VARCACHE_PREF(
Live,
"gfx.canvas.remote",
CanvasRemote,
RelaxedAtomicBool, false
)
VARCACHE_PREF(
Live,
"gfx.color_management.enablev4",

View File

@ -844,6 +844,7 @@ pref("gfx.font_ahem_antialias_none", false);
// e.g., pref("gfx.canvas.azure.backends", "direct2d,skia,cairo");
pref("gfx.canvas.azure.backends", "direct2d1.1,skia,cairo");
pref("gfx.content.azure.backends", "direct2d1.1,skia,cairo");
pref("gfx.canvas.remote", false);
#else
#ifdef XP_MACOSX
pref("gfx.content.azure.backends", "skia");

View File

@ -8396,15 +8396,6 @@
"n_buckets": 15,
"description": "Time (ms) it takes to figure out extension last modified time"
},
"TELEMETRY_MEMORY_REPORTER_MS": {
"record_in_processes": ["main", "content"],
"alert_emails": ["memshrink-telemetry-alerts@mozilla.com"],
"expires_in_version": "never",
"kind": "exponential",
"high": 5000,
"n_buckets": 10,
"description": "Time (ms) it takes to run memory reporters when sending a telemetry ping"
},
"SSL_SUCCESFUL_CERT_VALIDATION_TIME_MOZILLAPKIX" : {
"record_in_processes": ["main", "content"],
"alert_emails": ["seceng-telemetry@mozilla.com"],

View File

@ -1053,7 +1053,6 @@
"TELEMETRY_DISCARDED_PENDING_PINGS_SIZE_MB",
"TELEMETRY_DISCARDED_SEND_PINGS_SIZE_MB",
"TELEMETRY_INVALID_PING_TYPE_SUBMITTED",
"TELEMETRY_MEMORY_REPORTER_MS",
"TELEMETRY_PENDING_CHECKING_OVER_QUOTA_MS",
"TELEMETRY_PENDING_EVICTING_OVER_QUOTA_MS",
"TELEMETRY_PENDING_LOAD_FAILURE_PARSE",

View File

@ -231,8 +231,6 @@ nsresult MemoryTelemetry::GatherReports(
MOZ_DIAGNOSTIC_ASSERT(mgr);
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
auto startTime = TimeStamp::Now();
#define RECORD(id, metric, units) \
do { \
int64_t amt; \
@ -332,9 +330,6 @@ nsresult MemoryTelemetry::GatherReports(
mTotalMemoryGatherer->Begin(mThreadPool);
}
Telemetry::AccumulateTimeDelta(
Telemetry::HistogramID::TELEMETRY_MEMORY_REPORTER_MS, startTime,
TimeStamp::Now());
return NS_OK;
}

View File

@ -369,6 +369,8 @@ bool SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr) {
*/
extern bool NS_IsInCompositorThread();
extern bool NS_IsInCanvasThread();
extern bool NS_IsInVRThread();
//-----------------------------------------------------------------------------