chromium/gpu/vulkan/vulkan_util.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#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"  //nogncheck
#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"  //nogncheck
#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());

  // TODO(crbug.com/40136096): check Honor devices as well.
  if (manufacturer != "HUAWEI")
    return -1;

  // Huawei puts EMUI version in the build version incremental.
  // Example: 11.0.0.130C00
  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", ""};

  // Check block list against build info.
  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();
  // We require at least android T deqp test to pass for v2.
  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");
}

// Imagination is allowed with V2.
bool IsVulkanV2EnabledForImagination(const GPUInfo& gpu_info) {
  return IsVulkanV2Enabled(gpu_info, "Imagination");
}

// Everything except MediaTek.
bool IsVulkanV1EnabledForMali(const GPUInfo& gpu_info) {
  // https://crbug.com/1183702
  if (IsDeviceBlocked(gpu_info.gl_renderer, "*Mali-G?? M*")) {
    return false;
  }
  return true;
}

// Everything that passed 2022 deQP tests.
bool IsVulkanV2EnabledForMali(const GPUInfo& gpu_info) {
  // For V2 we MediaTek is allowed.
  return ShouldBypassMediatekBlock(gpu_info);
}

// Only Adreno 630 with drivers newer than 444.0
bool IsVulkanV1EnabledForAdreno(
    const GPUInfo& gpu_info,
    const VulkanPhysicalDeviceProperties& device_properties) {
  // https://crbug.com/1246857
  if (IsDeviceBlocked(gpu_info.gpu.driver_version,
                      "324.0|331.0|334.0|378.0|415.0|420.0|444.0")) {
    return false;
  }

  // https:://crbug.com/1165783: Performance is not yet as good as GL.
  return device_properties.device_name == std::string_view("Adreno (TM) 630");
}

// Adreno 630+ and 2022 deQP tests.
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);
      });

  // Don't run vulkan for old gpus or if we are not in v2.
  return !is_slow_gpu_for_v2 && IsVulkanV2Enabled(gpu_info, "Adreno");
}

// Adreno 610+ and drivers 502+.
bool IsVulkanV3EnabledForAdreno(
    const GPUInfo& gpu_info,
    const VulkanPhysicalDeviceProperties& device_properties) {
  // If IsVulkanV2Allowed(), this device is part of VulkanV2 finch and we should
  // not make decision again. This is to prevent VulkanV2 control group to get
  // Vulkan enabled by getting into VulkanV3 enabled group.
  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;  // 502.0
  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
}  // namespace

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) {}

}  // namespace gpu