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;
|
||||
};
|
||||
|
||||
class DrawEventRecorder : public RefCounted<DrawEventRecorder> {
|
||||
class DrawEventRecorder : public external::AtomicRefCounted<DrawEventRecorder> {
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorder)
|
||||
virtual RecorderType GetRecorderType() const { return RecorderType::UNKNOWN; }
|
||||
|
@ -16,9 +16,7 @@ namespace gfx {
|
||||
|
||||
DrawEventRecorderPrivate::DrawEventRecorderPrivate() : mExternalFonts(false) {}
|
||||
|
||||
DrawEventRecorderPrivate::~DrawEventRecorderPrivate() {
|
||||
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
||||
}
|
||||
DrawEventRecorderPrivate::~DrawEventRecorderPrivate() = default;
|
||||
|
||||
void DrawEventRecorderPrivate::SetDrawTarget(ReferencePtr aDT) {
|
||||
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
||||
|
@ -41,7 +41,7 @@ class DrawEventRecorderPrivate : public DrawEventRecorder {
|
||||
return true;
|
||||
}
|
||||
virtual void FlushItem(IntRect) {}
|
||||
void DetachResources() {
|
||||
virtual void DetachResources() {
|
||||
NS_ASSERT_OWNINGTHREAD(DrawEventRecorderPrivate);
|
||||
|
||||
nsTHashSet<ScaledFont*> fonts = std::move(mStoredFonts);
|
||||
@ -116,7 +116,7 @@ class DrawEventRecorderPrivate : public DrawEventRecorder {
|
||||
return mStoredObjects.EnsureInserted(aObject);
|
||||
}
|
||||
|
||||
void AddPendingDeletion(std::function<void()>&& aPendingDeletion) {
|
||||
virtual void AddPendingDeletion(std::function<void()>&& aPendingDeletion) {
|
||||
auto lockedPendingDeletions = mPendingDeletions.Lock();
|
||||
lockedPendingDeletions->emplace_back(std::move(aPendingDeletion));
|
||||
}
|
||||
|
@ -224,8 +224,9 @@ RefPtr<layers::CanvasChild> CanvasManagerChild::GetCanvasChild() {
|
||||
}
|
||||
|
||||
if (!mCanvasChild) {
|
||||
mCanvasChild = MakeAndAddRef<layers::CanvasChild>();
|
||||
mCanvasChild = MakeAndAddRef<layers::CanvasChild>(mWorkerRef);
|
||||
if (!SendPCanvasConstructor(mCanvasChild)) {
|
||||
mCanvasChild->Destroy();
|
||||
mCanvasChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,11 @@
|
||||
|
||||
#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/StaticPrefs_gfx.h"
|
||||
#include "RecordedCanvasEventImpl.h"
|
||||
@ -34,7 +39,9 @@ static Maybe<ShmemAndHandle> CreateAndMapShmem(size_t aSize) {
|
||||
return Some(ShmemAndHandle{shmem.forget(), std::move(shmemHandle)});
|
||||
}
|
||||
|
||||
CanvasDrawEventRecorder::CanvasDrawEventRecorder() {
|
||||
CanvasDrawEventRecorder::CanvasDrawEventRecorder(
|
||||
dom::ThreadSafeWorkerRef* aWorkerRef)
|
||||
: mWorkerRef(aWorkerRef), mIsOnWorker(!!aWorkerRef) {
|
||||
mDefaultBufferSize = ipc::SharedMemory::PageAlignedSize(
|
||||
StaticPrefs::gfx_canvas_remote_default_buffer_size());
|
||||
mMaxDefaultBuffers = StaticPrefs::gfx_canvas_remote_max_default_buffers();
|
||||
@ -43,6 +50,8 @@ CanvasDrawEventRecorder::CanvasDrawEventRecorder() {
|
||||
mDropBufferOnZero = mDropBufferLimit;
|
||||
}
|
||||
|
||||
CanvasDrawEventRecorder::~CanvasDrawEventRecorder() { MOZ_ASSERT(!mWorkerRef); }
|
||||
|
||||
bool CanvasDrawEventRecorder::Init(TextureType aTextureType,
|
||||
gfx::BackendType aBackendType,
|
||||
UniquePtr<Helpers> aHelpers) {
|
||||
@ -317,6 +326,106 @@ void CanvasDrawEventRecorder::CheckAndSignalReader() {
|
||||
} 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(
|
||||
gfx::SourceSurface* aSurface, const char* aReason) {
|
||||
NS_ASSERT_OWNINGTHREAD(CanvasDrawEventRecorder);
|
||||
|
@ -21,6 +21,10 @@ namespace mozilla {
|
||||
|
||||
using EventType = gfx::RecordedEvent::EventType;
|
||||
|
||||
namespace dom {
|
||||
class ThreadSafeWorkerRef;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
|
||||
typedef mozilla::ipc::SharedMemoryBasic::Handle Handle;
|
||||
@ -31,7 +35,8 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final)
|
||||
|
||||
CanvasDrawEventRecorder();
|
||||
explicit CanvasDrawEventRecorder(dom::ThreadSafeWorkerRef* aWorkerRef);
|
||||
~CanvasDrawEventRecorder() override;
|
||||
|
||||
enum class State : uint32_t {
|
||||
Processing,
|
||||
@ -98,6 +103,10 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
||||
*/
|
||||
void RecordEvent(const gfx::RecordedEvent& aEvent) final;
|
||||
|
||||
void DetachResources() final;
|
||||
|
||||
void AddPendingDeletion(std::function<void()>&& aPendingDeletion) override;
|
||||
|
||||
void StoreSourceSurfaceRecording(gfx::SourceSurface* aSurface,
|
||||
const char* aReason) final;
|
||||
|
||||
@ -134,6 +143,11 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
||||
|
||||
void CheckAndSignalReader();
|
||||
|
||||
void QueueProcessPendingDeletions(
|
||||
RefPtr<CanvasDrawEventRecorder>&& aRecorder);
|
||||
void QueueProcessPendingDeletionsLocked(
|
||||
RefPtr<CanvasDrawEventRecorder>&& aRecorder);
|
||||
|
||||
size_t mDefaultBufferSize;
|
||||
size_t mMaxDefaultBuffers;
|
||||
uint32_t mMaxSpinCount;
|
||||
@ -173,6 +187,9 @@ class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate,
|
||||
|
||||
UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
|
||||
UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
|
||||
|
||||
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
|
||||
bool mIsOnWorker = false;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "CanvasChild.h"
|
||||
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/dom/WorkerRef.h"
|
||||
#include "mozilla/gfx/CanvasManagerChild.h"
|
||||
#include "mozilla/gfx/DrawTargetRecording.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
@ -165,9 +166,10 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
|
||||
bool mDetached = false;
|
||||
};
|
||||
|
||||
CanvasChild::CanvasChild() = default;
|
||||
CanvasChild::CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef)
|
||||
: mWorkerRef(aWorkerRef) {}
|
||||
|
||||
CanvasChild::~CanvasChild() = default;
|
||||
CanvasChild::~CanvasChild() { MOZ_ASSERT(!mWorkerRef); }
|
||||
|
||||
static void NotifyCanvasDeviceReset() {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
@ -213,7 +215,7 @@ void CanvasChild::EnsureRecorder(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
|
||||
if (!mRecorder) {
|
||||
gfx::BackendType backendType =
|
||||
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
|
||||
auto recorder = MakeRefPtr<CanvasDrawEventRecorder>();
|
||||
auto recorder = MakeRefPtr<CanvasDrawEventRecorder>(mWorkerRef);
|
||||
if (!recorder->Init(aTextureType, backendType,
|
||||
MakeUnique<RecorderHelpers>(this))) {
|
||||
return;
|
||||
@ -242,6 +244,8 @@ void CanvasChild::Destroy() {
|
||||
if (CanSend()) {
|
||||
Send__delete__(this);
|
||||
}
|
||||
|
||||
mWorkerRef = nullptr;
|
||||
}
|
||||
|
||||
bool CanvasChild::EnsureBeginTransaction() {
|
||||
|
@ -15,6 +15,10 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class ThreadSafeWorkerRef;
|
||||
}
|
||||
|
||||
namespace gfx {
|
||||
class DrawTargetRecording;
|
||||
class SourceSurface;
|
||||
@ -28,7 +32,7 @@ class CanvasChild final : public PCanvasChild, public SupportsWeakPtr {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(CanvasChild)
|
||||
|
||||
CanvasChild();
|
||||
explicit CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef);
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef;
|
||||
RefPtr<CanvasDrawEventRecorder> mRecorder;
|
||||
|
||||
RefPtr<ipc::SharedMemoryBasic> mDataSurfaceShmem;
|
||||
|
Loading…
Reference in New Issue
Block a user