Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 "VideoBridgeChild.h"
#include "VideoBridgeParent.h"
#include "CompositorThread.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/ipc/Endpoint.h"
#include "mozilla/StaticMutex.h"
#include "transport/runnable_utils.h"
#include "SynchronousTask.h"
namespace mozilla {
namespace layers {
// Singleton
static StaticMutex sVideoBridgeLock MOZ_UNANNOTATED;
StaticRefPtr<VideoBridgeChild> sVideoBridge;
/* static */
void VideoBridgeChild::StartupForGPUProcess() {
ipc::Endpoint<PVideoBridgeParent> parentPipe;
ipc::Endpoint<PVideoBridgeChild> childPipe;
PVideoBridge::CreateEndpoints(ipc::EndpointProcInfo::Current(),
ipc::EndpointProcInfo::Current(), &parentPipe,
&childPipe);
VideoBridgeChild::Open(std::move(childPipe));
VideoBridgeParent::Open(std::move(parentPipe), VideoBridgeSource::GpuProcess);
}
/* static */
void VideoBridgeChild::Open(Endpoint<PVideoBridgeChild>&& aEndpoint) {
StaticMutexAutoLock lock(sVideoBridgeLock);
MOZ_ASSERT(!sVideoBridge || !sVideoBridge->CanSend());
sVideoBridge = new VideoBridgeChild();
if (!aEndpoint.Bind(sVideoBridge)) {
// We can't recover from this.
MOZ_CRASH("Failed to bind VideoBridgeChild to endpoint");
}
}
/* static */
void VideoBridgeChild::Shutdown() {
StaticMutexAutoLock lock(sVideoBridgeLock);
if (sVideoBridge) {
sVideoBridge->Close();
sVideoBridge = nullptr;
}
}
VideoBridgeChild::VideoBridgeChild()
: mThread(GetCurrentSerialEventTarget()), mCanSend(true) {}
VideoBridgeChild::~VideoBridgeChild() = default;
VideoBridgeChild* VideoBridgeChild::GetSingleton() {
StaticMutexAutoLock lock(sVideoBridgeLock);
return sVideoBridge;
}
bool VideoBridgeChild::AllocUnsafeShmem(size_t aSize, ipc::Shmem* aShmem) {
if (!mThread->IsOnCurrentThread()) {
return DispatchAllocShmemInternal(aSize, aShmem, true); // true: unsafe
}
if (!CanSend()) {
return false;
}
return PVideoBridgeChild::AllocUnsafeShmem(aSize, aShmem);
}
bool VideoBridgeChild::AllocShmem(size_t aSize, ipc::Shmem* aShmem) {
MOZ_ASSERT(CanSend());
return PVideoBridgeChild::AllocShmem(aSize, aShmem);
}
void VideoBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize,
ipc::Shmem* aShmem, bool aUnsafe,
bool* aSuccess) {
AutoCompleteTask complete(aTask);
if (!CanSend()) {
return;
}
bool ok = false;
if (aUnsafe) {
ok = AllocUnsafeShmem(aSize, aShmem);
} else {
ok = AllocShmem(aSize, aShmem);
}
*aSuccess = ok;
}
bool VideoBridgeChild::DispatchAllocShmemInternal(size_t aSize,
ipc::Shmem* aShmem,
bool aUnsafe) {
SynchronousTask task("AllocatorProxy alloc");
bool success = false;
RefPtr<Runnable> runnable = WrapRunnable(
RefPtr<VideoBridgeChild>(this), &VideoBridgeChild::ProxyAllocShmemNow,
&task, aSize, aShmem, aUnsafe, &success);
GetThread()->Dispatch(runnable.forget());
task.Wait();
return success;
}
void VideoBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask,
ipc::Shmem* aShmem, bool* aResult) {
AutoCompleteTask complete(aTask);
if (!CanSend()) {
return;
}
*aResult = DeallocShmem(*aShmem);
}
bool VideoBridgeChild::DeallocShmem(ipc::Shmem& aShmem) {
if (GetThread()->IsOnCurrentThread()) {
if (!CanSend()) {
return false;
}
return PVideoBridgeChild::DeallocShmem(aShmem);
}
SynchronousTask task("AllocatorProxy Dealloc");
bool result = false;
RefPtr<Runnable> runnable = WrapRunnable(
RefPtr<VideoBridgeChild>(this), &VideoBridgeChild::ProxyDeallocShmemNow,
&task, &aShmem, &result);
GetThread()->Dispatch(runnable.forget());
task.Wait();
return result;
}
PTextureChild* VideoBridgeChild::AllocPTextureChild(
const SurfaceDescriptor&, ReadLockDescriptor&, const LayersBackend&,
const TextureFlags&, const dom::ContentParentId& aContentId,
const uint64_t& aSerial) {
MOZ_ASSERT(CanSend());
return TextureClient::CreateIPDLActor();
}
bool VideoBridgeChild::DeallocPTextureChild(PTextureChild* actor) {
return TextureClient::DestroyIPDLActor(actor);
}
void VideoBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
mCanSend = false;
}
PTextureChild* VideoBridgeChild::CreateTexture(
const SurfaceDescriptor& aSharedData, ReadLockDescriptor&& aReadLock,
LayersBackend aLayersBackend, TextureFlags aFlags,
const dom::ContentParentId& aContentId, uint64_t aSerial,
wr::MaybeExternalImageId& aExternalImageId) {
MOZ_ASSERT(CanSend());
return SendPTextureConstructor(aSharedData, std::move(aReadLock),
aLayersBackend, aFlags, aContentId, aSerial);
}
bool VideoBridgeChild::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}
void VideoBridgeChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID());
}
mozilla::ipc::IPCResult VideoBridgeChild::RecvPing(PingResolver&& aResolver) {
aResolver(void_t{});
return IPC_OK();
}
} // namespace layers
} // namespace mozilla