summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc/CanvasChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/ipc/CanvasChild.cpp')
-rw-r--r--gfx/layers/ipc/CanvasChild.cpp164
1 files changed, 132 insertions, 32 deletions
diff --git a/gfx/layers/ipc/CanvasChild.cpp b/gfx/layers/ipc/CanvasChild.cpp
index 553217d82b..515463cd8e 100644
--- a/gfx/layers/ipc/CanvasChild.cpp
+++ b/gfx/layers/ipc/CanvasChild.cpp
@@ -7,6 +7,9 @@
#include "CanvasChild.h"
#include "MainThreadUtils.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRef.h"
+#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/gfx/CanvasManagerChild.h"
#include "mozilla/gfx/DrawTargetRecording.h"
#include "mozilla/gfx/Tools.h"
@@ -18,6 +21,7 @@
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/SourceSurfaceSharedData.h"
#include "mozilla/Maybe.h"
+#include "mozilla/Mutex.h"
#include "nsIObserverService.h"
#include "RecordedCanvasEventImpl.h"
@@ -33,9 +37,9 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers {
~RecorderHelpers() override = default;
- bool InitTranslator(TextureType aTextureType, gfx::BackendType aBackendType,
- Handle&& aReadHandle, nsTArray<Handle>&& aBufferHandles,
- uint64_t aBufferSize,
+ bool InitTranslator(TextureType aTextureType, TextureType aWebglTextureType,
+ gfx::BackendType aBackendType, Handle&& aReadHandle,
+ nsTArray<Handle>&& aBufferHandles, uint64_t aBufferSize,
CrossProcessSemaphoreHandle&& aReaderSem,
CrossProcessSemaphoreHandle&& aWriterSem) override {
NS_ASSERT_OWNINGTHREAD(RecorderHelpers);
@@ -43,7 +47,7 @@ class RecorderHelpers final : public CanvasDrawEventRecorder::Helpers {
return false;
}
return mCanvasChild->SendInitTranslator(
- aTextureType, aBackendType, std::move(aReadHandle),
+ aTextureType, aWebglTextureType, aBackendType, std::move(aReadHandle),
std::move(aBufferHandles), aBufferSize, std::move(aReaderSem),
std::move(aWriterSem));
}
@@ -165,9 +169,104 @@ class SourceSurfaceCanvasRecording final : public gfx::SourceSurface {
bool mDetached = false;
};
-CanvasChild::CanvasChild() = default;
+class CanvasDataShmemHolder {
+ public:
+ CanvasDataShmemHolder(ipc::SharedMemoryBasic* aShmem,
+ CanvasChild* aCanvasChild)
+ : mMutex("CanvasChild::DataShmemHolder::mMutex"),
+ mShmem(aShmem),
+ mCanvasChild(aCanvasChild) {}
+
+ bool Init(dom::ThreadSafeWorkerRef* aWorkerRef) {
+ if (!aWorkerRef) {
+ return true;
+ }
-CanvasChild::~CanvasChild() = default;
+ RefPtr<dom::StrongWorkerRef> workerRef = dom::StrongWorkerRef::Create(
+ aWorkerRef->Private(), "CanvasChild::DataShmemHolder",
+ [this]() { DestroyWorker(); });
+ if (NS_WARN_IF(!workerRef)) {
+ return false;
+ }
+
+ MutexAutoLock lock(mMutex);
+ mWorkerRef = new dom::ThreadSafeWorkerRef(workerRef);
+ return true;
+ }
+
+ void Destroy() {
+ class DestroyRunnable final : public dom::WorkerRunnable {
+ public:
+ DestroyRunnable(dom::WorkerPrivate* aWorkerPrivate,
+ CanvasDataShmemHolder* aShmemHolder)
+ : dom::WorkerRunnable(aWorkerPrivate,
+ "CanvasDataShmemHolder::Destroy",
+ dom::WorkerRunnable::WorkerThread),
+ mShmemHolder(aShmemHolder) {}
+
+ bool WorkerRun(JSContext* aCx,
+ dom::WorkerPrivate* aWorkerPrivate) override {
+ mShmemHolder->Destroy();
+ return true;
+ }
+
+ void PostRun(JSContext* aCx, dom::WorkerPrivate* aWorkerPrivate,
+ bool aRunResult) override {}
+
+ bool PreDispatch(dom::WorkerPrivate* aWorkerPrivate) override {
+ return true;
+ }
+
+ void PostDispatch(dom::WorkerPrivate* aWorkerPrivate,
+ bool aDispatchResult) override {}
+
+ private:
+ CanvasDataShmemHolder* mShmemHolder;
+ };
+
+ mMutex.Lock();
+
+ if (mCanvasChild) {
+ if (mWorkerRef) {
+ if (!mWorkerRef->Private()->IsOnCurrentThread()) {
+ auto task = MakeRefPtr<DestroyRunnable>(mWorkerRef->Private(), this);
+ mMutex.Unlock();
+ task->Dispatch();
+ return;
+ }
+ } else if (!NS_IsMainThread()) {
+ mMutex.Unlock();
+ NS_DispatchToMainThread(NS_NewRunnableFunction(
+ "CanvasDataShmemHolder::Destroy", [this]() { Destroy(); }));
+ return;
+ }
+
+ mCanvasChild->ReturnDataSurfaceShmem(mShmem.forget());
+ mCanvasChild = nullptr;
+ mWorkerRef = nullptr;
+ }
+
+ mMutex.Unlock();
+ delete this;
+ }
+
+ void DestroyWorker() {
+ MutexAutoLock lock(mMutex);
+ mCanvasChild = nullptr;
+ mWorkerRef = nullptr;
+ }
+
+ private:
+ Mutex mMutex;
+ RefPtr<ipc::SharedMemoryBasic> mShmem;
+ RefPtr<CanvasChild> mCanvasChild MOZ_GUARDED_BY(mMutex);
+ RefPtr<dom::ThreadSafeWorkerRef> mWorkerRef MOZ_GUARDED_BY(mMutex);
+};
+
+CanvasChild::CanvasChild(dom::ThreadSafeWorkerRef* aWorkerRef)
+ : mWorkerRef(aWorkerRef) {}
+
+CanvasChild::~CanvasChild() { MOZ_ASSERT(!mWorkerRef); }
static void NotifyCanvasDeviceReset() {
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
@@ -207,14 +306,15 @@ ipc::IPCResult CanvasChild::RecvBlockCanvas() {
}
void CanvasChild::EnsureRecorder(gfx::IntSize aSize, gfx::SurfaceFormat aFormat,
- TextureType aTextureType) {
+ TextureType aTextureType,
+ TextureType aWebglTextureType) {
NS_ASSERT_OWNINGTHREAD(CanvasChild);
if (!mRecorder) {
gfx::BackendType backendType =
gfxPlatform::GetPlatform()->GetPreferredCanvasBackend();
- auto recorder = MakeRefPtr<CanvasDrawEventRecorder>();
- if (!recorder->Init(aTextureType, backendType,
+ auto recorder = MakeRefPtr<CanvasDrawEventRecorder>(mWorkerRef);
+ if (!recorder->Init(aTextureType, aWebglTextureType, backendType,
MakeUnique<RecorderHelpers>(this))) {
return;
}
@@ -242,6 +342,8 @@ void CanvasChild::Destroy() {
if (CanSend()) {
Send__delete__(this);
}
+
+ mWorkerRef = nullptr;
}
bool CanvasChild::EnsureBeginTransaction() {
@@ -397,6 +499,10 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
return nullptr;
}
+ gfx::IntSize ssSize = aSurface->GetSize();
+ gfx::SurfaceFormat ssFormat = aSurface->GetFormat();
+ auto stride = ImageDataSerializer::ComputeRGBStride(ssFormat, ssSize.width);
+
// Shmem is only valid if the surface is the latest snapshot (not detached).
if (!aDetached) {
// If there is a shmem associated with this snapshot id, then we want to try
@@ -411,20 +517,22 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
if (NS_WARN_IF(!mRecorder->WaitForCheckpoint(checkpoint))) {
return nullptr;
}
- gfx::IntSize size = aSurface->GetSize();
- gfx::SurfaceFormat format = aSurface->GetFormat();
- auto stride = ImageDataSerializer::ComputeRGBStride(format, size.width);
+ auto* closure =
+ new CanvasDataShmemHolder(it->second.mSnapshotShmem, this);
+ if (NS_WARN_IF(!closure->Init(mWorkerRef))) {
+ delete closure;
+ return nullptr;
+ }
RefPtr<gfx::DataSourceSurface> dataSurface =
- gfx::Factory::CreateWrappingDataSourceSurface(shmemPtr, stride, size,
- format);
+ gfx::Factory::CreateWrappingDataSourceSurface(
+ shmemPtr, stride, ssSize, ssFormat, ReleaseDataShmemHolder,
+ closure);
return dataSurface.forget();
}
}
RecordEvent(RecordedPrepareDataForSurface(aSurface));
- gfx::IntSize ssSize = aSurface->GetSize();
- gfx::SurfaceFormat ssFormat = aSurface->GetFormat();
if (!EnsureDataSurfaceShmem(ssSize, ssFormat)) {
return nullptr;
}
@@ -435,15 +543,15 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
return nullptr;
}
+ auto* closure = new CanvasDataShmemHolder(mDataSurfaceShmem, this);
+ if (NS_WARN_IF(!closure->Init(mWorkerRef))) {
+ delete closure;
+ return nullptr;
+ }
+
mDataSurfaceShmemAvailable = false;
- struct DataShmemHolder {
- RefPtr<ipc::SharedMemoryBasic> shmem;
- RefPtr<CanvasChild> canvasChild;
- };
auto* data = static_cast<uint8_t*>(mDataSurfaceShmem->memory());
- auto* closure = new DataShmemHolder{do_AddRef(mDataSurfaceShmem), this};
- auto stride = ImageDataSerializer::ComputeRGBStride(ssFormat, ssSize.width);
RefPtr<gfx::DataSourceSurface> dataSurface =
gfx::Factory::CreateWrappingDataSourceSurface(
@@ -452,16 +560,8 @@ already_AddRefed<gfx::DataSourceSurface> CanvasChild::GetDataSurface(
}
/* static */ void CanvasChild::ReleaseDataShmemHolder(void* aClosure) {
- if (!NS_IsMainThread()) {
- NS_DispatchToMainThread(NS_NewRunnableFunction(
- "CanvasChild::ReleaseDataShmemHolder",
- [aClosure]() { ReleaseDataShmemHolder(aClosure); }));
- return;
- }
-
- auto* shmemHolder = static_cast<DataShmemHolder*>(aClosure);
- shmemHolder->canvasChild->ReturnDataSurfaceShmem(shmemHolder->shmem.forget());
- delete shmemHolder;
+ auto* shmemHolder = static_cast<CanvasDataShmemHolder*>(aClosure);
+ shmemHolder->Destroy();
}
already_AddRefed<gfx::SourceSurface> CanvasChild::WrapSurface(