Bug 1938053 - Accelerate canvas drawImage of a WebGL context. r=aosmond
Accelerated Canvas2D and WebGL both live within the GPU process and run within the same thread. We want to avoid any kind of readbacks from the GPU process to the content process when doing a drawImage of a WebGL context to an AC2D canvas. To achieve this, we pause the AC2D recording translation with an AwaitTranslationSync event identified by a sync-id. Then we send a request over IPDL to snapshot the WebGL context while this pause is ongoing via a SnapshotExternalCanvas IPDL message, which uses the sync-id to identify the snapshot safely in a table of such external snapshots and force translation to resume. Finally, we send a ResolveExternalSnapshot event within the recording stream to lookup the snapshot based on the sync-id and assign it an alias that can be used within the recording stream playback for drawImage. The sync-id mechanism acts as a sequenced fence so that multiple SnapshotExternalCanvas requests can be encountered simultaneously from IPDL without confusing the recording playback. Differential Revision: https://phabricator.services.mozilla.com/D243399
This commit is contained in:
@@ -1142,6 +1142,11 @@ already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
|
|||||||
return ret.forget();
|
return ret.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IProtocol* ClientWebGLContext::SupportsSnapshotExternalCanvas()
|
||||||
|
const {
|
||||||
|
return GetChild();
|
||||||
|
}
|
||||||
|
|
||||||
RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
|
RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
|
||||||
const bool requireAlphaPremult) {
|
const bool requireAlphaPremult) {
|
||||||
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>");
|
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>");
|
||||||
|
|||||||
@@ -1012,6 +1012,8 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
|||||||
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
|
already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
|
||||||
gfxAlphaType* out_alphaType) override;
|
gfxAlphaType* out_alphaType) override;
|
||||||
|
|
||||||
|
mozilla::ipc::IProtocol* SupportsSnapshotExternalCanvas() const override;
|
||||||
|
|
||||||
void SetOpaqueValueFromOpaqueAttr(bool) override {};
|
void SetOpaqueValueFromOpaqueAttr(bool) override {};
|
||||||
bool GetIsOpaque() override { return !mInitialOptions->alpha; }
|
bool GetIsOpaque() override { return !mInitialOptions->alpha; }
|
||||||
|
|
||||||
@@ -1420,6 +1422,8 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
|
|||||||
|
|
||||||
void Flush(bool flushGl = true) const;
|
void Flush(bool flushGl = true) const;
|
||||||
|
|
||||||
|
void SyncSnapshot() override { Flush(); }
|
||||||
|
|
||||||
void Finish();
|
void Finish();
|
||||||
|
|
||||||
void FrontFace(GLenum mode);
|
void FrontFace(GLenum mode);
|
||||||
|
|||||||
@@ -1032,9 +1032,10 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||||||
// process as the WebGL canvas. Query it for the surface.
|
// process as the WebGL canvas. Query it for the surface.
|
||||||
const auto& sdc = sd.get_SurfaceDescriptorCanvasSurface();
|
const auto& sdc = sd.get_SurfaceDescriptorCanvasSurface();
|
||||||
uint32_t managerId = sdc.managerId();
|
uint32_t managerId = sdc.managerId();
|
||||||
|
int32_t canvasId = sdc.canvasId();
|
||||||
uintptr_t surfaceId = sdc.surfaceId();
|
uintptr_t surfaceId = sdc.surfaceId();
|
||||||
surf = gfx::CanvasManagerParent::GetCanvasSurface(webgl->GetContentId(),
|
surf = gfx::CanvasManagerParent::GetCanvasSurface(
|
||||||
managerId, surfaceId);
|
webgl->GetContentId(), managerId, canvasId, surfaceId);
|
||||||
if (!surf) {
|
if (!surf) {
|
||||||
gfxCriticalNote << "TexUnpackSurface failed to get CanvasSurface";
|
gfxCriticalNote << "TexUnpackSurface failed to get CanvasSurface";
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -110,6 +110,8 @@ class WebGLParent : public PWebGLParent, public SupportsWeakPtr {
|
|||||||
const RefPtr<layers::SharedSurfacesHolder> mSharedSurfacesHolder;
|
const RefPtr<layers::SharedSurfacesHolder> mSharedSurfacesHolder;
|
||||||
const dom::ContentParentId mContentId;
|
const dom::ContentParentId mContentId;
|
||||||
|
|
||||||
|
HostWebGLContext* GetHostWebGLContext() const { return mHost.get(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~WebGLParent();
|
~WebGLParent();
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "mozilla/dom/Event.h"
|
#include "mozilla/dom/Event.h"
|
||||||
#include "mozilla/dom/WorkerCommon.h"
|
#include "mozilla/dom/WorkerCommon.h"
|
||||||
#include "mozilla/dom/WorkerPrivate.h"
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
|
#include "mozilla/gfx/DrawTargetRecording.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/PresShell.h"
|
#include "mozilla/PresShell.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
@@ -140,3 +141,27 @@ bool nsICanvasRenderingContextInternal::DispatchEvent(
|
|||||||
}
|
}
|
||||||
return useDefaultHandler;
|
return useDefaultHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<mozilla::gfx::SourceSurface>
|
||||||
|
nsICanvasRenderingContextInternal::GetOptimizedSnapshot(
|
||||||
|
mozilla::gfx::DrawTarget* aTarget, gfxAlphaType* out_alphaType) {
|
||||||
|
if (aTarget &&
|
||||||
|
aTarget->GetBackendType() == mozilla::gfx::BackendType::RECORDING) {
|
||||||
|
if (auto* actor = SupportsSnapshotExternalCanvas()) {
|
||||||
|
// If this snapshot is for a recording target, then try to avoid reading
|
||||||
|
// back any data by using SnapshotExternalCanvas instead. This avoids
|
||||||
|
// having sync interactions between GPU and content process.
|
||||||
|
if (RefPtr<mozilla::gfx::SourceSurface> surf =
|
||||||
|
static_cast<mozilla::gfx::DrawTargetRecording*>(aTarget)
|
||||||
|
->SnapshotExternalCanvas(this, actor)) {
|
||||||
|
if (out_alphaType) {
|
||||||
|
*out_alphaType =
|
||||||
|
GetIsOpaque() ? gfxAlphaType::Opaque : gfxAlphaType::Premult;
|
||||||
|
}
|
||||||
|
return surf.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetSurfaceSnapshot(out_alphaType);
|
||||||
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ class nsDisplayListBuilder;
|
|||||||
class ClientWebGLContext;
|
class ClientWebGLContext;
|
||||||
class PresShell;
|
class PresShell;
|
||||||
class WebGLFramebufferJS;
|
class WebGLFramebufferJS;
|
||||||
|
namespace ipc {
|
||||||
|
class IProtocol;
|
||||||
|
} // namespace ipc
|
||||||
namespace layers {
|
namespace layers {
|
||||||
class CanvasRenderer;
|
class CanvasRenderer;
|
||||||
class CompositableForwarder;
|
class CompositableForwarder;
|
||||||
@@ -138,11 +141,14 @@ class nsICanvasRenderingContextInternal : public nsISupports,
|
|||||||
// provided DrawTarget, which may be nullptr. By default, this will defer to
|
// provided DrawTarget, which may be nullptr. By default, this will defer to
|
||||||
// GetSurfaceSnapshot and ignore target-dependent optimization.
|
// GetSurfaceSnapshot and ignore target-dependent optimization.
|
||||||
virtual already_AddRefed<mozilla::gfx::SourceSurface> GetOptimizedSnapshot(
|
virtual already_AddRefed<mozilla::gfx::SourceSurface> GetOptimizedSnapshot(
|
||||||
mozilla::gfx::DrawTarget* aTarget,
|
mozilla::gfx::DrawTarget* aTarget, gfxAlphaType* out_alphaType = nullptr);
|
||||||
gfxAlphaType* out_alphaType = nullptr) {
|
|
||||||
return GetSurfaceSnapshot(out_alphaType);
|
virtual mozilla::ipc::IProtocol* SupportsSnapshotExternalCanvas() const {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void SyncSnapshot() {}
|
||||||
|
|
||||||
virtual RefPtr<mozilla::gfx::SourceSurface> GetFrontBufferSnapshot(bool) {
|
virtual RefPtr<mozilla::gfx::SourceSurface> GetFrontBufferSnapshot(bool) {
|
||||||
return GetSurfaceSnapshot();
|
return GetSurfaceSnapshot();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
#include "nsISupportsImpl.h"
|
#include "nsISupportsImpl.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
namespace layers {
|
||||||
|
class CanvasChild;
|
||||||
|
} // namespace layers
|
||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
|
|
||||||
class DrawTargetRecording;
|
class DrawTargetRecording;
|
||||||
@@ -224,6 +228,10 @@ class DrawEventRecorderPrivate : public DrawEventRecorder {
|
|||||||
|
|
||||||
using ExternalImagesHolder = std::deque<ExternalImageEntry>;
|
using ExternalImagesHolder = std::deque<ExternalImageEntry>;
|
||||||
|
|
||||||
|
virtual already_AddRefed<layers::CanvasChild> GetCanvasChild() const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NS_DECL_OWNINGTHREAD
|
NS_DECL_OWNINGTHREAD
|
||||||
|
|
||||||
|
|||||||
@@ -486,6 +486,24 @@ already_AddRefed<SourceSurface> DrawTargetRecording::Snapshot() {
|
|||||||
return retSurf.forget();
|
return retSurf.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<SourceSurface>
|
||||||
|
DrawTargetRecording::CreateExternalSourceSurface(const IntSize& aSize,
|
||||||
|
SurfaceFormat aFormat) {
|
||||||
|
RefPtr<SourceSurface> retSurf =
|
||||||
|
new SourceSurfaceRecording(aSize, aFormat, mRecorder);
|
||||||
|
|
||||||
|
return retSurf.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<SourceSurface> DrawTargetRecording::SnapshotExternalCanvas(
|
||||||
|
nsICanvasRenderingContextInternal* aCanvas,
|
||||||
|
mozilla::ipc::IProtocol* aActor) {
|
||||||
|
if (RefPtr<layers::CanvasChild> canvasChild = mRecorder->GetCanvasChild()) {
|
||||||
|
return canvasChild->SnapshotExternalCanvas(this, aCanvas, aActor);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<SourceSurface> DrawTargetRecording::IntoLuminanceSource(
|
already_AddRefed<SourceSurface> DrawTargetRecording::IntoLuminanceSource(
|
||||||
LuminanceType aLuminanceType, float aOpacity) {
|
LuminanceType aLuminanceType, float aOpacity) {
|
||||||
RefPtr<SourceSurface> retSurf =
|
RefPtr<SourceSurface> retSurf =
|
||||||
|
|||||||
@@ -10,8 +10,16 @@
|
|||||||
#include "2D.h"
|
#include "2D.h"
|
||||||
#include "DrawEventRecorder.h"
|
#include "DrawEventRecorder.h"
|
||||||
|
|
||||||
|
class nsICanvasRenderingContextInternal;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
class IProtocol;
|
||||||
|
} // namespace ipc
|
||||||
|
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
class CanvasChild;
|
||||||
class CanvasDrawEventRecorder;
|
class CanvasDrawEventRecorder;
|
||||||
class RecordedTextureData;
|
class RecordedTextureData;
|
||||||
struct RemoteTextureOwnerId;
|
struct RemoteTextureOwnerId;
|
||||||
@@ -392,6 +400,17 @@ class DrawTargetRecording final : public DrawTarget {
|
|||||||
|
|
||||||
layers::RecordedTextureData* mTextureData = nullptr;
|
layers::RecordedTextureData* mTextureData = nullptr;
|
||||||
|
|
||||||
|
friend class layers::CanvasChild;
|
||||||
|
|
||||||
|
already_AddRefed<SourceSurface> CreateExternalSourceSurface(
|
||||||
|
const IntSize& aSize, SurfaceFormat aFormat);
|
||||||
|
|
||||||
|
friend class ::nsICanvasRenderingContextInternal;
|
||||||
|
|
||||||
|
already_AddRefed<SourceSurface> SnapshotExternalCanvas(
|
||||||
|
nsICanvasRenderingContextInternal* aCanvas,
|
||||||
|
mozilla::ipc::IProtocol* aActor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Used for creating a DrawTargetRecording for a CreateSimilarDrawTarget call.
|
* Used for creating a DrawTargetRecording for a CreateSimilarDrawTarget call.
|
||||||
|
|||||||
@@ -239,20 +239,33 @@ mozilla::ipc::IPCResult CanvasManagerParent::RecvGetSnapshot(
|
|||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ mozilla::ipc::IProtocol* CanvasManagerParent::GetCanvasActor(
|
||||||
|
dom::ContentParentId aContentId, uint32_t aManagerId, int32_t aCanvasId) {
|
||||||
|
IProtocol* actor = nullptr;
|
||||||
|
for (CanvasManagerParent* i : sManagers) {
|
||||||
|
if (i->mContentId == aContentId && i->mId == aManagerId) {
|
||||||
|
actor = i->Lookup(aCanvasId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return actor;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ already_AddRefed<DataSourceSurface>
|
/* static */ already_AddRefed<DataSourceSurface>
|
||||||
CanvasManagerParent::GetCanvasSurface(dom::ContentParentId aContentId,
|
CanvasManagerParent::GetCanvasSurface(dom::ContentParentId aContentId,
|
||||||
uint32_t aManagerId,
|
uint32_t aManagerId, int32_t aCanvasId,
|
||||||
uintptr_t aSurfaceId) {
|
uintptr_t aSurfaceId) {
|
||||||
for (CanvasManagerParent* manager : sManagers) {
|
IProtocol* actor = GetCanvasActor(aContentId, aManagerId, aCanvasId);
|
||||||
if (manager->mContentId == aContentId && manager->mId == aManagerId) {
|
if (!actor) {
|
||||||
for (const auto& canvas : manager->ManagedPCanvasParent()) {
|
return nullptr;
|
||||||
RefPtr<layers::CanvasTranslator> ct =
|
}
|
||||||
static_cast<layers::CanvasTranslator*>(canvas);
|
switch (actor->GetProtocolId()) {
|
||||||
if (RefPtr<DataSourceSurface> surf = ct->WaitForSurface(aSurfaceId)) {
|
case ProtocolId::PCanvasMsgStart:
|
||||||
return surf.forget();
|
return static_cast<layers::CanvasTranslator*>(actor)->WaitForSurface(
|
||||||
}
|
aSurfaceId);
|
||||||
}
|
default:
|
||||||
}
|
MOZ_ASSERT_UNREACHABLE("Unsupported protocol");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,11 @@ class CanvasManagerParent final : public PCanvasManagerParent {
|
|||||||
const Maybe<RawId>& aCommandEncoderId,
|
const Maybe<RawId>& aCommandEncoderId,
|
||||||
webgl::FrontBufferSnapshotIpc* aResult);
|
webgl::FrontBufferSnapshotIpc* aResult);
|
||||||
|
|
||||||
|
static mozilla::ipc::IProtocol* GetCanvasActor(
|
||||||
|
dom::ContentParentId aContentId, uint32_t aManagerId, int32_t aCanvasId);
|
||||||
|
|
||||||
static already_AddRefed<DataSourceSurface> GetCanvasSurface(
|
static already_AddRefed<DataSourceSurface> GetCanvasSurface(
|
||||||
dom::ContentParentId aContentId, uint32_t aManagerId,
|
dom::ContentParentId aContentId, uint32_t aManagerId, int32_t aCanvasId,
|
||||||
uintptr_t aSurfaceId);
|
uintptr_t aSurfaceId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
|||||||
* Causes the reader to resume processing when it is in a stopped state.
|
* Causes the reader to resume processing when it is in a stopped state.
|
||||||
*/
|
*/
|
||||||
virtual bool RestartReader() = 0;
|
virtual bool RestartReader() = 0;
|
||||||
|
|
||||||
|
virtual already_AddRefed<layers::CanvasChild> GetCanvasChild() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Init(TextureType aTextureType, TextureType aWebglTextureType,
|
bool Init(TextureType aTextureType, TextureType aWebglTextureType,
|
||||||
@@ -137,6 +139,10 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
|||||||
|
|
||||||
void ClearProcessedExternalImages();
|
void ClearProcessedExternalImages();
|
||||||
|
|
||||||
|
already_AddRefed<layers::CanvasChild> GetCanvasChild() const override {
|
||||||
|
return mHelpers->GetCanvasChild();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
gfx::ContiguousBuffer& GetContiguousBuffer(size_t aSize) final;
|
gfx::ContiguousBuffer& GetContiguousBuffer(size_t aSize) final;
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ const EventType DROP_BUFFER = EventType(EventType::LAST + 16);
|
|||||||
const EventType PREPARE_SHMEM = EventType(EventType::LAST + 17);
|
const EventType PREPARE_SHMEM = EventType(EventType::LAST + 17);
|
||||||
const EventType PRESENT_TEXTURE = EventType(EventType::LAST + 18);
|
const EventType PRESENT_TEXTURE = EventType(EventType::LAST + 18);
|
||||||
const EventType DEVICE_RESET_ACKNOWLEDGED = EventType(EventType::LAST + 19);
|
const EventType DEVICE_RESET_ACKNOWLEDGED = EventType(EventType::LAST + 19);
|
||||||
const EventType LAST_CANVAS_EVENT_TYPE = DEVICE_RESET_ACKNOWLEDGED;
|
const EventType AWAIT_TRANSLATION_SYNC = EventType(EventType::LAST + 20);
|
||||||
|
const EventType RESOLVE_EXTERNAL_SNAPSHOT = EventType(EventType::LAST + 21);
|
||||||
|
const EventType LAST_CANVAS_EVENT_TYPE = RESOLVE_EXTERNAL_SNAPSHOT;
|
||||||
|
|
||||||
class RecordedCanvasBeginTransaction final
|
class RecordedCanvasBeginTransaction final
|
||||||
: public RecordedEventDerived<RecordedCanvasBeginTransaction> {
|
: public RecordedEventDerived<RecordedCanvasBeginTransaction> {
|
||||||
@@ -668,6 +670,87 @@ class RecordedPauseTranslation final
|
|||||||
std::string GetName() const final { return "RecordedPauseTranslation"; }
|
std::string GetName() const final { return "RecordedPauseTranslation"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RecordedAwaitTranslationSync final
|
||||||
|
: public RecordedEventDerived<RecordedAwaitTranslationSync> {
|
||||||
|
public:
|
||||||
|
explicit RecordedAwaitTranslationSync(uint64_t aSyncId)
|
||||||
|
: RecordedEventDerived(AWAIT_TRANSLATION_SYNC), mSyncId(aSyncId) {}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
MOZ_IMPLICIT RecordedAwaitTranslationSync(S& aStream);
|
||||||
|
|
||||||
|
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const {
|
||||||
|
aTranslator->AwaitTranslationSync(mSyncId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
void Record(S& aStream) const;
|
||||||
|
|
||||||
|
std::string GetName() const final { return "RecordedAwaitTranslationSync"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t mSyncId = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
void RecordedAwaitTranslationSync::Record(S& aStream) const {
|
||||||
|
WriteElement(aStream, mSyncId);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
RecordedAwaitTranslationSync::RecordedAwaitTranslationSync(S& aStream)
|
||||||
|
: RecordedEventDerived(AWAIT_TRANSLATION_SYNC) {
|
||||||
|
ReadElement(aStream, mSyncId);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecordedResolveExternalSnapshot final
|
||||||
|
: public RecordedEventDerived<RecordedResolveExternalSnapshot> {
|
||||||
|
public:
|
||||||
|
explicit RecordedResolveExternalSnapshot(uint64_t aSyncId,
|
||||||
|
ReferencePtr aRefPtr)
|
||||||
|
: RecordedEventDerived(RESOLVE_EXTERNAL_SNAPSHOT),
|
||||||
|
mSyncId(aSyncId),
|
||||||
|
mRefPtr(aRefPtr) {}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
MOZ_IMPLICIT RecordedResolveExternalSnapshot(S& aStream);
|
||||||
|
|
||||||
|
bool PlayCanvasEvent(CanvasTranslator* aTranslator) const {
|
||||||
|
RefPtr<gfx::SourceSurface> snapshot =
|
||||||
|
aTranslator->LookupExternalSnapshot(mSyncId);
|
||||||
|
if (!snapshot) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
aTranslator->AddSourceSurface(mRefPtr, snapshot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
void Record(S& aStream) const;
|
||||||
|
|
||||||
|
std::string GetName() const final {
|
||||||
|
return "RecordedResolveExternalSnapshot";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t mSyncId = 0;
|
||||||
|
ReferencePtr mRefPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
void RecordedResolveExternalSnapshot::Record(S& aStream) const {
|
||||||
|
WriteElement(aStream, mSyncId);
|
||||||
|
WriteElement(aStream, mRefPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class S>
|
||||||
|
RecordedResolveExternalSnapshot::RecordedResolveExternalSnapshot(S& aStream)
|
||||||
|
: RecordedEventDerived(RESOLVE_EXTERNAL_SNAPSHOT) {
|
||||||
|
ReadElement(aStream, mSyncId);
|
||||||
|
ReadElement(aStream, mRefPtr);
|
||||||
|
}
|
||||||
|
|
||||||
class RecordedRecycleBuffer final
|
class RecordedRecycleBuffer final
|
||||||
: public RecordedEventDerived<RecordedRecycleBuffer> {
|
: public RecordedEventDerived<RecordedRecycleBuffer> {
|
||||||
public:
|
public:
|
||||||
@@ -811,7 +894,9 @@ RecordedPresentTexture::RecordedPresentTexture(S& aStream)
|
|||||||
f(DROP_BUFFER, RecordedDropBuffer); \
|
f(DROP_BUFFER, RecordedDropBuffer); \
|
||||||
f(PREPARE_SHMEM, RecordedPrepareShmem); \
|
f(PREPARE_SHMEM, RecordedPrepareShmem); \
|
||||||
f(PRESENT_TEXTURE, RecordedPresentTexture); \
|
f(PRESENT_TEXTURE, RecordedPresentTexture); \
|
||||||
f(DEVICE_RESET_ACKNOWLEDGED, RecordedDeviceResetAcknowledged);
|
f(DEVICE_RESET_ACKNOWLEDGED, RecordedDeviceResetAcknowledged); \
|
||||||
|
f(AWAIT_TRANSLATION_SYNC, RecordedAwaitTranslationSync); \
|
||||||
|
f(RESOLVE_EXTERNAL_SNAPSHOT, RecordedResolveExternalSnapshot);
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "mozilla/gfx/CanvasManagerChild.h"
|
#include "mozilla/gfx/CanvasManagerChild.h"
|
||||||
#include "mozilla/gfx/CanvasShutdownManager.h"
|
#include "mozilla/gfx/CanvasShutdownManager.h"
|
||||||
#include "mozilla/gfx/DrawTargetRecording.h"
|
#include "mozilla/gfx/DrawTargetRecording.h"
|
||||||
|
#include "mozilla/gfx/gfxVars.h"
|
||||||
#include "mozilla/gfx/Tools.h"
|
#include "mozilla/gfx/Tools.h"
|
||||||
#include "mozilla/gfx/Rect.h"
|
#include "mozilla/gfx/Rect.h"
|
||||||
#include "mozilla/gfx/Point.h"
|
#include "mozilla/gfx/Point.h"
|
||||||
@@ -25,7 +26,9 @@
|
|||||||
#include "mozilla/AppShutdown.h"
|
#include "mozilla/AppShutdown.h"
|
||||||
#include "mozilla/Maybe.h"
|
#include "mozilla/Maybe.h"
|
||||||
#include "mozilla/Mutex.h"
|
#include "mozilla/Mutex.h"
|
||||||
|
#include "mozilla/StaticPrefs_gfx.h"
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
|
#include "nsICanvasRenderingContextInternal.h"
|
||||||
#include "RecordedCanvasEventImpl.h"
|
#include "RecordedCanvasEventImpl.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
@@ -81,6 +84,11 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers {
|
|||||||
return mCanvasChild->SendRestartTranslation();
|
return mCanvasChild->SendRestartTranslation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<CanvasChild> GetCanvasChild() const override {
|
||||||
|
RefPtr<CanvasChild> canvasChild(mCanvasChild);
|
||||||
|
return canvasChild.forget();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const WeakPtr<CanvasChild> mCanvasChild;
|
const WeakPtr<CanvasChild> mCanvasChild;
|
||||||
};
|
};
|
||||||
@@ -157,7 +165,7 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
|
|||||||
bool GetSurfaceDescriptor(SurfaceDescriptor& aDesc) const final {
|
bool GetSurfaceDescriptor(SurfaceDescriptor& aDesc) const final {
|
||||||
aDesc = SurfaceDescriptorCanvasSurface(
|
aDesc = SurfaceDescriptorCanvasSurface(
|
||||||
static_cast<gfx::CanvasManagerChild*>(mCanvasChild->Manager())->Id(),
|
static_cast<gfx::CanvasManagerChild*>(mCanvasChild->Manager())->Id(),
|
||||||
uintptr_t(gfx::ReferencePtr(this)));
|
mCanvasChild->Id(), uintptr_t(gfx::ReferencePtr(this)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -719,5 +727,51 @@ ipc::IPCResult CanvasChild::RecvNotifyTextureDestruction(
|
|||||||
return IPC_OK();
|
return IPC_OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<gfx::SourceSurface> CanvasChild::SnapshotExternalCanvas(
|
||||||
|
gfx::DrawTargetRecording* aTarget,
|
||||||
|
nsICanvasRenderingContextInternal* aCanvas,
|
||||||
|
mozilla::ipc::IProtocol* aActor) {
|
||||||
|
// SnapshotExternalCanvas is only valid to use if using Accelerated Canvas2D
|
||||||
|
// with the pending events queue enabled. This ensures WebGL and AC2D are
|
||||||
|
// running under the same thread, and that events can be paused or resumed
|
||||||
|
// while synchronizing between WebGL and AC2D.
|
||||||
|
if (!gfx::gfxVars::UseAcceleratedCanvas2D() ||
|
||||||
|
!StaticPrefs::gfx_canvas_remote_use_canvas_translator_event_AtStartup()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::SurfaceFormat format = aCanvas->GetIsOpaque()
|
||||||
|
? gfx::SurfaceFormat::B8G8R8X8
|
||||||
|
: gfx::SurfaceFormat::B8G8R8A8;
|
||||||
|
gfx::IntSize size(aCanvas->GetWidth(), aCanvas->GetHeight());
|
||||||
|
// Create a source sourface that will be associated with the snapshot.
|
||||||
|
RefPtr<gfx::SourceSurface> surface =
|
||||||
|
aTarget->CreateExternalSourceSurface(size, format);
|
||||||
|
if (!surface) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause translation until the sync-id identifying the snapshot is received.
|
||||||
|
uint64_t syncId = ++mLastSyncId;
|
||||||
|
mRecorder->RecordEvent(RecordedAwaitTranslationSync(syncId));
|
||||||
|
|
||||||
|
// Flush WebGL to cause any IPDL messages to get sent at this sync point.
|
||||||
|
aCanvas->SyncSnapshot();
|
||||||
|
|
||||||
|
// Once the IPDL message is sent to generate the snapshot, resolve the sync-id
|
||||||
|
// to a surface in the recording stream. The AwaitTranslationSync above will
|
||||||
|
// ensure this event is not translated until the snapshot is generated first.
|
||||||
|
mRecorder->RecordEvent(
|
||||||
|
RecordedResolveExternalSnapshot(syncId, gfx::ReferencePtr(surface)));
|
||||||
|
|
||||||
|
uint32_t managerId = static_cast<gfx::CanvasManagerChild*>(Manager())->Id();
|
||||||
|
int32_t canvasId = aActor->Id();
|
||||||
|
|
||||||
|
// Actually send the request via IPDL to snapshot the external WebGL canvas.
|
||||||
|
SendSnapshotExternalCanvas(syncId, managerId, canvasId);
|
||||||
|
|
||||||
|
return surface.forget();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#include "mozilla/layers/SourceSurfaceSharedData.h"
|
#include "mozilla/layers/SourceSurfaceSharedData.h"
|
||||||
#include "mozilla/WeakPtr.h"
|
#include "mozilla/WeakPtr.h"
|
||||||
|
|
||||||
|
class nsICanvasRenderingContextInternal;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@@ -166,6 +168,11 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
|
|||||||
void ReturnDataSurfaceShmem(
|
void ReturnDataSurfaceShmem(
|
||||||
std::shared_ptr<ipc::ReadOnlySharedMemoryMapping>&& aDataSurfaceShmem);
|
std::shared_ptr<ipc::ReadOnlySharedMemoryMapping>&& aDataSurfaceShmem);
|
||||||
|
|
||||||
|
already_AddRefed<gfx::SourceSurface> SnapshotExternalCanvas(
|
||||||
|
gfx::DrawTargetRecording* aTarget,
|
||||||
|
nsICanvasRenderingContextInternal* aCanvas,
|
||||||
|
mozilla::ipc::IProtocol* aActor);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ActorDestroy(ActorDestroyReason aWhy) final;
|
void ActorDestroy(ActorDestroyReason aWhy) final;
|
||||||
|
|
||||||
@@ -201,6 +208,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
|
|||||||
bool mIsInTransaction = false;
|
bool mIsInTransaction = false;
|
||||||
bool mDormant = false;
|
bool mDormant = false;
|
||||||
bool mBlocked = false;
|
bool mBlocked = false;
|
||||||
|
uint64_t mLastSyncId = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "mozilla/gfx/GPUParent.h"
|
#include "mozilla/gfx/GPUParent.h"
|
||||||
#include "mozilla/gfx/GPUProcessManager.h"
|
#include "mozilla/gfx/GPUProcessManager.h"
|
||||||
#include "mozilla/gfx/Logging.h"
|
#include "mozilla/gfx/Logging.h"
|
||||||
|
#include "mozilla/gfx/Swizzle.h"
|
||||||
#include "mozilla/ipc/Endpoint.h"
|
#include "mozilla/ipc/Endpoint.h"
|
||||||
#include "mozilla/ipc/SharedMemoryHandle.h"
|
#include "mozilla/ipc/SharedMemoryHandle.h"
|
||||||
#include "mozilla/layers/BufferTexture.h"
|
#include "mozilla/layers/BufferTexture.h"
|
||||||
@@ -29,6 +30,8 @@
|
|||||||
#include "mozilla/SyncRunnable.h"
|
#include "mozilla/SyncRunnable.h"
|
||||||
#include "mozilla/TaskQueue.h"
|
#include "mozilla/TaskQueue.h"
|
||||||
#include "GLContext.h"
|
#include "GLContext.h"
|
||||||
|
#include "HostWebGLContext.h"
|
||||||
|
#include "WebGLParent.h"
|
||||||
#include "RecordedCanvasEventImpl.h"
|
#include "RecordedCanvasEventImpl.h"
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
@@ -697,7 +700,7 @@ bool CanvasTranslator::TranslateRecording() {
|
|||||||
|
|
||||||
mHeader->processedCount++;
|
mHeader->processedCount++;
|
||||||
|
|
||||||
if (mHeader->readerState == State::Paused) {
|
if (mHeader->readerState == State::Paused || PauseUntilSync()) {
|
||||||
// We're waiting for an IPDL message return false, because we will resume
|
// We're waiting for an IPDL message return false, because we will resume
|
||||||
// translation after it is received.
|
// translation after it is received.
|
||||||
Flush();
|
Flush();
|
||||||
@@ -760,7 +763,7 @@ void CanvasTranslator::HandleCanvasTranslatorEvents() {
|
|||||||
{
|
{
|
||||||
MutexAutoLock lock(mCanvasTranslatorEventsLock);
|
MutexAutoLock lock(mCanvasTranslatorEventsLock);
|
||||||
MOZ_ASSERT_IF(mIPDLClosed, mPendingCanvasTranslatorEvents.empty());
|
MOZ_ASSERT_IF(mIPDLClosed, mPendingCanvasTranslatorEvents.empty());
|
||||||
if (mPendingCanvasTranslatorEvents.empty()) {
|
if (mPendingCanvasTranslatorEvents.empty() || PauseUntilSync()) {
|
||||||
mCanvasTranslatorEventsRunnable = nullptr;
|
mCanvasTranslatorEventsRunnable = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -800,6 +803,12 @@ void CanvasTranslator::HandleCanvasTranslatorEvents() {
|
|||||||
if (mIPDLClosed) {
|
if (mIPDLClosed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (PauseUntilSync()) {
|
||||||
|
mCanvasTranslatorEventsRunnable = nullptr;
|
||||||
|
mPendingCanvasTranslatorEvents.push_front(
|
||||||
|
CanvasTranslatorEvent::TranslateRecording());
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!mIPDLClosed && !dispatchTranslate &&
|
if (!mIPDLClosed && !dispatchTranslate &&
|
||||||
!mPendingCanvasTranslatorEvents.empty()) {
|
!mPendingCanvasTranslatorEvents.empty()) {
|
||||||
auto& front = mPendingCanvasTranslatorEvents.front();
|
auto& front = mPendingCanvasTranslatorEvents.front();
|
||||||
@@ -1621,6 +1630,175 @@ void CanvasTranslator::PauseTranslation() {
|
|||||||
mHeader->readerState = State::Paused;
|
mHeader->readerState = State::Paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CanvasTranslator::AwaitTranslationSync(uint64_t aSyncId) {
|
||||||
|
if (NS_WARN_IF(!UsePendingCanvasTranslatorEvents()) ||
|
||||||
|
NS_WARN_IF(!IsInTaskQueue()) || NS_WARN_IF(mAwaitSyncId >= aSyncId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAwaitSyncId = aSyncId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasTranslator::SyncTranslation(uint64_t aSyncId) {
|
||||||
|
if (NS_WARN_IF(!IsInTaskQueue()) || NS_WARN_IF(aSyncId <= mLastSyncId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasPaused = PauseUntilSync();
|
||||||
|
mLastSyncId = aSyncId;
|
||||||
|
// If translation was previously paused waiting on a sync-id, check if sync-id
|
||||||
|
// encountered requires restarting translation.
|
||||||
|
if (wasPaused && !PauseUntilSync()) {
|
||||||
|
HandleCanvasTranslatorEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebGLContextBackBufferAccess : public WebGLContext {
|
||||||
|
public:
|
||||||
|
already_AddRefed<gfx::SourceSurface> GetBackBufferSnapshot(
|
||||||
|
const bool requireAlphaPremult);
|
||||||
|
};
|
||||||
|
|
||||||
|
already_AddRefed<gfx::SourceSurface>
|
||||||
|
WebGLContextBackBufferAccess::GetBackBufferSnapshot(
|
||||||
|
const bool requireAlphaPremult) {
|
||||||
|
if (IsContextLost()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto surfSize = DrawingBufferSize();
|
||||||
|
if (surfSize.x <= 0 || surfSize.y <= 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& options = Options();
|
||||||
|
const auto surfFormat = options.alpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||||
|
: gfx::SurfaceFormat::B8G8R8X8;
|
||||||
|
|
||||||
|
RefPtr<gfx::DataSourceSurface> dataSurf =
|
||||||
|
gfx::Factory::CreateDataSourceSurface(
|
||||||
|
gfx::IntSize(surfSize.x, surfSize.y), surfFormat);
|
||||||
|
if (!dataSurf) {
|
||||||
|
NS_WARNING("Failed to alloc DataSourceSurface for GetBackBufferSnapshot");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
gfx::DataSourceSurface::ScopedMap map(dataSurf,
|
||||||
|
gfx::DataSourceSurface::READ_WRITE);
|
||||||
|
if (!map.IsMapped()) {
|
||||||
|
NS_WARNING("Failed to map DataSourceSurface for GetBackBufferSnapshot");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultFBForRead might overwrite FB state if it needs to resolve a
|
||||||
|
// multisampled FB, so save/restore the FB state here just in case.
|
||||||
|
const gl::ScopedBindFramebuffer bindFb(GL());
|
||||||
|
const auto fb = GetDefaultFBForRead();
|
||||||
|
if (!fb) {
|
||||||
|
gfxCriticalNote << "GetDefaultFBForRead failed for GetBackBufferSnapshot";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto byteCount = CheckedInt<size_t>(map.GetStride()) * surfSize.y;
|
||||||
|
if (!byteCount.isValid()) {
|
||||||
|
gfxCriticalNote << "Invalid byte count for GetBackBufferSnapshot";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const Range<uint8_t> range = {map.GetData(), byteCount.value()};
|
||||||
|
if (!SnapshotInto(fb->mFB, fb->mSize, range,
|
||||||
|
Some(size_t(map.GetStride())))) {
|
||||||
|
gfxCriticalNote << "SnapshotInto failed for GetBackBufferSnapshot";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requireAlphaPremult && options.alpha && !options.premultipliedAlpha) {
|
||||||
|
bool rv = gfx::PremultiplyYFlipData(
|
||||||
|
map.GetData(), map.GetStride(), gfx::SurfaceFormat::R8G8B8A8,
|
||||||
|
map.GetData(), map.GetStride(), surfFormat, dataSurf->GetSize());
|
||||||
|
MOZ_RELEASE_ASSERT(rv, "PremultiplyYFlipData failed!");
|
||||||
|
} else {
|
||||||
|
bool rv = gfx::SwizzleYFlipData(
|
||||||
|
map.GetData(), map.GetStride(), gfx::SurfaceFormat::R8G8B8A8,
|
||||||
|
map.GetData(), map.GetStride(), surfFormat, dataSurf->GetSize());
|
||||||
|
MOZ_RELEASE_ASSERT(rv, "SwizzleYFlipData failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataSurf.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
mozilla::ipc::IPCResult CanvasTranslator::RecvSnapshotExternalCanvas(
|
||||||
|
uint64_t aSyncId, uint32_t aManagerId, int32_t aCanvasId) {
|
||||||
|
if (NS_WARN_IF(!IsInTaskQueue())) {
|
||||||
|
return IPC_FAIL(this,
|
||||||
|
"RecvSnapshotExternalCanvas used outside of task queue.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that snapshot requests are not received out of order order.
|
||||||
|
if (NS_WARN_IF(aSyncId <= mLastSyncId)) {
|
||||||
|
return IPC_FAIL(this, "RecvSnapShotExternalCanvas received too late.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to snapshot an external canvas that is associated with the same
|
||||||
|
// content process as this canvas. On success, associate it with the sync-id.
|
||||||
|
RefPtr<gfx::SourceSurface> surf;
|
||||||
|
if (auto* actor = gfx::CanvasManagerParent::GetCanvasActor(
|
||||||
|
mContentId, aManagerId, aCanvasId)) {
|
||||||
|
switch (actor->GetProtocolId()) {
|
||||||
|
case ProtocolId::PWebGLMsgStart:
|
||||||
|
if (auto* hostContext =
|
||||||
|
static_cast<dom::WebGLParent*>(actor)->GetHostWebGLContext()) {
|
||||||
|
surf = static_cast<WebGLContextBackBufferAccess*>(
|
||||||
|
hostContext->GetWebGLContext())
|
||||||
|
->GetBackBufferSnapshot(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT_UNREACHABLE("Unsupported protocol");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surf) {
|
||||||
|
mExternalSnapshots.InsertOrUpdate(aSyncId, surf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regardless, sync translation so it may resume after attempting snapshot.
|
||||||
|
SyncTranslation(aSyncId);
|
||||||
|
|
||||||
|
if (!surf) {
|
||||||
|
return IPC_FAIL(this, "SnapshotExternalCanvas failed to get surface.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return IPC_OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<gfx::SourceSurface> CanvasTranslator::LookupExternalSnapshot(
|
||||||
|
uint64_t aSyncId) {
|
||||||
|
MOZ_ASSERT(IsInTaskQueue());
|
||||||
|
uint64_t prevSyncId = mLastSyncId;
|
||||||
|
if (NS_WARN_IF(aSyncId > mLastSyncId)) {
|
||||||
|
// If arriving here, a previous SnapshotExternalCanvas IPDL message never
|
||||||
|
// arrived for some reason. Sync translation here to avoid locking up.
|
||||||
|
SyncTranslation(aSyncId);
|
||||||
|
}
|
||||||
|
RefPtr<gfx::SourceSurface> surf;
|
||||||
|
// Check if the snapshot was added. This should only ever be called once per
|
||||||
|
// snapshot, as it is removed from the table when resolved.
|
||||||
|
if (mExternalSnapshots.Remove(aSyncId, getter_AddRefs(surf))) {
|
||||||
|
return surf.forget();
|
||||||
|
}
|
||||||
|
// There was no snapshot available, which can happen if this was called
|
||||||
|
// before or without a corresponding SnapshotExternalCanvas, or if called
|
||||||
|
// multiple times.
|
||||||
|
if (aSyncId > prevSyncId) {
|
||||||
|
gfxCriticalNoteOnce << "External canvas snapshot resolved before creation.";
|
||||||
|
} else {
|
||||||
|
gfxCriticalNoteOnce << "Exernal canvas snapshot already resolved.";
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<gfx::GradientStops> CanvasTranslator::GetOrCreateGradientStops(
|
already_AddRefed<gfx::GradientStops> CanvasTranslator::GetOrCreateGradientStops(
|
||||||
gfx::DrawTarget* aDrawTarget, gfx::GradientStop* aRawStops,
|
gfx::DrawTarget* aDrawTarget, gfx::GradientStop* aRawStops,
|
||||||
uint32_t aNumStops, gfx::ExtendMode aExtendMode) {
|
uint32_t aNumStops, gfx::ExtendMode aExtendMode) {
|
||||||
|
|||||||
@@ -181,6 +181,29 @@ class CanvasTranslator final : public gfx::InlineTranslator,
|
|||||||
|
|
||||||
void PauseTranslation();
|
void PauseTranslation();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a given sync-id to be encountered before resume translation.
|
||||||
|
*/
|
||||||
|
void AwaitTranslationSync(uint64_t aSyncId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal that translation should resume if waiting on the given sync-id.
|
||||||
|
*/
|
||||||
|
void SyncTranslation(uint64_t aSyncId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snapshot an external canvas and label it for later lookup under a sync-id.
|
||||||
|
*/
|
||||||
|
mozilla::ipc::IPCResult RecvSnapshotExternalCanvas(uint64_t aSyncId,
|
||||||
|
uint32_t aManagerId,
|
||||||
|
int32_t aCanvasId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the given sync-id from the recording stream to a snapshot from
|
||||||
|
* an external canvas that was received from an IPDL message.
|
||||||
|
*/
|
||||||
|
already_AddRefed<gfx::SourceSurface> LookupExternalSnapshot(uint64_t aSyncId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the texture and other objects associated with a texture ID.
|
* Removes the texture and other objects associated with a texture ID.
|
||||||
*
|
*
|
||||||
@@ -482,6 +505,18 @@ class CanvasTranslator final : public gfx::InlineTranslator,
|
|||||||
// so long as the checkpoint has not yet been reached.
|
// so long as the checkpoint has not yet been reached.
|
||||||
int64_t mFlushCheckpoint = 0;
|
int64_t mFlushCheckpoint = 0;
|
||||||
|
|
||||||
|
// The sync-id that the translator is awaiting and must be encountered before
|
||||||
|
// it is ready to resume translation.
|
||||||
|
uint64_t mAwaitSyncId = 0;
|
||||||
|
// The last sync-id that was actually encountered.
|
||||||
|
uint64_t mLastSyncId = 0;
|
||||||
|
// A table of external canvas snapshots associated with a given sync-id.
|
||||||
|
nsRefPtrHashtable<nsUint64HashKey, gfx::SourceSurface> mExternalSnapshots;
|
||||||
|
|
||||||
|
// Signal that translation should pause because it is still awaiting a sync-id
|
||||||
|
// that has not been encountered yet.
|
||||||
|
bool PauseUntilSync() const { return mAwaitSyncId > mLastSyncId; }
|
||||||
|
|
||||||
struct CanvasShmem {
|
struct CanvasShmem {
|
||||||
ipc::ReadOnlySharedMemoryMapping shmem;
|
ipc::ReadOnlySharedMemoryMapping shmem;
|
||||||
bool IsValid() const { return shmem.IsValid(); }
|
bool IsValid() const { return shmem.IsValid(); }
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ struct SurfaceDescriptorShared
|
|||||||
|
|
||||||
[Comparable] struct SurfaceDescriptorCanvasSurface {
|
[Comparable] struct SurfaceDescriptorCanvasSurface {
|
||||||
uint32_t managerId;
|
uint32_t managerId;
|
||||||
|
int32_t canvasId;
|
||||||
uintptr_t surfaceId;
|
uintptr_t surfaceId;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ parent:
|
|||||||
*/
|
*/
|
||||||
async DropFreeBuffersWhenDormant();
|
async DropFreeBuffersWhenDormant();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snapshot an external canvas and label it for later lookup under a sync-id.
|
||||||
|
*/
|
||||||
|
async SnapshotExternalCanvas(uint64_t aSyncId, uint32_t aManagerId, int32_t aCanvasId);
|
||||||
|
|
||||||
async __delete__();
|
async __delete__();
|
||||||
|
|
||||||
child:
|
child:
|
||||||
|
|||||||
Reference in New Issue
Block a user