forked from mirrors/gecko-dev
		
	 620833163a
			
		
	
	
		620833163a
		
	
	
	
	
		
			
			This patch makes the remote canvas enabled state global. If we failed to create a context, then it cannot recover, so we should never try again. In the event of stream errors, it is likely due to virtual memory shortages. Differential Revision: https://phabricator.services.mozilla.com/D187718
		
			
				
	
	
		
			371 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| #include "GPUChild.h"
 | |
| 
 | |
| #include "GPUProcessHost.h"
 | |
| #include "GPUProcessManager.h"
 | |
| #include "GfxInfoBase.h"
 | |
| #include "VRProcessManager.h"
 | |
| #include "gfxConfig.h"
 | |
| #include "gfxPlatform.h"
 | |
| #include "mozilla/Components.h"
 | |
| #include "mozilla/FOGIPC.h"
 | |
| #include "mozilla/StaticPrefs_dom.h"
 | |
| #include "mozilla/Telemetry.h"
 | |
| #include "mozilla/TelemetryIPC.h"
 | |
| #include "mozilla/dom/CheckerboardReportService.h"
 | |
| #include "mozilla/dom/ContentParent.h"
 | |
| #include "mozilla/dom/MemoryReportRequest.h"
 | |
| #include "mozilla/gfx/Logging.h"
 | |
| #include "mozilla/gfx/gfxVars.h"
 | |
| #if defined(XP_WIN)
 | |
| #  include "mozilla/gfx/DeviceManagerDx.h"
 | |
| #endif
 | |
| #include "mozilla/HangDetails.h"
 | |
| #include "mozilla/RemoteDecoderManagerChild.h"  // For RemoteDecodeIn
 | |
| #include "mozilla/Unused.h"
 | |
| #include "mozilla/ipc/Endpoint.h"
 | |
| #include "mozilla/layers/APZInputBridgeChild.h"
 | |
| #include "mozilla/layers/LayerTreeOwnerTracker.h"
 | |
| #include "nsHashPropertyBag.h"
 | |
| #include "nsIGfxInfo.h"
 | |
| #include "nsIObserverService.h"
 | |
| #include "nsIPropertyBag2.h"
 | |
| #include "ProfilerParent.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace gfx {
 | |
| 
 | |
| using namespace layers;
 | |
| 
 | |
| GPUChild::GPUChild(GPUProcessHost* aHost) : mHost(aHost), mGPUReady(false) {}
 | |
| 
 | |
| GPUChild::~GPUChild() = default;
 | |
| 
 | |
| void GPUChild::Init() {
 | |
|   nsTArray<GfxVarUpdate> updates = gfxVars::FetchNonDefaultVars();
 | |
| 
 | |
|   DevicePrefs devicePrefs;
 | |
|   devicePrefs.hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
 | |
|   devicePrefs.d3d11Compositing() =
 | |
|       gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
 | |
|   devicePrefs.oglCompositing() =
 | |
|       gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
 | |
|   devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
 | |
|   devicePrefs.d3d11HwAngle() = gfxConfig::GetValue(Feature::D3D11_HW_ANGLE);
 | |
| 
 | |
|   nsTArray<LayerTreeIdMapping> mappings;
 | |
|   LayerTreeOwnerTracker::Get()->Iterate(
 | |
|       [&](LayersId aLayersId, base::ProcessId aProcessId) {
 | |
|         mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
 | |
|       });
 | |
| 
 | |
|   nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
 | |
|   nsTArray<GfxInfoFeatureStatus> features;
 | |
|   if (gfxInfo) {
 | |
|     auto* gfxInfoRaw = static_cast<widget::GfxInfoBase*>(gfxInfo.get());
 | |
|     features = gfxInfoRaw->GetAllFeatures();
 | |
|   }
 | |
| 
 | |
|   SendInit(updates, devicePrefs, mappings, features,
 | |
|            GPUProcessManager::Get()->AllocateNamespace());
 | |
| 
 | |
|   gfxVars::AddReceiver(this);
 | |
| 
 | |
|   Unused << SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
 | |
| }
 | |
| 
 | |
| void GPUChild::OnVarChanged(const GfxVarUpdate& aVar) { SendUpdateVar(aVar); }
 | |
| 
 | |
| bool GPUChild::EnsureGPUReady() {
 | |
|   // On our initial process launch, we want to block on the GetDeviceStatus
 | |
|   // message. Additionally, we may have updated our compositor configuration
 | |
|   // through the gfxVars after fallback, in which case we want to ensure the
 | |
|   // GPU process has handled any updates before creating compositor sessions.
 | |
|   if (mGPUReady && !mWaitForVarUpdate) {
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   GPUDeviceData data;
 | |
|   if (!SendGetDeviceStatus(&data)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Only import and collect telemetry for the initial GPU process launch.
 | |
|   if (!mGPUReady) {
 | |
|     gfxPlatform::GetPlatform()->ImportGPUDeviceData(data);
 | |
|     Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_LAUNCH_TIME_MS_2,
 | |
|                                    mHost->GetLaunchTime());
 | |
|     mGPUReady = true;
 | |
|   }
 | |
| 
 | |
|   mWaitForVarUpdate = false;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void GPUChild::OnUnexpectedShutdown() { mUnexpectedShutdown = true; }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvInitComplete(const GPUDeviceData& aData) {
 | |
|   // We synchronously requested GPU parameters before this arrived.
 | |
|   if (mGPUReady) {
 | |
|     return IPC_OK();
 | |
|   }
 | |
| 
 | |
|   gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
 | |
|   Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_LAUNCH_TIME_MS_2,
 | |
|                                  mHost->GetLaunchTime());
 | |
|   mGPUReady = true;
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvDeclareStable() {
 | |
|   mHost->mListener->OnProcessDeclaredStable();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvReportCheckerboard(
 | |
|     const uint32_t& aSeverity, const nsCString& aLog) {
 | |
|   layers::CheckerboardEventStorage::Report(aSeverity, std::string(aLog.get()));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvGraphicsError(const nsCString& aError) {
 | |
|   gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder();
 | |
|   if (lf) {
 | |
|     std::stringstream message;
 | |
|     message << "GP+" << aError.get();
 | |
|     lf->UpdateStringsVector(message.str());
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvCreateVRProcess() {
 | |
|   // Make sure create VR process at the main process
 | |
|   MOZ_ASSERT(XRE_IsParentProcess());
 | |
|   if (StaticPrefs::dom_vr_process_enabled_AtStartup()) {
 | |
|     VRProcessManager::Initialize();
 | |
|     VRProcessManager* vr = VRProcessManager::Get();
 | |
|     MOZ_ASSERT(vr, "VRProcessManager must be initialized first.");
 | |
| 
 | |
|     if (vr) {
 | |
|       vr->LaunchVRProcess();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvShutdownVRProcess() {
 | |
|   // Make sure stopping VR process at the main process
 | |
|   MOZ_ASSERT(XRE_IsParentProcess());
 | |
|   if (StaticPrefs::dom_vr_process_enabled_AtStartup()) {
 | |
|     VRProcessManager::Shutdown();
 | |
|   }
 | |
| 
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvNotifyUiObservers(
 | |
|     const nsCString& aTopic) {
 | |
|   nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
 | |
|   MOZ_ASSERT(obsSvc);
 | |
|   if (obsSvc) {
 | |
|     obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvAccumulateChildHistograms(
 | |
|     nsTArray<HistogramAccumulation>&& aAccumulations) {
 | |
|   TelemetryIPC::AccumulateChildHistograms(Telemetry::ProcessID::Gpu,
 | |
|                                           aAccumulations);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvAccumulateChildKeyedHistograms(
 | |
|     nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
 | |
|   TelemetryIPC::AccumulateChildKeyedHistograms(Telemetry::ProcessID::Gpu,
 | |
|                                                aAccumulations);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvUpdateChildScalars(
 | |
|     nsTArray<ScalarAction>&& aScalarActions) {
 | |
|   TelemetryIPC::UpdateChildScalars(Telemetry::ProcessID::Gpu, aScalarActions);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvUpdateChildKeyedScalars(
 | |
|     nsTArray<KeyedScalarAction>&& aScalarActions) {
 | |
|   TelemetryIPC::UpdateChildKeyedScalars(Telemetry::ProcessID::Gpu,
 | |
|                                         aScalarActions);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvRecordChildEvents(
 | |
|     nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
 | |
|   TelemetryIPC::RecordChildEvents(Telemetry::ProcessID::Gpu, aEvents);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvRecordDiscardedData(
 | |
|     const mozilla::Telemetry::DiscardedData& aDiscardedData) {
 | |
|   TelemetryIPC::RecordDiscardedData(Telemetry::ProcessID::Gpu, aDiscardedData);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvNotifyDeviceReset(
 | |
|     const GPUDeviceData& aData) {
 | |
|   gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
 | |
|   mHost->mListener->OnRemoteProcessDeviceReset(mHost);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvNotifyOverlayInfo(
 | |
|     const OverlayInfo aInfo) {
 | |
|   gfxPlatform::GetPlatform()->SetOverlayInfo(aInfo);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvNotifySwapChainInfo(
 | |
|     const SwapChainInfo aInfo) {
 | |
|   gfxPlatform::GetPlatform()->SetSwapChainInfo(aInfo);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvNotifyDisableRemoteCanvas() {
 | |
|   gfxPlatform::DisableRemoteCanvas();
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvFlushMemory(const nsString& aReason) {
 | |
|   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
 | |
|   if (os) {
 | |
|     os->NotifyObservers(nullptr, "memory-pressure", aReason.get());
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
 | |
|                                        const bool& aAnonymize,
 | |
|                                        const bool& aMinimizeMemoryUsage,
 | |
|                                        const Maybe<FileDescriptor>& aDMDFile) {
 | |
|   mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
 | |
| 
 | |
|   PGPUChild::SendRequestMemoryReport(
 | |
|       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
 | |
|       [&](const uint32_t& aGeneration2) {
 | |
|         if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
 | |
|           if (GPUChild* child = gpm->GetGPUChild()) {
 | |
|             if (child->mMemoryReportRequest) {
 | |
|               child->mMemoryReportRequest->Finish(aGeneration2);
 | |
|               child->mMemoryReportRequest = nullptr;
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       },
 | |
|       [&](mozilla::ipc::ResponseRejectReason) {
 | |
|         if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
 | |
|           if (GPUChild* child = gpm->GetGPUChild()) {
 | |
|             child->mMemoryReportRequest = nullptr;
 | |
|           }
 | |
|         }
 | |
|       });
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvAddMemoryReport(
 | |
|     const MemoryReport& aReport) {
 | |
|   if (mMemoryReportRequest) {
 | |
|     mMemoryReportRequest->RecvReport(aReport);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| void GPUChild::ActorDestroy(ActorDestroyReason aWhy) {
 | |
|   if (aWhy == AbnormalShutdown || mUnexpectedShutdown) {
 | |
|     nsAutoString dumpId;
 | |
|     GenerateCrashReport(OtherPid(), &dumpId);
 | |
| 
 | |
|     Telemetry::Accumulate(
 | |
|         Telemetry::SUBPROCESS_ABNORMAL_ABORT,
 | |
|         nsDependentCString(XRE_GeckoProcessTypeToString(GeckoProcessType_GPU)),
 | |
|         1);
 | |
| 
 | |
|     // Notify the Telemetry environment so that we can refresh and do a
 | |
|     // subsession split. This also notifies the crash reporter on geckoview.
 | |
|     if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
 | |
|       RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
 | |
|       props->SetPropertyAsBool(u"abnormal"_ns, true);
 | |
|       props->SetPropertyAsAString(u"dumpID"_ns, dumpId);
 | |
|       obsvc->NotifyObservers((nsIPropertyBag2*)props,
 | |
|                              "compositor:process-aborted", nullptr);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gfxVars::RemoveReceiver(this);
 | |
|   mHost->OnChannelClosed();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvUpdateFeature(
 | |
|     const Feature& aFeature, const FeatureFailure& aChange) {
 | |
|   gfxConfig::SetFailed(aFeature, aChange.status(), aChange.message().get(),
 | |
|                        aChange.failureId());
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvUsedFallback(const Fallback& aFallback,
 | |
|                                                    const nsCString& aMessage) {
 | |
|   gfxConfig::EnableFallback(aFallback, aMessage.get());
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvBHRThreadHang(
 | |
|     const HangDetails& aDetails) {
 | |
|   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
 | |
|   if (obs) {
 | |
|     // Copy the HangDetails recieved over the network into a nsIHangDetails, and
 | |
|     // then fire our own observer notification.
 | |
|     // XXX: We should be able to avoid this potentially expensive copy here by
 | |
|     // moving our deserialized argument.
 | |
|     nsCOMPtr<nsIHangDetails> hangDetails =
 | |
|         new nsHangDetails(HangDetails(aDetails), PersistedToDisk::No);
 | |
|     obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
 | |
|   }
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvUpdateMediaCodecsSupported(
 | |
|     const media::MediaCodecsSupported& aSupported) {
 | |
|   dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
 | |
|       RemoteDecodeIn::GpuProcess, aSupported);
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| mozilla::ipc::IPCResult GPUChild::RecvFOGData(ByteBuf&& aBuf) {
 | |
|   glean::FOGData(std::move(aBuf));
 | |
|   return IPC_OK();
 | |
| }
 | |
| 
 | |
| class DeferredDeleteGPUChild : public Runnable {
 | |
|  public:
 | |
|   explicit DeferredDeleteGPUChild(RefPtr<GPUChild>&& aChild)
 | |
|       : Runnable("gfx::DeferredDeleteGPUChild"), mChild(std::move(aChild)) {}
 | |
| 
 | |
|   NS_IMETHODIMP Run() override { return NS_OK; }
 | |
| 
 | |
|  private:
 | |
|   RefPtr<GPUChild> mChild;
 | |
| };
 | |
| 
 | |
| /* static */
 | |
| void GPUChild::Destroy(RefPtr<GPUChild>&& aChild) {
 | |
|   NS_DispatchToMainThread(new DeferredDeleteGPUChild(std::move(aChild)));
 | |
| }
 | |
| 
 | |
| }  // namespace gfx
 | |
| }  // namespace mozilla
 |