#include "gpu/ipc/service/gpu_channel_manager.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/metrics/histogram_macros.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/traced_value.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/constants.h"
#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/gpu_tracer.h"
#include "gpu/command_buffer/service/memory_program_cache.h"
#include "gpu/command_buffer/service/passthrough_program_cache.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/config/gpu_crash_keys.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_switches.h"
#include "gpu/ipc/common/gpu_client_ids.h"
#include "gpu/ipc/common/memory_stats.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "third_party/skia/include/core/SkGraphics.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "third_party/skia/include/gpu/GrTypes.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_features.h"
#include "ui/gl/gl_share_group.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/init/gl_factory.h"
#if BUILDFLAG(USE_DAWN)
#include "gpu/command_buffer/service/dawn_caching_interface.h"
#endif
#if BUILDFLAG(SKIA_USE_DAWN)
#include "gpu/command_buffer/service/dawn_context_provider.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <dxgi1_3.h>
#include "ui/gl/gl_angle_util_win.h"
#endif
#if BUILDFLAG(ENABLE_VULKAN)
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_fence_helper.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "gpu/ipc/service/built_in_shader_cache_loader.h"
#include "gpu/ipc/service/built_in_shader_cache_writer.h"
#endif
namespace gpu {
namespace {
#if BUILDFLAG(IS_ANDROID)
const int kMaxGpuIdleTimeMs = 40;
const int kMaxKeepAliveTimeMs = 200;
#endif
#if BUILDFLAG(IS_WIN)
void TrimD3DResources(const scoped_refptr<SharedContextState>& context_state) {
Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
if (context_state) {
d3d11_device = context_state->GetD3D11Device();
}
if (d3d11_device) {
Microsoft::WRL::ComPtr<IDXGIDevice3> dxgi_device;
if (SUCCEEDED(d3d11_device.As(&dxgi_device))) {
dxgi_device->Trim();
}
}
Microsoft::WRL::ComPtr<ID3D11Device> angle_d3d11_device =
gl::QueryD3D11DeviceObjectFromANGLE();
if (angle_d3d11_device && angle_d3d11_device != d3d11_device) {
Microsoft::WRL::ComPtr<IDXGIDevice3> dxgi_device;
if (SUCCEEDED(angle_d3d11_device.As(&dxgi_device))) {
dxgi_device->Trim();
}
}
}
#endif
void APIENTRY CrashReportOnGLErrorDebugCallback(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const GLvoid* user_param) { … }
void FormatAllocationSourcesForTracing(
base::trace_event::TracedValue* dict,
base::flat_map<GpuPeakMemoryAllocationSource, uint64_t>&
allocation_sources) { … }
void SetCrashKeyTimeDelta(base::debug::CrashKeyString* key,
base::TimeDelta time_delta) { … }
}
GpuChannelManager::GpuPeakMemoryMonitor::GpuPeakMemoryMonitor(
GpuChannelManager* channel_manager,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: … { … }
GpuChannelManager::GpuPeakMemoryMonitor::~GpuPeakMemoryMonitor() = default;
base::flat_map<GpuPeakMemoryAllocationSource, uint64_t>
GpuChannelManager::GpuPeakMemoryMonitor::GetPeakMemoryUsage(
uint32_t sequence_num,
uint64_t* out_peak_memory) { … }
void GpuChannelManager::GpuPeakMemoryMonitor::StartGpuMemoryTracking(
uint32_t sequence_num) { … }
void GpuChannelManager::GpuPeakMemoryMonitor::StopGpuMemoryTracking(
uint32_t sequence_num) { … }
base::WeakPtr<MemoryTracker::Observer>
GpuChannelManager::GpuPeakMemoryMonitor::GetWeakPtr() { … }
void GpuChannelManager::GpuPeakMemoryMonitor::InvalidateWeakPtrs() { … }
GpuChannelManager::GpuPeakMemoryMonitor::SequenceTracker::SequenceTracker(
uint64_t current_memory,
base::flat_map<GpuPeakMemoryAllocationSource, uint64_t>
current_memory_per_source)
: … { … }
GpuChannelManager::GpuPeakMemoryMonitor::SequenceTracker::SequenceTracker(
const SequenceTracker& other) = default;
GpuChannelManager::GpuPeakMemoryMonitor::SequenceTracker::~SequenceTracker() =
default;
std::unique_ptr<base::trace_event::TracedValue>
GpuChannelManager::GpuPeakMemoryMonitor::StartTrackingTracedValue() { … }
std::unique_ptr<base::trace_event::TracedValue>
GpuChannelManager::GpuPeakMemoryMonitor::StopTrackingTracedValue(
SequenceTracker& sequence) { … }
void GpuChannelManager::GpuPeakMemoryMonitor::OnMemoryAllocatedChange(
CommandBufferId id,
uint64_t old_size,
uint64_t new_size,
GpuPeakMemoryAllocationSource source) { … }
GpuChannelManager::GpuChannelManager(
const GpuPreferences& gpu_preferences,
GpuChannelManagerDelegate* delegate,
GpuWatchdogThread* watchdog,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
Scheduler* scheduler,
SyncPointManager* sync_point_manager,
SharedImageManager* shared_image_manager,
GpuMemoryBufferFactory* gpu_memory_buffer_factory,
const GpuFeatureInfo& gpu_feature_info,
GpuProcessShmCount use_shader_cache_shm_count,
scoped_refptr<gl::GLSurface> default_offscreen_surface,
ImageDecodeAcceleratorWorker* image_decode_accelerator_worker,
viz::VulkanContextProvider* vulkan_context_provider,
viz::MetalContextProvider* metal_context_provider,
DawnContextProvider* dawn_context_provider,
webgpu::DawnCachingInterfaceFactory* dawn_caching_interface_factory)
: … { … }
GpuChannelManager::~GpuChannelManager() { … }
gles2::Outputter* GpuChannelManager::outputter() { … }
gles2::ProgramCache* GpuChannelManager::program_cache() { … }
void GpuChannelManager::RemoveChannel(int client_id) { … }
GpuChannel* GpuChannelManager::LookupChannel(int32_t client_id) const { … }
GpuChannel* GpuChannelManager::EstablishChannel(
const base::UnguessableToken& channel_token,
int client_id,
uint64_t client_tracing_id,
bool is_gpu_host,
const gfx::GpuExtraInfo& gpu_extra_info,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory) { … }
void GpuChannelManager::SetChannelClientPid(int client_id,
base::ProcessId client_pid) { … }
void GpuChannelManager::SetChannelDiskCacheHandle(
int client_id,
const gpu::GpuDiskCacheHandle& handle) { … }
void GpuChannelManager::OnDiskCacheHandleDestoyed(
const gpu::GpuDiskCacheHandle& handle) { … }
void GpuChannelManager::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id) { … }
void GpuChannelManager::PopulateCache(const gpu::GpuDiskCacheHandle& handle,
const std::string& key,
const std::string& data) { … }
void GpuChannelManager::LoseAllContexts() { … }
SharedContextState::ContextLostCallback
GpuChannelManager::GetContextLostCallback() { … }
GpuChannelManager::OnMemoryAllocatedChangeCallback
GpuChannelManager::GetOnMemoryAllocatedChangeCallback() { … }
void GpuChannelManager::DestroyAllChannels() { … }
void GpuChannelManager::GetVideoMemoryUsageStats(
VideoMemoryUsageStats* video_memory_usage_stats) const { … }
void GpuChannelManager::StartPeakMemoryMonitor(uint32_t sequence_num) { … }
base::flat_map<GpuPeakMemoryAllocationSource, uint64_t>
GpuChannelManager::GetPeakMemoryUsage(uint32_t sequence_num,
uint64_t* out_peak_memory) { … }
#if BUILDFLAG(IS_ANDROID)
void GpuChannelManager::DidAccessGpu() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
last_gpu_access_time_ = base::TimeTicks::Now();
}
void GpuChannelManager::WakeUpGpu() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
begin_wake_up_time_ = base::TimeTicks::Now();
ScheduleWakeUpGpu();
}
void GpuChannelManager::ScheduleWakeUpGpu() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
base::TimeTicks now = base::TimeTicks::Now();
TRACE_EVENT2("gpu", "GpuChannelManager::ScheduleWakeUp", "idle_time",
(now - last_gpu_access_time_).InMilliseconds(),
"keep_awake_time", (now - begin_wake_up_time_).InMilliseconds());
if (now - last_gpu_access_time_ < base::Milliseconds(kMaxGpuIdleTimeMs))
return;
if (now - begin_wake_up_time_ > base::Milliseconds(kMaxKeepAliveTimeMs))
return;
DoWakeUpGpu();
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&GpuChannelManager::ScheduleWakeUpGpu,
weak_factory_.GetWeakPtr()),
base::Milliseconds(kMaxGpuIdleTimeMs));
}
void GpuChannelManager::DoWakeUpGpu() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
const CommandBufferStub* stub = nullptr;
for (const auto& kv : gpu_channels_) {
const GpuChannel* channel = kv.second.get();
const CommandBufferStub* stub_candidate = channel->GetOneStub();
if (stub_candidate) {
DCHECK(stub_candidate->decoder_context());
if (stub_candidate->decoder_context()->GetGLContext()) {
stub = stub_candidate;
break;
}
}
}
if (!stub || !stub->decoder_context()->MakeCurrent())
return;
glFinish();
DidAccessGpu();
}
void GpuChannelManager::OnBackgroundCleanup() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
std::vector<int> channels_to_clear;
for (auto& kv : gpu_channels_) {
if (kv.second->HasActiveStatefulContext()) {
continue;
}
channels_to_clear.push_back(kv.first);
kv.second->MarkAllContextsLost();
}
for (int channel : channels_to_clear)
RemoveChannel(channel);
if (program_cache_)
program_cache_->Trim(0u);
if (shared_context_state_) {
shared_context_state_->MarkContextLost();
shared_context_state_.reset();
}
SkGraphics::PurgeAllCaches();
}
#endif
void GpuChannelManager::OnApplicationBackgrounded() { … }
void GpuChannelManager::OnApplicationForegounded() { … }
void GpuChannelManager::PerformImmediateCleanup() { … }
void GpuChannelManager::HandleMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) { … }
scoped_refptr<SharedContextState> GpuChannelManager::GetSharedContextState(
ContextResult* result) { … }
void GpuChannelManager::OnContextLost(
int context_lost_count,
bool synthetic_loss,
error::ContextLostReason context_lost_reason) { … }
void GpuChannelManager::ScheduleGrContextCleanup() { … }
void GpuChannelManager::StoreShader(const std::string& key,
const std::string& shader) { … }
void GpuChannelManager::SetImageDecodeAcceleratorWorkerForTesting(
ImageDecodeAcceleratorWorker* worker) { … }
}