/* -*- 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 "VsyncBridgeChild.h" #include "VsyncIOThreadHolder.h" #include "mozilla/dom/ContentChild.h" #include "mozilla/gfx/GPUProcessManager.h" #include "mozilla/ipc/Endpoint.h" namespace mozilla { namespace gfx { VsyncBridgeChild::VsyncBridgeChild(RefPtr aThread, const uint64_t& aProcessToken) : mThread(aThread), mProcessToken(aProcessToken) {} VsyncBridgeChild::~VsyncBridgeChild() = default; /* static */ RefPtr VsyncBridgeChild::Create( RefPtr aThread, const uint64_t& aProcessToken, Endpoint&& aEndpoint) { RefPtr child = new VsyncBridgeChild(aThread, aProcessToken); RefPtr task = NewRunnableMethod&&>( "gfx::VsyncBridgeChild::Open", child, &VsyncBridgeChild::Open, std::move(aEndpoint)); aThread->GetThread()->Dispatch(task.forget(), nsIThread::DISPATCH_NORMAL); return child; } void VsyncBridgeChild::Open(Endpoint&& aEndpoint) { if (!aEndpoint.Bind(this)) { // The GPU Process Manager might be gone if we receive ActorDestroy very // late in shutdown. if (GPUProcessManager* gpm = GPUProcessManager::Get()) gpm->NotifyRemoteActorDestroyed(mProcessToken); return; } } class NotifyVsyncTask : public Runnable { public: NotifyVsyncTask(RefPtr aVsyncBridge, const VsyncEvent& aVsync, const layers::LayersId& aLayersId) : Runnable("gfx::NotifyVsyncTask"), mVsyncBridge(aVsyncBridge), mVsync(aVsync), mLayersId(aLayersId) {} NS_IMETHOD Run() override { mVsyncBridge->NotifyVsyncImpl(mVsync, mLayersId); return NS_OK; } private: RefPtr mVsyncBridge; VsyncEvent mVsync; layers::LayersId mLayersId; }; bool VsyncBridgeChild::IsOnVsyncIOThread() const { return mThread->IsOnCurrentThread(); } void VsyncBridgeChild::NotifyVsync(const VsyncEvent& aVsync, const layers::LayersId& aLayersId) { // This should be on the Vsync thread (not the Vsync I/O thread). MOZ_ASSERT(!IsOnVsyncIOThread()); RefPtr task = new NotifyVsyncTask(this, aVsync, aLayersId); mThread->Dispatch(task.forget()); } void VsyncBridgeChild::NotifyVsyncImpl(const VsyncEvent& aVsync, const layers::LayersId& aLayersId) { // This should be on the Vsync I/O thread. MOZ_ASSERT(IsOnVsyncIOThread()); if (!mProcessToken) { return; } SendNotifyVsync(aVsync, aLayersId); } void VsyncBridgeChild::Close() { if (!IsOnVsyncIOThread()) { mThread->Dispatch(NewRunnableMethod("gfx::VsyncBridgeChild::Close", this, &VsyncBridgeChild::Close)); return; } // We clear mProcessToken when the channel is closed. if (!mProcessToken) { return; } // Clear the process token so we don't notify the GPUProcessManager. It // already knows we're closed since it manually called Close, and in fact the // GPM could have already been destroyed during shutdown. mProcessToken = 0; // Close the underlying IPC channel. PVsyncBridgeChild::Close(); } void VsyncBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { if (mProcessToken) { GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); mProcessToken = 0; } } void VsyncBridgeChild::ProcessingError(Result aCode, const char* aReason) { MOZ_RELEASE_ASSERT(aCode == MsgDropped, "Processing error in VsyncBridgeChild"); } void VsyncBridgeChild::HandleFatalError(const char* aMsg) { dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid()); } } // namespace gfx } // namespace mozilla