// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "gpu/config/gpu_util.h" #include #include #include "base/command_line.h" #include "base/debug/crash_logging.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/sys_info.h" #include "gpu/config/gpu_blacklist.h" #include "gpu/config/gpu_crash_keys.h" #include "gpu/config/gpu_driver_bug_list.h" #include "gpu/config/gpu_driver_bug_workaround_type.h" #include "gpu/config/gpu_feature_type.h" #include "gpu/config/gpu_finch_features.h" #include "gpu/config/gpu_info_collector.h" #include "gpu/config/gpu_switches.h" #include "ui/gl/gl_switches.h" #include "ui/gl/gpu_switching_manager.h" namespace gpu { namespace { // Combine the integers into a string, seperated by ','. std::string IntSetToString(const std::set& list) { std::string rt; for (std::set::const_iterator it = list.begin(); it != list.end(); ++it) { if (!rt.empty()) rt += ","; rt += base::IntToString(*it); } return rt; } void StringToIntSet(const std::string& str, std::set* list) { DCHECK(list); for (const base::StringPiece& piece : base::SplitStringPiece(str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { int number = 0; bool succeed = base::StringToInt(piece, &number); DCHECK(succeed); list->insert(number); } } // |str| is in the format of "0x040a;0x10de;...;hex32_N". void StringToIds(const std::string& str, std::vector* list) { DCHECK(list); for (const base::StringPiece& piece : base::SplitStringPiece( str, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { uint32_t id = 0; bool succeed = base::HexStringToUInt(piece, &id); DCHECK(succeed); list->push_back(id); } } GpuFeatureStatus GetGpuRasterizationFeatureStatus( const std::set& blacklisted_features, const base::CommandLine& command_line) { if (command_line.HasSwitch(switches::kDisableGpuRasterization)) return kGpuFeatureStatusDisabled; else if (command_line.HasSwitch(switches::kEnableGpuRasterization)) return kGpuFeatureStatusEnabled; if (blacklisted_features.count(GPU_FEATURE_TYPE_GPU_RASTERIZATION)) return kGpuFeatureStatusBlacklisted; #if defined(OS_ANDROID) // GPU Raster is always enabled on non-low-end Android. On low-end, it is // controlled by a Finch experiment. if (!base::SysInfo::IsLowEndDevice()) return kGpuFeatureStatusEnabled; #endif // defined(OS_ANDROID) // Gpu Rasterization on platforms that are not fully enabled is controlled by // a finch experiment. if (!base::FeatureList::IsEnabled(features::kDefaultEnableGpuRasterization)) return kGpuFeatureStatusDisabled; return kGpuFeatureStatusEnabled; } } // namespace anonymous void ApplyGpuDriverBugWorkarounds(const GPUInfo& gpu_info, base::CommandLine* command_line) { std::unique_ptr list(GpuDriverBugList::Create()); std::set workarounds = list->MakeDecision( GpuControlList::kOsAny, std::string(), gpu_info); GpuDriverBugList::AppendWorkaroundsFromCommandLine( &workarounds, *command_line); if (!workarounds.empty()) { command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds, IntSetToString(workarounds)); } std::vector buglist_disabled_extensions = list->GetDisabledExtensions(); std::set disabled_extensions( buglist_disabled_extensions.begin(), buglist_disabled_extensions.end()); // Must be outside if statement to remain in scope (referenced by // |disabled_extensions|). std::string command_line_disable_gl_extensions; if (command_line->HasSwitch(switches::kDisableGLExtensions)) { command_line_disable_gl_extensions = command_line->GetSwitchValueASCII(switches::kDisableGLExtensions); std::vector existing_disabled_extensions = base::SplitStringPiece(command_line_disable_gl_extensions, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); disabled_extensions.insert(existing_disabled_extensions.begin(), existing_disabled_extensions.end()); } if (!disabled_extensions.empty()) { std::vector v(disabled_extensions.begin(), disabled_extensions.end()); command_line->AppendSwitchASCII(switches::kDisableGLExtensions, base::JoinString(v, " ")); } } void StringToFeatureSet( const std::string& str, std::set* feature_set) { StringToIntSet(str, feature_set); } void ParseSecondaryGpuDevicesFromCommandLine( const base::CommandLine& command_line, GPUInfo* gpu_info) { DCHECK(gpu_info); const char* secondary_vendor_switch_key = switches::kGpuSecondaryVendorIDs; const char* secondary_device_switch_key = switches::kGpuSecondaryDeviceIDs; if (command_line.HasSwitch(switches::kGpuTestingSecondaryVendorIDs) && command_line.HasSwitch(switches::kGpuTestingSecondaryDeviceIDs)) { secondary_vendor_switch_key = switches::kGpuTestingSecondaryVendorIDs; secondary_device_switch_key = switches::kGpuTestingSecondaryDeviceIDs; } if (!command_line.HasSwitch(secondary_vendor_switch_key) || !command_line.HasSwitch(secondary_device_switch_key)) { return; } std::vector vendor_ids; std::vector device_ids; StringToIds(command_line.GetSwitchValueASCII(secondary_vendor_switch_key), &vendor_ids); StringToIds(command_line.GetSwitchValueASCII(secondary_device_switch_key), &device_ids); DCHECK(vendor_ids.size() == device_ids.size()); gpu_info->secondary_gpus.clear(); for (size_t i = 0; i < vendor_ids.size() && i < device_ids.size(); ++i) { gpu::GPUInfo::GPUDevice secondary_device; secondary_device.active = false; secondary_device.vendor_id = vendor_ids[i]; secondary_device.device_id = device_ids[i]; gpu_info->secondary_gpus.push_back(secondary_device); } } void InitializeDualGpusIfSupported( const std::set& driver_bug_workarounds) { ui::GpuSwitchingManager* switching_manager = ui::GpuSwitchingManager::GetInstance(); if (!switching_manager->SupportsDualGpus()) return; if (driver_bug_workarounds.count(gpu::FORCE_DISCRETE_GPU) == 1) ui::GpuSwitchingManager::GetInstance()->ForceUseOfDiscreteGpu(); else if (driver_bug_workarounds.count(gpu::FORCE_INTEGRATED_GPU) == 1) ui::GpuSwitchingManager::GetInstance()->ForceUseOfIntegratedGpu(); } GpuFeatureInfo GetGpuFeatureInfo(const GPUInfo& gpu_info, const base::CommandLine& command_line) { GpuFeatureInfo gpu_feature_info; std::set blacklisted_features; if (!command_line.HasSwitch(switches::kIgnoreGpuBlacklist)) { std::unique_ptr list(GpuBlacklist::Create()); blacklisted_features = list->MakeDecision(GpuControlList::kOsAny, std::string(), gpu_info); } // Currently only used for GPU rasterization. gpu_feature_info.status_values[GPU_FEATURE_TYPE_GPU_RASTERIZATION] = GetGpuRasterizationFeatureStatus(blacklisted_features, command_line); return gpu_feature_info; } void SetKeysForCrashLogging(const GPUInfo& gpu_info) { #if !defined(OS_ANDROID) base::debug::SetCrashKeyValue( crash_keys::kGPUVendorID, base::StringPrintf("0x%04x", gpu_info.gpu.vendor_id)); base::debug::SetCrashKeyValue( crash_keys::kGPUDeviceID, base::StringPrintf("0x%04x", gpu_info.gpu.device_id)); #endif base::debug::SetCrashKeyValue(crash_keys::kGPUDriverVersion, gpu_info.driver_version); base::debug::SetCrashKeyValue(crash_keys::kGPUPixelShaderVersion, gpu_info.pixel_shader_version); base::debug::SetCrashKeyValue(crash_keys::kGPUVertexShaderVersion, gpu_info.vertex_shader_version); #if defined(OS_MACOSX) base::debug::SetCrashKeyValue(crash_keys::kGPUGLVersion, gpu_info.gl_version); #elif defined(OS_POSIX) base::debug::SetCrashKeyValue(crash_keys::kGPUVendor, gpu_info.gl_vendor); base::debug::SetCrashKeyValue(crash_keys::kGPURenderer, gpu_info.gl_renderer); #endif } } // namespace gpu