tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GPUChild.cpp (14752B)


      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 #include "GPUChild.h"
      7 
      8 #include "GPUProcessHost.h"
      9 #include "GPUProcessManager.h"
     10 #include "GfxInfoBase.h"
     11 #include "TelemetryProbesReporter.h"
     12 #include "VideoUtils.h"
     13 #include "VRProcessManager.h"
     14 #include "gfxConfig.h"
     15 #include "gfxPlatform.h"
     16 #include "mozilla/Components.h"
     17 #include "mozilla/FOGIPC.h"
     18 #include "mozilla/StaticPrefs_dom.h"
     19 #include "mozilla/StaticPrefs_media.h"
     20 #include "mozilla/glean/GfxMetrics.h"
     21 #include "mozilla/glean/IpcMetrics.h"
     22 #include "mozilla/Telemetry.h"
     23 #include "mozilla/TelemetryIPC.h"
     24 #include "mozilla/dom/CheckerboardReportService.h"
     25 #include "mozilla/dom/ContentParent.h"
     26 #include "mozilla/dom/MemoryReportRequest.h"
     27 #include "mozilla/gfx/Logging.h"
     28 #include "mozilla/gfx/gfxVars.h"
     29 #include "mozilla/HangDetails.h"
     30 #include "mozilla/RemoteMediaManagerChild.h"  // For RemoteMediaIn
     31 #include "mozilla/ipc/Endpoint.h"
     32 #include "mozilla/layers/APZInputBridgeChild.h"
     33 #include "mozilla/layers/LayerTreeOwnerTracker.h"
     34 #include "nsHashPropertyBag.h"
     35 #include "nsIGfxInfo.h"
     36 #include "nsIObserverService.h"
     37 #include "nsIPropertyBag2.h"
     38 #include "ProfilerParent.h"
     39 
     40 namespace mozilla {
     41 namespace gfx {
     42 
     43 using namespace layers;
     44 
     45 GPUChild::GPUChild(GPUProcessHost* aHost) : mHost(aHost), mGPUReady(false) {}
     46 
     47 GPUChild::~GPUChild() = default;
     48 
     49 RefPtr<GPUChild::InitPromiseType> GPUChild::Init() {
     50  nsTArray<GfxVarUpdate> updates = gfxVars::FetchNonDefaultVars();
     51 
     52  DevicePrefs devicePrefs;
     53  devicePrefs.hwCompositing() = gfxConfig::GetValue(Feature::HW_COMPOSITING);
     54  devicePrefs.d3d11Compositing() =
     55      gfxConfig::GetValue(Feature::D3D11_COMPOSITING);
     56  devicePrefs.oglCompositing() =
     57      gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
     58  devicePrefs.d3d11HwAngle() = gfxConfig::GetValue(Feature::D3D11_HW_ANGLE);
     59 
     60  nsTArray<LayerTreeIdMapping> mappings;
     61  LayerTreeOwnerTracker::Get()->Iterate(
     62      [&](LayersId aLayersId, base::ProcessId aProcessId) {
     63        mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
     64      });
     65 
     66  nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service();
     67  nsTArray<GfxInfoFeatureStatus> features;
     68  if (gfxInfo) {
     69    auto* gfxInfoRaw = static_cast<widget::GfxInfoBase*>(gfxInfo.get());
     70    features = gfxInfoRaw->GetAllFeatures();
     71  }
     72 
     73  RefPtr<InitPromiseType> promise =
     74      SendInit(updates, devicePrefs, mappings, features,
     75               GPUProcessManager::Get()->AllocateNamespace())
     76          ->Then(
     77              GetCurrentSerialEventTarget(), __func__,
     78              [self = RefPtr{this}](GPUDeviceData&& aData) {
     79                self->OnInitComplete(aData);
     80                return InitPromiseType::CreateAndResolve(Ok{}, __func__);
     81              },
     82              [](ipc::ResponseRejectReason) {
     83                return InitPromiseType::CreateAndReject(Ok{}, __func__);
     84              });
     85 
     86  gfxVars::AddReceiver(this);
     87 
     88  (void)SendInitProfiler(ProfilerParent::CreateForProcess(OtherPid()));
     89 
     90  return promise;
     91 }
     92 
     93 void GPUChild::OnVarChanged(const nsTArray<GfxVarUpdate>& aVar) {
     94  SendUpdateVar(aVar);
     95 }
     96 
     97 bool GPUChild::EnsureGPUReady(bool aForceSync /* = false */) {
     98  // On our initial process launch, we want to block on the GetDeviceStatus
     99  // message. Additionally, we may have updated our compositor configuration
    100  // through the gfxVars after fallback, in which case we want to ensure the
    101  // GPU process has handled any updates before creating compositor sessions.
    102  if (mGPUReady && !aForceSync) {
    103    return true;
    104  }
    105 
    106  GPUDeviceData data;
    107  if (!SendGetDeviceStatus(&data)) {
    108    return false;
    109  }
    110 
    111  OnInitComplete(data);
    112  return true;
    113 }
    114 
    115 void GPUChild::OnUnexpectedShutdown() { mUnexpectedShutdown = true; }
    116 
    117 void GPUChild::GeneratePairedMinidump() {
    118  // At most generate the paired minidumps twice per session in order to
    119  // avoid accumulating a large number of unsubmitted minidumps on disk.
    120  if (mCrashReporter && mNumPairedMinidumpsCreated < 2) {
    121    nsAutoCString additionalDumps("browser");
    122    mCrashReporter->AddAnnotationNSCString(
    123        CrashReporter::Annotation::additional_minidumps, additionalDumps);
    124 
    125    nsAutoCString reason("GPUProcessKill");
    126    mCrashReporter->AddAnnotationNSCString(
    127        CrashReporter::Annotation::ipc_channel_error, reason);
    128 
    129    if (mCrashReporter->GenerateMinidumpAndPair(mHost, "browser"_ns)) {
    130      mCrashReporter->FinalizeCrashReport();
    131      mCreatedPairedMinidumps = true;
    132      mNumPairedMinidumpsCreated++;
    133    }
    134  }
    135 }
    136 
    137 void GPUChild::DeletePairedMinidump() {
    138  if (mCrashReporter && mCreatedPairedMinidumps) {
    139    mCrashReporter->DeleteCrashReport();
    140    mCreatedPairedMinidumps = false;
    141  }
    142 }
    143 
    144 void GPUChild::OnInitComplete(const GPUDeviceData& aData) {
    145  // This function may be called multiple times, for example if we synchronously
    146  // requested GPU parameters before the asynchronous SendInit completed, or if
    147  // EnsureGPUReady is called after launch to force a synchronization after a
    148  // configuration change. We only want to import device data and collect
    149  // telemetry for the initial GPU process launch.
    150  if (mGPUReady) {
    151    return;
    152  }
    153 
    154  gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
    155  glean::gpu_process::launch_time.AccumulateRawDuration(TimeStamp::Now() -
    156                                                        mHost->GetLaunchTime());
    157  mGPUReady = true;
    158 }
    159 
    160 mozilla::ipc::IPCResult GPUChild::RecvDeclareStable() {
    161  mHost->mListener->OnProcessDeclaredStable();
    162  return IPC_OK();
    163 }
    164 
    165 mozilla::ipc::IPCResult GPUChild::RecvReportCheckerboard(
    166    const uint32_t& aSeverity, const nsCString& aLog) {
    167  layers::CheckerboardEventStorage::Report(aSeverity, std::string(aLog.get()));
    168  return IPC_OK();
    169 }
    170 
    171 mozilla::ipc::IPCResult GPUChild::RecvGraphicsError(const nsCString& aError) {
    172  gfx::LogForwarder* lf = gfx::Factory::GetLogForwarder();
    173  if (lf) {
    174    std::stringstream message;
    175    message << "GP+" << aError.get();
    176    lf->UpdateStringsVector(message.str());
    177  }
    178  return IPC_OK();
    179 }
    180 
    181 mozilla::ipc::IPCResult GPUChild::RecvCreateVRProcess() {
    182  // Make sure create VR process at the main process
    183  MOZ_ASSERT(XRE_IsParentProcess());
    184  if (StaticPrefs::dom_vr_process_enabled_AtStartup()) {
    185    VRProcessManager::Initialize();
    186    VRProcessManager* vr = VRProcessManager::Get();
    187    MOZ_ASSERT(vr, "VRProcessManager must be initialized first.");
    188 
    189    if (vr) {
    190      vr->LaunchVRProcess();
    191    }
    192  }
    193 
    194  return IPC_OK();
    195 }
    196 
    197 mozilla::ipc::IPCResult GPUChild::RecvShutdownVRProcess() {
    198  // Make sure stopping VR process at the main process
    199  MOZ_ASSERT(XRE_IsParentProcess());
    200  if (StaticPrefs::dom_vr_process_enabled_AtStartup()) {
    201    VRProcessManager::Shutdown();
    202  }
    203 
    204  return IPC_OK();
    205 }
    206 
    207 mozilla::ipc::IPCResult GPUChild::RecvNotifyUiObservers(
    208    const nsCString& aTopic) {
    209  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
    210  MOZ_ASSERT(obsSvc);
    211  if (obsSvc) {
    212    obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr);
    213  }
    214  return IPC_OK();
    215 }
    216 
    217 mozilla::ipc::IPCResult GPUChild::RecvAccumulateChildHistograms(
    218    nsTArray<HistogramAccumulation>&& aAccumulations) {
    219  TelemetryIPC::AccumulateChildHistograms(Telemetry::ProcessID::Gpu,
    220                                          aAccumulations);
    221  return IPC_OK();
    222 }
    223 
    224 mozilla::ipc::IPCResult GPUChild::RecvAccumulateChildKeyedHistograms(
    225    nsTArray<KeyedHistogramAccumulation>&& aAccumulations) {
    226  TelemetryIPC::AccumulateChildKeyedHistograms(Telemetry::ProcessID::Gpu,
    227                                               aAccumulations);
    228  return IPC_OK();
    229 }
    230 
    231 mozilla::ipc::IPCResult GPUChild::RecvUpdateChildScalars(
    232    nsTArray<ScalarAction>&& aScalarActions) {
    233  TelemetryIPC::UpdateChildScalars(Telemetry::ProcessID::Gpu, aScalarActions);
    234  return IPC_OK();
    235 }
    236 
    237 mozilla::ipc::IPCResult GPUChild::RecvUpdateChildKeyedScalars(
    238    nsTArray<KeyedScalarAction>&& aScalarActions) {
    239  TelemetryIPC::UpdateChildKeyedScalars(Telemetry::ProcessID::Gpu,
    240                                        aScalarActions);
    241  return IPC_OK();
    242 }
    243 
    244 mozilla::ipc::IPCResult GPUChild::RecvRecordChildEvents(
    245    nsTArray<mozilla::Telemetry::ChildEventData>&& aEvents) {
    246  TelemetryIPC::RecordChildEvents(Telemetry::ProcessID::Gpu, aEvents);
    247  return IPC_OK();
    248 }
    249 
    250 mozilla::ipc::IPCResult GPUChild::RecvRecordDiscardedData(
    251    const mozilla::Telemetry::DiscardedData& aDiscardedData) {
    252  TelemetryIPC::RecordDiscardedData(Telemetry::ProcessID::Gpu, aDiscardedData);
    253  return IPC_OK();
    254 }
    255 
    256 mozilla::ipc::IPCResult GPUChild::RecvNotifyDeviceReset(
    257    const GPUDeviceData& aData, const DeviceResetReason& aReason,
    258    const DeviceResetDetectPlace& aPlace) {
    259  gfxPlatform::GetPlatform()->ImportGPUDeviceData(aData);
    260  mHost->mListener->OnRemoteProcessDeviceReset(mHost, aReason, aPlace);
    261  return IPC_OK();
    262 }
    263 
    264 mozilla::ipc::IPCResult GPUChild::RecvNotifyOverlayInfo(
    265    const OverlayInfo aInfo) {
    266  gfxPlatform::GetPlatform()->SetOverlayInfo(aInfo);
    267  return IPC_OK();
    268 }
    269 
    270 mozilla::ipc::IPCResult GPUChild::RecvNotifySwapChainInfo(
    271    const SwapChainInfo aInfo) {
    272  gfxPlatform::GetPlatform()->SetSwapChainInfo(aInfo);
    273  return IPC_OK();
    274 }
    275 
    276 mozilla::ipc::IPCResult GPUChild::RecvNotifyDisableRemoteCanvas() {
    277  gfxPlatform::DisableRemoteCanvas();
    278  return IPC_OK();
    279 }
    280 
    281 mozilla::ipc::IPCResult GPUChild::RecvFlushMemory(const nsString& aReason) {
    282  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
    283  if (os) {
    284    os->NotifyObservers(nullptr, "memory-pressure", aReason.get());
    285  }
    286  return IPC_OK();
    287 }
    288 
    289 bool GPUChild::SendRequestMemoryReport(const uint32_t& aGeneration,
    290                                       const bool& aAnonymize,
    291                                       const bool& aMinimizeMemoryUsage,
    292                                       const Maybe<FileDescriptor>& aDMDFile) {
    293  mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
    294 
    295  PGPUChild::SendRequestMemoryReport(
    296      aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
    297      [&](const uint32_t& aGeneration2) {
    298        if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
    299          if (GPUChild* child = gpm->GetGPUChild()) {
    300            if (child->mMemoryReportRequest) {
    301              child->mMemoryReportRequest->Finish(aGeneration2);
    302              child->mMemoryReportRequest = nullptr;
    303            }
    304          }
    305        }
    306      },
    307      [&](mozilla::ipc::ResponseRejectReason) {
    308        if (GPUProcessManager* gpm = GPUProcessManager::Get()) {
    309          if (GPUChild* child = gpm->GetGPUChild()) {
    310            child->mMemoryReportRequest = nullptr;
    311          }
    312        }
    313      });
    314 
    315  return true;
    316 }
    317 
    318 mozilla::ipc::IPCResult GPUChild::RecvAddMemoryReport(
    319    const MemoryReport& aReport) {
    320  if (mMemoryReportRequest) {
    321    mMemoryReportRequest->RecvReport(aReport);
    322  }
    323  return IPC_OK();
    324 }
    325 
    326 void GPUChild::ActorDestroy(ActorDestroyReason aWhy) {
    327  if (aWhy == AbnormalShutdown || mUnexpectedShutdown) {
    328    nsAutoCString processType(
    329        XRE_GeckoProcessTypeToString(GeckoProcessType_GPU));
    330    glean::subprocess::abnormal_abort.Get(processType).Add(1);
    331 
    332    nsAutoString dumpId;
    333    if (!mCreatedPairedMinidumps) {
    334      GenerateCrashReport(&dumpId);
    335    } else if (mCrashReporter) {
    336      dumpId = mCrashReporter->MinidumpID();
    337    }
    338 
    339    // Notify the Telemetry environment so that we can refresh and do a
    340    // subsession split. This also notifies the crash reporter on geckoview.
    341    if (nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService()) {
    342      RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
    343      props->SetPropertyAsBool(u"abnormal"_ns, true);
    344      props->SetPropertyAsAString(u"dumpID"_ns, dumpId);
    345      props->SetPropertyAsACString(u"processType"_ns, processType);
    346      obsvc->NotifyObservers((nsIPropertyBag2*)props,
    347                             "compositor:process-aborted", nullptr);
    348    }
    349  }
    350 
    351  gfxVars::RemoveReceiver(this);
    352  mHost->OnChannelClosed();
    353 }
    354 
    355 mozilla::ipc::IPCResult GPUChild::RecvUpdateFeature(
    356    const Feature& aFeature, const FeatureFailure& aChange) {
    357  gfxConfig::SetFailed(aFeature, aChange.status(), aChange.message().get(),
    358                       aChange.failureId());
    359  return IPC_OK();
    360 }
    361 
    362 mozilla::ipc::IPCResult GPUChild::RecvUsedFallback(const Fallback& aFallback,
    363                                                   const nsCString& aMessage) {
    364  gfxConfig::EnableFallback(aFallback, aMessage.get());
    365  return IPC_OK();
    366 }
    367 
    368 mozilla::ipc::IPCResult GPUChild::RecvBHRThreadHang(
    369    const HangDetails& aDetails) {
    370  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
    371  if (obs) {
    372    // Copy the HangDetails recieved over the network into a nsIHangDetails, and
    373    // then fire our own observer notification.
    374    // XXX: We should be able to avoid this potentially expensive copy here by
    375    // moving our deserialized argument.
    376    nsCOMPtr<nsIHangDetails> hangDetails =
    377        new nsHangDetails(HangDetails(aDetails), PersistedToDisk::No);
    378    obs->NotifyObservers(hangDetails, "bhr-thread-hang", nullptr);
    379  }
    380  return IPC_OK();
    381 }
    382 
    383 mozilla::ipc::IPCResult GPUChild::RecvUpdateMediaCodecsSupported(
    384    const media::MediaCodecsSupported& aSupported) {
    385  if (ContainHardwareCodecsSupported(aSupported)) {
    386    mozilla::TelemetryProbesReporter::ReportDeviceMediaCodecSupported(
    387        aSupported);
    388  }
    389 #if defined(XP_WIN)
    390  // Do not propagate HEVC support if the pref is off
    391  media::MediaCodecsSupported trimedSupported = aSupported;
    392  if (aSupported.contains(
    393          mozilla::media::MediaCodecsSupport::HEVCHardwareDecode) &&
    394      !StaticPrefs::media_hevc_enabled()) {
    395    trimedSupported -= mozilla::media::MediaCodecsSupport::HEVCHardwareDecode;
    396  }
    397  dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
    398      RemoteMediaIn::GpuProcess, trimedSupported);
    399 #else
    400  dom::ContentParent::BroadcastMediaCodecsSupportedUpdate(
    401      RemoteMediaIn::GpuProcess, aSupported);
    402 #endif
    403  return IPC_OK();
    404 }
    405 
    406 mozilla::ipc::IPCResult GPUChild::RecvFOGData(ByteBuf&& aBuf) {
    407  glean::FOGData(std::move(aBuf));
    408  return IPC_OK();
    409 }
    410 
    411 class DeferredDeleteGPUChild : public Runnable {
    412 public:
    413  explicit DeferredDeleteGPUChild(RefPtr<GPUChild>&& aChild)
    414      : Runnable("gfx::DeferredDeleteGPUChild"), mChild(std::move(aChild)) {}
    415 
    416  NS_IMETHODIMP Run() override { return NS_OK; }
    417 
    418 private:
    419  RefPtr<GPUChild> mChild;
    420 };
    421 
    422 /* static */
    423 void GPUChild::Destroy(RefPtr<GPUChild>&& aChild) {
    424  NS_DispatchToMainThread(new DeferredDeleteGPUChild(std::move(aChild)));
    425 }
    426 
    427 }  // namespace gfx
    428 }  // namespace mozilla