mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 1855742 - Part 2. Allow CanvasDrawEventRecorder to be created on DOM workers. r=gfx-reviewers,lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D189530
This commit is contained in:
parent
39d3e5d31c
commit
c743180764
@ -1987,7 +1987,7 @@ class DrawTarget : public external::AtomicRefCounted<DrawTarget> {
|
|||||||
SurfaceFormat mFormat;
|
SurfaceFormat mFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawEventRecorder : public RefCounted<DrawEventRecorder> {
|
class DrawEventRecorder : public external::AtomicRefCounted<DrawEventRecorder> {
|
||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
|
||||||
virtual RecorderType GetRecorderType() const { return RecorderType::UNKNOWN; }
|
virtual RecorderType GetRecorderType() const { return RecorderType::UNKNOWN; }
|
||||||
|
@ -16,9 +16,7 @@ namespace gfx {
|
|||||||
|
|
||||||
DrawEventRecorderPrivate::DrawEventRecorderPrivate() : mExternalFonts(false) {}
|
DrawEventRecorderPrivate::DrawEventRecorderPrivate() : mExternalFonts(false) {}
|
||||||
|
|
||||||
DrawEventRecorderPrivate::~DrawEventRecorderPrivate() {
|
DrawEventRecorderPrivate::~DrawEventRecorderPrivate() = default;
|
||||||
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DrawEventRecorderPrivate::SetDrawTarget(ReferencePtr aDT) {
|
void DrawEventRecorderPrivate::SetDrawTarget(ReferencePtr aDT) {
|
||||||
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
||||||
|
@ -41,7 +41,7 @@ class DrawEventRecorderPrivate : public DrawEventRecorder {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
virtual void FlushItem(IntRect) {}
|
virtual void FlushItem(IntRect) {}
|
||||||
void DetachResources() {
|
virtual void DetachResources() {
|
||||||
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
||||||
|
|
||||||
nsTHashSet<ScaledFont*> fonts = std::move(mStoredFonts);
|
nsTHashSet<ScaledFont*> fonts = std::move(mStoredFonts);
|
||||||
@ -116,7 +116,7 @@ class DrawEventRecorderPrivate : public DrawEventRecorder {
|
|||||||
return mStoredObjects.EnsureInserted(aObject);
|
return mStoredObjects.EnsureInserted(aObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddPendingDeletion(std::function<void()>&& aPendingDeletion) {
|
virtual void AddPendingDeletion(std::function<void()>&& aPendingDeletion) {
|
||||||
auto lockedPendingDeletions = mPendingDeletions.Lock();
|
auto lockedPendingDeletions = mPendingDeletions.Lock();
|
||||||
lockedPendingDeletions->emplace_back(std::move(aPendingDeletion));
|
lockedPendingDeletions->emplace_back(std::move(aPendingDeletion));
|
||||||
}
|
}
|
||||||
|
@ -224,8 +224,9 @@ RefPtr<layers::CanvasChild> CanvasManagerChild::GetCanvasChild() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mCanvasChild) {
|
if (!mCanvasChild) {
|
||||||
mCanvasChild = MakeAndAddRef<layers::CanvasChild>();
|
mCanvasChild = MakeAndAddRef<layers::CanvasChild>(mWorkerRef);
|
||||||
if (!SendPCanvasConstructor(mCanvasChild)) {
|
if (!SendPCanvasConstructor(mCanvasChild)) {
|
||||||
|
mCanvasChild->Destroy();
|
||||||
mCanvasChild = nullptr;
|
mCanvasChild = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,11 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "mozilla/dom/WorkerCommon.h"
|
||||||
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
|
#include "mozilla/dom/WorkerRef.h"
|
||||||
|
#include "mozilla/dom/WorkerRunnable.h"
|
||||||
|
#include "mozilla/layers/TextureRecorded.h"
|
||||||
#include "mozilla/layers/SharedSurfacesChild.h"
|
#include "mozilla/layers/SharedSurfacesChild.h"
|
||||||
#include "mozilla/StaticPrefs_gfx.h"
|
#include "mozilla/StaticPrefs_gfx.h"
|
||||||
#include "RecordedCanvasEventImpl.h"
|
#include "RecordedCanvasEventImpl.h"
|
||||||
@ -34,7 +39,9 @@ static Maybe<ShmemAndHandle> CreateAndMapShmem(size_t aSize) {
|
|||||||
return Some(ShmemAndHandle{shmem.forget(), std::move(shmemHandle)});
|
return Some(ShmemAndHandle{shmem.forget(), std::move(shmemHandle)});
|
||||||
}
|
}
|
||||||
|
|
||||||
CanvasDrawEventRecorder::CanvasDrawEventRecorder() {
|
CanvasDrawEventRecorder::CanvasDrawEventRecorder(
|
||||||
|
dom::ThreadSafeWorkerRef* aWorkerRef)
|
||||||
|
: mWorkerRef(aWorkerRef), mIsOnWorker(!!aWorkerRef) {
|
||||||
mDefaultBufferSize = ipc::SharedMemory::PageAlignedSize(
|
mDefaultBufferSize = ipc::SharedMemory::PageAlignedSize(
|
||||||
StaticPrefs::gfx_canvas_remote_default_buffer_size());
|
StaticPrefs::gfx_canvas_remote_default_buffer_size());
|
||||||
mMaxDefaultBuffers = StaticPrefs::gfx_canvas_remote_max_default_buffers();
|
mMaxDefaultBuffers = StaticPrefs::gfx_canvas_remote_max_default_buffers();
|
||||||
@ -43,6 +50,8 @@ CanvasDrawEventRecorder::CanvasDrawEventRecorder() {
|
|||||||
mDropBufferOnZero = mDropBufferLimit;
|
mDropBufferOnZero = mDropBufferLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CanvasDrawEventRecorder::~CanvasDrawEventRecorder() { MOZ_ASSERT(!mWorkerRef); }
|
||||||
|
|
||||||
bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
|
bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
|
||||||
gfx::BackendType aBackendType,
|
gfx::BackendType aBackendType,
|
||||||
UniquePtr<Helpers> aHelpers) {
|
UniquePtr<Helpers> aHelpers) {
|
||||||
@ -317,6 +326,106 @@ void CanvasDrawEventRecorder::CheckAndSignalReader() {
|
|||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CanvasDrawEventRecorder::DetachResources() {
|
||||||
|
NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder);
|
||||||
|
|
||||||
|
DrawEventRecorderPrivate::DetachResources();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lockedPendingDeletions = mPendingDeletions.Lock();
|
||||||
|
mWorkerRef = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasDrawEventRecorder::QueueProcessPendingDeletionsLocked(
|
||||||
|
RefPtr<CanvasDrawEventRecorder>&& aRecorder) {
|
||||||
|
if (!mWorkerRef) {
|
||||||
|
MOZ_RELEASE_ASSERT(
|
||||||
|
!mIsOnWorker,
|
||||||
|
"QueueProcessPendingDeletionsLocked called after worker shutdown!");
|
||||||
|
|
||||||
|
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||||
|
"CanvasDrawEventRecorder::QueueProcessPendingDeletionsLocked",
|
||||||
|
[self = std::move(aRecorder)]() { self->ProcessPendingDeletions(); }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NS_IsMainThread()) {
|
||||||
|
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||||
|
"CanvasDrawEventRecorder::QueueProcessPendingDeletionsLocked",
|
||||||
|
[self = std::move(aRecorder)]() mutable {
|
||||||
|
self->QueueProcessPendingDeletions(std::move(self));
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProcessPendingRunnable final : public dom::WorkerRunnable {
|
||||||
|
public:
|
||||||
|
ProcessPendingRunnable(dom::WorkerPrivate* aWorkerPrivate,
|
||||||
|
RefPtr<CanvasDrawEventRecorder>&& aRecorder)
|
||||||
|
: dom::WorkerRunnable(aWorkerPrivate),
|
||||||
|
mRecorder(std::move(aRecorder)) {}
|
||||||
|
|
||||||
|
bool WorkerRun(JSContext*, dom::WorkerPrivate*) override {
|
||||||
|
RefPtr<CanvasDrawEventRecorder> recorder = std::move(mRecorder);
|
||||||
|
recorder->ProcessPendingDeletions();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RefPtr<CanvasDrawEventRecorder> mRecorder;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto task = MakeRefPtr<ProcessPendingRunnable>(mWorkerRef->Private(),
|
||||||
|
std::move(aRecorder));
|
||||||
|
if (NS_WARN_IF(!task->Dispatch())) {
|
||||||
|
MOZ_CRASH("ProcessPendingRunnable leaked!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasDrawEventRecorder::QueueProcessPendingDeletions(
|
||||||
|
RefPtr<CanvasDrawEventRecorder>&& aRecorder) {
|
||||||
|
auto lockedPendingDeletions = mPendingDeletions.Lock();
|
||||||
|
if (lockedPendingDeletions->empty()) {
|
||||||
|
// We raced to handle the deletions, and something got there first.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueProcessPendingDeletionsLocked(std::move(aRecorder));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasDrawEventRecorder::AddPendingDeletion(
|
||||||
|
std::function<void()>&& aPendingDeletion) {
|
||||||
|
PendingDeletionsVector pendingDeletions;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lockedPendingDeletions = mPendingDeletions.Lock();
|
||||||
|
bool wasEmpty = lockedPendingDeletions->empty();
|
||||||
|
lockedPendingDeletions->emplace_back(std::move(aPendingDeletion));
|
||||||
|
|
||||||
|
MOZ_RELEASE_ASSERT(!mIsOnWorker || mWorkerRef,
|
||||||
|
"AddPendingDeletion called after worker shutdown!");
|
||||||
|
|
||||||
|
// If we are not on the owning thread, we must queue an event to run the
|
||||||
|
// deletions, if we transitioned from empty to non-empty.
|
||||||
|
if ((mWorkerRef && !mWorkerRef->Private()->IsOnCurrentThread()) ||
|
||||||
|
(!mWorkerRef && !NS_IsMainThread())) {
|
||||||
|
if (wasEmpty) {
|
||||||
|
RefPtr<CanvasDrawEventRecorder> self(this);
|
||||||
|
QueueProcessPendingDeletionsLocked(std::move(self));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we can just run all of them right now.
|
||||||
|
pendingDeletions.swap(*lockedPendingDeletions);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& pendingDeletion : pendingDeletions) {
|
||||||
|
pendingDeletion();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CanvasDrawEventRecorder::StoreSourceSurfaceRecording(
|
void CanvasDrawEventRecorder::StoreSourceSurfaceRecording(
|
||||||
gfx::SourceSurface* aSurface, const char* aReason) {
|
gfx::SourceSurface* aSurface, const char* aReason) {
|
||||||
NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder);
|
NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder);
|
||||||
|
@ -21,6 +21,10 @@ namespace mozilla {
|
|||||||
|
|
||||||
using EventType = gfx::RecordedEvent::EventType;
|
using EventType = gfx::RecordedEvent::EventType;
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
class ThreadSafeWorkerRef;
|
||||||
|
}
|
||||||
|
|
||||||
namespace layers {
|
namespace layers {
|
||||||
|
|
||||||
typedef mozilla::ipc::SharedMemoryBasic::Handle Handle;
|
typedef mozilla::ipc::SharedMemoryBasic::Handle Handle;
|
||||||
@ -31,7 +35,8 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
|||||||
public:
|
public:
|
||||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final)
|
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final)
|
||||||
|
|
||||||
CanvasDrawEventRecorder();
|
explicit CanvasDrawEventRecorder(dom::ThreadSafeWorkerRef* aWorkerRef);
|
||||||
|
~CanvasDrawEventRecorder() override;
|
||||||
|
|
||||||
enum class State : uint32_t {
|
enum class State : uint32_t {
|
||||||
Processing,
|
Processing,
|
||||||
@ -98,6 +103,10 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
|||||||
*/
|
*/
|
||||||
void RecordEvent(const gfx::RecordedEvent& aEvent) final;
|
void RecordEvent(const gfx::RecordedEvent& aEvent) final;
|
||||||
|
|
||||||
|
void DetachResources() final;
|
||||||
|
|
||||||
|
void AddPendingDeletion(std::function<void()>&& aPendingDeletion) override;
|
||||||
|
|
||||||
void StoreSourceSurfaceRecording(gfx::SourceSurface* aSurface,
|
void StoreSourceSurfaceRecording(gfx::SourceSurface* aSurface,
|
||||||
const char* aReason) final;
|
const char* aReason) final;
|
||||||
|
|
||||||
@ -134,6 +143,11 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
|||||||
|
|
||||||
void CheckAndSignalReader();
|
void CheckAndSignalReader();
|
||||||
|
|
||||||
|
void QueueProcessPendingDeletions(
|
||||||
|
RefPtr<CanvasDrawEventRecorder>&& aRecorder);
|
||||||
|
void QueueProcessPendingDeletionsLocked(
|
||||||
|
RefPtr<CanvasDrawEventRecorder>&& aRecorder);
|
||||||
|
|
||||||
size_t mDefaultBufferSize;
|
size_t mDefaultBufferSize;
|
||||||
size_t mMaxDefaultBuffers;
|
size_t mMaxDefaultBuffers;
|
||||||
uint32_t mMaxSpinCount;
|
uint32_t mMaxSpinCount;
|
||||||
@ -173,6 +187,9 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
|||||||
|
|
||||||
UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
|
UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
|
||||||
UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
|
UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
|
||||||
|
|
||||||
|
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
|
||||||
|
bool mIsOnWorker = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace layers
|
} // namespace layers
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "CanvasChild.h"
|
#include "CanvasChild.h"
|
||||||
|
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
|
#include "mozilla/dom/WorkerRef.h"
|
||||||
#include "mozilla/gfx/CanvasManagerChild.h"
|
#include "mozilla/gfx/CanvasManagerChild.h"
|
||||||
#include "mozilla/gfx/DrawTargetRecording.h"
|
#include "mozilla/gfx/DrawTargetRecording.h"
|
||||||
#include "mozilla/gfx/Tools.h"
|
#include "mozilla/gfx/Tools.h"
|
||||||
@ -165,9 +166,10 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
|
|||||||
bool mDetached = false;
|
bool mDetached = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
CanvasChild::CanvasChild() = default;
|
CanvasChild::CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef)
|
||||||
|
: mWorkerRef(aWorkerRef) {}
|
||||||
|
|
||||||
CanvasChild::~CanvasChild() = default;
|
CanvasChild::~CanvasChild() { MOZ_ASSERT(!mWorkerRef); }
|
||||||
|
|
||||||
static void NotifyCanvasDeviceReset() {
|
static void NotifyCanvasDeviceReset() {
|
||||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||||
@ -213,7 +215,7 @@ void CanvasChild::EnsureRecorder(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
|||||||
if (!mRecorder) {
|
if (!mRecorder) {
|
||||||
gfx::BackendType backendType =
|
gfx::BackendType backendType =
|
||||||
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
||||||
auto recorder = MakeRefPtr<CanvasDrawEventRecorder>();
|
auto recorder = MakeRefPtr<CanvasDrawEventRecorder>(mWorkerRef);
|
||||||
if (!recorder->Init(aTextureType, backendType,
|
if (!recorder->Init(aTextureType, backendType,
|
||||||
MakeUnique<RecorderHelpers>(this))) {
|
MakeUnique<RecorderHelpers>(this))) {
|
||||||
return;
|
return;
|
||||||
@ -242,6 +244,8 @@ void CanvasChild::Destroy() {
|
|||||||
if (CanSend()) {
|
if (CanSend()) {
|
||||||
Send__delete__(this);
|
Send__delete__(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mWorkerRef = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanvasChild::EnsureBeginTransaction() {
|
bool CanvasChild::EnsureBeginTransaction() {
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
namespace dom {
|
||||||
|
class ThreadSafeWorkerRef;
|
||||||
|
}
|
||||||
|
|
||||||
namespace gfx {
|
namespace gfx {
|
||||||
class DrawTargetRecording;
|
class DrawTargetRecording;
|
||||||
class SourceSurface;
|
class SourceSurface;
|
||||||
@ -28,7 +32,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
|
|||||||
public:
|
public:
|
||||||
NS_INLINE_DECL_REFCOUNTING(CanvasChild)
|
NS_INLINE_DECL_REFCOUNTING(CanvasChild)
|
||||||
|
|
||||||
CanvasChild();
|
explicit CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns true if remote canvas has been deactivated due to failure.
|
* @returns true if remote canvas has been deactivated due to failure.
|
||||||
@ -173,6 +177,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
|
|||||||
|
|
||||||
static bool mDeactivated;
|
static bool mDeactivated;
|
||||||
|
|
||||||
|
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
|
||||||
RefPtr<CanvasDrawEventRecorder> mRecorder;
|
RefPtr<CanvasDrawEventRecorder> mRecorder;
|
||||||
|
|
||||||
RefPtr<ipc::SharedMemoryBasic> mDataSurfaceShmem;
|
RefPtr<ipc::SharedMemoryBasic> mDataSurfaceShmem;
|
||||||
|
Loading…
Reference in New Issue
Block a user