summaryrefslogtreecommitdiffstats
path: root/gfx/ipc/GPUProcessManager.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--gfx/ipc/GPUProcessManager.h366
1 files changed, 366 insertions, 0 deletions
diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h
new file mode 100644
index 0000000000..bf5b7e6587
--- /dev/null
+++ b/gfx/ipc/GPUProcessManager.h
@@ -0,0 +1,366 @@
+/* -*- 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/. */
+#ifndef _include_mozilla_gfx_ipc_GPUProcessManager_h_
+#define _include_mozilla_gfx_ipc_GPUProcessManager_h_
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "Units.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/gfx/GPUProcessHost.h"
+#include "mozilla/gfx/PGPUChild.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/TaskFactory.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "nsIObserver.h"
+#include "nsThreadUtils.h"
+class nsBaseWidget;
+enum class DeviceResetReason;
+
+namespace mozilla {
+class MemoryReportingProcess;
+class PRemoteDecoderManagerChild;
+namespace layers {
+class IAPZCTreeManager;
+class CompositorOptions;
+class CompositorSession;
+class CompositorUpdateObserver;
+class PCompositorBridgeChild;
+class PCompositorManagerChild;
+class PImageBridgeChild;
+class PVideoBridgeParent;
+class RemoteCompositorSession;
+class InProcessCompositorSession;
+class UiCompositorControllerChild;
+class WebRenderLayerManager;
+} // namespace layers
+namespace widget {
+class CompositorWidget;
+} // namespace widget
+namespace dom {
+class ContentParent;
+class BrowserParent;
+} // namespace dom
+namespace ipc {
+class GeckoChildProcessHost;
+} // namespace ipc
+namespace gfx {
+
+class GPUChild;
+class GPUProcessListener;
+class PVRManagerChild;
+class VsyncBridgeChild;
+class VsyncIOThreadHolder;
+
+// The GPUProcessManager is a singleton responsible for creating GPU-bound
+// objects that may live in another process. Currently, it provides access
+// to the compositor via CompositorBridgeParent.
+class GPUProcessManager final : public GPUProcessHost::Listener {
+ friend class layers::RemoteCompositorSession;
+ friend class layers::InProcessCompositorSession;
+
+ typedef layers::CompositorOptions CompositorOptions;
+ typedef layers::CompositorSession CompositorSession;
+ typedef layers::CompositorUpdateObserver CompositorUpdateObserver;
+ typedef layers::IAPZCTreeManager IAPZCTreeManager;
+ typedef layers::WebRenderLayerManager WebRenderLayerManager;
+ typedef layers::LayersId LayersId;
+ typedef layers::PCompositorBridgeChild PCompositorBridgeChild;
+ typedef layers::PCompositorManagerChild PCompositorManagerChild;
+ typedef layers::PImageBridgeChild PImageBridgeChild;
+ typedef layers::PVideoBridgeParent PVideoBridgeParent;
+ typedef layers::RemoteCompositorSession RemoteCompositorSession;
+ typedef layers::InProcessCompositorSession InProcessCompositorSession;
+ typedef layers::UiCompositorControllerChild UiCompositorControllerChild;
+
+ public:
+ static void Initialize();
+ static void Shutdown();
+ static GPUProcessManager* Get();
+
+ ~GPUProcessManager();
+
+ // If not using a GPU process, launch a new GPU process asynchronously.
+ bool LaunchGPUProcess();
+ bool IsGPUProcessLaunching();
+
+ // Ensure that GPU-bound methods can be used. If no GPU process is being
+ // used, or one is launched and ready, this function returns immediately.
+ // Otherwise it blocks until the GPU process has finished launching.
+ // If the GPU process is enabled but has not yet been launched then this will
+ // launch the process. If that is not desired then check that return value of
+ // Process() is non-null before calling.
+ nsresult EnsureGPUReady(bool aRetryAfterFallback = true);
+
+ already_AddRefed<CompositorSession> CreateTopLevelCompositor(
+ nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
+ CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
+ bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize,
+ uint64_t aInnerWindowId, bool* aRetry);
+
+ bool CreateContentBridges(
+ base::ProcessId aOtherProcess,
+ mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
+ mozilla::ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
+ mozilla::ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
+ mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>* aOutVideoManager,
+ dom::ContentParentId aChildId, nsTArray<uint32_t>* aNamespaces);
+
+ // Initialize GPU process with consuming end of PVideoBridge.
+ void InitVideoBridge(
+ mozilla::ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge,
+ layers::VideoBridgeSource aSource);
+
+ // Maps the layer tree and process together so that aOwningPID is allowed
+ // to access aLayersId across process.
+ void MapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId);
+
+ // Release compositor-thread resources referred to by |aID|.
+ //
+ // Must run on the content main thread.
+ void UnmapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId);
+
+ // Checks to see if aLayersId and aRequestingPID have been mapped by
+ // MapLayerTreeId
+ bool IsLayerTreeIdMapped(LayersId aLayersId, base::ProcessId aRequestingId);
+
+ // Allocate an ID that can be used to refer to a layer tree and
+ // associated resources that live only on the compositor thread.
+ //
+ // Must run on the browser main thread.
+ LayersId AllocateLayerTreeId();
+
+ // Allocate an ID that can be used as Namespace and
+ // Must run on the browser main thread.
+ uint32_t AllocateNamespace();
+
+ // Allocate a layers ID and connect it to a compositor. If the compositor is
+ // null, the connect operation will not be performed, but an ID will still be
+ // allocated. This must be called from the browser main thread.
+ //
+ // Note that a layer tree id is always allocated, even if this returns false.
+ bool AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge,
+ base::ProcessId aOtherPid,
+ LayersId* aOutLayersId,
+ CompositorOptions* aOutCompositorOptions);
+
+ // Destroy and recreate all of the compositors
+ void ResetCompositors();
+
+ // Record the device reset in telemetry / annotate the crash report.
+ static void RecordDeviceReset(DeviceResetReason aReason);
+
+ void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
+ void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
+ void SimulateDeviceReset();
+ void DisableWebRender(wr::WebRenderError aError, const nsCString& aMsg);
+ void NotifyWebRenderError(wr::WebRenderError aError);
+ void OnInProcessDeviceReset(bool aTrackThreshold);
+ void OnRemoteProcessDeviceReset(GPUProcessHost* aHost) override;
+ void OnProcessDeclaredStable() override;
+ void NotifyListenersOnCompositeDeviceReset();
+
+ // Notify the GPUProcessManager that a top-level PGPU protocol has been
+ // terminated. This may be called from any thread.
+ void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
+
+ void AddListener(GPUProcessListener* aListener);
+ void RemoveListener(GPUProcessListener* aListener);
+
+ // Send a message to the GPU process observer service to broadcast. Returns
+ // true if the message was sent, false if not.
+ bool NotifyGpuObservers(const char* aTopic);
+
+ // Kills the GPU process. Used for tests and diagnostics
+ void KillProcess();
+
+ // Causes the GPU process to crash. Used for tests and diagnostics
+ void CrashProcess();
+
+ // Returns -1 if there is no GPU process, or the platform pid for it.
+ base::ProcessId GPUProcessPid();
+
+ // If a GPU process is present, create a MemoryReportingProcess object.
+ // Otherwise, return null.
+ RefPtr<MemoryReportingProcess> GetProcessMemoryReporter();
+
+ // Returns access to the PGPU protocol if a GPU process is present.
+ GPUChild* GetGPUChild() { return mGPUChild; }
+
+ // Returns whether or not a GPU process was ever launched.
+ bool AttemptedGPUProcess() const { return mTotalProcessAttempts > 0; }
+
+ // Returns the process host
+ GPUProcessHost* Process() { return mProcess; }
+
+ // Sets the value of mAppInForeground, and (on Windows) adjusts the priority
+ // of the GPU process accordingly.
+ void SetAppInForeground(bool aInForeground);
+
+ /*
+ * ** Test-only Method **
+ *
+ * Trigger GPU-process test metric instrumentation.
+ */
+ RefPtr<PGPUChild::TestTriggerMetricsPromise> TestTriggerMetrics();
+
+ private:
+ // Called from our xpcom-shutdown observer.
+ void OnXPCOMShutdown();
+ void OnPreferenceChange(const char16_t* aData);
+
+ bool CreateContentCompositorManager(
+ base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
+ uint32_t aNamespace,
+ mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
+ bool CreateContentImageBridge(
+ base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
+ mozilla::ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
+ bool CreateContentVRManager(
+ base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
+ mozilla::ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
+ void CreateContentRemoteDecoderManager(
+ base::ProcessId aOtherProcess, dom::ContentParentId aChildId,
+ mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>* aOutEndPoint);
+
+ // Called from RemoteCompositorSession. We track remote sessions so we can
+ // notify their owning widgets that the session must be restarted.
+ void RegisterRemoteProcessSession(RemoteCompositorSession* aSession);
+ void UnregisterRemoteProcessSession(RemoteCompositorSession* aSession);
+
+ // Called from InProcessCompositorSession. We track in process sessino so we
+ // can notify their owning widgets that the session must be restarted
+ void RegisterInProcessSession(InProcessCompositorSession* aSession);
+ void UnregisterInProcessSession(InProcessCompositorSession* aSession);
+
+ void DestroyRemoteCompositorSessions();
+ void DestroyInProcessCompositorSessions();
+
+ void OnBlockingProcessUnexpectedShutdown();
+
+ // Returns true if we crossed the threshold such that we should disable
+ // acceleration.
+ bool OnDeviceReset(bool aTrackThreshold);
+
+ // Returns true if WebRender was enabled and is now disabled.
+ bool DisableWebRenderConfig(wr::WebRenderError aError, const nsCString& aMsg);
+
+ void FallbackToSoftware(const char* aMessage);
+
+ private:
+ GPUProcessManager();
+
+ // Permanently disable the GPU process and record a message why.
+ void DisableGPUProcess(const char* aMessage);
+
+ // May permanently disable the GPU process and record a message why. May
+ // return false if the fallback process decided we should retry the GPU
+ // process, but only if aAllowRestart is also true.
+ bool MaybeDisableGPUProcess(const char* aMessage, bool aAllowRestart);
+
+ bool FallbackFromAcceleration(wr::WebRenderError aError,
+ const nsCString& aMsg);
+
+ void ResetProcessStable();
+
+ // Returns true if the composting pocess is currently considered to be stable.
+ bool IsProcessStable(const TimeStamp& aNow);
+
+ // Shutdown the GPU process.
+ void CleanShutdown();
+ // Destroy the process and clean up resources.
+ // Setting aUnexpectedShutdown = true indicates that this is being called to
+ // clean up resources in response to an unexpected shutdown having been
+ // detected.
+ void DestroyProcess(bool aUnexpectedShutdown = false);
+
+ void HandleProcessLost();
+ // Reinitialize rendering following a GPU process loss.
+ void ReinitializeRendering();
+
+ void EnsureVsyncIOThread();
+ void ShutdownVsyncIOThread();
+
+ bool EnsureProtocolsReady();
+ bool EnsureCompositorManagerChild();
+ bool EnsureImageBridgeChild();
+ bool EnsureVRManager();
+
+#if defined(XP_WIN)
+ void SetProcessIsForeground();
+#endif
+
+#if defined(MOZ_WIDGET_ANDROID)
+ already_AddRefed<UiCompositorControllerChild> CreateUiCompositorController(
+ nsBaseWidget* aWidget, const LayersId aId);
+#endif // defined(MOZ_WIDGET_ANDROID)
+
+ RefPtr<CompositorSession> CreateRemoteSession(
+ nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
+ const LayersId& aRootLayerTreeId, CSSToLayoutDeviceScale aScale,
+ const CompositorOptions& aOptions, bool aUseExternalSurfaceSize,
+ const gfx::IntSize& aSurfaceSize, uint64_t aInnerWindowId);
+
+ DISALLOW_COPY_AND_ASSIGN(GPUProcessManager);
+
+ class Observer final : public nsIObserver {
+ public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIOBSERVER
+ explicit Observer(GPUProcessManager* aManager);
+
+ protected:
+ virtual ~Observer() = default;
+
+ GPUProcessManager* mManager;
+ };
+ friend class Observer;
+
+ private:
+ bool mDecodeVideoOnGpuProcess = true;
+
+ RefPtr<Observer> mObserver;
+ mozilla::ipc::TaskFactory<GPUProcessManager> mTaskFactory;
+ RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
+ uint32_t mNextNamespace;
+ uint32_t mIdNamespace;
+ uint32_t mResourceId;
+
+ uint32_t mUnstableProcessAttempts;
+ uint32_t mTotalProcessAttempts;
+ TimeStamp mProcessAttemptLastTime;
+
+ nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions;
+ nsTArray<RefPtr<InProcessCompositorSession>> mInProcessSessions;
+ nsTArray<GPUProcessListener*> mListeners;
+
+ uint32_t mDeviceResetCount;
+ TimeStamp mDeviceResetLastTime;
+
+ // Keeps track of whether not the application is in the foreground on android.
+ bool mAppInForeground;
+
+ // Fields that are associated with the current GPU process.
+ GPUProcessHost* mProcess;
+ uint64_t mProcessToken;
+ bool mProcessStable;
+ Maybe<wr::WebRenderError> mLastError;
+ Maybe<nsCString> mLastErrorMsg;
+ GPUChild* mGPUChild;
+ RefPtr<VsyncBridgeChild> mVsyncBridge;
+ // Collects any pref changes that occur during process launch (after
+ // the initial map is passed in command-line arguments) to be sent
+ // when the process can receive IPC messages.
+ nsTArray<mozilla::dom::Pref> mQueuedPrefs;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif // _include_mozilla_gfx_ipc_GPUProcessManager_h_