summaryrefslogtreecommitdiffstats
path: root/gfx/layers/ipc/CompositorManagerChild.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/layers/ipc/CompositorManagerChild.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/gfx/layers/ipc/CompositorManagerChild.cpp b/gfx/layers/ipc/CompositorManagerChild.cpp
new file mode 100644
index 0000000000..b629d28229
--- /dev/null
+++ b/gfx/layers/ipc/CompositorManagerChild.cpp
@@ -0,0 +1,256 @@
+/* -*- 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 "mozilla/layers/CompositorManagerChild.h"
+
+#include "mozilla/StaticPrefs_layers.h"
+#include "mozilla/layers/CompositorBridgeChild.h"
+#include "mozilla/layers/CompositorManagerParent.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/gfx/GPUProcessManager.h"
+#include "mozilla/dom/ContentChild.h" // for ContentChild
+#include "mozilla/dom/BrowserChild.h" // for BrowserChild
+#include "mozilla/ipc/Endpoint.h"
+#include "VsyncSource.h"
+
+namespace mozilla {
+namespace layers {
+
+using gfx::GPUProcessManager;
+
+StaticRefPtr<CompositorManagerChild> CompositorManagerChild::sInstance;
+
+/* static */
+bool CompositorManagerChild::IsInitialized(uint64_t aProcessToken) {
+ MOZ_ASSERT(NS_IsMainThread());
+ return sInstance && sInstance->CanSend() &&
+ sInstance->mProcessToken == aProcessToken;
+}
+
+/* static */
+void CompositorManagerChild::InitSameProcess(uint32_t aNamespace,
+ uint64_t aProcessToken) {
+ MOZ_ASSERT(NS_IsMainThread());
+ if (NS_WARN_IF(IsInitialized(aProcessToken))) {
+ MOZ_ASSERT_UNREACHABLE("Already initialized same process");
+ return;
+ }
+
+ RefPtr<CompositorManagerParent> parent =
+ CompositorManagerParent::CreateSameProcess();
+ RefPtr<CompositorManagerChild> child =
+ new CompositorManagerChild(parent, aProcessToken, aNamespace);
+ if (NS_WARN_IF(!child->CanSend())) {
+ MOZ_DIAGNOSTIC_ASSERT(false, "Failed to open same process protocol");
+ return;
+ }
+
+ parent->BindComplete(/* aIsRoot */ true);
+ sInstance = std::move(child);
+}
+
+/* static */
+bool CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
+ uint32_t aNamespace,
+ uint64_t aProcessToken /* = 0 */) {
+ MOZ_ASSERT(NS_IsMainThread());
+ if (sInstance) {
+ MOZ_ASSERT(sInstance->mNamespace != aNamespace);
+ }
+
+ sInstance = new CompositorManagerChild(std::move(aEndpoint), aProcessToken,
+ aNamespace);
+ return sInstance->CanSend();
+}
+
+/* static */
+void CompositorManagerChild::Shutdown() {
+ MOZ_ASSERT(NS_IsMainThread());
+ CompositorBridgeChild::ShutDown();
+
+ if (!sInstance) {
+ return;
+ }
+
+ sInstance->Close();
+ sInstance = nullptr;
+}
+
+/* static */
+void CompositorManagerChild::OnGPUProcessLost(uint64_t aProcessToken) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
+ // cannot know if the CompositorManagerChild is about to be released but has
+ // yet to be. As such, we want to pre-emptively set mCanSend to false.
+ if (sInstance && sInstance->mProcessToken == aProcessToken) {
+ sInstance->mCanSend = false;
+ }
+}
+
+/* static */
+bool CompositorManagerChild::CreateContentCompositorBridge(
+ uint32_t aNamespace) {
+ MOZ_ASSERT(NS_IsMainThread());
+ if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
+ return false;
+ }
+
+ CompositorBridgeOptions options = ContentCompositorOptions();
+
+ RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
+ if (NS_WARN_IF(
+ !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
+ return false;
+ }
+
+ bridge->InitForContent(aNamespace);
+ return true;
+}
+
+/* static */
+already_AddRefed<CompositorBridgeChild>
+CompositorManagerChild::CreateWidgetCompositorBridge(
+ uint64_t aProcessToken, LayerManager* aLayerManager, uint32_t aNamespace,
+ CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
+ bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+ if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
+ return nullptr;
+ }
+
+ TimeDuration vsyncRate = gfxPlatform::GetPlatform()
+ ->GetHardwareVsync()
+ ->GetGlobalDisplay()
+ .GetVsyncRate();
+
+ CompositorBridgeOptions options = WidgetCompositorOptions(
+ aScale, vsyncRate, aOptions, aUseExternalSurfaceSize, aSurfaceSize);
+
+ RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
+ if (NS_WARN_IF(
+ !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
+ return nullptr;
+ }
+
+ bridge->InitForWidget(aProcessToken, aLayerManager, aNamespace);
+ return bridge.forget();
+}
+
+/* static */
+already_AddRefed<CompositorBridgeChild>
+CompositorManagerChild::CreateSameProcessWidgetCompositorBridge(
+ LayerManager* aLayerManager, uint32_t aNamespace) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+ if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
+ return nullptr;
+ }
+
+ CompositorBridgeOptions options = SameProcessWidgetCompositorOptions();
+
+ RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
+ if (NS_WARN_IF(
+ !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
+ return nullptr;
+ }
+
+ bridge->InitForWidget(1, aLayerManager, aNamespace);
+ return bridge.forget();
+}
+
+CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent,
+ uint64_t aProcessToken,
+ uint32_t aNamespace)
+ : mProcessToken(aProcessToken),
+ mNamespace(aNamespace),
+ mResourceId(0),
+ mCanSend(false) {
+ MOZ_ASSERT(aParent);
+
+ SetOtherProcessId(base::GetCurrentProcId());
+ ipc::MessageChannel* channel = aParent->GetIPCChannel();
+ if (NS_WARN_IF(!Open(channel, CompositorThread(), ipc::ChildSide))) {
+ return;
+ }
+
+ mCanSend = true;
+ AddRef();
+ SetReplyTimeout();
+}
+
+CompositorManagerChild::CompositorManagerChild(
+ Endpoint<PCompositorManagerChild>&& aEndpoint, uint64_t aProcessToken,
+ uint32_t aNamespace)
+ : mProcessToken(aProcessToken),
+ mNamespace(aNamespace),
+ mResourceId(0),
+ mCanSend(false) {
+ if (NS_WARN_IF(!aEndpoint.Bind(this))) {
+ return;
+ }
+
+ mCanSend = true;
+ AddRef();
+ SetReplyTimeout();
+}
+
+void CompositorManagerChild::ActorDealloc() {
+ MOZ_ASSERT(!mCanSend);
+ Release();
+}
+
+void CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason) {
+ mCanSend = false;
+ if (sInstance == this) {
+ sInstance = nullptr;
+ }
+}
+
+void CompositorManagerChild::HandleFatalError(const char* aMsg) const {
+ dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
+}
+
+void CompositorManagerChild::ProcessingError(Result aCode,
+ const char* aReason) {
+ if (aCode != MsgDropped) {
+ gfxDevCrash(gfx::LogReason::ProcessingError)
+ << "Processing error in CompositorBridgeChild: " << int(aCode);
+ }
+}
+
+void CompositorManagerChild::SetReplyTimeout() {
+#ifndef DEBUG
+ // Add a timeout for release builds to kill GPU process when it hangs.
+ if (XRE_IsParentProcess() && GPUProcessManager::Get()->GetGPUChild()) {
+ int32_t timeout =
+ StaticPrefs::layers_gpu_process_ipc_reply_timeout_ms_AtStartup();
+ SetReplyTimeoutMs(timeout);
+ }
+#endif
+}
+
+bool CompositorManagerChild::ShouldContinueFromReplyTimeout() {
+ if (XRE_IsParentProcess()) {
+ gfxCriticalNote << "Killing GPU process due to IPC reply timeout";
+ MOZ_DIAGNOSTIC_ASSERT(GPUProcessManager::Get()->GetGPUChild());
+ GPUProcessManager::Get()->KillProcess();
+ }
+ return false;
+}
+
+mozilla::ipc::IPCResult CompositorManagerChild::RecvNotifyWebRenderError(
+ const WebRenderError&& aError) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ MOZ_ASSERT(NS_IsMainThread());
+ GPUProcessManager::Get()->NotifyWebRenderError(aError);
+ return IPC_OK();
+}
+
+} // namespace layers
+} // namespace mozilla