mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 00:35:44 +00:00
Merge mozilla-central to autoland. on a CLOSED TREE
This commit is contained in:
commit
851bd2386e
@ -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;
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -8632,7 +8632,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType,
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(usage >= 0);
|
||||
MOZ_ASSERT(usage >= 0);
|
||||
|
||||
if (!aForGetUsage) {
|
||||
InitUsageForOrigin(aOrigin, usage);
|
||||
|
12
gfx/2d/2D.h
12
gfx/2d/2D.h
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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()) {
|
||||
|
@ -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; }
|
||||
|
||||
|
@ -135,7 +135,8 @@ enum class LogReason : int {
|
||||
NativeFontResourceNotFound,
|
||||
UnscaledFontNotFound,
|
||||
ScaledFontNotFound,
|
||||
InvalidLayerType,
|
||||
InvalidLayerType, // 40
|
||||
PlayEventFailed,
|
||||
// End
|
||||
MustBeLessThanThis = 101,
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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();
|
||||
|
455
gfx/layers/CanvasDrawEventRecorder.cpp
Normal file
455
gfx/layers/CanvasDrawEventRecorder.cpp
Normal 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
|
232
gfx/layers/CanvasDrawEventRecorder.h
Normal file
232
gfx/layers/CanvasDrawEventRecorder.h
Normal 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
|
245
gfx/layers/CanvasTranslator.cpp
Normal file
245
gfx/layers/CanvasTranslator.cpp
Normal 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
|
216
gfx/layers/CanvasTranslator.h
Normal file
216
gfx/layers/CanvasTranslator.h
Normal 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
|
@ -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 };
|
||||
|
@ -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) {
|
||||
|
@ -180,6 +180,7 @@ class PersistentBufferProviderShared : public PersistentBufferProvider,
|
||||
|
||||
RefPtr<gfx::DrawTarget> mDrawTarget;
|
||||
RefPtr<gfx::SourceSurface> mSnapshot;
|
||||
RefPtr<gfx::SourceSurface> mPreviousSnapshot;
|
||||
};
|
||||
|
||||
struct AutoReturnSnapshot final {
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
384
gfx/layers/RecordedCanvasEventImpl.h
Normal file
384
gfx/layers/RecordedCanvasEventImpl.h
Normal 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
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
110
gfx/layers/client/TextureRecorded.cpp
Normal file
110
gfx/layers/client/TextureRecorded.cpp
Normal 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
|
53
gfx/layers/client/TextureRecorded.h
Normal file
53
gfx/layers/client/TextureRecorded.h
Normal 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
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class Compositor;
|
||||
class CompositorScreenshotGrabberImpl;
|
||||
|
||||
/**
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
150
gfx/layers/ipc/CanvasChild.cpp
Normal file
150
gfx/layers/ipc/CanvasChild.cpp
Normal 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
|
117
gfx/layers/ipc/CanvasChild.h
Normal file
117
gfx/layers/ipc/CanvasChild.h
Normal 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
|
159
gfx/layers/ipc/CanvasParent.cpp
Normal file
159
gfx/layers/ipc/CanvasParent.cpp
Normal 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
|
97
gfx/layers/ipc/CanvasParent.h
Normal file
97
gfx/layers/ipc/CanvasParent.h
Normal 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
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
37
gfx/layers/ipc/PCanvas.ipdl
Normal file
37
gfx/layers/ipc/PCanvas.ipdl
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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',
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "mozilla/layers/RenderRootStateManager.h"
|
||||
|
||||
#include "mozilla/layers/WebRenderBridgeChild.h"
|
||||
#include "mozilla/layers/WebRenderLayerManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -11,8 +11,6 @@ namespace layout {
|
||||
|
||||
void DrawEventRecorderPRFileDesc::RecordEvent(
|
||||
const gfx::RecordedEvent& aEvent) {
|
||||
WriteElement(mOutputStream, aEvent.GetType());
|
||||
|
||||
aEvent.RecordToStream(mOutputStream);
|
||||
|
||||
Flush();
|
||||
|
@ -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; }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -209,7 +209,7 @@ class nsPrintJob final : public nsIObserver,
|
||||
eDocTitleDefault aDefType);
|
||||
|
||||
bool CheckBeforeDestroy();
|
||||
nsresult Cancelled();
|
||||
nsresult Cancel();
|
||||
|
||||
mozilla::PresShell* GetPrintPreviewPresShell() {
|
||||
return mPrtPreview->mPrintObject->mPresShell;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -2525,6 +2525,13 @@ VARCACHE_PREF(
|
||||
RelaxedAtomicInt32, 0x7fff
|
||||
)
|
||||
|
||||
VARCACHE_PREF(
|
||||
Live,
|
||||
"gfx.canvas.remote",
|
||||
CanvasRemote,
|
||||
RelaxedAtomicBool, false
|
||||
)
|
||||
|
||||
VARCACHE_PREF(
|
||||
Live,
|
||||
"gfx.color_management.enablev4",
|
||||
|
@ -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");
|
||||
|
@ -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"],
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -369,6 +369,8 @@ bool SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr) {
|
||||
*/
|
||||
extern bool NS_IsInCompositorThread();
|
||||
|
||||
extern bool NS_IsInCanvasThread();
|
||||
|
||||
extern bool NS_IsInVRThread();
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user