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/. */
8 #include "GPUProcessHost.h"
9 #include "GPUProcessManager.h"
10 #include "GfxInfoBase.h"
11 #include "VRProcessManager.h"
12 #include "gfxConfig.h"
13 #include "gfxPlatform.h"
14 #include "mozilla/Components.h"
15 #include "mozilla/FOGIPC.h"
16 #include "mozilla/StaticPrefs_dom.h"
17 #include "mozilla/Telemetry.h"
18 #include "mozilla/TelemetryIPC.h"
19 #include "mozilla/dom/CheckerboardReportService.h"
20 #include "mozilla/dom/ContentParent.h"
21 #include "mozilla/dom/MemoryReportRequest.h"
22 #include "mozilla/gfx/Logging.h"
23 #include "mozilla/gfx/gfxVars.h"
25 # include "mozilla/gfx/DeviceManagerDx.h"
27 #include "mozilla/HangDetails.h"
28 #include "mozilla/RemoteDecoderManagerChild.h" // For RemoteDecodeIn
29 #include "mozilla/Unused.h"
30 #include "mozilla/ipc/Endpoint.h"
31 #include "mozilla/layers/APZInputBridgeChild.h"
32 #include "mozilla/layers/LayerTreeOwnerTracker.h"
33 #include "nsHashPropertyBag.h"
34 #include "nsIGfxInfo.h"
35 #include "nsIObserverService.h"
36 #include "nsIPropertyBag2.h"
37 #include "ProfilerParent.h"
42 using namespace layers
;
44 GPUChild::GPUChild(GPUProcessHost
* aHost
) : mHost(aHost
), mGPUReady(false) {}
46 GPUChild::~GPUChild() = default;
48 void GPUChild::Init() {
49 nsTArray
<GfxVarUpdate
> updates
= gfxVars::FetchNonDefaultVars();
51 DevicePrefs devicePrefs
;
52 devicePrefs
.hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING
);
53 devicePrefs
.d3d11Compositing() =
54 gfxConfig::GetValue(Feature::D3D11_COMPOSITING
);
55 devicePrefs
.oglCompositing() =
56 gfxConfig::GetValue(Feature::OPENGL_COMPOSITING
);
57 devicePrefs
.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D
);
58 devicePrefs
.d3d11HwAngle() = gfxConfig::GetValue(Feature::D3D11_HW_ANGLE
);
60 nsTArray
<LayerTreeIdMapping
> mappings
;
61 LayerTreeOwnerTracker::Get()->Iterate(
62 [&](LayersId aLayersId
, base::ProcessId aProcessId
) {
63 mappings
.AppendElement(LayerTreeIdMapping(aLayersId
, aProcessId
));
66 nsCOMPtr
<nsIGfxInfo
> gfxInfo
= components::GfxInfo::Service();
67 nsTArray
<GfxInfoFeatureStatus
> features
;
69 auto* gfxInfoRaw
= static_cast<widget::GfxInfoBase
*>(gfxInfo
.get());
70 features
= gfxInfoRaw
->GetAllFeatures();
73 SendInit(updates
, devicePrefs
, mappings
, features
,
74 GPUProcessManager::Get()->AllocateNamespace());
76 gfxVars::AddReceiver(this);
78 Unused
<< SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
81 void GPUChild::OnVarChanged(const GfxVarUpdate
& aVar
) { SendUpdateVar(aVar
); }
83 bool GPUChild::EnsureGPUReady() {
84 // On our initial process launch, we want to block on the GetDeviceStatus
85 // message. Additionally, we may have updated our compositor configuration
86 // through the gfxVars after fallback, in which case we want to ensure the
87 // GPU process has handled any updates before creating compositor sessions.
88 if (mGPUReady
&& !mWaitForVarUpdate
) {
93 if (!SendGetDeviceStatus(&data
)) {
97 // Only import and collect telemetry for the initial GPU process launch.
99 gfxPlatform::GetPlatform()->ImportGPUDeviceData(data
);
100 Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_LAUNCH_TIME_MS_2
,
101 mHost
->GetLaunchTime());
105 mWaitForVarUpdate
= false;
109 void GPUChild::OnUnexpectedShutdown() { mUnexpectedShutdown
= true; }
111 mozilla::ipc::IPCResult
GPUChild::RecvInitComplete(const GPUDeviceData
& aData
) {
112 // We synchronously requested GPU parameters before this arrived.
117 gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData
);
118 Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_LAUNCH_TIME_MS_2
,
119 mHost
->GetLaunchTime());
124 mozilla::ipc::IPCResult
GPUChild::RecvDeclareStable() {
125 mHost
->mListener
->OnProcessDeclaredStable();
129 mozilla::ipc::IPCResult
GPUChild::RecvReportCheckerboard(
130 const uint32_t& aSeverity
, const nsCString
& aLog
) {
131 layers::CheckerboardEventStorage::Report(aSeverity
, std::string(aLog
.get()));
135 mozilla::ipc::IPCResult
GPUChild::RecvGraphicsError(const nsCString
& aError
) {
136 gfx::LogForwarder
* lf
= gfx::Factory::GetLogForwarder();
138 std::stringstream message
;
139 message
<< "GP+" << aError
.get();
140 lf
->UpdateStringsVector(message
.str());
145 mozilla::ipc::IPCResult
GPUChild::RecvCreateVRProcess() {
146 // Make sure create VR process at the main process
147 MOZ_ASSERT(XRE_IsParentProcess());
148 if (StaticPrefs::dom_vr_process_enabled_AtStartup()) {
149 VRProcessManager::Initialize();
150 VRProcessManager
* vr
= VRProcessManager::Get();
151 MOZ_ASSERT(vr
, "VRProcessManager must be initialized first.");
154 vr
->LaunchVRProcess();
161 mozilla::ipc::IPCResult
GPUChild::RecvShutdownVRProcess() {
162 // Make sure stopping VR process at the main process
163 MOZ_ASSERT(XRE_IsParentProcess());
164 if (StaticPrefs::dom_vr_process_enabled_AtStartup()) {
165 VRProcessManager::Shutdown();
171 mozilla::ipc::IPCResult
GPUChild::RecvNotifyUiObservers(
172 const nsCString
& aTopic
) {
173 nsCOMPtr
<nsIObserverService
> obsSvc
= mozilla::services::GetObserverService();
176 obsSvc
->NotifyObservers(nullptr, aTopic
.get(), nullptr);
181 mozilla::ipc::IPCResult
GPUChild::RecvAccumulateChildHistograms(
182 nsTArray
<HistogramAccumulation
>&& aAccumulations
) {
183 TelemetryIPC::AccumulateChildHistograms(Telemetry::ProcessID::Gpu
,
188 mozilla::ipc::IPCResult
GPUChild::RecvAccumulateChildKeyedHistograms(
189 nsTArray
<KeyedHistogramAccumulation
>&& aAccumulations
) {
190 TelemetryIPC::AccumulateChildKeyedHistograms(Telemetry::ProcessID::Gpu
,
195 mozilla::ipc::IPCResult
GPUChild::RecvUpdateChildScalars(
196 nsTArray
<ScalarAction
>&& aScalarActions
) {
197 TelemetryIPC::UpdateChildScalars(Telemetry::ProcessID::Gpu
, aScalarActions
);
201 mozilla::ipc::IPCResult
GPUChild::RecvUpdateChildKeyedScalars(
202 nsTArray
<KeyedScalarAction
>&& aScalarActions
) {
203 TelemetryIPC::UpdateChildKeyedScalars(Telemetry::ProcessID::Gpu
,
208 mozilla::ipc::IPCResult
GPUChild::RecvRecordChildEvents(
209 nsTArray
<mozilla::Telemetry::ChildEventData
>&& aEvents
) {
210 TelemetryIPC::RecordChildEvents(Telemetry::ProcessID::Gpu
, aEvents
);
214 mozilla::ipc::IPCResult
GPUChild::RecvRecordDiscardedData(
215 const mozilla::Telemetry::DiscardedData
& aDiscardedData
) {
216 TelemetryIPC::RecordDiscardedData(Telemetry::ProcessID::Gpu
, aDiscardedData
);
220 mozilla::ipc::IPCResult
GPUChild::RecvNotifyDeviceReset(
221 const GPUDeviceData
& aData
) {
222 gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData
);
223 mHost
->mListener
->OnRemoteProcessDeviceReset(mHost
);
227 mozilla::ipc::IPCResult
GPUChild::RecvNotifyOverlayInfo(
228 const OverlayInfo aInfo
) {
229 gfxPlatform::GetPlatform()->SetOverlayInfo(aInfo
);
233 mozilla::ipc::IPCResult
GPUChild::RecvNotifySwapChainInfo(
234 const SwapChainInfo aInfo
) {
235 gfxPlatform::GetPlatform()->SetSwapChainInfo(aInfo
);
239 mozilla::ipc::IPCResult
GPUChild::RecvNotifyDisableRemoteCanvas() {
240 gfxPlatform::DisableRemoteCanvas();
244 mozilla::ipc::IPCResult
GPUChild::RecvFlushMemory(const nsString
& aReason
) {
245 nsCOMPtr
<nsIObserverService
> os
= mozilla::services::GetObserverService();
247 os
->NotifyObservers(nullptr, "memory-pressure", aReason
.get());
252 bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration
,
253 const bool& aAnonymize
,
254 const bool& aMinimizeMemoryUsage
,
255 const Maybe
<FileDescriptor
>& aDMDFile
) {
256 mMemoryReportRequest
= MakeUnique
<MemoryReportRequestHost
>(aGeneration
);
258 PGPUChild::SendRequestMemoryReport(
259 aGeneration
, aAnonymize
, aMinimizeMemoryUsage
, aDMDFile
,
260 [&](const uint32_t& aGeneration2
) {
261 if (GPUProcessManager
* gpm
= GPUProcessManager::Get()) {
262 if (GPUChild
* child
= gpm
->GetGPUChild()) {
263 if (child
->mMemoryReportRequest
) {
264 child
->mMemoryReportRequest
->Finish(aGeneration2
);
265 child
->mMemoryReportRequest
= nullptr;
270 [&](mozilla::ipc::ResponseRejectReason
) {
271 if (GPUProcessManager
* gpm
= GPUProcessManager::Get()) {
272 if (GPUChild
* child
= gpm
->GetGPUChild()) {
273 child
->mMemoryReportRequest
= nullptr;
281 mozilla::ipc::IPCResult
GPUChild::RecvAddMemoryReport(
282 const MemoryReport
& aReport
) {
283 if (mMemoryReportRequest
) {
284 mMemoryReportRequest
->RecvReport(aReport
);
289 void GPUChild::ActorDestroy(ActorDestroyReason aWhy
) {
290 if (aWhy
== AbnormalShutdown
|| mUnexpectedShutdown
) {
292 GenerateCrashReport(OtherPid(), &dumpId
);
294 Telemetry::Accumulate(
295 Telemetry::SUBPROCESS_ABNORMAL_ABORT
,
296 nsDependentCString(XRE_GeckoProcessTypeToString(GeckoProcessType_GPU
)),
299 // Notify the Telemetry environment so that we can refresh and do a
300 // subsession split. This also notifies the crash reporter on geckoview.
301 if (nsCOMPtr
<nsIObserverService
> obsvc
= services::GetObserverService()) {
302 RefPtr
<nsHashPropertyBag
> props
= new nsHashPropertyBag();
303 props
->SetPropertyAsBool(u
"abnormal"_ns
, true);
304 props
->SetPropertyAsAString(u
"dumpID"_ns
, dumpId
);
305 obsvc
->NotifyObservers((nsIPropertyBag2
*)props
,
306 "compositor:process-aborted", nullptr);
310 gfxVars::RemoveReceiver(this);
311 mHost
->OnChannelClosed();
314 mozilla::ipc::IPCResult
GPUChild::RecvUpdateFeature(
315 const Feature
& aFeature
, const FeatureFailure
& aChange
) {
316 gfxConfig::SetFailed(aFeature
, aChange
.status(), aChange
.message().get(),
317 aChange
.failureId());
321 mozilla::ipc::IPCResult
GPUChild::RecvUsedFallback(const Fallback
& aFallback
,
322 const nsCString
& aMessage
) {
323 gfxConfig::EnableFallback(aFallback
, aMessage
.get());
327 mozilla::ipc::IPCResult
GPUChild::RecvBHRThreadHang(
328 const HangDetails
& aDetails
) {
329 nsCOMPtr
<nsIObserverService
> obs
= mozilla::services::GetObserverService();
331 // Copy the HangDetails recieved over the network into a nsIHangDetails, and
332 // then fire our own observer notification.
333 // XXX: We should be able to avoid this potentially expensive copy here by
334 // moving our deserialized argument.
335 nsCOMPtr
<nsIHangDetails
> hangDetails
=
336 new nsHangDetails(HangDetails(aDetails
), PersistedToDisk::No
);
337 obs
->NotifyObservers(hangDetails
, "bhr-thread-hang", nullptr);
342 mozilla::ipc::IPCResult
GPUChild::RecvUpdateMediaCodecsSupported(
343 const media::MediaCodecsSupported
& aSupported
) {
344 dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
345 RemoteDecodeIn::GpuProcess
, aSupported
);
349 mozilla::ipc::IPCResult
GPUChild::RecvFOGData(ByteBuf
&& aBuf
) {
350 glean::FOGData(std::move(aBuf
));
354 class DeferredDeleteGPUChild
: public Runnable
{
356 explicit DeferredDeleteGPUChild(RefPtr
<GPUChild
>&& aChild
)
357 : Runnable("gfx::DeferredDeleteGPUChild"), mChild(std::move(aChild
)) {}
359 NS_IMETHODIMP
Run() override
{ return NS_OK
; }
362 RefPtr
<GPUChild
> mChild
;
366 void GPUChild::Destroy(RefPtr
<GPUChild
>&& aChild
) {
367 NS_DispatchToMainThread(new DeferredDeleteGPUChild(std::move(aChild
)));
371 } // namespace mozilla