#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "gpu/vulkan/vulkan_util.h"
#include <string_view>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/ranges/algorithm.h"
#include "base/strings/pattern.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "gpu/config/gpu_info.h"
#include "gpu/config/vulkan_info.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "third_party/abseil-cpp/absl/cleanup/cleanup.h"
#include "ui/gl/gl_switches.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/linux/drm_util_linux.h"
#endif
#define GL_NONE …
#define GL_LAYOUT_GENERAL_EXT …
#define GL_LAYOUT_COLOR_ATTACHMENT_EXT …
#define GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT …
#define GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT …
#define GL_LAYOUT_SHADER_READ_ONLY_EXT …
#define GL_LAYOUT_TRANSFER_SRC_EXT …
#define GL_LAYOUT_TRANSFER_DST_EXT …
#define GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT …
#define GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT …
namespace gpu {
namespace {
#if BUILDFLAG(IS_ANDROID)
bool IsDeviceBlocked(std::string_view field, std::string_view block_list) {
auto disable_patterns = base::SplitString(
block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
for (const auto& disable_pattern : disable_patterns) {
if (base::MatchPattern(field, disable_pattern)) {
return true;
}
}
return false;
}
int GetEMUIVersion() {
const auto* build_info = base::android::BuildInfo::GetInstance();
std::string_view manufacturer(build_info->manufacturer());
if (manufacturer != "HUAWEI")
return -1;
int version = 0;
if (sscanf(build_info->version_incremental(), "%d.", &version) != 1)
return -1;
return version;
}
bool IsBlockedByBuildInfo() {
const char* kBlockListByHardware = "mt*";
const char* kBlockListByBrand = "HONOR";
const char* kBlockListByDevice = "OP4863|OP4883";
const char* kBlockListByBoard =
"RM67*|RM68*|k68*|mt6*|oppo67*|oppo68*|QM215|rk30sdk";
const auto* build_info = base::android::BuildInfo::GetInstance();
if (IsDeviceBlocked(build_info->hardware(), kBlockListByHardware)) {
return true;
}
if (IsDeviceBlocked(build_info->brand(), kBlockListByBrand)) {
return true;
}
if (IsDeviceBlocked(build_info->device(), kBlockListByDevice)) {
return true;
}
if (IsDeviceBlocked(build_info->board(), kBlockListByBoard)) {
return true;
}
return false;
}
BASE_FEATURE(kVulkanV2, "VulkanV2", base::FEATURE_DISABLED_BY_DEFAULT);
BASE_FEATURE(kVulkanV3, "VulkanV3", base::FEATURE_DISABLED_BY_DEFAULT);
bool IsDeviceBlockedByFeatureParams(const GPUInfo& gpu_info,
const base::Feature* feature) {
const auto* build_info = base::android::BuildInfo::GetInstance();
const base::FeatureParam<std::string> kBlockListByHardware{
feature, "BlockListByHardware", ""};
const base::FeatureParam<std::string> kBlockListByBrand{
feature, "BlockListByBrand", ""};
const base::FeatureParam<std::string> kBlockListByDevice{
feature, "BlockListByDevice", ""};
const base::FeatureParam<std::string> kBlockListByAndroidBuildId{
feature, "BlockListByAndroidBuildId", ""};
const base::FeatureParam<std::string> kBlockListByManufacturer{
feature, "BlockListByManufacturer", ""};
const base::FeatureParam<std::string> kBlockListByModel{
feature, "BlockListByModel", ""};
const base::FeatureParam<std::string> kBlockListByBoard{
feature, "BlockListByBoard", ""};
const base::FeatureParam<std::string> kBlockListByAndroidBuildFP{
feature, "BlockListByAndroidBuildFP", ""};
const base::FeatureParam<std::string> kBlockListByGLDriver{
feature, "BlockListByGLDriver", ""};
const base::FeatureParam<std::string> kBlockListByGLRenderer{
feature, "BlockListByGLRenderer", ""};
if (IsDeviceBlocked(build_info->hardware(), kBlockListByHardware.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->brand(), kBlockListByBrand.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->device(), kBlockListByDevice.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->android_build_id(),
kBlockListByAndroidBuildId.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->manufacturer(),
kBlockListByManufacturer.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->model(), kBlockListByModel.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->board(), kBlockListByBoard.Get())) {
return true;
}
if (IsDeviceBlocked(build_info->android_build_fp(),
kBlockListByAndroidBuildFP.Get())) {
return true;
}
if (IsDeviceBlocked(gpu_info.gl_renderer, kBlockListByGLRenderer.Get())) {
return true;
}
if (IsDeviceBlocked(gpu_info.gpu.driver_version,
kBlockListByGLDriver.Get())) {
return true;
}
return false;
}
bool IsVulkanV2Allowed() {
const auto* build_info = base::android::BuildInfo::GetInstance();
constexpr int32_t kVulkanDEQPAndroidT = 0x07E60301;
if (build_info->vulkan_deqp_level() < kVulkanDEQPAndroidT) {
return false;
}
return true;
}
bool IsVulkanV2Enabled(const GPUInfo& gpu_info,
std::string_view experiment_arm) {
if (!IsVulkanV2Allowed()) {
return false;
}
if (!base::FeatureList::IsEnabled(kVulkanV2)) {
return false;
}
if (IsDeviceBlockedByFeatureParams(gpu_info, &kVulkanV2)) {
return false;
}
const base::FeatureParam<std::string> kBlockListByExperimentArm{
&kVulkanV2, "BlockListByExperimentArm", ""};
if (IsDeviceBlocked(experiment_arm, kBlockListByExperimentArm.Get())) {
return false;
}
return true;
}
bool ShouldBypassMediatekBlock(const GPUInfo& gpu_info) {
return IsVulkanV2Enabled(gpu_info, "Mediatek");
}
bool IsVulkanV2EnabledForImagination(const GPUInfo& gpu_info) {
return IsVulkanV2Enabled(gpu_info, "Imagination");
}
bool IsVulkanV1EnabledForMali(const GPUInfo& gpu_info) {
if (IsDeviceBlocked(gpu_info.gl_renderer, "*Mali-G?? M*")) {
return false;
}
return true;
}
bool IsVulkanV2EnabledForMali(const GPUInfo& gpu_info) {
return ShouldBypassMediatekBlock(gpu_info);
}
bool IsVulkanV1EnabledForAdreno(
const GPUInfo& gpu_info,
const VulkanPhysicalDeviceProperties& device_properties) {
if (IsDeviceBlocked(gpu_info.gpu.driver_version,
"324.0|331.0|334.0|378.0|415.0|420.0|444.0")) {
return false;
}
return device_properties.device_name == std::string_view("Adreno (TM) 630");
}
bool IsVulkanV2EnabledForAdreno(
const GPUInfo& gpu_info,
const VulkanPhysicalDeviceProperties& device_properties) {
std::vector<const char*> slow_gpus_for_v2 = {
"Adreno (TM) 2??", "Adreno (TM) 3??", "Adreno (TM) 4??",
"Adreno (TM) 5??", "Adreno (TM) 61?", "Adreno (TM) 62?",
};
const bool is_slow_gpu_for_v2 =
base::ranges::any_of(slow_gpus_for_v2, [&](const char* pattern) {
return base::MatchPattern(device_properties.device_name, pattern);
});
return !is_slow_gpu_for_v2 && IsVulkanV2Enabled(gpu_info, "Adreno");
}
bool IsVulkanV3EnabledForAdreno(
const GPUInfo& gpu_info,
const VulkanPhysicalDeviceProperties& device_properties) {
if (IsVulkanV2Allowed()) {
return false;
}
std::vector<const char*> slow_gpus_for_v3 = {
"Adreno (TM) 2??",
"Adreno (TM) 3??",
"Adreno (TM) 4??",
"Adreno (TM) 5??",
};
const bool is_slow_gpu_for_v3 =
base::ranges::any_of(slow_gpus_for_v3, [&](const char* pattern) {
return base::MatchPattern(device_properties.device_name, pattern);
});
if (is_slow_gpu_for_v3) {
return false;
}
constexpr uint32_t kMinVersion = 0x801F6000;
if (device_properties.driver_version < kMinVersion) {
return false;
}
if (!base::FeatureList::IsEnabled(kVulkanV3)) {
return false;
}
if (IsDeviceBlockedByFeatureParams(gpu_info, &kVulkanV3)) {
return false;
}
return true;
}
#endif
}
VulkanPhysicalDeviceProperties::VulkanPhysicalDeviceProperties() = default;
VulkanPhysicalDeviceProperties::VulkanPhysicalDeviceProperties(
const VkPhysicalDeviceProperties& properties)
: … { … }
VulkanPhysicalDeviceProperties::~VulkanPhysicalDeviceProperties() = default;
bool SubmitSignalVkSemaphores(VkQueue vk_queue,
const base::span<VkSemaphore>& vk_semaphores,
VkFence vk_fence) { … }
bool SubmitSignalVkSemaphore(VkQueue vk_queue,
VkSemaphore vk_semaphore,
VkFence vk_fence) { … }
bool SubmitWaitVkSemaphores(VkQueue vk_queue,
const base::span<VkSemaphore>& vk_semaphores,
VkFence vk_fence) { … }
bool SubmitWaitVkSemaphore(VkQueue vk_queue,
VkSemaphore vk_semaphore,
VkFence vk_fence) { … }
VkSemaphore CreateExternalVkSemaphore(
VkDevice vk_device,
VkExternalSemaphoreHandleTypeFlags handle_types) { … }
std::string VkVersionToString(uint32_t version) { … }
VkResult CreateGraphicsPipelinesHook(
VkDevice device,
VkPipelineCache pipelineCache,
uint32_t createInfoCount,
const VkGraphicsPipelineCreateInfo* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkPipeline* pPipelines) { … }
VkResult VulkanQueueSubmitHook(VkQueue queue,
uint32_t submitCount,
const VkSubmitInfo* pSubmits,
VkFence fence) { … }
VkResult VulkanQueueWaitIdleHook(VkQueue queue) { … }
VkResult VulkanQueuePresentKHRHook(VkQueue queue,
const VkPresentInfoKHR* pPresentInfo) { … }
bool CheckVulkanCompatibilities(
const VulkanPhysicalDeviceProperties& device_properties,
const GPUInfo& gpu_info) { … }
VkImageLayout GLImageLayoutToVkImageLayout(uint32_t layout) { … }
uint32_t VkImageLayoutToGLImageLayout(VkImageLayout layout) { … }
bool IsVkExternalSemaphoreHandleTypeSupported(
VulkanDeviceQueue* device_queue,
VkExternalSemaphoreHandleTypeFlagBits handle_type) { … }
VkResult QueryVkExternalMemoryProperties(
VkPhysicalDevice physical_device,
VkFormat format,
VkImageType type,
VkImageTiling tiling,
VkImageUsageFlags usage,
VkImageCreateFlags flags,
VkExternalMemoryHandleTypeFlagBits handle_type,
VkExternalMemoryProperties* external_memory_properties) { … }
std::vector<VkDrmFormatModifierPropertiesEXT>
QueryVkDrmFormatModifierPropertiesEXT(VkPhysicalDevice physical_device,
VkFormat format) { … }
void PopulateVkDrmFormatsAndModifiers(
VulkanDeviceQueue* device_queue,
base::flat_map<uint32_t, std::vector<uint64_t>>&
drm_formats_and_modifiers) { … }
}