/src/mozilla-central/gfx/ipc/GPUProcessManager.cpp
Line | Count | Source (jump to first uncovered line) |
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 "GPUProcessManager.h" |
8 | | |
9 | | #include "gfxPrefs.h" |
10 | | #include "GPUProcessHost.h" |
11 | | #include "GPUProcessListener.h" |
12 | | #include "mozilla/MemoryReportingProcess.h" |
13 | | #include "mozilla/Sprintf.h" |
14 | | #include "mozilla/StaticPtr.h" |
15 | | #include "mozilla/StaticPrefs.h" |
16 | | #include "mozilla/dom/ContentParent.h" |
17 | | #include "mozilla/gfx/gfxVars.h" |
18 | | #include "mozilla/layers/APZCTreeManagerChild.h" |
19 | | #include "mozilla/layers/CompositorBridgeParent.h" |
20 | | #include "mozilla/layers/CompositorManagerChild.h" |
21 | | #include "mozilla/layers/CompositorManagerParent.h" |
22 | | #include "mozilla/layers/CompositorOptions.h" |
23 | | #include "mozilla/layers/ImageBridgeChild.h" |
24 | | #include "mozilla/layers/ImageBridgeParent.h" |
25 | | #include "mozilla/layers/InProcessCompositorSession.h" |
26 | | #include "mozilla/layers/LayerTreeOwnerTracker.h" |
27 | | #include "mozilla/layers/RemoteCompositorSession.h" |
28 | | #include "mozilla/widget/PlatformWidgetTypes.h" |
29 | | #include "nsAppRunner.h" |
30 | | #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING |
31 | | # include "mozilla/widget/CompositorWidgetChild.h" |
32 | | #endif |
33 | | #include "nsBaseWidget.h" |
34 | | #include "nsContentUtils.h" |
35 | | #include "VRManagerChild.h" |
36 | | #include "VRManagerParent.h" |
37 | | #include "VsyncBridgeChild.h" |
38 | | #include "VsyncIOThreadHolder.h" |
39 | | #include "VsyncSource.h" |
40 | | #include "mozilla/dom/VideoDecoderManagerChild.h" |
41 | | #include "mozilla/dom/VideoDecoderManagerParent.h" |
42 | | #include "nsExceptionHandler.h" |
43 | | #include "nsPrintfCString.h" |
44 | | |
45 | | #if defined(MOZ_WIDGET_ANDROID) |
46 | | #include "mozilla/widget/AndroidUiThread.h" |
47 | | #include "mozilla/layers/UiCompositorControllerChild.h" |
48 | | #endif // defined(MOZ_WIDGET_ANDROID) |
49 | | |
50 | | namespace mozilla { |
51 | | namespace gfx { |
52 | | |
53 | | using namespace mozilla::layers; |
54 | | |
55 | | enum class FallbackType : uint32_t |
56 | | { |
57 | | NONE = 0, |
58 | | DECODINGDISABLED, |
59 | | DISABLED, |
60 | | }; |
61 | | |
62 | | static StaticAutoPtr<GPUProcessManager> sSingleton; |
63 | | |
64 | | GPUProcessManager* |
65 | | GPUProcessManager::Get() |
66 | 0 | { |
67 | 0 | return sSingleton; |
68 | 0 | } |
69 | | |
70 | | void |
71 | | GPUProcessManager::Initialize() |
72 | 0 | { |
73 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
74 | 0 | sSingleton = new GPUProcessManager(); |
75 | 0 | } |
76 | | |
77 | | void |
78 | | GPUProcessManager::Shutdown() |
79 | 0 | { |
80 | 0 | sSingleton = nullptr; |
81 | 0 | } |
82 | | |
83 | | GPUProcessManager::GPUProcessManager() |
84 | | : mTaskFactory(this), |
85 | | mNextNamespace(0), |
86 | | mIdNamespace(0), |
87 | | mResourceId(0), |
88 | | mNumProcessAttempts(0), |
89 | | mDeviceResetCount(0), |
90 | | mProcess(nullptr), |
91 | | mProcessToken(0), |
92 | | mGPUChild(nullptr) |
93 | 0 | { |
94 | 0 | MOZ_COUNT_CTOR(GPUProcessManager); |
95 | 0 |
|
96 | 0 | mIdNamespace = AllocateNamespace(); |
97 | 0 | mObserver = new Observer(this); |
98 | 0 | nsContentUtils::RegisterShutdownObserver(mObserver); |
99 | 0 |
|
100 | 0 | mDeviceResetLastTime = TimeStamp::Now(); |
101 | 0 |
|
102 | 0 | LayerTreeOwnerTracker::Initialize(); |
103 | 0 | } |
104 | | |
105 | | GPUProcessManager::~GPUProcessManager() |
106 | 0 | { |
107 | 0 | MOZ_COUNT_DTOR(GPUProcessManager); |
108 | 0 |
|
109 | 0 | LayerTreeOwnerTracker::Shutdown(); |
110 | 0 |
|
111 | 0 | // The GPU process should have already been shut down. |
112 | 0 | MOZ_ASSERT(!mProcess && !mGPUChild); |
113 | 0 |
|
114 | 0 | // We should have already removed observers. |
115 | 0 | MOZ_ASSERT(!mObserver); |
116 | 0 | } |
117 | | |
118 | | NS_IMPL_ISUPPORTS(GPUProcessManager::Observer, nsIObserver); |
119 | | |
120 | | GPUProcessManager::Observer::Observer(GPUProcessManager* aManager) |
121 | | : mManager(aManager) |
122 | 0 | { |
123 | 0 | } |
124 | | |
125 | | NS_IMETHODIMP |
126 | | GPUProcessManager::Observer::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) |
127 | 0 | { |
128 | 0 | if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { |
129 | 0 | mManager->OnXPCOMShutdown(); |
130 | 0 | } |
131 | 0 | return NS_OK; |
132 | 0 | } |
133 | | |
134 | | void |
135 | | GPUProcessManager::OnXPCOMShutdown() |
136 | 0 | { |
137 | 0 | if (mObserver) { |
138 | 0 | nsContentUtils::UnregisterShutdownObserver(mObserver); |
139 | 0 | mObserver = nullptr; |
140 | 0 | } |
141 | 0 |
|
142 | 0 | CleanShutdown(); |
143 | 0 | } |
144 | | |
145 | | void |
146 | | GPUProcessManager::LaunchGPUProcess() |
147 | 0 | { |
148 | 0 | if (mProcess) { |
149 | 0 | return; |
150 | 0 | } |
151 | 0 | |
152 | 0 | // Start the Vsync I/O thread so can use it as soon as the process launches. |
153 | 0 | EnsureVsyncIOThread(); |
154 | 0 |
|
155 | 0 | mNumProcessAttempts++; |
156 | 0 |
|
157 | 0 | std::vector<std::string> extraArgs; |
158 | 0 | nsCString parentBuildID(mozilla::PlatformBuildID()); |
159 | 0 | extraArgs.push_back("-parentBuildID"); |
160 | 0 | extraArgs.push_back(parentBuildID.get()); |
161 | 0 |
|
162 | 0 | // The subprocess is launched asynchronously, so we wait for a callback to |
163 | 0 | // acquire the IPDL actor. |
164 | 0 | mProcess = new GPUProcessHost(this); |
165 | 0 | if (!mProcess->Launch(extraArgs)) { |
166 | 0 | DisableGPUProcess("Failed to launch GPU process"); |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | | void |
171 | | GPUProcessManager::DisableGPUProcess(const char* aMessage) |
172 | 0 | { |
173 | 0 | if (!gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { |
174 | 0 | return; |
175 | 0 | } |
176 | 0 | |
177 | 0 | gfxConfig::SetFailed(Feature::GPU_PROCESS, FeatureStatus::Failed, aMessage); |
178 | 0 | gfxCriticalNote << aMessage; |
179 | 0 |
|
180 | 0 | gfxPlatform::NotifyGPUProcessDisabled(); |
181 | 0 |
|
182 | 0 | Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS, |
183 | 0 | uint32_t(FallbackType::DISABLED)); |
184 | 0 |
|
185 | 0 | DestroyProcess(); |
186 | 0 | ShutdownVsyncIOThread(); |
187 | 0 |
|
188 | 0 | // We may have been in the middle of guaranteeing our various services are |
189 | 0 | // available when one failed. Some callers may fallback to using the same |
190 | 0 | // process equivalent, and we need to make sure those services are setup |
191 | 0 | // correctly. We cannot re-enter DisableGPUProcess from this call because we |
192 | 0 | // know that it is disabled in the config above. |
193 | 0 | EnsureProtocolsReady(); |
194 | 0 |
|
195 | 0 | // If we disable the GPU process during reinitialization after a previous |
196 | 0 | // crash, then we need to tell the content processes again, because they |
197 | 0 | // need to rebind to the UI process. |
198 | 0 | HandleProcessLost(); |
199 | 0 | } |
200 | | |
201 | | bool |
202 | | GPUProcessManager::EnsureGPUReady() |
203 | 0 | { |
204 | 0 | if (mProcess && !mProcess->IsConnected()) { |
205 | 0 | if (!mProcess->WaitForLaunch()) { |
206 | 0 | // If this fails, we should have fired OnProcessLaunchComplete and |
207 | 0 | // removed the process. |
208 | 0 | MOZ_ASSERT(!mProcess && !mGPUChild); |
209 | 0 | return false; |
210 | 0 | } |
211 | 0 | } |
212 | 0 |
|
213 | 0 | if (mGPUChild) { |
214 | 0 | if (mGPUChild->EnsureGPUReady()) { |
215 | 0 | return true; |
216 | 0 | } |
217 | 0 | |
218 | 0 | // If the initialization above fails, we likely have a GPU process teardown |
219 | 0 | // waiting in our message queue (or will soon). We need to ensure we don't |
220 | 0 | // restart it later because if we fail here, our callers assume they should |
221 | 0 | // fall back to a combined UI/GPU process. This also ensures our internal |
222 | 0 | // state is consistent (e.g. process token is reset). |
223 | 0 | DisableGPUProcess("Failed to initialize GPU process"); |
224 | 0 | } |
225 | 0 |
|
226 | 0 | return false; |
227 | 0 | } |
228 | | |
229 | | void |
230 | | GPUProcessManager::EnsureProtocolsReady() |
231 | 0 | { |
232 | 0 | EnsureCompositorManagerChild(); |
233 | 0 | EnsureImageBridgeChild(); |
234 | 0 | EnsureVRManager(); |
235 | 0 | } |
236 | | |
237 | | void |
238 | | GPUProcessManager::EnsureCompositorManagerChild() |
239 | 0 | { |
240 | 0 | bool gpuReady = EnsureGPUReady(); |
241 | 0 | if (CompositorManagerChild::IsInitialized(mProcessToken)) { |
242 | 0 | return; |
243 | 0 | } |
244 | 0 | |
245 | 0 | if (!gpuReady) { |
246 | 0 | CompositorManagerChild::InitSameProcess(AllocateNamespace(), mProcessToken); |
247 | 0 | return; |
248 | 0 | } |
249 | 0 | |
250 | 0 | ipc::Endpoint<PCompositorManagerParent> parentPipe; |
251 | 0 | ipc::Endpoint<PCompositorManagerChild> childPipe; |
252 | 0 | nsresult rv = PCompositorManager::CreateEndpoints( |
253 | 0 | mGPUChild->OtherPid(), |
254 | 0 | base::GetCurrentProcId(), |
255 | 0 | &parentPipe, |
256 | 0 | &childPipe); |
257 | 0 | if (NS_FAILED(rv)) { |
258 | 0 | DisableGPUProcess("Failed to create PCompositorManager endpoints"); |
259 | 0 | return; |
260 | 0 | } |
261 | 0 | |
262 | 0 | mGPUChild->SendInitCompositorManager(std::move(parentPipe)); |
263 | 0 | CompositorManagerChild::Init(std::move(childPipe), AllocateNamespace(), |
264 | 0 | mProcessToken); |
265 | 0 | } |
266 | | |
267 | | void |
268 | | GPUProcessManager::EnsureImageBridgeChild() |
269 | 0 | { |
270 | 0 | if (ImageBridgeChild::GetSingleton()) { |
271 | 0 | return; |
272 | 0 | } |
273 | 0 | |
274 | 0 | if (!EnsureGPUReady()) { |
275 | 0 | ImageBridgeChild::InitSameProcess(AllocateNamespace()); |
276 | 0 | return; |
277 | 0 | } |
278 | 0 | |
279 | 0 | ipc::Endpoint<PImageBridgeParent> parentPipe; |
280 | 0 | ipc::Endpoint<PImageBridgeChild> childPipe; |
281 | 0 | nsresult rv = PImageBridge::CreateEndpoints( |
282 | 0 | mGPUChild->OtherPid(), |
283 | 0 | base::GetCurrentProcId(), |
284 | 0 | &parentPipe, |
285 | 0 | &childPipe); |
286 | 0 | if (NS_FAILED(rv)) { |
287 | 0 | DisableGPUProcess("Failed to create PImageBridge endpoints"); |
288 | 0 | return; |
289 | 0 | } |
290 | 0 | |
291 | 0 | mGPUChild->SendInitImageBridge(std::move(parentPipe)); |
292 | 0 | ImageBridgeChild::InitWithGPUProcess(std::move(childPipe), AllocateNamespace()); |
293 | 0 | } |
294 | | |
295 | | void |
296 | | GPUProcessManager::EnsureVRManager() |
297 | 0 | { |
298 | 0 | if (VRManagerChild::IsCreated()) { |
299 | 0 | return; |
300 | 0 | } |
301 | 0 | |
302 | 0 | if (!EnsureGPUReady()) { |
303 | 0 | VRManagerChild::InitSameProcess(); |
304 | 0 | return; |
305 | 0 | } |
306 | 0 | |
307 | 0 | ipc::Endpoint<PVRManagerParent> parentPipe; |
308 | 0 | ipc::Endpoint<PVRManagerChild> childPipe; |
309 | 0 | nsresult rv = PVRManager::CreateEndpoints( |
310 | 0 | mGPUChild->OtherPid(), |
311 | 0 | base::GetCurrentProcId(), |
312 | 0 | &parentPipe, |
313 | 0 | &childPipe); |
314 | 0 | if (NS_FAILED(rv)) { |
315 | 0 | DisableGPUProcess("Failed to create PVRManager endpoints"); |
316 | 0 | return; |
317 | 0 | } |
318 | 0 | |
319 | 0 | mGPUChild->SendInitVRManager(std::move(parentPipe)); |
320 | 0 | VRManagerChild::InitWithGPUProcess(std::move(childPipe)); |
321 | 0 | } |
322 | | |
323 | | #if defined(MOZ_WIDGET_ANDROID) |
324 | | already_AddRefed<UiCompositorControllerChild> |
325 | | GPUProcessManager::CreateUiCompositorController(nsBaseWidget* aWidget, const LayersId aId) |
326 | | { |
327 | | RefPtr<UiCompositorControllerChild> result; |
328 | | |
329 | | if (!EnsureGPUReady()) { |
330 | | result = UiCompositorControllerChild::CreateForSameProcess(aId); |
331 | | } else { |
332 | | ipc::Endpoint<PUiCompositorControllerParent> parentPipe; |
333 | | ipc::Endpoint<PUiCompositorControllerChild> childPipe; |
334 | | nsresult rv = PUiCompositorController::CreateEndpoints( |
335 | | mGPUChild->OtherPid(), |
336 | | base::GetCurrentProcId(), |
337 | | &parentPipe, |
338 | | &childPipe); |
339 | | if (NS_FAILED(rv)) { |
340 | | DisableGPUProcess("Failed to create PUiCompositorController endpoints"); |
341 | | return nullptr; |
342 | | } |
343 | | |
344 | | mGPUChild->SendInitUiCompositorController(aId, std::move(parentPipe)); |
345 | | result = UiCompositorControllerChild::CreateForGPUProcess(mProcessToken, std::move(childPipe)); |
346 | | } |
347 | | if (result) { |
348 | | result->SetBaseWidget(aWidget); |
349 | | } |
350 | | return result.forget(); |
351 | | } |
352 | | #endif // defined(MOZ_WIDGET_ANDROID) |
353 | | |
354 | | void |
355 | | GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) |
356 | 0 | { |
357 | 0 | MOZ_ASSERT(mProcess && mProcess == aHost); |
358 | 0 |
|
359 | 0 | if (!mProcess->IsConnected()) { |
360 | 0 | DisableGPUProcess("Failed to connect GPU process"); |
361 | 0 | return; |
362 | 0 | } |
363 | 0 | |
364 | 0 | mGPUChild = mProcess->GetActor(); |
365 | 0 | mProcessToken = mProcess->GetProcessToken(); |
366 | 0 |
|
367 | 0 | Endpoint<PVsyncBridgeParent> vsyncParent; |
368 | 0 | Endpoint<PVsyncBridgeChild> vsyncChild; |
369 | 0 | nsresult rv = PVsyncBridge::CreateEndpoints( |
370 | 0 | mGPUChild->OtherPid(), |
371 | 0 | base::GetCurrentProcId(), |
372 | 0 | &vsyncParent, |
373 | 0 | &vsyncChild); |
374 | 0 | if (NS_FAILED(rv)) { |
375 | 0 | DisableGPUProcess("Failed to create PVsyncBridge endpoints"); |
376 | 0 | return; |
377 | 0 | } |
378 | 0 | |
379 | 0 | mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken, std::move(vsyncChild)); |
380 | 0 | mGPUChild->SendInitVsyncBridge(std::move(vsyncParent)); |
381 | 0 |
|
382 | 0 | CrashReporter::AnnotateCrashReport( |
383 | 0 | CrashReporter::Annotation::GPUProcessStatus, NS_LITERAL_CSTRING("Running")); |
384 | 0 |
|
385 | 0 | CrashReporter::AnnotateCrashReport( |
386 | 0 | CrashReporter::Annotation::GPUProcessLaunchCount, |
387 | 0 | static_cast<int>(mNumProcessAttempts)); |
388 | 0 | } |
389 | | |
390 | | static bool |
391 | | ShouldLimitDeviceResets(uint32_t count, int32_t deltaMilliseconds) |
392 | 0 | { |
393 | 0 | // We decide to limit by comparing the amount of resets that have happened |
394 | 0 | // and time since the last reset to two prefs. |
395 | 0 | int32_t timeLimit = gfxPrefs::DeviceResetThresholdMilliseconds(); |
396 | 0 | int32_t countLimit = gfxPrefs::DeviceResetLimitCount(); |
397 | 0 |
|
398 | 0 | bool hasTimeLimit = timeLimit >= 0; |
399 | 0 | bool hasCountLimit = countLimit >= 0; |
400 | 0 |
|
401 | 0 | bool triggeredTime = deltaMilliseconds < timeLimit; |
402 | 0 | bool triggeredCount = count > (uint32_t)countLimit; |
403 | 0 |
|
404 | 0 | // If we have both prefs set then it needs to trigger both limits, |
405 | 0 | // otherwise we only test the pref that is set or none |
406 | 0 | if (hasTimeLimit && hasCountLimit) { |
407 | 0 | return triggeredTime && triggeredCount; |
408 | 0 | } else if (hasTimeLimit) { |
409 | 0 | return triggeredTime; |
410 | 0 | } else if (hasCountLimit) { |
411 | 0 | return triggeredCount; |
412 | 0 | } |
413 | 0 | |
414 | 0 | return false; |
415 | 0 | } |
416 | | |
417 | | void |
418 | | GPUProcessManager::ResetCompositors() |
419 | 0 | { |
420 | 0 | // Note: this will recreate devices in addition to recreating compositors. |
421 | 0 | // This isn't optimal, but this is only used on linux where acceleration |
422 | 0 | // isn't enabled by default, and this way we don't need a new code path. |
423 | 0 | SimulateDeviceReset(); |
424 | 0 | } |
425 | | |
426 | | void |
427 | | GPUProcessManager::SimulateDeviceReset() |
428 | 0 | { |
429 | 0 | // Make sure we rebuild environment and configuration for accelerated features. |
430 | 0 | gfxPlatform::GetPlatform()->CompositorUpdated(); |
431 | 0 |
|
432 | 0 | if (mProcess) { |
433 | 0 | GPUDeviceData data; |
434 | 0 | if (mGPUChild->SendSimulateDeviceReset(&data)) { |
435 | 0 | gfxPlatform::GetPlatform()->ImportGPUDeviceData(data); |
436 | 0 | } |
437 | 0 | OnRemoteProcessDeviceReset(mProcess); |
438 | 0 | } else { |
439 | 0 | OnInProcessDeviceReset(); |
440 | 0 | } |
441 | 0 | } |
442 | | |
443 | | void |
444 | | GPUProcessManager::DisableWebRender(wr::WebRenderError aError) |
445 | 0 | { |
446 | 0 | if (!gfx::gfxVars::UseWebRender()) { |
447 | 0 | return; |
448 | 0 | } |
449 | 0 | // Disable WebRender |
450 | 0 | if (aError == wr::WebRenderError::INITIALIZE) { |
451 | 0 | gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER).ForceDisable( |
452 | 0 | gfx::FeatureStatus::Unavailable, |
453 | 0 | "WebRender initialization failed", |
454 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_INITIALIZE")); |
455 | 0 | } else if (aError == wr::WebRenderError::MAKE_CURRENT) { |
456 | 0 | gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER).ForceDisable( |
457 | 0 | gfx::FeatureStatus::Unavailable, |
458 | 0 | "Failed to make render context current", |
459 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_MAKE_CURRENT")); |
460 | 0 | } else if (aError == wr::WebRenderError::RENDER) { |
461 | 0 | gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER).ForceDisable( |
462 | 0 | gfx::FeatureStatus::Unavailable, |
463 | 0 | "Failed to render WebRender", |
464 | 0 | NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_RENDER")); |
465 | 0 | } else { |
466 | 0 | MOZ_ASSERT_UNREACHABLE("Invalid value"); |
467 | 0 | } |
468 | 0 | gfx::gfxVars::SetUseWebRender(false); |
469 | 0 |
|
470 | 0 | if (mProcess) { |
471 | 0 | OnRemoteProcessDeviceReset(mProcess); |
472 | 0 | } else { |
473 | 0 | OnInProcessDeviceReset(); |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | | void |
478 | | GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) |
479 | 0 | { |
480 | 0 | DisableWebRender(aError); |
481 | 0 | } |
482 | | |
483 | | void |
484 | | GPUProcessManager::OnInProcessDeviceReset() |
485 | 0 | { |
486 | 0 | RebuildInProcessSessions(); |
487 | 0 | NotifyListenersOnCompositeDeviceReset(); |
488 | 0 | } |
489 | | |
490 | | void |
491 | | GPUProcessManager::OnRemoteProcessDeviceReset(GPUProcessHost* aHost) |
492 | 0 | { |
493 | 0 | // Detect whether the device is resetting too quickly or too much |
494 | 0 | // indicating that we should give up and use software |
495 | 0 | mDeviceResetCount++; |
496 | 0 |
|
497 | 0 | auto newTime = TimeStamp::Now(); |
498 | 0 | auto delta = (int32_t)(newTime - mDeviceResetLastTime).ToMilliseconds(); |
499 | 0 | mDeviceResetLastTime = newTime; |
500 | 0 |
|
501 | 0 | if (ShouldLimitDeviceResets(mDeviceResetCount, delta)) { |
502 | 0 | DestroyProcess(); |
503 | 0 | DisableGPUProcess("GPU processed experienced too many device resets"); |
504 | 0 |
|
505 | 0 | // Reaches the limited TDR attempts, fallback to software solution. |
506 | 0 | gfxConfig::SetFailed(Feature::HW_COMPOSITING, |
507 | 0 | FeatureStatus::Blocked, |
508 | 0 | "Too many attemps of D3D11 creation, fallback to software solution."); |
509 | 0 | gfxConfig::SetFailed(Feature::D3D11_COMPOSITING, |
510 | 0 | FeatureStatus::Blocked, |
511 | 0 | "Too many attemps of D3D11 creation, fallback to software solution."); |
512 | 0 | gfxConfig::SetFailed(Feature::DIRECT2D, |
513 | 0 | FeatureStatus::Blocked, |
514 | 0 | "Too many attemps of D3D11 creation, fallback to software solution."); |
515 | 0 |
|
516 | 0 | HandleProcessLost(); |
517 | 0 | return; |
518 | 0 | } |
519 | 0 | |
520 | 0 | RebuildRemoteSessions(); |
521 | 0 | NotifyListenersOnCompositeDeviceReset(); |
522 | 0 | } |
523 | | |
524 | | void |
525 | | GPUProcessManager::NotifyListenersOnCompositeDeviceReset() |
526 | 0 | { |
527 | 0 | for (const auto& listener : mListeners) { |
528 | 0 | listener->OnCompositorDeviceReset(); |
529 | 0 | } |
530 | 0 | } |
531 | | |
532 | | void |
533 | | GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost) |
534 | 0 | { |
535 | 0 | MOZ_ASSERT(mProcess && mProcess == aHost); |
536 | 0 |
|
537 | 0 | CompositorManagerChild::OnGPUProcessLost(aHost->GetProcessToken()); |
538 | 0 | DestroyProcess(); |
539 | 0 |
|
540 | 0 | if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestarts())) { |
541 | 0 | char disableMessage[64]; |
542 | 0 | SprintfLiteral(disableMessage, "GPU process disabled after %d attempts", |
543 | 0 | mNumProcessAttempts); |
544 | 0 | DisableGPUProcess(disableMessage); |
545 | 0 | } else if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestartsWithDecoder()) && |
546 | 0 | mDecodeVideoOnGpuProcess) { |
547 | 0 | mDecodeVideoOnGpuProcess = false; |
548 | 0 | Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS, |
549 | 0 | uint32_t(FallbackType::DECODINGDISABLED)); |
550 | 0 | HandleProcessLost(); |
551 | 0 | } else { |
552 | 0 | Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS, |
553 | 0 | uint32_t(FallbackType::NONE)); |
554 | 0 | HandleProcessLost(); |
555 | 0 | } |
556 | 0 | } |
557 | | |
558 | | void |
559 | | GPUProcessManager::HandleProcessLost() |
560 | 0 | { |
561 | 0 | if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) { |
562 | 0 | LaunchGPUProcess(); |
563 | 0 | } |
564 | 0 |
|
565 | 0 | // The shutdown and restart sequence for the GPU process is as follows: |
566 | 0 | // |
567 | 0 | // (1) The GPU process dies. IPDL will enqueue an ActorDestroy message on |
568 | 0 | // each channel owning a bridge to the GPU process, on the thread |
569 | 0 | // owning that channel. |
570 | 0 | // |
571 | 0 | // (2) The first channel to process its ActorDestroy message will post a |
572 | 0 | // message to the main thread to call NotifyRemoteActorDestroyed on |
573 | 0 | // the GPUProcessManager, which calls OnProcessUnexpectedShutdown if |
574 | 0 | // it has not handled shutdown for this process yet. |
575 | 0 | // |
576 | 0 | // (3) We then notify each widget that its session with the compositor is |
577 | 0 | // now invalid. The widget is responsible for destroying its layer |
578 | 0 | // manager and CompositorBridgeChild. Note that at this stage, not |
579 | 0 | // all actors may have received ActorDestroy yet. CompositorBridgeChild |
580 | 0 | // may attempt to send messages, and if this happens, it will probably |
581 | 0 | // report a MsgDropped error. This is okay. |
582 | 0 | // |
583 | 0 | // (4) At this point, the UI process has a clean slate: no layers should |
584 | 0 | // exist for the old compositor. We may make a decision on whether or |
585 | 0 | // not to re-launch the GPU process. Currently, we do not relaunch it, |
586 | 0 | // and any new compositors will be created in-process and will default |
587 | 0 | // to software. |
588 | 0 | // |
589 | 0 | // (5) Next we notify each ContentParent of the lost connection. It will |
590 | 0 | // request new endpoints from the GPUProcessManager and forward them |
591 | 0 | // to its ContentChild. The parent-side of these endpoints may come |
592 | 0 | // from the compositor thread of the UI process, or the compositor |
593 | 0 | // thread of the GPU process. However, no actual compositors should |
594 | 0 | // exist yet. |
595 | 0 | // |
596 | 0 | // (6) Each ContentChild will receive new endpoints. It will destroy its |
597 | 0 | // Compositor/ImageBridgeChild singletons and recreate them, as well |
598 | 0 | // as invalidate all retained layers. |
599 | 0 | // |
600 | 0 | // (7) In addition, each ContentChild will ask each of its TabChildren |
601 | 0 | // to re-request association with the compositor for the window |
602 | 0 | // owning the tab. The sequence of calls looks like: |
603 | 0 | // (a) [CONTENT] ContentChild::RecvReinitRendering |
604 | 0 | // (b) [CONTENT] TabChild::ReinitRendering |
605 | 0 | // (c) [CONTENT] TabChild::SendEnsureLayersConnected |
606 | 0 | // (d) [UI] TabParent::RecvEnsureLayersConnected |
607 | 0 | // (e) [UI] RenderFrameParent::EnsureLayersConnected |
608 | 0 | // (f) [UI] CompositorBridgeChild::SendNotifyChildRecreated |
609 | 0 | // |
610 | 0 | // Note that at step (e), RenderFrameParent will call GetLayerManager |
611 | 0 | // on the nsIWidget owning the tab. This step ensures that a compositor |
612 | 0 | // exists for the window. If we decided to launch a new GPU Process, |
613 | 0 | // at this point we block until the process has launched and we're |
614 | 0 | // able to create a new window compositor. Otherwise, if compositing |
615 | 0 | // is now in-process, this will simply create a new |
616 | 0 | // CompositorBridgeParent in the UI process. If there are multiple tabs |
617 | 0 | // in the same window, additional tabs will simply return the already- |
618 | 0 | // established compositor. |
619 | 0 | // |
620 | 0 | // Finally, this step serves one other crucial function: tabs must be |
621 | 0 | // associated with a window compositor or else they can't forward |
622 | 0 | // layer transactions. So this step both ensures that a compositor |
623 | 0 | // exists, and that the tab can forward layers. |
624 | 0 | // |
625 | 0 | // (8) Last, if the window had no remote tabs, step (7) will not have |
626 | 0 | // applied, and the window will not have a new compositor just yet. |
627 | 0 | // The next refresh tick and paint will ensure that one exists, again |
628 | 0 | // via nsIWidget::GetLayerManager. |
629 | 0 | RebuildRemoteSessions(); |
630 | 0 |
|
631 | 0 | // Notify content. This will ensure that each content process re-establishes |
632 | 0 | // a connection to the compositor thread (whether it's in-process or in a |
633 | 0 | // newly launched GPU process). |
634 | 0 | for (const auto& listener : mListeners) { |
635 | 0 | listener->OnCompositorUnexpectedShutdown(); |
636 | 0 | } |
637 | 0 | } |
638 | | |
639 | | void |
640 | | GPUProcessManager::RebuildRemoteSessions() |
641 | 0 | { |
642 | 0 | // Build a list of sessions to notify, since notification might delete |
643 | 0 | // entries from the list. |
644 | 0 | nsTArray<RefPtr<RemoteCompositorSession>> sessions; |
645 | 0 | for (auto& session : mRemoteSessions) { |
646 | 0 | sessions.AppendElement(session); |
647 | 0 | } |
648 | 0 |
|
649 | 0 | // Notify each widget that we have lost the GPU process. This will ensure |
650 | 0 | // that each widget destroys its layer manager and CompositorBridgeChild. |
651 | 0 | for (const auto& session : sessions) { |
652 | 0 | session->NotifySessionLost(); |
653 | 0 | } |
654 | 0 | } |
655 | | |
656 | | void |
657 | | GPUProcessManager::RebuildInProcessSessions() |
658 | 0 | { |
659 | 0 | // Build a list of sessions to notify, since notification might delete |
660 | 0 | // entries from the list. |
661 | 0 | nsTArray<RefPtr<InProcessCompositorSession>> sessions; |
662 | 0 | for (auto& session : mInProcessSessions) { |
663 | 0 | sessions.AppendElement(session); |
664 | 0 | } |
665 | 0 |
|
666 | 0 | // Notify each widget that we have lost the GPU process. This will ensure |
667 | 0 | // that each widget destroys its layer manager and CompositorBridgeChild. |
668 | 0 | for (const auto& session : sessions) { |
669 | 0 | session->NotifySessionLost(); |
670 | 0 | } |
671 | 0 | } |
672 | | |
673 | | void |
674 | | GPUProcessManager::NotifyRemoteActorDestroyed(const uint64_t& aProcessToken) |
675 | 0 | { |
676 | 0 | if (!NS_IsMainThread()) { |
677 | 0 | RefPtr<Runnable> task = mTaskFactory.NewRunnableMethod( |
678 | 0 | &GPUProcessManager::NotifyRemoteActorDestroyed, aProcessToken); |
679 | 0 | NS_DispatchToMainThread(task.forget()); |
680 | 0 | return; |
681 | 0 | } |
682 | 0 | |
683 | 0 | if (mProcessToken != aProcessToken) { |
684 | 0 | // This token is for an older process; we can safely ignore it. |
685 | 0 | return; |
686 | 0 | } |
687 | 0 | |
688 | 0 | // One of the bridged top-level actors for the GPU process has been |
689 | 0 | // prematurely terminated, and we're receiving a notification. This |
690 | 0 | // can happen if the ActorDestroy for a bridged protocol fires |
691 | 0 | // before the ActorDestroy for PGPUChild. |
692 | 0 | OnProcessUnexpectedShutdown(mProcess); |
693 | 0 | } |
694 | | |
695 | | void |
696 | | GPUProcessManager::CleanShutdown() |
697 | 0 | { |
698 | 0 | DestroyProcess(); |
699 | 0 | mVsyncIOThread = nullptr; |
700 | 0 | } |
701 | | |
702 | | void |
703 | | GPUProcessManager::KillProcess() |
704 | 0 | { |
705 | 0 | if (!mProcess) { |
706 | 0 | return; |
707 | 0 | } |
708 | 0 | |
709 | 0 | mProcess->KillProcess(); |
710 | 0 | } |
711 | | |
712 | | void |
713 | | GPUProcessManager::DestroyProcess() |
714 | 0 | { |
715 | 0 | if (!mProcess) { |
716 | 0 | return; |
717 | 0 | } |
718 | 0 | |
719 | 0 | mProcess->Shutdown(); |
720 | 0 | mProcessToken = 0; |
721 | 0 | mProcess = nullptr; |
722 | 0 | mGPUChild = nullptr; |
723 | 0 | if (mVsyncBridge) { |
724 | 0 | mVsyncBridge->Close(); |
725 | 0 | mVsyncBridge = nullptr; |
726 | 0 | } |
727 | 0 |
|
728 | 0 | CrashReporter::AnnotateCrashReport( |
729 | 0 | CrashReporter::Annotation::GPUProcessStatus, |
730 | 0 | NS_LITERAL_CSTRING("Destroyed")); |
731 | 0 | } |
732 | | |
733 | | already_AddRefed<CompositorSession> |
734 | | GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget, |
735 | | LayerManager* aLayerManager, |
736 | | CSSToLayoutDeviceScale aScale, |
737 | | const CompositorOptions& aOptions, |
738 | | bool aUseExternalSurfaceSize, |
739 | | const gfx::IntSize& aSurfaceSize, |
740 | | bool* aRetryOut) |
741 | 0 | { |
742 | 0 | MOZ_ASSERT(aRetryOut); |
743 | 0 |
|
744 | 0 | LayersId layerTreeId = AllocateLayerTreeId(); |
745 | 0 |
|
746 | 0 | EnsureProtocolsReady(); |
747 | 0 |
|
748 | 0 | RefPtr<CompositorSession> session; |
749 | 0 |
|
750 | 0 | if (EnsureGPUReady()) { |
751 | 0 | session = CreateRemoteSession( |
752 | 0 | aWidget, |
753 | 0 | aLayerManager, |
754 | 0 | layerTreeId, |
755 | 0 | aScale, |
756 | 0 | aOptions, |
757 | 0 | aUseExternalSurfaceSize, |
758 | 0 | aSurfaceSize); |
759 | 0 | if (!session) { |
760 | 0 | // We couldn't create a remote compositor, so abort the process. |
761 | 0 | DisableGPUProcess("Failed to create remote compositor"); |
762 | 0 | *aRetryOut = true; |
763 | 0 | return nullptr; |
764 | 0 | } |
765 | 0 | } else { |
766 | 0 | session = InProcessCompositorSession::Create( |
767 | 0 | aWidget, |
768 | 0 | aLayerManager, |
769 | 0 | layerTreeId, |
770 | 0 | aScale, |
771 | 0 | aOptions, |
772 | 0 | aUseExternalSurfaceSize, |
773 | 0 | aSurfaceSize, |
774 | 0 | AllocateNamespace()); |
775 | 0 | } |
776 | 0 |
|
777 | | #if defined(MOZ_WIDGET_ANDROID) |
778 | | if (session) { |
779 | | // Nothing to do if controller gets a nullptr |
780 | | RefPtr<UiCompositorControllerChild> controller = CreateUiCompositorController(aWidget, session->RootLayerTreeId()); |
781 | | session->SetUiCompositorControllerChild(controller); |
782 | | } |
783 | | #endif // defined(MOZ_WIDGET_ANDROID) |
784 | |
|
785 | 0 | *aRetryOut = false; |
786 | 0 | return session.forget(); |
787 | 0 | } |
788 | | |
789 | | RefPtr<CompositorSession> |
790 | | GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget, |
791 | | LayerManager* aLayerManager, |
792 | | const LayersId& aRootLayerTreeId, |
793 | | CSSToLayoutDeviceScale aScale, |
794 | | const CompositorOptions& aOptions, |
795 | | bool aUseExternalSurfaceSize, |
796 | | const gfx::IntSize& aSurfaceSize) |
797 | 0 | { |
798 | 0 | #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING |
799 | 0 | CompositorWidgetInitData initData; |
800 | 0 | aWidget->GetCompositorWidgetInitData(&initData); |
801 | 0 |
|
802 | 0 | RefPtr<CompositorBridgeChild> child = |
803 | 0 | CompositorManagerChild::CreateWidgetCompositorBridge( |
804 | 0 | mProcessToken, |
805 | 0 | aLayerManager, |
806 | 0 | AllocateNamespace(), |
807 | 0 | aScale, |
808 | 0 | aOptions, |
809 | 0 | aUseExternalSurfaceSize, |
810 | 0 | aSurfaceSize); |
811 | 0 | if (!child) { |
812 | 0 | gfxCriticalNote << "Failed to create CompositorBridgeChild"; |
813 | 0 | return nullptr; |
814 | 0 | } |
815 | 0 |
|
816 | 0 | RefPtr<CompositorVsyncDispatcher> dispatcher = aWidget->GetCompositorVsyncDispatcher(); |
817 | 0 | RefPtr<CompositorWidgetVsyncObserver> observer = |
818 | 0 | new CompositorWidgetVsyncObserver(mVsyncBridge, aRootLayerTreeId); |
819 | 0 |
|
820 | 0 | CompositorWidgetChild* widget = new CompositorWidgetChild(dispatcher, observer); |
821 | 0 | if (!child->SendPCompositorWidgetConstructor(widget, initData)) { |
822 | 0 | return nullptr; |
823 | 0 | } |
824 | 0 | if (!child->SendInitialize(aRootLayerTreeId)) { |
825 | 0 | return nullptr; |
826 | 0 | } |
827 | 0 | |
828 | 0 | RefPtr<APZCTreeManagerChild> apz = nullptr; |
829 | 0 | if (aOptions.UseAPZ()) { |
830 | 0 | PAPZCTreeManagerChild* papz = child->SendPAPZCTreeManagerConstructor(LayersId{0}); |
831 | 0 | if (!papz) { |
832 | 0 | return nullptr; |
833 | 0 | } |
834 | 0 | apz = static_cast<APZCTreeManagerChild*>(papz); |
835 | 0 |
|
836 | 0 | PAPZInputBridgeChild* pinput = mGPUChild->SendPAPZInputBridgeConstructor(aRootLayerTreeId); |
837 | 0 | if (!pinput) { |
838 | 0 | return nullptr; |
839 | 0 | } |
840 | 0 | apz->SetInputBridge(static_cast<APZInputBridgeChild*>(pinput)); |
841 | 0 | } |
842 | 0 |
|
843 | 0 | RefPtr<RemoteCompositorSession> session = |
844 | 0 | new RemoteCompositorSession(aWidget, child, widget, apz, aRootLayerTreeId); |
845 | 0 | return session.forget(); |
846 | | #else |
847 | | gfxCriticalNote << "Platform does not support out-of-process compositing"; |
848 | | return nullptr; |
849 | | #endif |
850 | | } |
851 | | |
852 | | bool |
853 | | GPUProcessManager::CreateContentBridges(base::ProcessId aOtherProcess, |
854 | | ipc::Endpoint<PCompositorManagerChild>* aOutCompositor, |
855 | | ipc::Endpoint<PImageBridgeChild>* aOutImageBridge, |
856 | | ipc::Endpoint<PVRManagerChild>* aOutVRBridge, |
857 | | ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager, |
858 | | nsTArray<uint32_t>* aNamespaces) |
859 | 0 | { |
860 | 0 | if (!CreateContentCompositorManager(aOtherProcess, aOutCompositor) || |
861 | 0 | !CreateContentImageBridge(aOtherProcess, aOutImageBridge) || |
862 | 0 | !CreateContentVRManager(aOtherProcess, aOutVRBridge)) |
863 | 0 | { |
864 | 0 | return false; |
865 | 0 | } |
866 | 0 | // VideoDeocderManager is only supported in the GPU process, so we allow this to be |
867 | 0 | // fallible. |
868 | 0 | CreateContentVideoDecoderManager(aOtherProcess, aOutVideoManager); |
869 | 0 | // Allocates 3 namespaces(for CompositorManagerChild, CompositorBridgeChild and ImageBridgeChild) |
870 | 0 | aNamespaces->AppendElement(AllocateNamespace()); |
871 | 0 | aNamespaces->AppendElement(AllocateNamespace()); |
872 | 0 | aNamespaces->AppendElement(AllocateNamespace()); |
873 | 0 | return true; |
874 | 0 | } |
875 | | |
876 | | bool |
877 | | GPUProcessManager::CreateContentCompositorManager(base::ProcessId aOtherProcess, |
878 | | ipc::Endpoint<PCompositorManagerChild>* aOutEndpoint) |
879 | 0 | { |
880 | 0 | ipc::Endpoint<PCompositorManagerParent> parentPipe; |
881 | 0 | ipc::Endpoint<PCompositorManagerChild> childPipe; |
882 | 0 |
|
883 | 0 | base::ProcessId parentPid = EnsureGPUReady() |
884 | 0 | ? mGPUChild->OtherPid() |
885 | 0 | : base::GetCurrentProcId(); |
886 | 0 |
|
887 | 0 | nsresult rv = PCompositorManager::CreateEndpoints( |
888 | 0 | parentPid, |
889 | 0 | aOtherProcess, |
890 | 0 | &parentPipe, |
891 | 0 | &childPipe); |
892 | 0 | if (NS_FAILED(rv)) { |
893 | 0 | gfxCriticalNote << "Could not create content compositor manager: " << hexa(int(rv)); |
894 | 0 | return false; |
895 | 0 | } |
896 | 0 |
|
897 | 0 | if (mGPUChild) { |
898 | 0 | mGPUChild->SendNewContentCompositorManager(std::move(parentPipe)); |
899 | 0 | } else { |
900 | 0 | CompositorManagerParent::Create(std::move(parentPipe)); |
901 | 0 | } |
902 | 0 |
|
903 | 0 | *aOutEndpoint = std::move(childPipe); |
904 | 0 | return true; |
905 | 0 | } |
906 | | |
907 | | bool |
908 | | GPUProcessManager::CreateContentImageBridge(base::ProcessId aOtherProcess, |
909 | | ipc::Endpoint<PImageBridgeChild>* aOutEndpoint) |
910 | 0 | { |
911 | 0 | EnsureImageBridgeChild(); |
912 | 0 |
|
913 | 0 | base::ProcessId parentPid = EnsureGPUReady() |
914 | 0 | ? mGPUChild->OtherPid() |
915 | 0 | : base::GetCurrentProcId(); |
916 | 0 |
|
917 | 0 | ipc::Endpoint<PImageBridgeParent> parentPipe; |
918 | 0 | ipc::Endpoint<PImageBridgeChild> childPipe; |
919 | 0 | nsresult rv = PImageBridge::CreateEndpoints( |
920 | 0 | parentPid, |
921 | 0 | aOtherProcess, |
922 | 0 | &parentPipe, |
923 | 0 | &childPipe); |
924 | 0 | if (NS_FAILED(rv)) { |
925 | 0 | gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv)); |
926 | 0 | return false; |
927 | 0 | } |
928 | 0 |
|
929 | 0 | if (mGPUChild) { |
930 | 0 | mGPUChild->SendNewContentImageBridge(std::move(parentPipe)); |
931 | 0 | } else { |
932 | 0 | if (!ImageBridgeParent::CreateForContent(std::move(parentPipe))) { |
933 | 0 | return false; |
934 | 0 | } |
935 | 0 | } |
936 | 0 | |
937 | 0 | *aOutEndpoint = std::move(childPipe); |
938 | 0 | return true; |
939 | 0 | } |
940 | | |
941 | | base::ProcessId |
942 | | GPUProcessManager::GPUProcessPid() |
943 | 0 | { |
944 | 0 | base::ProcessId gpuPid = mGPUChild |
945 | 0 | ? mGPUChild->OtherPid() |
946 | 0 | : -1; |
947 | 0 | return gpuPid; |
948 | 0 | } |
949 | | |
950 | | bool |
951 | | GPUProcessManager::CreateContentVRManager(base::ProcessId aOtherProcess, |
952 | | ipc::Endpoint<PVRManagerChild>* aOutEndpoint) |
953 | 0 | { |
954 | 0 | EnsureVRManager(); |
955 | 0 |
|
956 | 0 | base::ProcessId parentPid = EnsureGPUReady() |
957 | 0 | ? mGPUChild->OtherPid() |
958 | 0 | : base::GetCurrentProcId(); |
959 | 0 |
|
960 | 0 | ipc::Endpoint<PVRManagerParent> parentPipe; |
961 | 0 | ipc::Endpoint<PVRManagerChild> childPipe; |
962 | 0 | nsresult rv = PVRManager::CreateEndpoints( |
963 | 0 | parentPid, |
964 | 0 | aOtherProcess, |
965 | 0 | &parentPipe, |
966 | 0 | &childPipe); |
967 | 0 | if (NS_FAILED(rv)) { |
968 | 0 | gfxCriticalNote << "Could not create content compositor bridge: " << hexa(int(rv)); |
969 | 0 | return false; |
970 | 0 | } |
971 | 0 |
|
972 | 0 | if (mGPUChild) { |
973 | 0 | mGPUChild->SendNewContentVRManager(std::move(parentPipe)); |
974 | 0 | } else { |
975 | 0 | if (!VRManagerParent::CreateForContent(std::move(parentPipe))) { |
976 | 0 | return false; |
977 | 0 | } |
978 | 0 | } |
979 | 0 | |
980 | 0 | *aOutEndpoint = std::move(childPipe); |
981 | 0 | return true; |
982 | 0 | } |
983 | | |
984 | | void |
985 | | GPUProcessManager::CreateContentVideoDecoderManager(base::ProcessId aOtherProcess, |
986 | | ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndpoint) |
987 | 0 | { |
988 | 0 | if (!EnsureGPUReady() || |
989 | 0 | !StaticPrefs::MediaGpuProcessDecoder() || |
990 | 0 | !mDecodeVideoOnGpuProcess) { |
991 | 0 | return; |
992 | 0 | } |
993 | 0 | |
994 | 0 | ipc::Endpoint<dom::PVideoDecoderManagerParent> parentPipe; |
995 | 0 | ipc::Endpoint<dom::PVideoDecoderManagerChild> childPipe; |
996 | 0 |
|
997 | 0 | nsresult rv = dom::PVideoDecoderManager::CreateEndpoints( |
998 | 0 | mGPUChild->OtherPid(), |
999 | 0 | aOtherProcess, |
1000 | 0 | &parentPipe, |
1001 | 0 | &childPipe); |
1002 | 0 | if (NS_FAILED(rv)) { |
1003 | 0 | gfxCriticalNote << "Could not create content video decoder: " << hexa(int(rv)); |
1004 | 0 | return; |
1005 | 0 | } |
1006 | 0 |
|
1007 | 0 | mGPUChild->SendNewContentVideoDecoderManager(std::move(parentPipe)); |
1008 | 0 |
|
1009 | 0 | *aOutEndpoint = std::move(childPipe); |
1010 | 0 | } |
1011 | | |
1012 | | void |
1013 | | GPUProcessManager::MapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId) |
1014 | 0 | { |
1015 | 0 | LayerTreeOwnerTracker::Get()->Map(aLayersId, aOwningId); |
1016 | 0 |
|
1017 | 0 | if (EnsureGPUReady()) { |
1018 | 0 | mGPUChild->SendAddLayerTreeIdMapping(LayerTreeIdMapping(aLayersId, aOwningId)); |
1019 | 0 | } |
1020 | 0 | } |
1021 | | |
1022 | | void |
1023 | | GPUProcessManager::UnmapLayerTreeId(LayersId aLayersId, base::ProcessId aOwningId) |
1024 | 0 | { |
1025 | 0 | LayerTreeOwnerTracker::Get()->Unmap(aLayersId, aOwningId); |
1026 | 0 |
|
1027 | 0 | if (EnsureGPUReady()) { |
1028 | 0 | mGPUChild->SendRemoveLayerTreeIdMapping(LayerTreeIdMapping(aLayersId, aOwningId)); |
1029 | 0 | return; |
1030 | 0 | } |
1031 | 0 | CompositorBridgeParent::DeallocateLayerTreeId(aLayersId); |
1032 | 0 | } |
1033 | | |
1034 | | bool |
1035 | | GPUProcessManager::IsLayerTreeIdMapped(LayersId aLayersId, base::ProcessId aRequestingId) |
1036 | 0 | { |
1037 | 0 | return LayerTreeOwnerTracker::Get()->IsMapped(aLayersId, aRequestingId); |
1038 | 0 | } |
1039 | | |
1040 | | LayersId |
1041 | | GPUProcessManager::AllocateLayerTreeId() |
1042 | 0 | { |
1043 | 0 | // Allocate tree id by using id namespace. |
1044 | 0 | // By it, tree id does not conflict with external image id and |
1045 | 0 | // async image pipeline id. |
1046 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1047 | 0 | ++mResourceId; |
1048 | 0 | if (mResourceId == UINT32_MAX) { |
1049 | 0 | // Move to next id namespace. |
1050 | 0 | mIdNamespace = AllocateNamespace(); |
1051 | 0 | mResourceId = 1; |
1052 | 0 | } |
1053 | 0 |
|
1054 | 0 | uint64_t layerTreeId = mIdNamespace; |
1055 | 0 | layerTreeId = (layerTreeId << 32) | mResourceId; |
1056 | 0 | return LayersId{layerTreeId}; |
1057 | 0 | } |
1058 | | |
1059 | | uint32_t |
1060 | | GPUProcessManager::AllocateNamespace() |
1061 | 0 | { |
1062 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1063 | 0 | return ++mNextNamespace; |
1064 | 0 | } |
1065 | | |
1066 | | bool |
1067 | | GPUProcessManager::AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge, |
1068 | | base::ProcessId aOtherPid, |
1069 | | LayersId* aOutLayersId, |
1070 | | CompositorOptions* aOutCompositorOptions) |
1071 | 0 | { |
1072 | 0 | LayersId layersId = AllocateLayerTreeId(); |
1073 | 0 | *aOutLayersId = layersId; |
1074 | 0 |
|
1075 | 0 | if (!mGPUChild || !aCompositorBridge) { |
1076 | 0 | // If we're not remoting to another process, or there is no compositor, |
1077 | 0 | // then we'll send at most one message. In this case we can just keep |
1078 | 0 | // the old behavior of making sure the mapping occurs, and maybe sending |
1079 | 0 | // a creation notification. |
1080 | 0 | MapLayerTreeId(layersId, aOtherPid); |
1081 | 0 | if (!aCompositorBridge) { |
1082 | 0 | return false; |
1083 | 0 | } |
1084 | 0 | return aCompositorBridge->SendNotifyChildCreated(layersId, aOutCompositorOptions); |
1085 | 0 | } |
1086 | 0 | |
1087 | 0 | // Use the combined message path. |
1088 | 0 | LayerTreeOwnerTracker::Get()->Map(layersId, aOtherPid); |
1089 | 0 | return aCompositorBridge->SendMapAndNotifyChildCreated(layersId, aOtherPid, aOutCompositorOptions); |
1090 | 0 | } |
1091 | | |
1092 | | void |
1093 | | GPUProcessManager::EnsureVsyncIOThread() |
1094 | 0 | { |
1095 | 0 | if (mVsyncIOThread) { |
1096 | 0 | return; |
1097 | 0 | } |
1098 | 0 | |
1099 | 0 | mVsyncIOThread = new VsyncIOThreadHolder(); |
1100 | 0 | MOZ_RELEASE_ASSERT(mVsyncIOThread->Start()); |
1101 | 0 | } |
1102 | | |
1103 | | void |
1104 | | GPUProcessManager::ShutdownVsyncIOThread() |
1105 | 0 | { |
1106 | 0 | mVsyncIOThread = nullptr; |
1107 | 0 | } |
1108 | | |
1109 | | void |
1110 | | GPUProcessManager::RegisterRemoteProcessSession(RemoteCompositorSession* aSession) |
1111 | 0 | { |
1112 | 0 | mRemoteSessions.AppendElement(aSession); |
1113 | 0 | } |
1114 | | |
1115 | | void |
1116 | | GPUProcessManager::UnregisterRemoteProcessSession(RemoteCompositorSession* aSession) |
1117 | 0 | { |
1118 | 0 | mRemoteSessions.RemoveElement(aSession); |
1119 | 0 | } |
1120 | | |
1121 | | void |
1122 | | GPUProcessManager::RegisterInProcessSession(InProcessCompositorSession* aSession) |
1123 | 0 | { |
1124 | 0 | mInProcessSessions.AppendElement(aSession); |
1125 | 0 | } |
1126 | | |
1127 | | void |
1128 | | GPUProcessManager::UnregisterInProcessSession(InProcessCompositorSession* aSession) |
1129 | 0 | { |
1130 | 0 | mInProcessSessions.RemoveElement(aSession); |
1131 | 0 | } |
1132 | | |
1133 | | void |
1134 | | GPUProcessManager::AddListener(GPUProcessListener* aListener) |
1135 | 0 | { |
1136 | 0 | mListeners.AppendElement(aListener); |
1137 | 0 | } |
1138 | | |
1139 | | void |
1140 | | GPUProcessManager::RemoveListener(GPUProcessListener* aListener) |
1141 | 0 | { |
1142 | 0 | mListeners.RemoveElement(aListener); |
1143 | 0 | } |
1144 | | |
1145 | | bool |
1146 | | GPUProcessManager::NotifyGpuObservers(const char* aTopic) |
1147 | 0 | { |
1148 | 0 | if (!EnsureGPUReady()) { |
1149 | 0 | return false; |
1150 | 0 | } |
1151 | 0 | nsCString topic(aTopic); |
1152 | 0 | mGPUChild->SendNotifyGpuObservers(topic); |
1153 | 0 | return true; |
1154 | 0 | } |
1155 | | |
1156 | | class GPUMemoryReporter : public MemoryReportingProcess |
1157 | | { |
1158 | | public: |
1159 | | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GPUMemoryReporter, override) |
1160 | | |
1161 | 0 | bool IsAlive() const override { |
1162 | 0 | if (GPUProcessManager* gpm = GPUProcessManager::Get()) { |
1163 | 0 | return !!gpm->GetGPUChild(); |
1164 | 0 | } |
1165 | 0 | return false; |
1166 | 0 | } |
1167 | | |
1168 | | bool SendRequestMemoryReport(const uint32_t& aGeneration, |
1169 | | const bool& aAnonymize, |
1170 | | const bool& aMinimizeMemoryUsage, |
1171 | | const dom::MaybeFileDesc& aDMDFile) override |
1172 | 0 | { |
1173 | 0 | GPUChild* child = GetChild(); |
1174 | 0 | if (!child) { |
1175 | 0 | return false; |
1176 | 0 | } |
1177 | 0 | |
1178 | 0 | return child->SendRequestMemoryReport( |
1179 | 0 | aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile); |
1180 | 0 | } |
1181 | | |
1182 | 0 | int32_t Pid() const override { |
1183 | 0 | if (GPUChild* child = GetChild()) { |
1184 | 0 | return (int32_t)child->OtherPid(); |
1185 | 0 | } |
1186 | 0 | return 0; |
1187 | 0 | } |
1188 | | |
1189 | | private: |
1190 | 0 | GPUChild* GetChild() const { |
1191 | 0 | if (GPUProcessManager* gpm = GPUProcessManager::Get()) { |
1192 | 0 | if (GPUChild* child = gpm->GetGPUChild()) { |
1193 | 0 | return child; |
1194 | 0 | } |
1195 | 0 | } |
1196 | 0 | return nullptr; |
1197 | 0 | } |
1198 | | |
1199 | | protected: |
1200 | | ~GPUMemoryReporter() = default; |
1201 | | }; |
1202 | | |
1203 | | RefPtr<MemoryReportingProcess> |
1204 | | GPUProcessManager::GetProcessMemoryReporter() |
1205 | 0 | { |
1206 | 0 | if (!EnsureGPUReady()) { |
1207 | 0 | return nullptr; |
1208 | 0 | } |
1209 | 0 | return new GPUMemoryReporter(); |
1210 | 0 | } |
1211 | | |
1212 | | } // namespace gfx |
1213 | | } // namespace mozilla |