2018-12-02 17:19:11 +03:00
|
|
|
/* -*- 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"
|
2018-12-02 17:22:28 +03:00
|
|
|
#include "mozilla/SharedThreadPool.h"
|
|
|
|
#include "prsystem.h"
|
2018-12-02 17:19:11 +03:00
|
|
|
|
|
|
|
#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;
|
2018-12-02 17:22:28 +03:00
|
|
|
static StaticRefPtr<nsIThreadPool> sCanvasWorkers;
|
|
|
|
static bool sShuttingDown = false;
|
2018-12-02 17:19:11 +03:00
|
|
|
|
|
|
|
static MessageLoop* CanvasPlaybackLoop() {
|
2018-12-02 17:22:28 +03:00
|
|
|
if (!sCanvasThread && !sShuttingDown) {
|
2018-12-02 17:19:11 +03:00
|
|
|
MOZ_ASSERT(NS_IsInCompositorThread());
|
|
|
|
base::Thread* canvasThread = new base::Thread("Canvas");
|
|
|
|
if (canvasThread->Start()) {
|
|
|
|
sCanvasThread = canvasThread;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-02 17:22:28 +03:00
|
|
|
return sCanvasThread ? sCanvasThread->message_loop() : nullptr;
|
2018-12-02 17:19:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */
|
|
|
|
already_AddRefed<CanvasParent> CanvasParent::Create(
|
|
|
|
ipc::Endpoint<PCanvasParent>&& aEndpoint) {
|
|
|
|
MOZ_ASSERT(NS_IsInCompositorThread());
|
|
|
|
|
2018-12-02 17:22:28 +03:00
|
|
|
if (sShuttingDown) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-12-02 17:19:11 +03:00
|
|
|
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() {
|
2018-12-02 17:22:28 +03:00
|
|
|
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);
|
2018-12-02 17:19:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void CanvasParent::Shutdown() {
|
2018-12-02 17:22:28 +03:00
|
|
|
sShuttingDown = true;
|
|
|
|
|
2018-12-02 17:19:11 +03:00
|
|
|
if (sCanvasThread) {
|
2018-12-02 17:22:28 +03:00
|
|
|
sCanvasThread->Stop();
|
2018-12-02 17:19:11 +03:00
|
|
|
delete sCanvasThread;
|
|
|
|
sCanvasThread = nullptr;
|
|
|
|
}
|
2018-12-02 17:22:28 +03:00
|
|
|
|
|
|
|
if (sCanvasWorkers) {
|
|
|
|
sCanvasWorkers->Shutdown();
|
|
|
|
sCanvasWorkers = nullptr;
|
|
|
|
}
|
2018-12-02 17:19:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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.");
|
|
|
|
}
|
|
|
|
|
2018-12-02 17:22:28 +03:00
|
|
|
PostStartTranslationTask(nsIThread::DISPATCH_NORMAL);
|
2018-12-02 17:19:11 +03:00
|
|
|
|
|
|
|
return IPC_OK();
|
|
|
|
}
|
|
|
|
|
2018-12-02 17:22:28 +03:00
|
|
|
void CanvasParent::PostStartTranslationTask(uint32_t aDispatchFlags) {
|
|
|
|
if (sShuttingDown) {
|
|
|
|
return;
|
2018-12-02 17:19:11 +03:00
|
|
|
}
|
2018-12-02 17:22:28 +03:00
|
|
|
|
|
|
|
RefPtr<nsIThreadPool> canvasWorkers = GetCanvasWorkers();
|
|
|
|
RefPtr<Runnable> runnable = NewRunnableMethod(
|
|
|
|
"CanvasParent::StartTranslation", this, &CanvasParent::StartTranslation);
|
|
|
|
canvasWorkers->Dispatch(runnable.forget(), aDispatchFlags);
|
2018-12-02 17:19:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasParent::StartTranslation() {
|
|
|
|
if (!mTranslator->TranslateRecording()) {
|
2018-12-02 17:22:28 +03:00
|
|
|
PostStartTranslationTask(nsIThread::DISPATCH_AT_END);
|
2018-12-02 17:19:11 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UniquePtr<SurfaceDescriptor>
|
|
|
|
CanvasParent::LookupSurfaceDescriptorForClientDrawTarget(
|
|
|
|
const uintptr_t aDrawTarget) {
|
|
|
|
return mTranslator->WaitForSurfaceDescriptor(
|
|
|
|
reinterpret_cast<void*>(aDrawTarget));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CanvasParent::DeallocPCanvasParent() { mSelfRef = nullptr; }
|
|
|
|
|
|
|
|
} // namespace layers
|
|
|
|
} // namespace mozilla
|