diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /gfx/ipc/GPUParent.cpp | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/ipc/GPUParent.cpp')
-rw-r--r-- | gfx/ipc/GPUParent.cpp | 831 |
1 files changed, 831 insertions, 0 deletions
diff --git a/gfx/ipc/GPUParent.cpp b/gfx/ipc/GPUParent.cpp new file mode 100644 index 0000000000..283fb87ee9 --- /dev/null +++ b/gfx/ipc/GPUParent.cpp @@ -0,0 +1,831 @@ +/* -*- 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/. */ + +#ifdef XP_WIN +# include "WMF.h" +# include "WMFDecoderModule.h" +#endif +#include "GLContextProvider.h" +#include "GPUParent.h" +#include "GPUProcessHost.h" +#include "GPUProcessManager.h" +#include "gfxGradientCache.h" +#include "GfxInfoBase.h" +#include "VRGPUChild.h" +#include "VRManager.h" +#include "VRManagerParent.h" +#include "VsyncBridgeParent.h" +#include "cairo.h" +#include "gfxConfig.h" +#include "gfxCrashReporterUtils.h" +#include "gfxPlatform.h" +#include "mozilla/Assertions.h" +#include "mozilla/Components.h" +#include "mozilla/FOGIPC.h" +#include "mozilla/HangDetails.h" +#include "mozilla/PerfStats.h" +#include "mozilla/Preferences.h" +#include "mozilla/ProcessPriorityManager.h" +#include "mozilla/RemoteDecoderManagerChild.h" +#include "mozilla/RemoteDecoderManagerParent.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/StaticPrefs_dom.h" +#include "mozilla/StaticPrefs_media.h" +#include "mozilla/Telemetry.h" +#include "mozilla/TimeStamp.h" +#include "mozilla/dom/MemoryReportRequest.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/CanvasRenderThread.h" +#include "mozilla/gfx/gfxVars.h" +#include "mozilla/glean/GleanMetrics.h" +#include "mozilla/image/ImageMemoryReporter.h" +#include "mozilla/ipc/CrashReporterClient.h" +#include "mozilla/ipc/ProcessChild.h" +#include "mozilla/ipc/ProcessUtils.h" +#include "mozilla/layers/APZInputBridgeParent.h" +#include "mozilla/layers/APZPublicUtils.h" // for apz::InitializeGlobalState +#include "mozilla/layers/APZThreadUtils.h" +#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorManagerParent.h" +#include "mozilla/layers/CompositorThread.h" +#include "mozilla/layers/ImageBridgeParent.h" +#include "mozilla/layers/LayerTreeOwnerTracker.h" +#include "mozilla/layers/RemoteTextureMap.h" +#include "mozilla/layers/UiCompositorControllerParent.h" +#include "mozilla/layers/VideoBridgeParent.h" +#include "mozilla/webrender/RenderThread.h" +#include "mozilla/webrender/WebRenderAPI.h" +#include "nsDebugImpl.h" +#include "nsIGfxInfo.h" +#include "nsIXULRuntime.h" +#include "nsThreadManager.h" +#include "nscore.h" +#include "prenv.h" +#include "skia/include/core/SkGraphics.h" +#if defined(XP_WIN) +# include <dwrite.h> +# include <process.h> +# include <windows.h> + +# include "gfxDWriteFonts.h" +# include "gfxWindowsPlatform.h" +# include "mozilla/WindowsVersion.h" +# include "mozilla/gfx/DeviceManagerDx.h" +# include "mozilla/layers/GpuProcessD3D11TextureMap.h" +# include "mozilla/layers/GpuProcessD3D11QueryMap.h" +# include "mozilla/layers/TextureD3D11.h" +# include "mozilla/widget/WinCompositorWindowThread.h" +# include "MediaCodecsSupport.h" +# include "WMFDecoderModule.h" +#else +# include <unistd.h> +#endif +#ifdef MOZ_WIDGET_GTK +# include <gtk/gtk.h> + +# include "skia/include/ports/SkTypeface_cairo.h" +#endif +#ifdef ANDROID +# include "mozilla/layers/AndroidHardwareBuffer.h" +# include "skia/include/ports/SkTypeface_cairo.h" +#endif +#include "ChildProfilerController.h" +#include "nsAppRunner.h" + +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) +# include "mozilla/SandboxTestingChild.h" +#endif + +namespace mozilla::gfx { + +using namespace ipc; +using namespace layers; + +static GPUParent* sGPUParent; + +static void ReportHardwareMediaCodecSupportIfNeeded() { + // We only need to report the result once. + static bool sReported = false; + if (sReported) { + return; + } +#if defined(XP_WIN) + NS_GetCurrentThread()->Dispatch(NS_NewRunnableFunction( + "GPUParent:ReportHardwareMediaCodecSupportIfNeeded", []() { + // Only report telemetry when hardware decoding is available. + if (!gfx::gfxVars::IsInitialized() || + !gfx::gfxVars::CanUseHardwareVideoDecoding()) { + return; + } + sReported = true; + + // TODO : we can remove this after HEVC is enabled by default. + // HEVC is not enabled. We need to force to enable it in order to know + // its support as well, and it would be turn off later. + if (StaticPrefs::media_wmf_hevc_enabled() != 1) { + WMFDecoderModule::Init(WMFDecoderModule::Config::ForceEnableHEVC); + } + const auto support = PDMFactory::Supported(true /* force refresh */); + if (support.contains( + mozilla::media::MediaCodecsSupport::H264HardwareDecode)) { + Telemetry::ScalarSet( + Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, + u"h264"_ns, true); + } + if (support.contains( + mozilla::media::MediaCodecsSupport::VP8HardwareDecode)) { + Telemetry::ScalarSet( + Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, + u"vp8"_ns, true); + } + if (support.contains( + mozilla::media::MediaCodecsSupport::VP9HardwareDecode)) { + Telemetry::ScalarSet( + Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, + u"vp9"_ns, true); + } + if (support.contains( + mozilla::media::MediaCodecsSupport::AV1HardwareDecode)) { + Telemetry::ScalarSet( + Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, + u"av1"_ns, true); + } + if (support.contains( + mozilla::media::MediaCodecsSupport::HEVCHardwareDecode)) { + Telemetry::ScalarSet( + Telemetry::ScalarID::MEDIA_DEVICE_HARDWARE_DECODING_SUPPORT, + u"hevc"_ns, true); + } + if (StaticPrefs::media_wmf_hevc_enabled() != 1) { + WMFDecoderModule::Init(); + } + })); +#endif + // TODO : in the future, when we have GPU procss on MacOS, then we can report + // HEVC usage as well. +} + +GPUParent::GPUParent() : mLaunchTime(TimeStamp::Now()) { sGPUParent = this; } + +GPUParent::~GPUParent() { sGPUParent = nullptr; } + +/* static */ +GPUParent* GPUParent::GetSingleton() { + MOZ_DIAGNOSTIC_ASSERT(sGPUParent); + return sGPUParent; +} + +/* static */ bool GPUParent::MaybeFlushMemory() { +#if defined(XP_WIN) && !defined(HAVE_64BIT_BUILD) + MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); + if (!XRE_IsGPUProcess()) { + return false; + } + + MEMORYSTATUSEX stat; + stat.dwLength = sizeof(stat); + if (!GlobalMemoryStatusEx(&stat)) { + return false; + } + + // We only care about virtual process memory space in the GPU process because + // the UI process is already watching total memory usage. + static const size_t kLowVirtualMemoryThreshold = 384 * 1024 * 1024; + bool lowMemory = stat.ullAvailVirtual < kLowVirtualMemoryThreshold; + + // We suppress more than one low memory notification until we exit the + // condition. The UI process goes through more effort, reporting on-going + // memory pressure, but rather than try to manage a shared state, we just + // send one notification here to try to resolve it. + static bool sLowMemory = false; + if (lowMemory && !sLowMemory) { + NS_DispatchToMainThread( + NS_NewRunnableFunction("gfx::GPUParent::FlushMemory", []() -> void { + Unused << GPUParent::GetSingleton()->SendFlushMemory( + u"low-memory"_ns); + })); + } + sLowMemory = lowMemory; + return lowMemory; +#else + return false; +#endif +} + +bool GPUParent::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint, + const char* aParentBuildID) { + // Initialize the thread manager before starting IPC. Otherwise, messages + // may be posted to the main thread and we won't be able to process them. + if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) { + return false; + } + + // Now it's safe to start IPC. + if (NS_WARN_IF(!aEndpoint.Bind(this))) { + return false; + } + + nsDebugImpl::SetMultiprocessMode("GPU"); + + // This must be checked before any IPDL message, which may hit sentinel + // errors due to parent and content processes having different + // versions. + MessageChannel* channel = GetIPCChannel(); + if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) { + // We need to quit this process if the buildID doesn't match the parent's. + // This can occur when an update occurred in the background. + ProcessChild::QuickExit(); + } + + if (NS_FAILED(NS_InitMinimalXPCOM())) { + return false; + } + + // Ensure the observer service exists. + ProcessPriorityManager::Init(); + + // Init crash reporter support. + CrashReporterClient::InitSingleton(this); + + gfxConfig::Init(); + gfxVars::Initialize(); + gfxPlatform::InitNullMetadata(); + // Ensure our Factory is initialised, mainly for gfx logging to work. + gfxPlatform::InitMoz2DLogging(); +#if defined(XP_WIN) + gfxWindowsPlatform::InitMemoryReportersForGPUProcess(); + DeviceManagerDx::Init(); + GpuProcessD3D11TextureMap::Init(); + GpuProcessD3D11QueryMap::Init(); +#endif + + CompositorThreadHolder::Start(); + RemoteTextureMap::Init(); + APZThreadUtils::SetControllerThread(NS_GetCurrentThread()); + apz::InitializeGlobalState(); + LayerTreeOwnerTracker::Initialize(); + CompositorBridgeParent::InitializeStatics(); + mozilla::ipc::SetThisProcessName("GPU Process"); + + return true; +} + +void GPUParent::NotifyDeviceReset() { + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "gfx::GPUParent::NotifyDeviceReset", + []() -> void { GPUParent::GetSingleton()->NotifyDeviceReset(); })); + return; + } + + // Reset and reinitialize the compositor devices +#ifdef XP_WIN + if (!DeviceManagerDx::Get()->MaybeResetAndReacquireDevices()) { + // If the device doesn't need to be reset then the device + // has already been reset by a previous NotifyDeviceReset message. + return; + } +#endif + + // Notify the main process that there's been a device reset + // and that they should reset their compositors and repaint + GPUDeviceData data; + RecvGetDeviceStatus(&data); + Unused << SendNotifyDeviceReset(data); +} + +void GPUParent::NotifyOverlayInfo(layers::OverlayInfo aInfo) { + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "gfx::GPUParent::NotifyOverlayInfo", [aInfo]() -> void { + GPUParent::GetSingleton()->NotifyOverlayInfo(aInfo); + })); + return; + } + Unused << SendNotifyOverlayInfo(aInfo); +} + +void GPUParent::NotifySwapChainInfo(layers::SwapChainInfo aInfo) { + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "gfx::GPUParent::NotifySwapChainInfo", [aInfo]() -> void { + GPUParent::GetSingleton()->NotifySwapChainInfo(aInfo); + })); + return; + } + Unused << SendNotifySwapChainInfo(aInfo); +} + +void GPUParent::NotifyDisableRemoteCanvas() { + if (!NS_IsMainThread()) { + NS_DispatchToMainThread(NS_NewRunnableFunction( + "gfx::GPUParent::NotifyDisableRemoteCanvas", []() -> void { + GPUParent::GetSingleton()->NotifyDisableRemoteCanvas(); + })); + return; + } + Unused << SendNotifyDisableRemoteCanvas(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInit( + nsTArray<GfxVarUpdate>&& vars, const DevicePrefs& devicePrefs, + nsTArray<LayerTreeIdMapping>&& aMappings, + nsTArray<GfxInfoFeatureStatus>&& aFeatures, uint32_t aWrNamespace) { + for (const auto& var : vars) { + gfxVars::ApplyUpdate(var); + } + + // Inherit device preferences. + gfxConfig::Inherit(Feature::HW_COMPOSITING, devicePrefs.hwCompositing()); + gfxConfig::Inherit(Feature::D3D11_COMPOSITING, + devicePrefs.d3d11Compositing()); + gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, devicePrefs.oglCompositing()); + gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1()); + gfxConfig::Inherit(Feature::D3D11_HW_ANGLE, devicePrefs.d3d11HwAngle()); + + { // Let the crash reporter know if we've got WR enabled or not. For other + // processes this happens in gfxPlatform::InitWebRenderConfig. + ScopedGfxFeatureReporter reporter("WR", + gfxPlatform::WebRenderPrefEnabled()); + reporter.SetSuccessful(); + } + + for (const LayerTreeIdMapping& map : aMappings) { + LayerTreeOwnerTracker::Get()->Map(map.layersId(), map.ownerId()); + } + + widget::GfxInfoBase::SetFeatureStatus(std::move(aFeatures)); + + // We bypass gfxPlatform::Init, so we must initialize any relevant libraries + // here that would normally be initialized there. + SkGraphics::Init(); + + bool useRemoteCanvas = + gfxVars::RemoteCanvasEnabled() || gfxVars::UseAcceleratedCanvas2D(); + if (useRemoteCanvas) { + gfxGradientCache::Init(); + } + +#if defined(XP_WIN) + if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { + if (DeviceManagerDx::Get()->CreateCompositorDevices() && useRemoteCanvas) { + if (DeviceManagerDx::Get()->CreateCanvasDevice()) { + gfxDWriteFont::InitDWriteSupport(); + } else { + gfxWarning() << "Failed to create canvas device."; + } + } + } + DeviceManagerDx::Get()->CreateDirectCompositionDevice(); + // Ensure to initialize GfxInfo + nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service(); + Unused << gfxInfo; + + Factory::EnsureDWriteFactory(); +#endif + +#if defined(MOZ_WIDGET_GTK) + char* display_name = PR_GetEnv("MOZ_GDK_DISPLAY"); + if (!display_name) { + bool waylandEnabled = false; +# ifdef MOZ_WAYLAND + waylandEnabled = IsWaylandEnabled(); +# endif + if (!waylandEnabled) { + display_name = PR_GetEnv("DISPLAY"); + } + } + if (display_name) { + int argc = 3; + char option_name[] = "--display"; + char* argv[] = {// argv0 is unused because g_set_prgname() was called in + // XRE_InitChildProcess(). + nullptr, option_name, display_name, nullptr}; + char** argvp = argv; + gtk_init(&argc, &argvp); + } else { + gtk_init(nullptr, nullptr); + } + + // Ensure we have an FT library for font instantiation. + // This would normally be set by gfxPlatform::Init(). + // Since we bypass that, we must do it here instead. + FT_Library library = Factory::NewFTLibrary(); + MOZ_ASSERT(library); + Factory::SetFTLibrary(library); + + // true to match gfxPlatform::FontHintingEnabled(). We must hardcode + // this value because we do not have a gfxPlatform instance. + SkInitCairoFT(true); + + // Ensure that GfxInfo::Init is called on the main thread. + nsCOMPtr<nsIGfxInfo> gfxInfo = components::GfxInfo::Service(); + Unused << gfxInfo; +#endif + +#ifdef ANDROID + // Ensure we have an FT library for font instantiation. + // This would normally be set by gfxPlatform::Init(). + // Since we bypass that, we must do it here instead. + FT_Library library = Factory::NewFTLibrary(); + MOZ_ASSERT(library); + Factory::SetFTLibrary(library); + + // false to match gfxAndroidPlatform::FontHintingEnabled(). We must + // hardcode this value because we do not have a gfxPlatform instance. + SkInitCairoFT(false); + + if (gfxVars::UseAHardwareBufferSharedSurfaceWebglOop()) { + layers::AndroidHardwareBufferApi::Init(); + layers::AndroidHardwareBufferManager::Init(); + } + +#endif + + // Make sure to do this *after* we update gfxVars above. + wr::RenderThread::Start(aWrNamespace); + gfx::CanvasRenderThread::Start(); + image::ImageMemoryReporter::InitForWebRender(); + + VRManager::ManagerInit(); + // Send a message to the UI process that we're done. + GPUDeviceData data; + RecvGetDeviceStatus(&data); + Unused << SendInitComplete(data); + + // Dispatch a task to run when idle that will determine which codecs are + // usable. The primary goal is to determine if the media feature pack is + // installed. + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThreadQueue( + NS_NewRunnableFunction( + "GPUParent::Supported", + []() { + auto supported = PDMFactory::Supported(); + Unused << GPUParent::GetSingleton()->SendUpdateMediaCodecsSupported( + supported); + ReportHardwareMediaCodecSupportIfNeeded(); + }), + 2000 /* 2 seconds timeout */, EventQueuePriority::Idle)); + + Telemetry::AccumulateTimeDelta(Telemetry::GPU_PROCESS_INITIALIZATION_TIME_MS, + mLaunchTime); + return IPC_OK(); +} + +#if defined(MOZ_SANDBOX) && defined(MOZ_DEBUG) && defined(ENABLE_TESTS) +mozilla::ipc::IPCResult GPUParent::RecvInitSandboxTesting( + Endpoint<PSandboxTestingChild>&& aEndpoint) { + if (!SandboxTestingChild::Initialize(std::move(aEndpoint))) { + return IPC_FAIL( + this, "InitSandboxTesting failed to initialise the child process."); + } + return IPC_OK(); +} +#endif + +mozilla::ipc::IPCResult GPUParent::RecvInitCompositorManager( + Endpoint<PCompositorManagerParent>&& aEndpoint, uint32_t aNamespace) { + CompositorManagerParent::Create(std::move(aEndpoint), ContentParentId(), + aNamespace, /* aIsRoot */ true); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitVsyncBridge( + Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) { + mVsyncBridge = VsyncBridgeParent::Start(std::move(aVsyncEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitImageBridge( + Endpoint<PImageBridgeParent>&& aEndpoint) { + ImageBridgeParent::CreateForGPUProcess(std::move(aEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitVideoBridge( + Endpoint<PVideoBridgeParent>&& aEndpoint, + const layers::VideoBridgeSource& aSource) { + // For GPU decoding, the video bridge would be opened in + // `VideoBridgeChild::StartupForGPUProcess`. + MOZ_ASSERT(aSource == layers::VideoBridgeSource::RddProcess || + aSource == layers::VideoBridgeSource::MFMediaEngineCDMProcess); + VideoBridgeParent::Open(std::move(aEndpoint), aSource); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitVRManager( + Endpoint<PVRManagerParent>&& aEndpoint) { + VRManagerParent::CreateForGPUProcess(std::move(aEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitVR( + Endpoint<PVRGPUChild>&& aEndpoint) { + gfx::VRGPUChild::InitForGPUProcess(std::move(aEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitUiCompositorController( + const LayersId& aRootLayerTreeId, + Endpoint<PUiCompositorControllerParent>&& aEndpoint) { + UiCompositorControllerParent::Start(aRootLayerTreeId, std::move(aEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitAPZInputBridge( + const LayersId& aRootLayerTreeId, + Endpoint<PAPZInputBridgeParent>&& aEndpoint) { + APZInputBridgeParent::Create(aRootLayerTreeId, std::move(aEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvInitProfiler( + Endpoint<PProfilerChild>&& aEndpoint) { + mProfilerController = ChildProfilerController::Create(std::move(aEndpoint)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvUpdateVar(const GfxVarUpdate& aUpdate) { +#if defined(XP_WIN) + auto scopeExit = MakeScopeExit( + [couldUseHWDecoder = gfx::gfxVars::CanUseHardwareVideoDecoding()] { + if (couldUseHWDecoder != gfx::gfxVars::CanUseHardwareVideoDecoding()) { + // The capabilities of the system may have changed, force a refresh by + // re-initializing the WMF PDM. + WMFDecoderModule::Init(); + Unused << GPUParent::GetSingleton()->SendUpdateMediaCodecsSupported( + PDMFactory::Supported(true /* force refresh */)); + ReportHardwareMediaCodecSupportIfNeeded(); + } + }); +#endif + gfxVars::ApplyUpdate(aUpdate); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvPreferenceUpdate(const Pref& aPref) { + Preferences::SetPreference(aPref); + return IPC_OK(); +} + +static void CopyFeatureChange(Feature aFeature, Maybe<FeatureFailure>* aOut) { + FeatureState& feature = gfxConfig::GetFeature(aFeature); + if (feature.DisabledByDefault() || feature.IsEnabled()) { + // No change: + // - Disabled-by-default means the parent process told us not to use this + // feature. + // - Enabled means we were told to use this feature, and we didn't + // discover anything + // that would prevent us from doing so. + *aOut = Nothing(); + return; + } + + MOZ_ASSERT(!feature.IsEnabled()); + + nsCString message; + message.AssignASCII(feature.GetFailureMessage()); + + *aOut = + Some(FeatureFailure(feature.GetValue(), message, feature.GetFailureId())); +} + +mozilla::ipc::IPCResult GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut) { + CopyFeatureChange(Feature::D3D11_COMPOSITING, &aOut->d3d11Compositing()); + CopyFeatureChange(Feature::OPENGL_COMPOSITING, &aOut->oglCompositing()); + +#if defined(XP_WIN) + if (DeviceManagerDx* dm = DeviceManagerDx::Get()) { + D3D11DeviceStatus deviceStatus; + dm->ExportDeviceInfo(&deviceStatus); + aOut->gpuDevice() = Some(deviceStatus); + } +#else + aOut->gpuDevice() = Nothing(); +#endif + + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvSimulateDeviceReset() { +#if defined(XP_WIN) + DeviceManagerDx::Get()->ForceDeviceReset( + ForcedDeviceResetReason::COMPOSITOR_UPDATED); +#endif + wr::RenderThread::Get()->SimulateDeviceReset(); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvNewContentCompositorManager( + Endpoint<PCompositorManagerParent>&& aEndpoint, + const ContentParentId& aChildId, uint32_t aNamespace) { + CompositorManagerParent::Create(std::move(aEndpoint), aChildId, aNamespace, + /* aIsRoot */ false); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvNewContentImageBridge( + Endpoint<PImageBridgeParent>&& aEndpoint, const ContentParentId& aChildId) { + if (!ImageBridgeParent::CreateForContent(std::move(aEndpoint), aChildId)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvNewContentVRManager( + Endpoint<PVRManagerParent>&& aEndpoint, const ContentParentId& aChildId) { + if (!VRManagerParent::CreateForContent(std::move(aEndpoint), aChildId)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvNewContentRemoteDecoderManager( + Endpoint<PRemoteDecoderManagerParent>&& aEndpoint, + const ContentParentId& aChildId) { + if (!RemoteDecoderManagerParent::CreateForContent(std::move(aEndpoint), + aChildId)) { + return IPC_FAIL_NO_REASON(this); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvAddLayerTreeIdMapping( + const LayerTreeIdMapping& aMapping) { + LayerTreeOwnerTracker::Get()->Map(aMapping.layersId(), aMapping.ownerId()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvRemoveLayerTreeIdMapping( + const LayerTreeIdMapping& aMapping) { + LayerTreeOwnerTracker::Get()->Unmap(aMapping.layersId(), aMapping.ownerId()); + CompositorBridgeParent::DeallocateLayerTreeId(aMapping.layersId()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvNotifyGpuObservers( + const nsCString& aTopic) { + nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService(); + MOZ_ASSERT(obsSvc); + if (obsSvc) { + obsSvc->NotifyObservers(nullptr, aTopic.get(), nullptr); + } + return IPC_OK(); +} + +/* static */ +void GPUParent::GetGPUProcessName(nsACString& aStr) { + auto processType = XRE_GetProcessType(); + unsigned pid = 0; + if (processType == GeckoProcessType_GPU) { + pid = getpid(); + } else { + MOZ_DIAGNOSTIC_ASSERT(processType == GeckoProcessType_Default); + pid = GPUProcessManager::Get()->GPUProcessPid(); + } + + nsPrintfCString processName("GPU (pid %u)", pid); + aStr.Assign(processName); +} + +mozilla::ipc::IPCResult GPUParent::RecvRequestMemoryReport( + const uint32_t& aGeneration, const bool& aAnonymize, + const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile, + const RequestMemoryReportResolver& aResolver) { + nsAutoCString processName; + GetGPUProcessName(processName); + + mozilla::dom::MemoryReportRequestClient::Start( + aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile, processName, + [&](const MemoryReport& aReport) { + Unused << GetSingleton()->SendAddMemoryReport(aReport); + }, + aResolver); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvShutdownVR() { + if (StaticPrefs::dom_vr_process_enabled_AtStartup()) { + VRGPUChild::Shutdown(); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvUpdatePerfStatsCollectionMask( + const uint64_t& aMask) { + PerfStats::SetCollectionMask(static_cast<PerfStats::MetricMask>(aMask)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvCollectPerfStatsJSON( + CollectPerfStatsJSONResolver&& aResolver) { + aResolver(PerfStats::CollectLocalPerfStatsJSON()); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvFlushFOGData( + FlushFOGDataResolver&& aResolver) { + glean::FlushFOGData(std::move(aResolver)); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvTestTriggerMetrics( + TestTriggerMetricsResolver&& aResolve) { + mozilla::glean::test_only_ipc::a_counter.Add(nsIXULRuntime::PROCESS_TYPE_GPU); + aResolve(true); + return IPC_OK(); +} + +mozilla::ipc::IPCResult GPUParent::RecvCrashProcess() { + MOZ_CRASH("Deliberate GPU process crash"); + return IPC_OK(); +} + +void GPUParent::ActorDestroy(ActorDestroyReason aWhy) { + if (AbnormalShutdown == aWhy) { + NS_WARNING("Shutting down GPU process early due to a crash!"); + ProcessChild::QuickExit(); + } + + // Send the last bits of Glean data over to the main process. + glean::FlushFOGData( + [](ByteBuf&& aBuf) { glean::SendFOGData(std::move(aBuf)); }); + +#ifndef NS_FREE_PERMANENT_DATA + // No point in going through XPCOM shutdown because we don't keep persistent + // state. + ProcessChild::QuickExit(); +#endif + + // Wait until all RemoteDecoderManagerParent have closed. + mShutdownBlockers.WaitUntilClear(10 * 1000 /* 10s timeout*/) + ->Then(GetCurrentSerialEventTarget(), __func__, [self = RefPtr{this}]() { + if (self->mProfilerController) { + self->mProfilerController->Shutdown(); + self->mProfilerController = nullptr; + } + + if (self->mVsyncBridge) { + self->mVsyncBridge->Shutdown(); + self->mVsyncBridge = nullptr; + } + VideoBridgeParent::Shutdown(); + // This could be running on either the Compositor thread, the Renderer + // thread, or the dedicated CanvasRender thread, so we need to shutdown + // before the former two. + CanvasRenderThread::Shutdown(); + CompositorThreadHolder::Shutdown(); + RemoteTextureMap::Shutdown(); + // There is a case that RenderThread exists when gfxVars::UseWebRender() + // is false. This could happen when WebRender was fallbacked to + // compositor. + if (wr::RenderThread::Get()) { + wr::RenderThread::ShutDown(); + } +#ifdef XP_WIN + if (widget::WinCompositorWindowThread::Get()) { + widget::WinCompositorWindowThread::ShutDown(); + } +#endif + + image::ImageMemoryReporter::ShutdownForWebRender(); + + // Shut down the default GL context provider. + gl::GLContextProvider::Shutdown(); + +#if defined(XP_WIN) + // The above shutdown calls operate on the available context providers + // on most platforms. Windows is a "special snowflake", though, and has + // three context providers available, so we have to shut all of them + // down. We should only support the default GL provider on Windows; + // then, this could go away. Unfortunately, we currently support WGL + // (the default) for WebGL on Optimus. + gl::GLContextProviderEGL::Shutdown(); +#endif + + Factory::ShutDown(); + + // We bypass gfxPlatform shutdown, so we must shutdown any libraries here + // that would normally be handled by it. +#ifdef NS_FREE_PERMANENT_DATA + SkGraphics::PurgeFontCache(); + cairo_debug_reset_static_data(); +#endif + +#if defined(XP_WIN) + GpuProcessD3D11QueryMap::Shutdown(); + GpuProcessD3D11TextureMap::Shutdown(); + DeviceManagerDx::Shutdown(); +#endif + LayerTreeOwnerTracker::Shutdown(); + gfxVars::Shutdown(); + gfxConfig::Shutdown(); + CrashReporterClient::DestroySingleton(); + XRE_ShutdownChildProcess(); + }); +} + +} // namespace mozilla::gfx |