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
7 #include "mozilla/layers/CompositorManagerChild.h"
8
9 #include "mozilla/StaticPrefs_layers.h"
10 #include "mozilla/layers/CompositorBridgeChild.h"
11 #include "mozilla/layers/CompositorManagerParent.h"
12 #include "mozilla/layers/CompositorThread.h"
13 #include "mozilla/gfx/gfxVars.h"
14 #include "mozilla/gfx/GPUProcessManager.h"
15 #include "mozilla/dom/ContentChild.h" // for ContentChild
16 #include "mozilla/dom/BrowserChild.h" // for BrowserChild
17 #include "mozilla/ipc/Endpoint.h"
18 #include "VsyncSource.h"
19
20 namespace mozilla {
21 namespace layers {
22
23 using gfx::GPUProcessManager;
24
25 StaticRefPtr<CompositorManagerChild> CompositorManagerChild::sInstance;
26
27 /* static */
IsInitialized(uint64_t aProcessToken)28 bool CompositorManagerChild::IsInitialized(uint64_t aProcessToken) {
29 MOZ_ASSERT(NS_IsMainThread());
30 return sInstance && sInstance->CanSend() &&
31 sInstance->mProcessToken == aProcessToken;
32 }
33
34 /* static */
InitSameProcess(uint32_t aNamespace,uint64_t aProcessToken)35 void CompositorManagerChild::InitSameProcess(uint32_t aNamespace,
36 uint64_t aProcessToken) {
37 MOZ_ASSERT(NS_IsMainThread());
38 if (NS_WARN_IF(IsInitialized(aProcessToken))) {
39 MOZ_ASSERT_UNREACHABLE("Already initialized same process");
40 return;
41 }
42
43 RefPtr<CompositorManagerParent> parent =
44 CompositorManagerParent::CreateSameProcess();
45 RefPtr<CompositorManagerChild> child =
46 new CompositorManagerChild(parent, aProcessToken, aNamespace);
47 if (NS_WARN_IF(!child->CanSend())) {
48 MOZ_DIAGNOSTIC_ASSERT(false, "Failed to open same process protocol");
49 return;
50 }
51
52 parent->BindComplete(/* aIsRoot */ true);
53 sInstance = std::move(child);
54 }
55
56 /* static */
Init(Endpoint<PCompositorManagerChild> && aEndpoint,uint32_t aNamespace,uint64_t aProcessToken)57 bool CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
58 uint32_t aNamespace,
59 uint64_t aProcessToken /* = 0 */) {
60 MOZ_ASSERT(NS_IsMainThread());
61 if (sInstance) {
62 MOZ_ASSERT(sInstance->mNamespace != aNamespace);
63 }
64
65 sInstance = new CompositorManagerChild(std::move(aEndpoint), aProcessToken,
66 aNamespace);
67 return sInstance->CanSend();
68 }
69
70 /* static */
Shutdown()71 void CompositorManagerChild::Shutdown() {
72 MOZ_ASSERT(NS_IsMainThread());
73 CompositorBridgeChild::ShutDown();
74
75 if (!sInstance) {
76 return;
77 }
78
79 sInstance->Close();
80 sInstance = nullptr;
81 }
82
83 /* static */
OnGPUProcessLost(uint64_t aProcessToken)84 void CompositorManagerChild::OnGPUProcessLost(uint64_t aProcessToken) {
85 MOZ_ASSERT(NS_IsMainThread());
86
87 // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
88 // cannot know if the CompositorManagerChild is about to be released but has
89 // yet to be. As such, we want to pre-emptively set mCanSend to false.
90 if (sInstance && sInstance->mProcessToken == aProcessToken) {
91 sInstance->mCanSend = false;
92 }
93 }
94
95 /* static */
CreateContentCompositorBridge(uint32_t aNamespace)96 bool CompositorManagerChild::CreateContentCompositorBridge(
97 uint32_t aNamespace) {
98 MOZ_ASSERT(NS_IsMainThread());
99 if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
100 return false;
101 }
102
103 CompositorBridgeOptions options = ContentCompositorOptions();
104
105 RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
106 if (NS_WARN_IF(
107 !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
108 return false;
109 }
110
111 bridge->InitForContent(aNamespace);
112 return true;
113 }
114
115 /* static */
116 already_AddRefed<CompositorBridgeChild>
CreateWidgetCompositorBridge(uint64_t aProcessToken,LayerManager * aLayerManager,uint32_t aNamespace,CSSToLayoutDeviceScale aScale,const CompositorOptions & aOptions,bool aUseExternalSurfaceSize,const gfx::IntSize & aSurfaceSize)117 CompositorManagerChild::CreateWidgetCompositorBridge(
118 uint64_t aProcessToken, LayerManager* aLayerManager, uint32_t aNamespace,
119 CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
120 bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) {
121 MOZ_ASSERT(XRE_IsParentProcess());
122 MOZ_ASSERT(NS_IsMainThread());
123 if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
124 return nullptr;
125 }
126
127 TimeDuration vsyncRate = gfxPlatform::GetPlatform()
128 ->GetHardwareVsync()
129 ->GetGlobalDisplay()
130 .GetVsyncRate();
131
132 CompositorBridgeOptions options = WidgetCompositorOptions(
133 aScale, vsyncRate, aOptions, aUseExternalSurfaceSize, aSurfaceSize);
134
135 RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
136 if (NS_WARN_IF(
137 !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
138 return nullptr;
139 }
140
141 bridge->InitForWidget(aProcessToken, aLayerManager, aNamespace);
142 return bridge.forget();
143 }
144
145 /* static */
146 already_AddRefed<CompositorBridgeChild>
CreateSameProcessWidgetCompositorBridge(LayerManager * aLayerManager,uint32_t aNamespace)147 CompositorManagerChild::CreateSameProcessWidgetCompositorBridge(
148 LayerManager* aLayerManager, uint32_t aNamespace) {
149 MOZ_ASSERT(XRE_IsParentProcess());
150 MOZ_ASSERT(NS_IsMainThread());
151 if (NS_WARN_IF(!sInstance || !sInstance->CanSend())) {
152 return nullptr;
153 }
154
155 CompositorBridgeOptions options = SameProcessWidgetCompositorOptions();
156
157 RefPtr<CompositorBridgeChild> bridge = new CompositorBridgeChild(sInstance);
158 if (NS_WARN_IF(
159 !sInstance->SendPCompositorBridgeConstructor(bridge, options))) {
160 return nullptr;
161 }
162
163 bridge->InitForWidget(1, aLayerManager, aNamespace);
164 return bridge.forget();
165 }
166
CompositorManagerChild(CompositorManagerParent * aParent,uint64_t aProcessToken,uint32_t aNamespace)167 CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent,
168 uint64_t aProcessToken,
169 uint32_t aNamespace)
170 : mProcessToken(aProcessToken),
171 mNamespace(aNamespace),
172 mResourceId(0),
173 mCanSend(false) {
174 MOZ_ASSERT(aParent);
175
176 SetOtherProcessId(base::GetCurrentProcId());
177 ipc::MessageChannel* channel = aParent->GetIPCChannel();
178 if (NS_WARN_IF(!Open(channel, CompositorThread(), ipc::ChildSide))) {
179 return;
180 }
181
182 mCanSend = true;
183 AddRef();
184 SetReplyTimeout();
185 }
186
CompositorManagerChild(Endpoint<PCompositorManagerChild> && aEndpoint,uint64_t aProcessToken,uint32_t aNamespace)187 CompositorManagerChild::CompositorManagerChild(
188 Endpoint<PCompositorManagerChild>&& aEndpoint, uint64_t aProcessToken,
189 uint32_t aNamespace)
190 : mProcessToken(aProcessToken),
191 mNamespace(aNamespace),
192 mResourceId(0),
193 mCanSend(false) {
194 if (NS_WARN_IF(!aEndpoint.Bind(this))) {
195 return;
196 }
197
198 mCanSend = true;
199 AddRef();
200 SetReplyTimeout();
201 }
202
ActorDealloc()203 void CompositorManagerChild::ActorDealloc() {
204 MOZ_ASSERT(!mCanSend);
205 Release();
206 }
207
ActorDestroy(ActorDestroyReason aReason)208 void CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason) {
209 mCanSend = false;
210 if (sInstance == this) {
211 sInstance = nullptr;
212 }
213 }
214
HandleFatalError(const char * aMsg) const215 void CompositorManagerChild::HandleFatalError(const char* aMsg) const {
216 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
217 }
218
ProcessingError(Result aCode,const char * aReason)219 void CompositorManagerChild::ProcessingError(Result aCode,
220 const char* aReason) {
221 if (aCode != MsgDropped) {
222 gfxDevCrash(gfx::LogReason::ProcessingError)
223 << "Processing error in CompositorBridgeChild: " << int(aCode);
224 }
225 }
226
SetReplyTimeout()227 void CompositorManagerChild::SetReplyTimeout() {
228 #ifndef DEBUG
229 // Add a timeout for release builds to kill GPU process when it hangs.
230 if (XRE_IsParentProcess() && GPUProcessManager::Get()->GetGPUChild()) {
231 int32_t timeout =
232 StaticPrefs::layers_gpu_process_ipc_reply_timeout_ms_AtStartup();
233 SetReplyTimeoutMs(timeout);
234 }
235 #endif
236 }
237
ShouldContinueFromReplyTimeout()238 bool CompositorManagerChild::ShouldContinueFromReplyTimeout() {
239 if (XRE_IsParentProcess()) {
240 gfxCriticalNote << "Killing GPU process due to IPC reply timeout";
241 MOZ_DIAGNOSTIC_ASSERT(GPUProcessManager::Get()->GetGPUChild());
242 GPUProcessManager::Get()->KillProcess();
243 }
244 return false;
245 }
246
RecvNotifyWebRenderError(const WebRenderError && aError)247 mozilla::ipc::IPCResult CompositorManagerChild::RecvNotifyWebRenderError(
248 const WebRenderError&& aError) {
249 MOZ_ASSERT(XRE_IsParentProcess());
250 MOZ_ASSERT(NS_IsMainThread());
251 GPUProcessManager::Get()->NotifyWebRenderError(aError);
252 return IPC_OK();
253 }
254
255 } // namespace layers
256 } // namespace mozilla
257