| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/viz/service/gl/gpu_service_impl.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/allocator/partition_alloc_support.h" |
| #include "base/android/android_info.h" |
| #include "base/command_line.h" |
| #include "base/debug/crash_logging.h" |
| #include "base/feature_list.h" |
| #include "base/functional/bind.h" |
| #include "base/memory/memory_pressure_listener_registry.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/no_destructor.h" |
| #include "base/observer_list.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/system/sys_info.h" |
| #include "base/task/bind_post_task.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/trace_event/trace_event.h" |
| #include "base/unguessable_token.h" |
| #include "build/build_config.h" |
| #include "components/persistent_cache/pending_backend.h" |
| #include "components/startup_metric_utils/gpu/startup_metric_utils.h" |
| #include "components/version_info/version_info.h" |
| #include "components/viz/common/features.h" |
| #include "components/viz/common/resources/peak_gpu_memory_tracker_util.h" |
| #include "components/viz/service/gl/gpu_log_message_manager.h" |
| #include "gpu/command_buffer/service/dawn_caching_interface.h" |
| #include "gpu/command_buffer/service/gpu_switches.h" |
| #include "gpu/command_buffer/service/scheduler.h" |
| #include "gpu/command_buffer/service/shared_context_state.h" |
| #include "gpu/command_buffer/service/shared_image/shared_image_factory.h" |
| #include "gpu/command_buffer/service/shared_image/shared_image_manager.h" |
| #include "gpu/command_buffer/service/skia_utils.h" |
| #include "gpu/command_buffer/service/sync_point_manager.h" |
| #include "gpu/config/gpu_finch_features.h" |
| #include "gpu/config/gpu_info_collector.h" |
| #include "gpu/config/gpu_preferences.h" |
| #include "gpu/config/gpu_switches.h" |
| #include "gpu/config/gpu_util.h" |
| #include "gpu/ipc/common/gpu_client_ids.h" |
| #include "gpu/ipc/common/gpu_peak_memory.h" |
| #include "gpu/ipc/common/memory_stats.h" |
| #include "gpu/ipc/service/gpu_channel.h" |
| #include "gpu/ipc/service/gpu_channel_manager.h" |
| #include "gpu/ipc/service/gpu_watchdog_thread.h" |
| #include "gpu/vulkan/buildflags.h" |
| #include "ipc/ipc_channel.h" |
| #include "ipc/ipc_sync_channel.h" |
| #include "media/base/media_log.h" |
| #include "media/base/media_switches.h" |
| #include "media/gpu/buildflags.h" |
| #include "media/gpu/gpu_video_accelerator_util.h" |
| #include "media/gpu/gpu_video_encode_accelerator_factory.h" |
| #include "media/gpu/ipc/service/media_gpu_channel_manager.h" |
| #include "media/mojo/services/gpu_mojo_media_client.h" |
| #include "media/mojo/services/mojo_video_encode_accelerator_provider.h" |
| #include "mojo/public/cpp/bindings/self_owned_receiver.h" |
| #include "services/webnn/webnn_context_provider_impl.h" |
| #include "skia/buildflags.h" |
| #include "third_party/perfetto/include/perfetto/tracing/track.h" |
| #include "third_party/skia/include/gpu/ganesh/GrDirectContext.h" |
| #include "third_party/skia/include/gpu/ganesh/gl/GrGLAssembleInterface.h" |
| #include "third_party/skia/include/gpu/ganesh/gl/GrGLInterface.h" |
| #include "ui/base/ozone_buildflags.h" |
| #include "ui/base/ui_base_features.h" |
| #include "ui/gl/gl_context.h" |
| #include "ui/gl/gl_implementation.h" |
| #include "ui/gl/gl_switches.h" |
| #include "ui/gl/gl_utils.h" |
| #include "ui/gl/gpu_switching_manager.h" |
| #include "ui/gl/init/create_gr_gl_interface.h" |
| #include "ui/gl/init/gl_factory.h" |
| #include "url/gurl.h" |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "components/viz/service/gl/throw_uncaught_exception.h" |
| #include "media/base/android/media_codec_util.h" |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| #include "components/chromeos_camera/gpu_mjpeg_decode_accelerator_factory.h" |
| #include "components/chromeos_camera/mojo_jpeg_encode_accelerator_service.h" |
| #include "components/chromeos_camera/mojo_mjpeg_decode_accelerator_service.h" |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "gpu/command_buffer/service/shared_image/d3d_image_backing_factory.h" |
| #include "mojo/public/cpp/system/platform_handle.h" |
| #include "ui/gl/dcomp_surface_registry.h" |
| #include "ui/gl/direct_composition_support.h" |
| #endif |
| |
| #if BUILDFLAG(IS_APPLE) |
| #include "ui/base/cocoa/quartz_util.h" |
| #endif |
| |
| #if BUILDFLAG(SKIA_USE_DAWN) |
| #include "gpu/command_buffer/service/dawn_context_provider.h" |
| #include "gpu/command_buffer/service/gpu_persistent_cache.h" |
| #endif |
| |
| #if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) |
| #include "base/test/clang_profiling.h" |
| #endif |
| |
| #if BUILDFLAG(ENABLE_VULKAN) |
| #include "components/viz/common/gpu/vulkan_context_provider.h" |
| #include "components/viz/common/gpu/vulkan_in_process_context_provider.h" |
| #endif |
| |
| #if BUILDFLAG(IS_OZONE) |
| #include "ui/ozone/public/ozone_platform.h" |
| #include "ui/ozone/public/surface_factory_ozone.h" |
| #endif // BUILDFLAG(IS_OZONE) |
| |
| namespace viz { |
| |
| namespace { |
| |
| // The names emitted for GPU initialization trace events. |
| // This code may be removed after the following investigation: |
| // crbug.com/1350257 |
| constexpr char kGpuInitializationEventCategory[] = "latency"; |
| constexpr char kGpuInitializationEvent[] = "GpuInitialization"; |
| |
| bool IsAcceleratedJpegDecodeSupported() { |
| #if BUILDFLAG(IS_CHROMEOS) |
| return chromeos_camera::GpuMjpegDecodeAcceleratorFactory:: |
| IsAcceleratedJpegDecodeSupported(); |
| #else |
| return false; |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| } |
| |
| void RunGetPeakGpuMemoryUsageCallbackOnMainThread( |
| GpuServiceImpl::GetPeakMemoryUsageCallback callback, |
| uint64_t peak_memory, |
| base::flat_map<gpu::GpuPeakMemoryAllocationSource, uint64_t> |
| allocation_per_source) { |
| std::move(callback).Run(peak_memory, std::move(allocation_per_source)); |
| } |
| |
| gpu::GpuPersistentCache::AsyncDiskWriteOpts |
| GetPersistentCacheAsyncDiskWriteOpts() { |
| gpu::GpuPersistentCache::AsyncDiskWriteOpts async_opts; |
| // The GpuPersistentCache uses a task runner for doing disk writes in the |
| // background. These are low priority tasks but once the task starts running, |
| // we do not want it to be interrupted because it holds locks on the database. |
| // This behaviour is achieved with the BEST_EFFORT priority and |
| // MUST_USE_FOREGROUND policy. |
| async_opts.task_runner = base::ThreadPool::CreateSequencedTaskRunner( |
| {base::MayBlock(), base::TaskPriority::BEST_EFFORT, |
| base::ThreadPolicy::MUST_USE_FOREGROUND, |
| base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}); |
| async_opts.max_pending_bytes_to_write = gpu::GetDefaultGpuDiskCacheSize(); |
| return async_opts; |
| } |
| |
| } // namespace |
| |
| GpuServiceImpl::GpuServiceImpl( |
| const gpu::GpuPreferences& gpu_preferences, |
| const gpu::GPUInfo& gpu_info, |
| const gpu::GpuFeatureInfo& gpu_feature_info, |
| const std::optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu, |
| const std::optional<gpu::GpuFeatureInfo>& gpu_feature_info_for_hardware_gpu, |
| const gfx::GpuExtraInfo& gpu_extra_info, |
| InitParams init_params) |
| : main_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()), |
| io_runner_(std::move(init_params.io_runner)), |
| watchdog_thread_(std::move(init_params.watchdog_thread)), |
| gpu_preferences_(gpu_preferences), |
| gpu_info_(gpu_info), |
| gpu_feature_info_(gpu_feature_info), |
| gpu_driver_bug_workarounds_( |
| gpu_feature_info_.enabled_gpu_driver_bug_workarounds), |
| gpu_info_for_hardware_gpu_(gpu_info_for_hardware_gpu), |
| gpu_feature_info_for_hardware_gpu_(gpu_feature_info_for_hardware_gpu), |
| gpu_extra_info_(gpu_extra_info), |
| #if BUILDFLAG(ENABLE_VULKAN) |
| vulkan_implementation_(init_params.vulkan_implementation), |
| #endif |
| persistent_caches_( |
| /*max_in_memory_cache_size=*/gpu::GetDefaultGpuDiskCacheSize(), |
| /*async_write_options=*/GetPersistentCacheAsyncDiskWriteOpts()), |
| clear_shader_cache_(base::FeatureList::IsEnabled( |
| features::kClearGrShaderDiskCacheOnInvalidPrefix)) { |
| DCHECK(!io_runner_->BelongsToCurrentThread()); |
| |
| #if BUILDFLAG(ENABLE_VULKAN) |
| if (vulkan_implementation_) { |
| bool is_native_vulkan = |
| gpu_preferences_.use_vulkan == gpu::VulkanImplementationName::kNative || |
| gpu_preferences_.use_vulkan == |
| gpu::VulkanImplementationName::kForcedNative; |
| // With swiftshader the vendor_id is 0xffff. For some tests gpu_info is not |
| // initialized, so the vendor_id is 0. |
| bool is_native_gl = |
| gpu_info_.gpu.vendor_id != 0xffff && gpu_info_.gpu.vendor_id != 0; |
| |
| const bool is_thread_safe = features::IsDrDcEnabled(gpu_feature_info); |
| |
| // If GL is using a real GPU, the gpu_info will be passed in and vulkan will |
| // use the same GPU. |
| vulkan_context_provider_ = VulkanInProcessContextProvider::Create( |
| vulkan_implementation_, gpu_preferences_.vulkan_heap_memory_limit, |
| gpu_preferences_.vulkan_sync_cpu_memory_limit, is_thread_safe, |
| (is_native_vulkan && is_native_gl) ? &gpu_info_ : nullptr); |
| if (!vulkan_context_provider_) { |
| DLOG(ERROR) << "Failed to create Vulkan context provider."; |
| } |
| } |
| #endif |
| |
| #if BUILDFLAG(USE_DAWN) || BUILDFLAG(SKIA_USE_DAWN) |
| dawn_caching_interface_factory_ = |
| std::make_unique<gpu::webgpu::DawnCachingInterfaceFactory>(); |
| #endif |
| |
| #if BUILDFLAG(SKIA_USE_DAWN) |
| if (gpu_preferences_.gr_context_type == gpu::GrContextType::kGraphiteDawn) { |
| dawn_context_provider_ = std::move(init_params.dawn_context_provider); |
| |
| if (dawn_context_provider_) { |
| // GpuServiceImpl holds the instance of DawnContextProvider, so it |
| // outlives the DawnContextProvider. |
| if (features::kSkiaGraphiteDawnUsePersistentCache.Get()) { |
| auto persistent_cache = |
| persistent_caches_.GetCache(gpu::kGraphiteDawnGpuDiskCacheHandle); |
| dawn_context_provider_->SetCachingInterface( |
| std::move(persistent_cache)); |
| } else { |
| auto cache_blob_callback = base::BindRepeating( |
| [](GpuServiceImpl* self, const std::string& key, |
| const std::string& blob) { |
| self->StoreBlobToDisk(gpu::kGraphiteDawnGpuDiskCacheHandle, key, |
| blob); |
| }, |
| base::Unretained(this)); |
| auto dawn_caching_interface = |
| dawn_caching_interface_factory_->CreateInstance( |
| gpu::kGraphiteDawnGpuDiskCacheHandle, |
| std::move(cache_blob_callback)); |
| dawn_context_provider_->SetCachingInterface( |
| std::move(dawn_caching_interface)); |
| } |
| } |
| } |
| #endif // BUILDFLAG(SKIA_USE_DAWN) |
| |
| weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| GpuServiceImpl::GpuServiceImpl() |
| : persistent_caches_( |
| /*max_in_memory_cache_size=*/gpu::GetDefaultGpuDiskCacheSize(), |
| /*async_write_options=*/GetPersistentCacheAsyncDiskWriteOpts()), |
| clear_shader_cache_(base::FeatureList::IsEnabled( |
| features::kClearGrShaderDiskCacheOnInvalidPrefix)) {} |
| |
| GpuServiceImpl::~GpuServiceImpl() { |
| if (main_runner_) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| } |
| |
| // Ensure we don't try to exit when already in the process of exiting. |
| is_exiting_.Set(); |
| |
| bind_task_tracker_.TryCancelAll(); |
| |
| #if BUILDFLAG(IS_WIN) |
| gl::DirectCompositionOverlayCapsMonitor::GetInstance()->RemoveObserver(this); |
| #endif |
| |
| // Destroy the receiver on the IO thread. |
| { |
| base::WaitableEvent wait; |
| auto destroy_receiver_task = base::BindOnce( |
| [](mojo::Receiver<mojom::GpuService>* receiver, |
| base::WaitableEvent* wait) { |
| receiver->reset(); |
| wait->Signal(); |
| }, |
| &receiver_, base::Unretained(&wait)); |
| if (io_runner_ && |
| io_runner_->PostTask(FROM_HERE, std::move(destroy_receiver_task))) { |
| wait.Wait(); |
| } |
| } |
| |
| if (watchdog_thread_) |
| watchdog_thread_->OnGpuProcessTearDown(); |
| |
| compositor_gpu_thread_.reset(); |
| media_gpu_channel_manager_.reset(); |
| gpu_channel_manager_.reset(); |
| |
| // WebNN must be destroyed before the scheduler is destroyed. |
| webnn_context_provider_.reset(); |
| |
| // Scheduler must be destroyed before sync point manager is destroyed. |
| owned_scheduler_.reset(); |
| owned_sync_point_manager_.reset(); |
| owned_shared_image_manager_.reset(); |
| |
| // The image decode accelerator worker must outlive the GPU channel manager so |
| // that it doesn't get any decode requests during/after destruction. |
| DCHECK(!gpu_channel_manager_); |
| |
| // Signal this event before destroying the child process. That way all |
| // background threads can cleanup. For example, in the renderer the |
| // RenderThread instances will be able to notice shutdown before the render |
| // process begins waiting for them to exit. |
| if (owned_shutdown_event_) |
| owned_shutdown_event_->Signal(); |
| } |
| |
| void GpuServiceImpl::UpdateGPUInfo() { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| DCHECK(!gpu_host_); |
| |
| gpu_info_.jpeg_decode_accelerator_supported = |
| IsAcceleratedJpegDecodeSupported(); |
| |
| // Record initialization only after collecting the GPU info because that can |
| // take a significant amount of time. |
| base::TimeTicks now = base::TimeTicks::Now(); |
| gpu_info_.initialization_time = now - start_time_; |
| startup_metric_utils::GetGpu().RecordGpuInitialized(now); |
| |
| // This metric code may be removed after the following investigation: |
| // crbug.com/1350257 |
| UMA_HISTOGRAM_CUSTOM_TIMES("GPU.GPUInitializationTime.V4", |
| gpu_info_.initialization_time, |
| base::Milliseconds(5), base::Seconds(90), 100); |
| TRACE_EVENT_BEGIN(kGpuInitializationEventCategory, kGpuInitializationEvent, |
| perfetto::Track::FromPointer(this), start_time_); |
| TRACE_EVENT_END(kGpuInitializationEventCategory, |
| /* kGpuInitializationEvent */ |
| perfetto::Track::FromPointer(this), now); |
| } |
| |
| void GpuServiceImpl::UpdateGPUInfoGL() { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| gpu::CollectGraphicsInfoGL(&gpu_info_, GetContextState()->display()); |
| gpu_host_->DidUpdateGPUInfo(gpu_info_); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| void GpuServiceImpl::InitializeWithHost( |
| mojo::PendingRemote<mojom::GpuHost> pending_gpu_host, |
| gpu::GpuProcessShmCount use_shader_cache_shm_count, |
| scoped_refptr<gl::GLSurface> default_offscreen_surface, |
| mojom::GpuServiceCreationParamsPtr creation_params, |
| gpu::SyncPointManager* sync_point_manager, |
| gpu::SharedImageManager* shared_image_manager, |
| gpu::Scheduler* scheduler, |
| base::WaitableEvent* shutdown_event, |
| const gpu::SharedContextState::GrContextOptionsProvider* |
| gr_context_options_provider) { |
| if (!sync_point_manager) { |
| sync_point_manager = CreateSyncPointManager(); |
| } |
| |
| if (!shared_image_manager) { |
| shared_image_manager = CreateSharedImageManager(); |
| } |
| |
| if (!scheduler) { |
| scheduler = CreateScheduler(sync_point_manager); |
| } |
| |
| if (!shutdown_event) { |
| shutdown_event = CreateShutdownEvent(); |
| } |
| |
| gr_context_options_provider_ = gr_context_options_provider; |
| |
| InitializeWithHostInternal( |
| std::move(pending_gpu_host), std::move(use_shader_cache_shm_count), |
| default_offscreen_surface, std::move(creation_params), sync_point_manager, |
| shared_image_manager, scheduler, shutdown_event); |
| } |
| #else |
| void GpuServiceImpl::InitializeWithHost( |
| mojo::PendingRemote<mojom::GpuHost> pending_gpu_host, |
| gpu::GpuProcessShmCount use_shader_cache_shm_count, |
| scoped_refptr<gl::GLSurface> default_offscreen_surface, |
| mojom::GpuServiceCreationParamsPtr creation_params, |
| base::WaitableEvent* shutdown_event) { |
| gpu::SyncPointManager* sync_point_manager = CreateSyncPointManager(); |
| #if BUILDFLAG(IS_OZONE) |
| gpu::SharedImageManager* shared_image_manager = |
| CreateSharedImageManager(creation_params->supports_overlays); |
| #else |
| gpu::SharedImageManager* shared_image_manager = CreateSharedImageManager(); |
| #endif |
| gpu::Scheduler* scheduler = CreateScheduler(sync_point_manager); |
| |
| if (!shutdown_event) { |
| shutdown_event = CreateShutdownEvent(); |
| } |
| |
| InitializeWithHostInternal( |
| std::move(pending_gpu_host), std::move(use_shader_cache_shm_count), |
| default_offscreen_surface, std::move(creation_params), sync_point_manager, |
| shared_image_manager, scheduler, shutdown_event); |
| |
| #if BUILDFLAG(IS_WIN) |
| // shared_image_d3d must be initialized after we call |
| // InitializeWithHostInternal as that is where the shared context state is |
| // created. |
| auto shared_context_state = GetContextState(); |
| if (shared_context_state) { |
| gpu_info_.shared_image_d3d = |
| gpu::D3DImageBackingFactory::IsD3DSharedImageSupported( |
| shared_context_state->GetD3D11Device().Get(), gpu_preferences_); |
| |
| gpu_host_->DidUpdateGPUInfo(gpu_info_); |
| } |
| #endif |
| } |
| #endif |
| |
| void GpuServiceImpl::InitializeWithHostInternal( |
| mojo::PendingRemote<mojom::GpuHost> pending_gpu_host, |
| gpu::GpuProcessShmCount use_shader_cache_shm_count, |
| scoped_refptr<gl::GLSurface> default_offscreen_surface, |
| mojom::GpuServiceCreationParamsPtr creation_params, |
| gpu::SyncPointManager* sync_point_manager, |
| gpu::SharedImageManager* shared_image_manager, |
| gpu::Scheduler* scheduler, |
| base::WaitableEvent* shutdown_event) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| |
| scheduler_ = scheduler; |
| shutdown_event_ = shutdown_event; |
| |
| use_shader_cache_shm_count_ = |
| base::MakeRefCounted<gpu::RefCountedGpuProcessShmCount>( |
| std::move(use_shader_cache_shm_count)); |
| |
| mojo::Remote<mojom::GpuHost> gpu_host(std::move(pending_gpu_host)); |
| |
| #if BUILDFLAG(IS_LINUX) |
| gpu_extra_info_.is_gmb_nv12_supported = IsGMBNV12Supported(); |
| #endif |
| |
| gpu_host->DidInitialize(gpu_info_, gpu_feature_info_, |
| gpu_info_for_hardware_gpu_, |
| gpu_feature_info_for_hardware_gpu_, gpu_extra_info_); |
| gpu_host_ = mojo::SharedRemote<mojom::GpuHost>(gpu_host.Unbind(), io_runner_); |
| |
| // Defer creation of the render thread. This is to prevent it from handling |
| // IPC messages before the sandbox has been enabled and all other necessary |
| // initialization has succeeded. |
| gpu_channel_manager_ = std::make_unique<gpu::GpuChannelManager>( |
| gpu_preferences_, this, watchdog_thread_.get(), main_runner_, io_runner_, |
| scheduler_, sync_point_manager, shared_image_manager, gpu_feature_info_, |
| &use_shader_cache_shm_count_->data, std::move(default_offscreen_surface), |
| vulkan_context_provider(), dawn_context_provider(), |
| dawn_caching_interface_factory(), gr_context_options_provider_, |
| &persistent_caches_); |
| |
| media_gpu_channel_manager_ = std::make_unique<media::MediaGpuChannelManager>( |
| gpu_channel_manager_.get()); |
| |
| // Create and Initialize compositor gpu thread. |
| if (features::IsDrDcEnabled(gpu_feature_info_)) { |
| // Add a crash key for DrDC. |
| static auto* drdc_crash_key = base::debug::AllocateCrashKeyString( |
| "is-drdc-enabled", base::debug::CrashKeySize::Size32); |
| base::debug::SetCrashKeyString(drdc_crash_key, "1"); |
| |
| CompositorGpuThread::CreateParams params; |
| params.gpu_channel_manager = gpu_channel_manager_.get(); |
| params.display = |
| gpu_channel_manager_->default_offscreen_surface() |
| ? gpu_channel_manager_->default_offscreen_surface()->GetGLDisplay() |
| : nullptr; |
| params.enable_watchdog = !!watchdog_thread_; |
| |
| #if BUILDFLAG(ENABLE_VULKAN) |
| params.vulkan_implementation = vulkan_implementation_; |
| params.device_queue = vulkan_context_provider_ |
| ? vulkan_context_provider_->GetDeviceQueue() |
| : nullptr; |
| #endif |
| #if BUILDFLAG(SKIA_USE_DAWN) |
| // Initialize the thread-safe GraphiteSharedContext before starting the DrDC |
| // thread to prevent a race on accessing it via SharedContextState. |
| if (dawn_context_provider_ && |
| dawn_context_provider_->use_thread_safe_shared_context()) { |
| dawn_context_provider_->InitializeThreadSafeGraphiteContext( |
| gpu::GetDefaultGraphiteContextOptions(gpu_driver_bug_workarounds_), |
| &use_shader_cache_shm_count_->data); |
| } |
| params.dawn_context_provider = dawn_context_provider_.get(); |
| #endif |
| |
| compositor_gpu_thread_ = CompositorGpuThread::Create(params); |
| } |
| |
| UMA_HISTOGRAM_BOOLEAN("GPU.DrDcEnabled", !!compositor_gpu_thread_); |
| |
| #if BUILDFLAG(IS_WIN) |
| // Add GpuServiceImpl to DirectCompositionOverlayCapsMonitor observer list for |
| // overlay and DXGI info update. This should be added after |gpu_host_| is |
| // initialized. |
| gl::DirectCompositionOverlayCapsMonitor::GetInstance()->AddObserver(this); |
| #endif |
| } |
| |
| void GpuServiceImpl::Bind( |
| mojo::PendingReceiver<mojom::GpuService> pending_receiver) { |
| if (main_runner_->BelongsToCurrentThread()) { |
| bind_task_tracker_.PostTask( |
| io_runner_.get(), FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::Bind, base::Unretained(this), |
| std::move(pending_receiver))); |
| return; |
| } |
| DCHECK(!receiver_.is_bound()); |
| receiver_.Bind(std::move(pending_receiver)); |
| } |
| |
| void GpuServiceImpl::DisableGpuCompositing() { |
| // Can be called from any thread. |
| gpu_host_->DisableGpuCompositing(); |
| } |
| |
| scoped_refptr<gpu::SharedContextState> GpuServiceImpl::GetContextState() { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| gpu::ContextResult result; |
| return gpu_channel_manager_->GetSharedContextState(&result); |
| } |
| |
| void GpuServiceImpl::SetPriorityChangedCallback( |
| PriorityChangedCallback callback) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| priority_changed_callback_ = std::move(callback); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| void GpuServiceImpl::CreateJpegDecodeAccelerator( |
| mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator> |
| jda_receiver) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| chromeos_camera::MojoMjpegDecodeAcceleratorService::Create( |
| std::move(jda_receiver), |
| base::BindRepeating( |
| &GpuServiceImpl::SetMjpegDecodeAcceleratorBeginFrameCB, |
| base::Unretained(this))); |
| } |
| |
| void GpuServiceImpl::CreateJpegEncodeAccelerator( |
| mojo::PendingReceiver<chromeos_camera::mojom::JpegEncodeAccelerator> |
| jea_receiver) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| chromeos_camera::MojoJpegEncodeAcceleratorService::Create( |
| std::move(jea_receiver)); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_WIN) |
| void GpuServiceImpl::RegisterDCOMPSurfaceHandle( |
| mojo::PlatformHandle surface_handle, |
| RegisterDCOMPSurfaceHandleCallback callback) { |
| base::UnguessableToken token = |
| gl::DCOMPSurfaceRegistry::GetInstance()->RegisterDCOMPSurfaceHandle( |
| surface_handle.TakeHandle()); |
| std::move(callback).Run(token); |
| } |
| |
| void GpuServiceImpl::UnregisterDCOMPSurfaceHandle( |
| const base::UnguessableToken& token) { |
| gl::DCOMPSurfaceRegistry::GetInstance()->UnregisterDCOMPSurfaceHandle(token); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| void GpuServiceImpl::CreateVideoEncodeAcceleratorProvider( |
| mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProvider> |
| vea_provider_receiver) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| |
| // Offload VEA providers to a dedicated runner. Things like loading profiles |
| // and creating encoder might take quite some time, and they might block |
| // processing of other mojo calls if executed on the current runner. |
| scoped_refptr<base::SequencedTaskRunner> runner; |
| #if BUILDFLAG(IS_FUCHSIA) |
| // TODO(crbug.com/40850116): Fuchsia does not support FIDL communication from |
| // ThreadPool's worker threads. |
| if (!vea_thread_) { |
| base::Thread::Options thread_options(base::MessagePumpType::IO, /*size=*/0); |
| vea_thread_ = |
| std::make_unique<base::Thread>("GpuVideoEncodeAcceleratorThread"); |
| CHECK(vea_thread_->StartWithOptions(std::move(thread_options))); |
| } |
| runner = vea_thread_->task_runner(); |
| #elif BUILDFLAG(IS_WIN) |
| // Windows hardware encoder requires a COM STA thread. |
| runner = base::ThreadPool::CreateCOMSTATaskRunner({base::MayBlock()}); |
| #else |
| // MayBlock() because MF VEA can take long time running GetSupportedProfiles() |
| if (base::FeatureList::IsEnabled( |
| media::kUseSequencedTaskRunnerForMojoVEAProvider)) { |
| runner = base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}); |
| } else { |
| runner = base::ThreadPool::CreateSingleThreadTaskRunner({base::MayBlock()}); |
| } |
| #endif |
| media::MojoVideoEncodeAcceleratorProvider::Create( |
| std::move(vea_provider_receiver), |
| base::BindRepeating(&media::GpuVideoEncodeAcceleratorFactory::CreateVEA), |
| gpu_preferences_, gpu_channel_manager_->gpu_driver_bug_workarounds(), |
| gpu_info_.active_gpu(), std::move(runner), |
| media_gpu_channel_manager_->AsWeakPtr(), main_runner_); |
| } |
| |
| void GpuServiceImpl::BindWebNNContextProvider( |
| mojo::PendingReceiver<webnn::mojom::WebNNContextProvider> pending_receiver, |
| int client_id, |
| bool is_incognito) { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::BindWebNNContextProvider, weak_ptr_, |
| std::move(pending_receiver), client_id, is_incognito)); |
| return; |
| } |
| |
| if (!webnn_context_provider_) { |
| scoped_refptr<gpu::SharedContextState> shared_context_state = |
| GetContextState(); |
| // `shared_context_state` may be nullptr if there is no GPU acceleration. |
| // For such case, WebNN CPU backend, e.g. TFLite XNNPACK, is still useful. |
| |
| // TODO(crbug.com/345352987): manage `WebNNContextProviderImpl` instance per |
| // `client_id` in order to support memory metrics. |
| webnn_context_provider_ = webnn::WebNNContextProviderImpl::Create( |
| std::move(shared_context_state), gpu_feature_info_, gpu_info_, |
| shared_image_manager(), |
| base::BindOnce(&GpuServiceImpl::LoseAllContexts, weak_ptr_), |
| main_runner(), GetGpuScheduler(), gpu_host_); |
| } |
| |
| webnn_context_provider_->BindWebNNContextProvider(std::move(pending_receiver), |
| {is_incognito, client_id}); |
| } |
| |
| void GpuServiceImpl::GetVideoMemoryUsageStats( |
| GetVideoMemoryUsageStatsCallback callback) { |
| if (io_runner_->BelongsToCurrentThread()) { |
| auto wrap_callback = base::BindPostTask(io_runner_, std::move(callback)); |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::GetVideoMemoryUsageStats, |
| weak_ptr_, std::move(wrap_callback))); |
| return; |
| } |
| gpu::VideoMemoryUsageStats video_memory_usage_stats; |
| gpu_channel_manager_->GetVideoMemoryUsageStats(&video_memory_usage_stats); |
| |
| if (compositor_gpu_thread()) { |
| // when DrDC is enabled, add SKIA and SHARED_CONTEXT_STATE memory from |
| // CompositorGpuThread. |
| compositor_gpu_thread()->AddVideoMemoryUsageStatsOnCompositorGpu( |
| std::move(callback), video_memory_usage_stats); |
| } else { |
| std::move(callback).Run(video_memory_usage_stats); |
| } |
| } |
| |
| void GpuServiceImpl::StartPeakMemoryMonitor(uint32_t sequence_num) { |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::StartPeakMemoryMonitorOnMainThread, |
| weak_ptr_, sequence_num)); |
| } |
| |
| void GpuServiceImpl::GetPeakMemoryUsage(uint32_t sequence_num, |
| GetPeakMemoryUsageCallback callback) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::GetPeakMemoryUsageOnMainThread, |
| weak_ptr_, sequence_num, std::move(callback))); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| void GpuServiceImpl::RequestDXGIInfo(RequestDXGIInfoCallback callback) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::RequestDXGIInfoOnMainThread, |
| weak_ptr_, std::move(callback))); |
| } |
| |
| void GpuServiceImpl::RequestDXGIInfoOnMainThread( |
| RequestDXGIInfoCallback callback) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| dxgi_info_ = gl::GetDirectCompositionHDRMonitorDXGIInfo(); |
| io_runner_->PostTask(FROM_HERE, |
| base::BindOnce(std::move(callback), dxgi_info_.Clone())); |
| } |
| #endif |
| |
| void GpuServiceImpl::LoseAllContexts() { |
| if (IsExiting()) |
| return; |
| gpu_channel_manager_->LoseAllContexts(); |
| if (compositor_gpu_thread_) |
| compositor_gpu_thread_->LoseContext(); |
| } |
| |
| void GpuServiceImpl::DidCreateContextSuccessfully() { |
| gpu_host_->DidCreateContextSuccessfully(); |
| } |
| |
| void GpuServiceImpl::DidCreateOffscreenContext(const GURL& active_url) { |
| gpu_host_->DidCreateOffscreenContext(active_url); |
| } |
| |
| void GpuServiceImpl::DidDestroyChannel(int client_id) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| media_gpu_channel_manager_->RemoveChannel(client_id); |
| gpu_host_->DidDestroyChannel(client_id); |
| } |
| |
| void GpuServiceImpl::DidDestroyAllChannels() { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| gpu_host_->DidDestroyAllChannels(); |
| } |
| |
| void GpuServiceImpl::DidDestroyOffscreenContext(const GURL& active_url) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| gpu_host_->DidDestroyOffscreenContext(active_url); |
| } |
| |
| void GpuServiceImpl::DidLoseContext(gpu::error::ContextLostReason reason, |
| const GURL& active_url) { |
| gpu_host_->DidLoseContext(reason, active_url); |
| } |
| |
| std::string GpuServiceImpl::GetShaderPrefixKey() { |
| if (shader_prefix_key_.empty()) { |
| const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info_.active_gpu(); |
| std::string product = |
| std::string(version_info::GetProductNameAndVersionForUserAgent()); |
| |
| shader_prefix_key_ = |
| product + "-" + gpu_info_.gl_vendor + "-" + gpu_info_.gl_renderer + |
| "-" + active_gpu.driver_version + "-" + active_gpu.driver_vendor + "-" + |
| base::SysInfo::ProcessCPUArchitecture(); |
| |
| #if BUILDFLAG(IS_ANDROID) |
| std::string build_fp = base::android::android_info::android_build_fp(); |
| shader_prefix_key_ += "-" + build_fp; |
| #endif |
| } |
| |
| return shader_prefix_key_; |
| } |
| |
| void GpuServiceImpl::StoreBlobToDisk(const gpu::GpuDiskCacheHandle& handle, |
| const std::string& key, |
| const std::string& shader) { |
| std::string prefix_key = key; |
| if (GetHandleType(handle) == gpu::GpuDiskCacheType::kGlShaders) { |
| std::string prefix = GetShaderPrefixKey(); |
| prefix_key = prefix + ":" + key; |
| } |
| gpu_host_->StoreBlobToDisk(handle, prefix_key, shader); |
| } |
| |
| void GpuServiceImpl::LoadedBlob(const gpu::GpuDiskCacheHandle& handle, |
| const std::string& key, |
| const std::string& data) { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::LoadedBlob, weak_ptr_, |
| handle, key, data)); |
| return; |
| } |
| |
| std::string no_prefix_key = key; |
| if (GetHandleType(handle) == gpu::GpuDiskCacheType::kGlShaders) { |
| std::string prefix = GetShaderPrefixKey(); |
| bool prefix_ok = !key.compare(0, prefix.length(), prefix); |
| UMA_HISTOGRAM_BOOLEAN("GPU.ShaderLoadPrefixOK", prefix_ok); |
| if (prefix_ok) { |
| // Remove the prefix from the key before load. |
| no_prefix_key = key.substr(prefix.length() + 1); |
| } else { |
| // If the prefix is not ok, its likely that all the other entries in the |
| // cache will have prefix that does not matches. Clear the whole disk |
| // cache in that case to remove all stale entries and make room for newer |
| // entries. |
| if (clear_shader_cache_) { |
| gpu_host_->ClearGrShaderDiskCache(); |
| } |
| return; |
| } |
| } |
| gpu_channel_manager_->PopulateCache(handle, no_prefix_key, data); |
| } |
| |
| void GpuServiceImpl::GetIsolationKey( |
| int client_id, |
| const blink::WebGPUExecutionContextToken& token, |
| GetIsolationKeyCallback cb) { |
| gpu_host_->GetIsolationKey(client_id, token, std::move(cb)); |
| } |
| |
| void GpuServiceImpl::MaybeExitOnContextLost( |
| gpu::error::ContextLostReason context_lost_reason) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| |
| if (in_host_process()) { |
| // We can't restart the GPU process when running in the host process; |
| // instead, just hope for recovery from the context loss. |
| return; |
| } |
| |
| RestartGpuProcessForContextLoss("Context was lost."); |
| } |
| |
| bool GpuServiceImpl::IsExiting() const { |
| return is_exiting_.IsSet(); |
| } |
| |
| void GpuServiceImpl::EstablishGpuChannel(int32_t client_id, |
| uint64_t client_tracing_id, |
| bool is_gpu_host, |
| bool enable_extra_handles_validation, |
| EstablishGpuChannelCallback callback) { |
| // This should always be called on the IO thread first. |
| if (io_runner_->BelongsToCurrentThread()) { |
| if (IsExiting()) { |
| // We are already exiting so there is no point in responding. Close the |
| // receiver so we can safely drop the callback. |
| receiver_.reset(); |
| return; |
| } |
| |
| if (gpu::IsReservedClientId(client_id)) { |
| // This returns a null handle, which is treated by the client as a failure |
| // case. |
| std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(), |
| gpu::GpuFeatureInfo(), |
| gpu::SharedImageCapabilities()); |
| return; |
| } |
| |
| EstablishGpuChannelCallback wrap_callback = |
| base::BindPostTask(io_runner_, std::move(callback)); |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::EstablishGpuChannel, |
| weak_ptr_, client_id, client_tracing_id, |
| is_gpu_host, enable_extra_handles_validation, |
| std::move(wrap_callback))); |
| return; |
| } |
| |
| auto channel_token = base::UnguessableToken::Create(); |
| gpu::GpuChannel* gpu_channel = gpu_channel_manager_->EstablishChannel( |
| channel_token, client_id, client_tracing_id, is_gpu_host, |
| enable_extra_handles_validation, gpu_extra_info_); |
| |
| if (!gpu_channel) { |
| // This returns a null handle, which is treated by the client as a failure |
| // case. |
| std::move(callback).Run(mojo::ScopedMessagePipeHandle(), gpu::GPUInfo(), |
| gpu::GpuFeatureInfo(), |
| gpu::SharedImageCapabilities()); |
| return; |
| } |
| mojo::MessagePipe pipe; |
| if (features::IsLegacyIpcDisabled()) { |
| gpu_channel->Start(std::move(pipe.handle0)); |
| } else { |
| gpu_channel->Init(pipe.handle0.release(), shutdown_event_); |
| } |
| |
| media_gpu_channel_manager_->AddChannel(client_id, channel_token); |
| |
| std::move(callback).Run( |
| std::move(pipe.handle1), gpu_info_, gpu_feature_info_, |
| gpu_channel->shared_image_stub()->factory()->MakeCapabilities()); |
| } |
| |
| void GpuServiceImpl::SetChannelClientPid(int32_t client_id, |
| base::ProcessId client_pid) { |
| if (io_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask(FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::SetChannelClientPid, |
| weak_ptr_, client_id, client_pid)); |
| return; |
| } |
| |
| // Note that the GpuService client must be trusted by definition, so DCHECKing |
| // this condition is reasonable. |
| DCHECK_NE(client_pid, base::kNullProcessId); |
| gpu_channel_manager_->SetChannelClientPid(client_id, client_pid); |
| } |
| |
| void GpuServiceImpl::SetChannelPersistentCachePendingBackend( |
| int32_t client_id, |
| const gpu::GpuDiskCacheHandle& handle, |
| persistent_cache::PendingBackend pending_backend) { |
| TRACE_EVENT2("gpu", "GpuServiceImpl::SetChannelPersistentCachePendingBackend", |
| "client_id", client_id, "handle_type", GetHandleType(handle)); |
| |
| // TODO(399642827): Support persistent cache for non-reserved clients (WebGPU, |
| // WebGL) |
| CHECK(gpu::IsReservedGpuDiskCacheHandle(handle)); |
| // The persistent cache does not use a separate cache for the display |
| // compositor. |
| CHECK_NE(client_id, gpu::kDisplayCompositorClientId); |
| |
| scoped_refptr<gpu::GpuPersistentCache> cache = |
| persistent_caches_.GetCache(handle); |
| CHECK(cache); |
| cache->InitializeCache(std::move(pending_backend), |
| use_shader_cache_shm_count_); |
| } |
| |
| void GpuServiceImpl::SetChannelDiskCacheHandle( |
| int32_t client_id, |
| const gpu::GpuDiskCacheHandle& handle) { |
| if (io_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::SetChannelDiskCacheHandle, |
| weak_ptr_, client_id, handle)); |
| return; |
| } |
| gpu_channel_manager_->SetChannelDiskCacheHandle(client_id, handle); |
| } |
| |
| void GpuServiceImpl::OnDiskCacheHandleDestoyed( |
| const gpu::GpuDiskCacheHandle& handle) { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::OnDiskCacheHandleDestoyed, |
| weak_ptr_, handle)); |
| return; |
| } |
| gpu_channel_manager_->OnDiskCacheHandleDestoyed(handle); |
| } |
| |
| void GpuServiceImpl::CloseChannel(int32_t client_id) { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::CloseChannel, weak_ptr_, client_id)); |
| return; |
| } |
| gpu_channel_manager_->RemoveChannel(client_id); |
| } |
| |
| void GpuServiceImpl::SetWakeUpGpuClosure(base::RepeatingClosure closure) { |
| wake_up_closure_ = std::move(closure); |
| } |
| |
| void GpuServiceImpl::WakeUpGpu() { |
| if (wake_up_closure_) |
| wake_up_closure_.Run(); |
| if (main_runner_->BelongsToCurrentThread()) { |
| WakeUpGpuOnMainThread(); |
| return; |
| } |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::WakeUpGpuOnMainThread, weak_ptr_)); |
| } |
| |
| void GpuServiceImpl::WakeUpGpuOnMainThread() { |
| if (gpu_feature_info_.IsWorkaroundEnabled(gpu::WAKE_UP_GPU_BEFORE_DRAWING)) { |
| #if BUILDFLAG(IS_ANDROID) |
| gpu_channel_manager_->WakeUpGpu(); |
| #else |
| NOTREACHED() << "WakeUpGpu() not supported on this platform."; |
| #endif |
| } |
| } |
| |
| void GpuServiceImpl::GpuSwitched() { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::GpuSwitched, weak_ptr_)); |
| return; |
| } |
| DVLOG(1) << "GPU: GPU has switched"; |
| |
| if (watchdog_thread_) |
| watchdog_thread_->ReportProgress(); |
| |
| if (!in_host_process()) { |
| ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched(); |
| } |
| GpuServiceImpl::UpdateGPUInfoGL(); |
| } |
| |
| void GpuServiceImpl::DisplayAdded() { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::DisplayAdded, weak_ptr_)); |
| return; |
| } |
| DVLOG(1) << "GPU: A monitor is plugged in"; |
| |
| if (!in_host_process()) |
| ui::GpuSwitchingManager::GetInstance()->NotifyDisplayAdded(); |
| } |
| |
| void GpuServiceImpl::DisplayRemoved() { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, base::BindOnce(&GpuServiceImpl::DisplayRemoved, weak_ptr_)); |
| return; |
| } |
| DVLOG(1) << "GPU: A monitor is unplugged "; |
| |
| if (!in_host_process()) |
| ui::GpuSwitchingManager::GetInstance()->NotifyDisplayRemoved(); |
| } |
| |
| void GpuServiceImpl::DisplayMetricsChanged() { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::DisplayMetricsChanged, weak_ptr_)); |
| return; |
| } |
| DVLOG(1) << "GPU: Display Metrics changed"; |
| |
| if (!in_host_process()) |
| ui::GpuSwitchingManager::GetInstance()->NotifyDisplayMetricsChanged(); |
| } |
| |
| void GpuServiceImpl::DestroyAllChannels() { |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::DestroyAllChannels, weak_ptr_)); |
| return; |
| } |
| DVLOG(1) << "GPU: Removing all contexts"; |
| gpu_channel_manager_->DestroyAllChannels(); |
| } |
| |
| void GpuServiceImpl::OnBackgroundCleanup() { |
| OnBackgroundCleanupGpuMainThread(); |
| OnBackgroundCleanupCompositorGpuThread(); |
| } |
| |
| void GpuServiceImpl::OnBackgroundCleanupGpuMainThread() { |
| // Currently only called on Android. |
| #if BUILDFLAG(IS_ANDROID) |
| if (!main_runner_->BelongsToCurrentThread()) { |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::OnBackgroundCleanupGpuMainThread, |
| weak_ptr_)); |
| return; |
| } |
| DVLOG(1) << "GPU: Performing background cleanup"; |
| gpu_channel_manager_->OnBackgroundCleanup(); |
| #else |
| NOTREACHED(); |
| #endif |
| } |
| |
| void GpuServiceImpl::OnBackgroundCleanupCompositorGpuThread() { |
| // Currently only called on Android. |
| #if BUILDFLAG(IS_ANDROID) |
| if (compositor_gpu_thread_) |
| compositor_gpu_thread_->OnBackgroundCleanup(); |
| #else |
| NOTREACHED(); |
| #endif |
| } |
| |
| void GpuServiceImpl::OnBackgrounded() { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| if (watchdog_thread_) |
| watchdog_thread_->OnBackgrounded(); |
| if (compositor_gpu_thread_) |
| compositor_gpu_thread_->OnBackgrounded(); |
| |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::OnBackgroundedOnMainThread, weak_ptr_)); |
| } |
| |
| void GpuServiceImpl::OnBackgroundedOnMainThread() { |
| gpu_channel_manager_->OnApplicationBackgrounded(); |
| |
| if (priority_changed_callback_) { |
| priority_changed_callback_.Run(base::Process::Priority::kBestEffort); |
| if (gpu_preferences_.enable_gpu_benchmarking_extension) { |
| ++gpu_info_.visibility_callback_call_count; |
| UpdateGPUInfoGL(); |
| } |
| } |
| |
| base::allocator::PartitionAllocSupport::Get()->OnBackgrounded(); |
| } |
| |
| void GpuServiceImpl::OnForegrounded() { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| if (watchdog_thread_) |
| watchdog_thread_->OnForegrounded(); |
| if (compositor_gpu_thread_) |
| compositor_gpu_thread_->OnForegrounded(); |
| |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::OnForegroundedOnMainThread, weak_ptr_)); |
| } |
| |
| void GpuServiceImpl::OnForegroundedOnMainThread() { |
| if (priority_changed_callback_) { |
| priority_changed_callback_.Run(base::Process::Priority::kUserBlocking); |
| if (gpu_preferences_.enable_gpu_benchmarking_extension) { |
| ++gpu_info_.visibility_callback_call_count; |
| UpdateGPUInfoGL(); |
| } |
| } |
| gpu_channel_manager_->OnApplicationForegounded(); |
| base::allocator::PartitionAllocSupport::Get()->OnForegrounded(); |
| } |
| |
| #if BUILDFLAG(IS_APPLE) |
| void GpuServiceImpl::BeginCATransaction() { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| main_runner_->PostTask(FROM_HERE, base::BindOnce(&ui::BeginCATransaction)); |
| } |
| |
| void GpuServiceImpl::CommitCATransaction(CommitCATransactionCallback callback) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| main_runner_->PostTaskAndReply( |
| FROM_HERE, base::BindOnce(&ui::CommitCATransaction), |
| base::BindPostTask(io_runner_, std::move(callback))); |
| } |
| #endif |
| |
| #if BUILDFLAG(CLANG_PROFILING_INSIDE_SANDBOX) |
| void GpuServiceImpl::WriteClangProfilingProfile( |
| WriteClangProfilingProfileCallback callback) { |
| base::WriteClangProfilingProfile(); |
| std::move(callback).Run(); |
| } |
| #endif |
| |
| void GpuServiceImpl::Crash() { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| gl::Crash(); |
| } |
| |
| void GpuServiceImpl::Hang() { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| main_runner_->PostTask(FROM_HERE, base::BindOnce(&gl::Hang)); |
| } |
| |
| void GpuServiceImpl::ThrowJavaException() { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| #if BUILDFLAG(IS_ANDROID) |
| ThrowUncaughtException(); |
| #else |
| NOTREACHED() << "Java exception not supported on this platform."; |
| #endif |
| } |
| |
| void GpuServiceImpl::StartPeakMemoryMonitorOnMainThread(uint32_t sequence_num) { |
| gpu_channel_manager_->StartPeakMemoryMonitor(sequence_num); |
| } |
| |
| void GpuServiceImpl::GetPeakMemoryUsageOnMainThread( |
| uint32_t sequence_num, |
| GetPeakMemoryUsageCallback callback) { |
| uint64_t peak_memory = 0u; |
| auto allocation_per_source = |
| gpu_channel_manager_->GetPeakMemoryUsage(sequence_num, &peak_memory); |
| |
| auto seq_loc = GetPeakMemoryUsageRequestLocation(sequence_num); |
| if (seq_loc == SequenceLocation::kGpuProcess) { |
| RunGetPeakGpuMemoryUsageCallbackOnMainThread( |
| std::move(callback), peak_memory, std::move(allocation_per_source)); |
| return; |
| } |
| io_runner_->PostTask(FROM_HERE, |
| base::BindOnce(std::move(callback), peak_memory, |
| std::move(allocation_per_source))); |
| } |
| |
| gpu::Scheduler* GpuServiceImpl::GetGpuScheduler() { |
| return scheduler_; |
| } |
| |
| bool GpuServiceImpl::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { |
| io_runner_->PostTask(FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::OnBeginFrameOnIO, |
| base::Unretained(this), args)); |
| return true; |
| } |
| |
| #if BUILDFLAG(IS_LINUX) |
| bool GpuServiceImpl::IsGMBNV12Supported() { |
| CHECK(main_runner_->BelongsToCurrentThread()); |
| |
| // Determine whether it's possible to create an NV12 NativePixmap with |
| // GPU_READ_CPU_READ_WRITE usage (the relevant usage for the clients of this |
| // method). |
| auto format = MultiPlaneFormat::kNV12; |
| auto buffer_usage = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE; |
| |
| if (!gpu::SharedImageFactory::IsNativeBufferSupported(format, buffer_usage, |
| gpu_extra_info_)) { |
| return false; |
| } |
| |
| auto size = gfx::Size(2, 2); |
| scoped_refptr<gfx::NativePixmap> pixmap = |
| ui::OzonePlatform::GetInstance() |
| ->GetSurfaceFactoryOzone() |
| ->CreateNativePixmap(gpu::kNullSurfaceHandle, |
| vulkan_context_provider() |
| ? vulkan_context_provider()->GetDeviceQueue() |
| : nullptr, |
| size, format, buffer_usage, size); |
| if (!pixmap.get() || pixmap->ExportHandle().planes.empty()) { |
| return false; |
| } |
| |
| return true; |
| } |
| #endif |
| |
| void GpuServiceImpl::OnBeginFrameSourcePausedChanged(bool paused) {} |
| |
| void GpuServiceImpl::OnBeginFrameOnIO(const BeginFrameArgs& args) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| |
| if (mjpeg_decode_accelerator_begin_frame_cb_) { |
| mjpeg_decode_accelerator_begin_frame_cb_->Run(); |
| } |
| } |
| |
| void GpuServiceImpl::SetRequestBeginFrameForGpuServiceCB( |
| RequestBeginFrameForGpuServiceCB cb) { |
| request_begin_frame_for_gpu_service_cb_ = std::move(cb); |
| } |
| |
| void GpuServiceImpl::SetMjpegDecodeAcceleratorBeginFrameCB( |
| std::optional<base::RepeatingClosure> cb) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| |
| main_runner_->PostTask(FROM_HERE, |
| base::BindOnce(request_begin_frame_for_gpu_service_cb_, |
| cb ? true : false)); |
| mjpeg_decode_accelerator_begin_frame_cb_ = std::move(cb); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| // Update Overlay and DXGI Info |
| void GpuServiceImpl::OnOverlayCapsChanged() { |
| gpu::OverlayInfo old_overlay_info = gpu_info_.overlay_info; |
| gpu::CollectHardwareOverlayInfo(&gpu_info_.overlay_info); |
| |
| // Update overlay info in the GPU process and send the updated data back to |
| // the GPU host in the Browser process through mojom if the info has changed. |
| if (old_overlay_info != gpu_info_.overlay_info) |
| gpu_host_->DidUpdateOverlayInfo(gpu_info_.overlay_info); |
| |
| // Update DXGI adapter info in the GPU process through the GPU host mojom. |
| auto old_dxgi_info = std::move(dxgi_info_); |
| dxgi_info_ = gl::GetDirectCompositionHDRMonitorDXGIInfo(); |
| if (!mojo::Equals(dxgi_info_, old_dxgi_info)) { |
| gpu_host_->DidUpdateDXGIInfo(dxgi_info_.Clone()); |
| } |
| } |
| #endif |
| |
| gpu::SyncPointManager* GpuServiceImpl::CreateSyncPointManager() { |
| owned_sync_point_manager_ = std::make_unique<gpu::SyncPointManager>(); |
| return owned_sync_point_manager_.get(); |
| } |
| |
| gpu::SharedImageManager* GpuServiceImpl::CreateSharedImageManager( |
| bool supports_overlays) { |
| // When using real buffers for testing overlay configurations, we need |
| // access to SharedImageManager on the viz thread to obtain the buffer |
| // corresponding to a mailbox. |
| const bool display_context_on_another_thread = |
| features::IsDrDcEnabled(gpu_feature_info_); |
| |
| // |display_context_on_another_thread|, features::IsUsingRawDraw(), |
| // kAlwaysUseRealBufferTestingOnOzone, and kSharedBitmapToSharedImage |
| // requires |thread_safe_manager| to be true. |
| bool thread_safe_manager = true; |
| owned_shared_image_manager_ = std::make_unique<gpu::SharedImageManager>( |
| thread_safe_manager, display_context_on_another_thread, |
| vulkan_context_provider(), io_runner_); |
| #if BUILDFLAG(IS_OZONE) |
| owned_shared_image_manager_->SetSupportsOverlays(supports_overlays); |
| #endif |
| return owned_shared_image_manager_.get(); |
| } |
| |
| gpu::Scheduler* GpuServiceImpl::CreateScheduler( |
| gpu::SyncPointManager* sync_point_manager) { |
| owned_scheduler_ = std::make_unique<gpu::Scheduler>(sync_point_manager); |
| return owned_scheduler_.get(); |
| } |
| |
| base::WaitableEvent* GpuServiceImpl::CreateShutdownEvent() { |
| owned_shutdown_event_ = std::make_unique<base::WaitableEvent>( |
| base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| return owned_shutdown_event_.get(); |
| } |
| |
| void GpuServiceImpl::GetDawnInfo(bool collect_metrics, |
| GetDawnInfoCallback callback) { |
| DCHECK(io_runner_->BelongsToCurrentThread()); |
| |
| main_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&GpuServiceImpl::GetDawnInfoOnMain, base::Unretained(this), |
| collect_metrics, std::move(callback))); |
| } |
| |
| void GpuServiceImpl::GetDawnInfoOnMain(bool collect_metrics, |
| GetDawnInfoCallback callback) { |
| DCHECK(main_runner_->BelongsToCurrentThread()); |
| |
| std::vector<std::string> dawn_info_list; |
| // Pause the watchdog around Dawn info collection since it is known to be |
| // slow loading GPU drivers. |
| if (watchdog_thread_) { |
| watchdog_thread_->PauseWatchdog(); |
| } |
| |
| // Don't collect metrics if gpu watchdog is still running. Otherwise fast |
| // timings will be recorded, and very-slow timings will crash and not |
| // record, skewing the results. |
| { |
| SCOPED_UMA_HISTOGRAM_TIMER("GPU.Dawn.InfoCollectionTimeMS"); |
| gpu::CollectDawnInfo(gpu_preferences_, collect_metrics, &dawn_info_list); |
| } |
| |
| if (watchdog_thread_) { |
| watchdog_thread_->ResumeWatchdog(); |
| } |
| |
| io_runner_->PostTask(FROM_HERE, |
| base::BindOnce(std::move(callback), dawn_info_list)); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| void GpuServiceImpl::SetHostProcessId(base::ProcessId pid) { |
| host_process_id_ = pid; |
| } |
| #endif |
| |
| GpuServiceImpl::InitParams::InitParams() = default; |
| GpuServiceImpl::InitParams::InitParams(InitParams&& other) = default; |
| GpuServiceImpl::InitParams& GpuServiceImpl::InitParams::operator=( |
| InitParams&& other) = default; |
| GpuServiceImpl::InitParams::~InitParams() = default; |
| |
| } // namespace viz |