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/Point.h"
16 #include "mozilla/ipc/ProtocolUtils.h"
17 #include "mozilla/ipc/TaskFactory.h"
18 #include "mozilla/ipc/Transport.h"
19 #include "mozilla/layers/LayersTypes.h"
20 #include "mozilla/webrender/WebRenderTypes.h"
21 #include "nsThreadUtils.h"
22 class nsBaseWidget;
23 
24 namespace mozilla {
25 class MemoryReportingProcess;
26 class PRemoteDecoderManagerChild;
27 namespace layers {
28 class IAPZCTreeManager;
29 class CompositorOptions;
30 class CompositorSession;
31 class CompositorUpdateObserver;
32 class PCompositorBridgeChild;
33 class PCompositorManagerChild;
34 class PImageBridgeChild;
35 class PVideoBridgeParent;
36 class RemoteCompositorSession;
37 class InProcessCompositorSession;
38 class UiCompositorControllerChild;
39 }  // namespace layers
40 namespace widget {
41 class CompositorWidget;
42 }  // namespace widget
43 namespace dom {
44 class ContentParent;
45 class BrowserParent;
46 }  // namespace dom
47 namespace ipc {
48 class GeckoChildProcessHost;
49 }  // namespace ipc
50 namespace gfx {
51 
52 class GPUChild;
53 class GPUProcessListener;
54 class PVRManagerChild;
55 class VsyncBridgeChild;
56 class VsyncIOThreadHolder;
57 
58 // The GPUProcessManager is a singleton responsible for creating GPU-bound
59 // objects that may live in another process. Currently, it provides access
60 // to the compositor via CompositorBridgeParent.
61 class GPUProcessManager final : public GPUProcessHost::Listener {
62   friend class layers::RemoteCompositorSession;
63   friend class layers::InProcessCompositorSession;
64 
65   typedef layers::CompositorOptions CompositorOptions;
66   typedef layers::CompositorSession CompositorSession;
67   typedef layers::CompositorUpdateObserver CompositorUpdateObserver;
68   typedef layers::IAPZCTreeManager IAPZCTreeManager;
69   typedef layers::LayerManager LayerManager;
70   typedef layers::LayersId LayersId;
71   typedef layers::PCompositorBridgeChild PCompositorBridgeChild;
72   typedef layers::PCompositorManagerChild PCompositorManagerChild;
73   typedef layers::PImageBridgeChild PImageBridgeChild;
74   typedef layers::PVideoBridgeParent PVideoBridgeParent;
75   typedef layers::RemoteCompositorSession RemoteCompositorSession;
76   typedef layers::InProcessCompositorSession InProcessCompositorSession;
77   typedef layers::UiCompositorControllerChild UiCompositorControllerChild;
78 
79  public:
80   static void Initialize();
81   static void Shutdown();
82   static GPUProcessManager* Get();
83 
84   ~GPUProcessManager();
85 
86   // If not using a GPU process, launch a new GPU process asynchronously.
87   void LaunchGPUProcess();
88   bool IsGPUProcessLaunching();
89 
90   // Ensure that GPU-bound methods can be used. If no GPU process is being
91   // used, or one is launched and ready, this function returns immediately.
92   // Otherwise it blocks until the GPU process has finished launching.
93   bool EnsureGPUReady();
94 
95   already_AddRefed<CompositorSession> CreateTopLevelCompositor(
96       nsBaseWidget* aWidget, LayerManager* aLayerManager,
97       CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
98       bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize,
99       bool* aRetry);
100 
101   bool CreateContentBridges(
102       base::ProcessId aOtherProcess,
103       mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutCompositor,
104       mozilla::ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
105       mozilla::ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
106       mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>* aOutVideoManager,
107       nsTArray<uint32_t>* aNamespaces);
108 
109   // Initialize GPU process with consuming end of PVideoBridge.
110   void InitVideoBridge(
111       mozilla::ipc::Endpoint<PVideoBridgeParent>&& aVideoBridge);
112 
113   // Maps the layer tree and process together so that aOwningPID is allowed
114   // to access aLayersId across process.
115   void MapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId);
116 
117   // Release compositor-thread resources referred to by |aID|.
118   //
119   // Must run on the content main thread.
120   void UnmapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId);
121 
122   // Checks to see if aLayersId and aRequestingPID have been mapped by
123   // MapLayerTreeId
124   bool IsLayerTreeIdMapped(LayersId aLayersId, base::ProcessId aRequestingId);
125 
126   // Allocate an ID that can be used to refer to a layer tree and
127   // associated resources that live only on the compositor thread.
128   //
129   // Must run on the browser main thread.
130   LayersId AllocateLayerTreeId();
131 
132   // Allocate an ID that can be used as Namespace and
133   // Must run on the browser main thread.
134   uint32_t AllocateNamespace();
135 
136   // Allocate a layers ID and connect it to a compositor. If the compositor is
137   // null, the connect operation will not be performed, but an ID will still be
138   // allocated. This must be called from the browser main thread.
139   //
140   // Note that a layer tree id is always allocated, even if this returns false.
141   bool AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge,
142                                      base::ProcessId aOtherPid,
143                                      LayersId* aOutLayersId,
144                                      CompositorOptions* aOutCompositorOptions);
145 
146   // Destroy and recreate all of the compositors
147   void ResetCompositors();
148 
149   void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
150   void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
151   void SimulateDeviceReset();
152   void DisableWebRender(wr::WebRenderError aError);
153   void NotifyWebRenderError(wr::WebRenderError aError);
154   void OnInProcessDeviceReset();
155   void OnRemoteProcessDeviceReset(GPUProcessHost* aHost) override;
156   void NotifyListenersOnCompositeDeviceReset();
157 
158   // Notify the GPUProcessManager that a top-level PGPU protocol has been
159   // terminated. This may be called from any thread.
160   void NotifyRemoteActorDestroyed(const uint64_t& aProcessToken);
161 
162   void AddListener(GPUProcessListener* aListener);
163   void RemoveListener(GPUProcessListener* aListener);
164 
165   // Send a message to the GPU process observer service to broadcast. Returns
166   // true if the message was sent, false if not.
167   bool NotifyGpuObservers(const char* aTopic);
168 
169   // Used for tests and diagnostics
170   void KillProcess();
171 
172   // Returns -1 if there is no GPU process, or the platform pid for it.
173   base::ProcessId GPUProcessPid();
174 
175   // If a GPU process is present, create a MemoryReportingProcess object.
176   // Otherwise, return null.
177   RefPtr<MemoryReportingProcess> GetProcessMemoryReporter();
178 
179   // Returns access to the PGPU protocol if a GPU process is present.
GetGPUChild()180   GPUChild* GetGPUChild() { return mGPUChild; }
181 
182   // Returns whether or not a GPU process was ever launched.
AttemptedGPUProcess()183   bool AttemptedGPUProcess() const { return mNumProcessAttempts > 0; }
184 
185   // Returns the process host
Process()186   GPUProcessHost* Process() { return mProcess; }
187 
188  private:
189   // Called from our xpcom-shutdown observer.
190   void OnXPCOMShutdown();
191   void OnPreferenceChange(const char16_t* aData);
192 
193   bool CreateContentCompositorManager(
194       base::ProcessId aOtherProcess,
195       mozilla::ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint);
196   bool CreateContentImageBridge(
197       base::ProcessId aOtherProcess,
198       mozilla::ipc::Endpoint<PImageBridgeChild>* aOutEndpoint);
199   bool CreateContentVRManager(
200       base::ProcessId aOtherProcess,
201       mozilla::ipc::Endpoint<PVRManagerChild>* aOutEndpoint);
202   void CreateContentRemoteDecoderManager(
203       base::ProcessId aOtherProcess,
204       mozilla::ipc::Endpoint<PRemoteDecoderManagerChild>* aOutEndPoint);
205 
206   // Called from RemoteCompositorSession. We track remote sessions so we can
207   // notify their owning widgets that the session must be restarted.
208   void RegisterRemoteProcessSession(RemoteCompositorSession* aSession);
209   void UnregisterRemoteProcessSession(RemoteCompositorSession* aSession);
210 
211   // Called from InProcessCompositorSession. We track in process sessino so we
212   // can notify their owning widgets that the session must be restarted
213   void RegisterInProcessSession(InProcessCompositorSession* aSession);
214   void UnregisterInProcessSession(InProcessCompositorSession* aSession);
215 
216   void RebuildRemoteSessions();
217   void RebuildInProcessSessions();
218 
219   void NotifyDisablingWebRender();
220 
221   void FallbackToSoftware(const char* aMessage);
222 
223  private:
224   GPUProcessManager();
225 
226   // Permanently disable the GPU process and record a message why.
227   void DisableGPUProcess(const char* aMessage);
228 
229   // Shutdown the GPU process.
230   void CleanShutdown();
231   void DestroyProcess();
232 
233   void HandleProcessLost();
234 
235   void EnsureVsyncIOThread();
236   void ShutdownVsyncIOThread();
237 
238   void EnsureProtocolsReady();
239   void EnsureCompositorManagerChild();
240   void EnsureImageBridgeChild();
241   void EnsureVRManager();
242 
243 #if defined(MOZ_WIDGET_ANDROID)
244   already_AddRefed<UiCompositorControllerChild> CreateUiCompositorController(
245       nsBaseWidget* aWidget, const LayersId aId);
246 #endif  // defined(MOZ_WIDGET_ANDROID)
247 
248   RefPtr<CompositorSession> CreateRemoteSession(
249       nsBaseWidget* aWidget, LayerManager* aLayerManager,
250       const LayersId& aRootLayerTreeId, CSSToLayoutDeviceScale aScale,
251       const CompositorOptions& aOptions, bool aUseExternalSurfaceSize,
252       const gfx::IntSize& aSurfaceSize);
253 
254   DISALLOW_COPY_AND_ASSIGN(GPUProcessManager);
255 
256   class Observer final : public nsIObserver {
257    public:
258     NS_DECL_ISUPPORTS
259     NS_DECL_NSIOBSERVER
260     explicit Observer(GPUProcessManager* aManager);
261 
262    protected:
263     virtual ~Observer() = default;
264 
265     GPUProcessManager* mManager;
266   };
267   friend class Observer;
268 
269  private:
270   bool mDecodeVideoOnGpuProcess = true;
271 
272   RefPtr<Observer> mObserver;
273   mozilla::ipc::TaskFactory<GPUProcessManager> mTaskFactory;
274   RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
275   uint32_t mNextNamespace;
276   uint32_t mIdNamespace;
277   uint32_t mResourceId;
278   uint32_t mNumProcessAttempts;
279 
280   nsTArray<RefPtr<RemoteCompositorSession>> mRemoteSessions;
281   nsTArray<RefPtr<InProcessCompositorSession>> mInProcessSessions;
282   nsTArray<GPUProcessListener*> mListeners;
283 
284   uint32_t mDeviceResetCount;
285   TimeStamp mDeviceResetLastTime;
286 
287   // Fields that are associated with the current GPU process.
288   GPUProcessHost* mProcess;
289   uint64_t mProcessToken;
290   GPUChild* mGPUChild;
291   RefPtr<VsyncBridgeChild> mVsyncBridge;
292   // Collects any pref changes that occur during process launch (after
293   // the initial map is passed in command-line arguments) to be sent
294   // when the process can receive IPC messages.
295   nsTArray<mozilla::dom::Pref> mQueuedPrefs;
296 };
297 
298 }  // namespace gfx
299 }  // namespace mozilla
300 
301 #endif  // _include_mozilla_gfx_ipc_GPUProcessManager_h_
302