1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef _include_mozilla_gfx_ipc_GPUProcessManager_h_
7 #define _include_mozilla_gfx_ipc_GPUProcessManager_h_
8 
9 #include "base/basictypes.h"
10 #include "base/process.h"
11 #include "Units.h"
12 #include "mozilla/UniquePtr.h"
13 #include "mozilla/dom/ipc/IdType.h"
14 #include "mozilla/gfx/GPUProcessHost.h"
15 #include "mozilla/gfx/PGPUChild.h"
16 #include "mozilla/gfx/Point.h"
17 #include "mozilla/ipc/ProtocolUtils.h"
18 #include "mozilla/ipc/TaskFactory.h"
19 #include "mozilla/layers/LayersTypes.h"
20 #include "mozilla/webrender/WebRenderTypes.h"
21 #include "nsIObserver.h"
22 #include "nsThreadUtils.h"
23 class nsBaseWidget;
24 enum class DeviceResetReason;
25 
26 namespace mozilla {
27 class MemoryReportingProcess;
28 class PRemoteDecoderManagerChild;
29 namespace layers {
30 class IAPZCTreeManager;
31 class CompositorOptions;
32 class CompositorSession;
33 class CompositorUpdateObserver;
34 class PCompositorBridgeChild;
35 class PCompositorManagerChild;
36 class PImageBridgeChild;
37 class PVideoBridgeParent;
38 class RemoteCompositorSession;
39 class InProcessCompositorSession;
40 class UiCompositorControllerChild;
41 class WebRenderLayerManager;
42 }  // namespace layers
43 namespace widget {
44 class CompositorWidget;
45 }  // namespace widget
46 namespace dom {
47 class ContentParent;
48 class BrowserParent;
49 }  // namespace dom
50 namespace ipc {
51 class GeckoChildProcessHost;
52 }  // namespace ipc
53 namespace gfx {
54 
55 class GPUChild;
56 class GPUProcessListener;
57 class PVRManagerChild;
58 class VsyncBridgeChild;
59 class VsyncIOThreadHolder;
60 
61 // The GPUProcessManager is a singleton responsible for creating GPU-bound
62 // objects that may live in another process. Currently, it provides access
63 // to the compositor via CompositorBridgeParent.
64 class GPUProcessManager final : public GPUProcessHost::Listener {
65   friend class layers::RemoteCompositorSession;
66   friend class layers::InProcessCompositorSession;
67 
68   typedef layers::CompositorOptions CompositorOptions;
69   typedef layers::CompositorSession CompositorSession;
70   typedef layers::CompositorUpdateObserver CompositorUpdateObserver;
71   typedef layers::IAPZCTreeManager IAPZCTreeManager;
72   typedef layers::WebRenderLayerManager WebRenderLayerManager;
73   typedef layers::LayersId LayersId;
74   typedef layers::PCompositorBridgeChild PCompositorBridgeChild;
75   typedef layers::PCompositorManagerChild PCompositorManagerChild;
76   typedef layers::PImageBridgeChild PImageBridgeChild;
77   typedef layers::PVideoBridgeParent PVideoBridgeParent;
78   typedef layers::RemoteCompositorSession RemoteCompositorSession;
79   typedef layers::InProcessCompositorSession InProcessCompositorSession;
80   typedef layers::UiCompositorControllerChild UiCompositorControllerChild;
81 
82  public:
83   static void Initialize();
84   static void Shutdown();
85   static GPUProcessManager* Get();
86 
87   ~GPUProcessManager();
88 
89   // If not using a GPU process, launch a new GPU process asynchronously.
90   void LaunchGPUProcess();
91   bool IsGPUProcessLaunching();
92 
93   // Ensure that GPU-bound methods can be used. If no GPU process is being
94   // used, or one is launched and ready, this function returns immediately.
95   // Otherwise it blocks until the GPU process has finished launching.
96   // If the GPU process is enabled but has not yet been launched then this will
97   // launch the process. If that is not desired then check that return value of
98   // Process() is non-null before calling.
99   bool EnsureGPUReady();
100 
101   already_AddRefed<CompositorSession> CreateTopLevelCompositor(
102       nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
103       CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
104       bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize,
105       bool* aRetry);
106 
107   bool CreateContentBridges(
108       base::ProcessId aOtherProcess,
109       mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
110       mozilla::ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
111       mozilla::ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
112       mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>* aOutVideoManager,
113       nsTArray<uint32_t>* aNamespaces);
114 
115   // Initialize GPU process with consuming end of PVideoBridge.
116   void InitVideoBridge(
117       mozilla::ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge);
118 
119   // Maps the layer tree and process together so that aOwningPID is allowed
120   // to access aLayersId across process.
121   void MapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId);
122 
123   // Release compositor-thread resources referred to by |aID|.
124   //
125   // Must run on the content main thread.
126   void UnmapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId);
127 
128   // Checks to see if aLayersId and aRequestingPID have been mapped by
129   // MapLayerTreeId
130   bool IsLayerTreeIdMapped(LayersId aLayersId, base::ProcessId aRequestingId);
131 
132   // Allocate an ID that can be used to refer to a layer tree and
133   // associated resources that live only on the compositor thread.
134   //
135   // Must run on the browser main thread.
136   LayersId AllocateLayerTreeId();
137 
138   // Allocate an ID that can be used as Namespace and
139   // Must run on the browser main thread.
140   uint32_t AllocateNamespace();
141 
142   // Allocate a layers ID and connect it to a compositor. If the compositor is
143   // null, the connect operation will not be performed, but an ID will still be
144   // allocated. This must be called from the browser main thread.
145   //
146   // Note that a layer tree id is always allocated, even if this returns false.
147   bool AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge,
148                                      base::ProcessId aOtherPid,
149                                      LayersId* aOutLayersId,
150                                      CompositorOptions* aOutCompositorOptions);
151 
152   // Destroy and recreate all of the compositors
153   void ResetCompositors();
154 
155   // Record the device reset in telemetry / annotate the crash report.
156   static void RecordDeviceReset(DeviceResetReason aReason);
157 
158   void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
159   void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
160   void SimulateDeviceReset();
161   void DisableWebRender(wr::WebRenderError aError, const nsCString& aMsg);
162   void NotifyWebRenderError(wr::WebRenderError aError);
163   void OnInProcessDeviceReset(bool aTrackThreshold);
164   void OnRemoteProcessDeviceReset(GPUProcessHost* aHost) override;
165   void OnProcessDeclaredStable() override;
166   void NotifyListenersOnCompositeDeviceReset();
167 
168   // Notify the GPUProcessManager that a top-level PGPU protocol has been
169   // terminated. This may be called from any thread.
170   void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
171 
172   void AddListener(GPUProcessListener* aListener);
173   void RemoveListener(GPUProcessListener* aListener);
174 
175   // Send a message to the GPU process observer service to broadcast. Returns
176   // true if the message was sent, false if not.
177   bool NotifyGpuObservers(const char* aTopic);
178 
179   // Kills the GPU process. Used for tests and diagnostics
180   void KillProcess();
181 
182   // Causes the GPU process to crash. Used for tests and diagnostics
183   void CrashProcess();
184 
185   // Returns -1 if there is no GPU process, or the platform pid for it.
186   base::ProcessId GPUProcessPid();
187 
188   // If a GPU process is present, create a MemoryReportingProcess object.
189   // Otherwise, return null.
190   RefPtr<MemoryReportingProcess> GetProcessMemoryReporter();
191 
192   // Returns access to the PGPU protocol if a GPU process is present.
GetGPUChild()193   GPUChild* GetGPUChild() { return mGPUChild; }
194 
195   // Returns whether or not a GPU process was ever launched.
AttemptedGPUProcess()196   bool AttemptedGPUProcess() const { return mTotalProcessAttempts > 0; }
197 
198   // Returns the process host
Process()199   GPUProcessHost* Process() { return mProcess; }
200 
201   /*
202    * ** Test-only Method **
203    *
204    * Trigger GPU-process test metric instrumentation.
205    */
206   RefPtr<PGPUChild::TestTriggerMetricsPromise> TestTriggerMetrics();
207 
208  private:
209   // Called from our xpcom-shutdown observer.
210   void OnXPCOMShutdown();
211   void OnPreferenceChange(const char16_t* aData);
212 
213   bool CreateContentCompositorManager(
214       base::ProcessId aOtherProcess,
215       mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
216   bool CreateContentImageBridge(
217       base::ProcessId aOtherProcess,
218       mozilla::ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
219   bool CreateContentVRManager(
220       base::ProcessId aOtherProcess,
221       mozilla::ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
222   void CreateContentRemoteDecoderManager(
223       base::ProcessId aOtherProcess,
224       mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>* aOutEndPoint);
225 
226   // Called from RemoteCompositorSession. We track remote sessions so we can
227   // notify their owning widgets that the session must be restarted.
228   void RegisterRemoteProcessSession(RemoteCompositorSession* aSession);
229   void UnregisterRemoteProcessSession(RemoteCompositorSession* aSession);
230 
231   // Called from InProcessCompositorSession. We track in process sessino so we
232   // can notify their owning widgets that the session must be restarted
233   void RegisterInProcessSession(InProcessCompositorSession* aSession);
234   void UnregisterInProcessSession(InProcessCompositorSession* aSession);
235 
236   void DestroyRemoteCompositorSessions();
237   void DestroyInProcessCompositorSessions();
238 
239   // Returns true if we crossed the threshold such that we should disable
240   // acceleration.
241   bool OnDeviceReset(bool aTrackThreshold);
242 
243   // Returns true if WebRender was enabled and is now disabled.
244   bool DisableWebRenderConfig(wr::WebRenderError aError, const nsCString& aMsg);
245 
246   void FallbackToSoftware(const char* aMessage);
247 
248  private:
249   GPUProcessManager();
250 
251   // Permanently disable the GPU process and record a message why.
252   void DisableGPUProcess(const char* aMessage);
253 
254   // May permanently disable the GPU process and record a message why. May
255   // return false if the fallback process decided we should retry the GPU
256   // process, but only if aAllowRestart is also true.
257   bool MaybeDisableGPUProcess(const char* aMessage, bool aAllowRestart);
258 
259   // Shutdown the GPU process.
260   void CleanShutdown();
261   // Destroy the process and clean up resources.
262   // Setting aUnexpectedShutdown = true indicates that this is being called to
263   // clean up resources in response to an unexpected shutdown having been
264   // detected.
265   void DestroyProcess(bool aUnexpectedShutdown = false);
266 
267   void HandleProcessLost();
268   // Reinitialize rendering following a GPU process loss.
269   void ReinitializeRendering();
270 
271   void EnsureVsyncIOThread();
272   void ShutdownVsyncIOThread();
273 
274   void EnsureProtocolsReady();
275   void EnsureCompositorManagerChild();
276   void EnsureImageBridgeChild();
277   void EnsureVRManager();
278 
279 #if defined(MOZ_WIDGET_ANDROID)
280   already_AddRefed<UiCompositorControllerChild> CreateUiCompositorController(
281       nsBaseWidget* aWidget, const LayersId aId);
282 #endif  // defined(MOZ_WIDGET_ANDROID)
283 
284   RefPtr<CompositorSession> CreateRemoteSession(
285       nsBaseWidget* aWidget, WebRenderLayerManager* aLayerManager,
286       const LayersId& aRootLayerTreeId, CSSToLayoutDeviceScale aScale,
287       const CompositorOptions& aOptions, bool aUseExternalSurfaceSize,
288       const gfx::IntSize& aSurfaceSize);
289 
290   DISALLOW_COPY_AND_ASSIGN(GPUProcessManager);
291 
292   class Observer final : public nsIObserver {
293    public:
294     NS_DECL_ISUPPORTS
295     NS_DECL_NSIOBSERVER
296     explicit Observer(GPUProcessManager* aManager);
297 
298    protected:
299     virtual ~Observer() = default;
300 
301     GPUProcessManager* mManager;
302   };
303   friend class Observer;
304 
305  private:
306   bool mDecodeVideoOnGpuProcess = true;
307 
308   RefPtr<Observer> mObserver;
309   mozilla::ipc::TaskFactory<GPUProcessManager> mTaskFactory;
310   RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
311   uint32_t mNextNamespace;
312   uint32_t mIdNamespace;
313   uint32_t mResourceId;
314 
315   uint32_t mUnstableProcessAttempts;
316   uint32_t mTotalProcessAttempts;
317   TimeStamp mProcessAttemptLastTime;
318 
319   nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions;
320   nsTArray<RefPtr<InProcessCompositorSession>> mInProcessSessions;
321   nsTArray<GPUProcessListener*> mListeners;
322 
323   uint32_t mDeviceResetCount;
324   TimeStamp mDeviceResetLastTime;
325 
326   // Keeps track of whether not the application is in the foreground on android.
327   bool mAppInForeground;
328 
329   // Fields that are associated with the current GPU process.
330   GPUProcessHost* mProcess;
331   uint64_t mProcessToken;
332   bool mProcessStable;
333   GPUChild* mGPUChild;
334   RefPtr<VsyncBridgeChild> mVsyncBridge;
335   // Collects any pref changes that occur during process launch (after
336   // the initial map is passed in command-line arguments) to be sent
337   // when the process can receive IPC messages.
338   nsTArray<mozilla::dom::Pref> mQueuedPrefs;
339 };
340 
341 }  // namespace gfx
342 }  // namespace mozilla
343 
344 #endif  // _include_mozilla_gfx_ipc_GPUProcessManager_h_
345