blob: 5d05fdc98087c72021193854e4013dbf6bfe85ae [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_CONFIG_GPU_CONTROL_LIST_H_
#define GPU_CONFIG_GPU_CONTROL_LIST_H_
#include <stddef.h>
#include <set>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/containers/span.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/raw_span.h"
#include "base/values.h"
#include "gpu/config/gpu_config_export.h"
#include "gpu/config/gpu_info.h"
namespace gpu {
struct GPUInfo;
class GPU_CONFIG_EXPORT GpuControlList {
public:
typedef std::unordered_map<int, std::string> FeatureMap;
enum OsType {
kOsLinux,
kOsMacosx,
kOsWin,
kOsChromeOS,
kOsAndroid,
kOsFuchsia,
kOsIOS,
kOsAny
};
enum OsFilter {
// In loading, ignore all entries that belong to other OS.
kCurrentOsOnly,
// In loading, keep all entries. This is for testing only.
kAllOs
};
enum NumericOp {
kBetween, // <= * <=
kEQ, // =
kLT, // <
kLE, // <=
kGT, // >
kGE, // >=
kAny,
kUnknown // Indicates the data is invalid.
};
enum MultiGpuStyle {
kMultiGpuStyleOptimus,
kMultiGpuStyleAMDSwitchable,
kMultiGpuStyleAMDSwitchableIntegrated,
kMultiGpuStyleAMDSwitchableDiscrete,
kMultiGpuStyleNone
};
enum MultiGpuCategory {
// This entry applies if this is the primary GPU on the system.
kMultiGpuCategoryPrimary,
// This entry applies if this is a secondary GPU on the system.
kMultiGpuCategorySecondary,
// This entry applies if this is the NPU on the system.
kMultiGpuCategoryNpu,
// This entry applies if this is the active GPU on the system.
kMultiGpuCategoryActive,
// This entry applies if this is any of the GPUs on the system.
kMultiGpuCategoryAny,
kMultiGpuCategoryNone
};
enum GLType {
kGLTypeGLES,
kGLTypeANGLE_GL,
kGLTypeANGLE_GLES,
kGLTypeANGLE_VULKAN,
kGLTypeNone
};
enum VersionStyle {
kVersionStyleNumerical,
kVersionStyleLexical,
kVersionStyleUnknown
};
enum VersionSchema {
// All digits are meaningful when distinguishing versions.
kVersionSchemaCommon,
// The version format of Intel graphics driver is AA.BB.CCC.DDDD.
// DDDD(old schema) or CCC.DDDD(new schema) is the build number.
// That is, indicates the actual driver number.
kVersionSchemaIntelDriver,
// The version format of Nvidia drivers is XX.XX.XXXA.AAAA where the X's
// can be any digits, and the A's are the actual version. The workaround
// list specifies them as AAA.AA to match how Nvidia publishes them.
kVersionSchemaNvidiaDriver,
};
enum SupportedOrNot {
kSupported,
kUnsupported,
kDontCare,
};
struct GPU_CONFIG_EXPORT Version {
NumericOp op;
VersionStyle style;
VersionSchema schema;
const char* value1;
const char* value2;
bool IsSpecified() const { return op != kUnknown; }
bool Contains(const std::string& version_string, char splitter) const;
bool Contains(const std::string& version_string) const {
return Contains(version_string, '.');
}
// Compare two version strings.
// Return 1 if version > version_ref,
// 0 if version = version_ref,
// -1 if version < version_ref.
// Note that we only compare as many segments as both versions contain.
// For example: Compare("10.3.1", "10.3") returns 0,
// Compare("10.3", "10.3.1") returns 0.
// If "version_style" is Lexical, the first segment is compared
// numerically, all other segments are compared lexically.
// Lexical is used for AMD Linux driver versions only.
static int Compare(const std::vector<std::string>& version,
const std::vector<std::string>& version_ref,
VersionStyle version_style);
};
struct GPU_CONFIG_EXPORT DriverInfo {
const char* driver_vendor;
Version driver_version;
bool Contains(const std::vector<GPUInfo::GPUDevice>& gpus) const;
};
struct GPU_CONFIG_EXPORT GLStrings {
const char* gl_vendor;
const char* gl_renderer;
const char* gl_extensions;
const char* gl_version;
bool Contains(const GPUInfo& gpu_info) const;
};
struct GPU_CONFIG_EXPORT MachineModelInfo {
base::raw_span<const char* const> machine_model_names;
Version machine_model_version;
bool Contains(const GPUInfo& gpu_info) const;
};
struct GPU_CONFIG_EXPORT More {
// These are just part of Entry fields that are less common.
// Putting them to a separate struct to save Entry data size.
GLType gl_type;
Version gl_version;
Version pixel_shader_version;
bool in_process_gpu;
uint32_t gl_reset_notification_strategy;
Version direct_rendering_version;
Version gpu_count;
SupportedOrNot hardware_overlay;
uint32_t test_group;
SupportedOrNot subpixel_font_rendering;
// Return true if GL_VERSION string does not fit the entry info
// on GL version.
bool GLVersionInfoMismatch(const std::string& gl_version_string) const;
bool Contains(const GPUInfo& gpu_info) const;
};
struct GPU_CONFIG_EXPORT Device {
uint32_t device_id;
uint32_t revision = 0u;
};
struct GPU_CONFIG_EXPORT IntelConditions {
base::raw_span<const IntelGpuSeriesType> intel_gpu_series_list;
Version intel_gpu_generation;
bool Contains(const std::vector<GPUInfo::GPUDevice>& candidates,
const GPUInfo& gpu_info) const;
};
struct GPU_CONFIG_EXPORT Conditions {
OsType os_type;
Version os_version;
uint32_t vendor_id;
// TODO(367764863) Rewrite to base::raw_span.
RAW_PTR_EXCLUSION base::span<const Device> devices;
MultiGpuCategory multi_gpu_category;
MultiGpuStyle multi_gpu_style;
// RAW_PTR_EXCLUSION: since these pointers only ever point to other
// globals, and `Conditions` itself is used to construct globals, using
// raw_ptr would add additional (unnecessary) complexity with
// `NoDestructor`.
RAW_PTR_EXCLUSION const DriverInfo* driver_info;
RAW_PTR_EXCLUSION const GLStrings* gl_strings;
RAW_PTR_EXCLUSION const MachineModelInfo* machine_model_info;
RAW_PTR_EXCLUSION const IntelConditions* intel_conditions;
RAW_PTR_EXCLUSION const More* more;
Conditions(OsType os_type,
Version os_version,
uint32_t vendor_id,
base::span<const Device> devices,
MultiGpuCategory multi_gpu_category,
MultiGpuStyle multi_gpu_style,
const DriverInfo* driver_info,
const GLStrings* gl_strings,
const MachineModelInfo* machine_model_info,
const IntelConditions* intel_conditions,
const More* more);
Conditions(const Conditions& other);
bool Contains(OsType os_type,
const std::string& os_version,
const GPUInfo& gpu_info) const;
// Determines whether we needs more gpu info to make the blocklisting
// decision. It should only be checked if Contains() returns true.
bool NeedsMoreInfo(const GPUInfo& gpu_info) const;
};
struct GPU_CONFIG_EXPORT Entry {
uint32_t id;
const char* description;
// `Entry` is used extensively in
// `gen/gpu/config/software_rendering_list_autogen.cc`, where making these
// `raw_span` would cause a warning:
//
// > declaration requires an exit-time destructor
//
// These only seem to be set in files generated by
// gpu/config/process_json.py, which only ever sets them to point at
// statically-allocated data which is never freed. Thus these can never
// dangle, so making them raw_span is unnecessary.
RAW_PTR_EXCLUSION base::span<const int> features;
RAW_PTR_EXCLUSION base::span<const char* const> disabled_extensions;
RAW_PTR_EXCLUSION base::span<const char* const> disabled_webgl_extensions;
RAW_PTR_EXCLUSION base::span<const uint32_t> cr_bugs;
Conditions conditions;
RAW_PTR_EXCLUSION base::span<const Conditions> exceptions;
bool Contains(OsType os_type,
const std::string& os_version,
const GPUInfo& gpu_info) const;
bool AppliesToTestGroup(uint32_t target_test_group) const;
// Determines whether we needs more gpu info to make the blocklisting
// decision. It should only be checked if Contains() returns true.
bool NeedsMoreInfo(const GPUInfo& gpu_info, bool consider_exceptions) const;
base::Value::List GetFeatureNames(const FeatureMap& feature_map) const;
// Logs a control list match for this rule in the list identified by
// |control_list_logging_name|.
void LogControlListMatch(
const std::string& control_list_logging_name) const;
};
explicit GpuControlList(base::span<const GpuControlList::Entry> data);
virtual ~GpuControlList();
// Collects system information and combines them with gpu_info and control
// list information to decide which entries are applied to the current
// system and returns the union of features specified in each entry.
// If os is kOsAny, use the current OS; if os_version is empty, use the
// current OS version.
std::set<int32_t> MakeDecision(OsType os,
const std::string& os_version,
const GPUInfo& gpu_info);
// Same as the above function, but instead of using the entries with no
// "test_group" specified or "test_group" = 0, using the entries with
// "test_group" = |target_test_group|.
std::set<int32_t> MakeDecision(OsType os,
const std::string& os_version,
const GPUInfo& gpu_info,
uint32_t target_test_group);
// Return the active entry indices from the last MakeDecision() call.
const std::vector<uint32_t>& GetActiveEntries() const;
// Return corresponding entry IDs from entry indices.
std::vector<uint32_t> GetEntryIDsFromIndices(
const std::vector<uint32_t>& entry_indices) const;
// Collects all disabled extensions.
std::vector<std::string> GetDisabledExtensions();
// Collects all disabled WebGL extensions.
std::vector<std::string> GetDisabledWebGLExtensions();
// Returns the description and bugs from active entries provided.
// Each problems has:
// {
// "description": "Your GPU is too old",
// "crBugs": [1234],
// }
// The use case is we compute the entries from GPU process and send them to
// browser process, and call GetReasons() in browser process.
void GetReasons(base::Value::List& problem_list,
const std::string& tag,
const std::vector<uint32_t>& entries) const;
// Return the largest entry id. This is used for histogramming.
uint32_t max_entry_id() const;
// Check if we need more gpu info to make the decisions.
// This is computed from the last MakeDecision() call.
// If yes, we should create a gl context and do a full gpu info collection.
bool needs_more_info() const { return needs_more_info_; }
// Returns the number of entries. This is only for tests.
size_t num_entries() const;
// Register a feature to FeatureMap.
void AddSupportedFeature(const std::string& feature_name, int feature_id);
// Enables logging of control list decisions.
void EnableControlListLogging(const std::string& control_list_logging_name) {
control_list_logging_enabled_ = true;
control_list_logging_name_ = control_list_logging_name;
}
protected:
// Return false if an entry index goes beyond |total_entries|.
static bool AreEntryIndicesValid(const std::vector<uint32_t>& entry_indices,
size_t total_entries);
private:
// Returns kGLTypeNone if gl_renderer is empty.
// Returns kGLTypeGLES if gl_renderer isn't in the format of ANGLE(_,_,_).
// Returns kGLTypeANGLE_VULKAN or kGLTypeANGLE_GLES otherwise.
static GLType ProcessANGLEGLRenderer(const std::string& gl_renderer,
std::string* vendor = nullptr,
std::string* renderer = nullptr,
std::string* version = nullptr);
friend class GpuControlListEntryTest;
friend class VersionInfoTest;
friend class GpuControlListTest;
// Gets the current OS type.
static OsType GetOsType();
// These always point to built-in arrays of constants, so raw_ptr doesn't
// add any protection but costs some overhead.
base::raw_span<const Entry> entries_;
// This records all the entries that are applicable to the current user
// machine. It is updated everytime MakeDecision() is called and is used
// later by GetDecisionEntries().
std::vector<uint32_t> active_entries_;
uint32_t max_entry_id_ = 0;
bool needs_more_info_ = false;
// The features a GpuControlList recognizes and handles.
FeatureMap feature_map_;
bool control_list_logging_enabled_ = false;
std::string control_list_logging_name_;
};
} // namespace gpu
#endif // GPU_CONFIG_GPU_CONTROL_LIST_H_