VkQuality Unity 引擎插件

针对 Unity 引擎的 VkQuality 插件提供了在特定设备上为你的游戏使用图形 API(Vulkan 或 OpenGL ES)的启动时建议。

VkQuality 在比 Unity 引擎的默认允许列表更严格的设备集上推荐 Vulkan。使用 VkQuality 可以获得 Vulkan 的性能优势,同时将 Vulkan 的使用限制在具有较新图形驱动程序的较新设备上,这可以限制你的游戏暴露于驱动程序问题。VkQuality 仅提供质量建议,不提供保证,因为它仍然有可能在推荐的设备上遇到驱动程序问题。VkQuality 支持自定义列表,这使你能够为你的游戏添加或删除设备建议。

在你的 Unity 引擎游戏中启用 Vulkan

VkQuality 要求你的游戏在 Unity 项目设置中同时启用 OpenGL ES 和 Vulkan 渲染器。使用 自动图形 API 选项或通过 手动设置 图形 API 来启用渲染器。

获取针对 Unity 引擎的 VkQuality 插件

GitHub 下载 VkQuality 插件。该插件与 Unity 2021 及更高版本兼容。使用 Unity 2021 LTS 或更高版本在 Android 上启用 Vulkan。插件包包含一个基本示例项目,该项目使用插件在启动时设置图形 API,然后显示一个设置为设备活动图形 API 的字符串。

管理 VkQuality Vulkan 建议列表

VkQuality 包含一个支持设备的默认建议列表。有关使用自定义建议列表的信息,请参阅 使用自定义建议列表 部分。

建议列表包含三个类别

  • Vulkan 设备允许列表
  • GPU 建议允许列表
  • GPU 建议拒绝列表

设备允许列表匹配

VkQuality 首先检查活动设备是否包含在设备允许列表中,以及它是否运行允许列表中为该设备指定的最低 Android 版本和 Vulkan 驱动程序版本。如果满足这些条件,VkQuality 会通过返回 RECOMMENDATION_VULKAN_BECAUSE_DEVICE_MATCH 枚举值来推荐 Vulkan。

如果设备在允许列表中,但运行的 Android 版本或驱动程序版本低于为其在允许列表中指定的最低版本,VkQuality 会通过返回 RECOMMENDATION_GLES_BECAUSE_OLD_DRIVER 来推荐 OpenGL ES。

GPU 建议匹配

如果没有在设备允许列表中找到设备匹配,VkQuality 会根据 GPU 模型和驱动程序版本评估 GPU 建议允许和拒绝列表。如果 GPU 模型和驱动程序版本与 GPU 建议允许列表中的条目匹配,VkQuality 会通过返回 RECOMMENDATION_VULKAN_BECAUSE_PREDICTION_MATCH 枚举常量来推荐 Vulkan。

如果 GPU 模型和驱动程序版本与 GPU 建议拒绝列表中的条目匹配,VkQuality 会通过返回 RECOMMENDATION_GLES_BECAUSE_PREDICTION_MATCH 来推荐 OpenGL ES。

没有匹配的建议

如果没有找到匹配项,如果运行设备的 Android API 级别等于或高于建议列表中的未来 API 级别,VkQuality 会推荐 Vulkan。默认建议列表的未来 API 级别为 36,这意味着在运行 API 级别 36 或更高版本的未匹配设备上,VkQuality 会返回 RECOMMENDATION_VULKAN_BECAUSE_FUTURE_ANDROID 枚举常量。

如果没有在设备允许列表或 GPU 建议列表中找到匹配项,并且设备的 API 级别低于未来 API 级别,VkQuality 会通过返回 RECOMMENDATION_GLES_BECAUSE_NO_DEVICE_MATCH 来推荐 OpenGL ES。

将 VkQuality 存档文件添加到你的项目

VkQuality 插件是位于下载的包存档的 Assets/Android/Plugins 目录中的 VkQuality-1.x.x.aar 文件。实际的 .aar 文件版本号与包存档名称的版本号匹配。要安装插件,请执行以下步骤

  1. 将 .aar 文件复制到项目的 Assets/Android/Plugins 目录。(如果不存在,请创建所需的 AndroidPlugins 子目录。)
The VkQuality .aar file in the required project directory.
图 1.位于所需项目目录中的 VkQuality .aar 文件。
  1. 在 Unity 项目层次结构中选择 VkQuality-1.x.x 插件文件以在 检查器窗格中显示其 导入设置。确保选中 Android 平台。
Figure 2. The VkQuality plugin platform import settings.
图 2. VkQuality 插件平台导入设置。

使用自定义活动调用 VkQuality

与典型的 Unity 引擎插件不同,必须执行 VkQuality 以在初始化 Unity 引擎之前获得图形 API 建议。然后,你可以使用 Unity 播放器命令行参数 功能根据 VkQuality 建议设置图形 API。在 Android 上,传递命令行参数需要通过 创建自定义活动 来覆盖 UnityPlayerActivity 的默认行为。

如果你的游戏已经在使用自定义活动,请参阅 将 VkQuality 添加到现有自定义活动 部分。要为你的游戏创建一个新的自定义活动,请参阅 将自定义活动添加到你的 Unity 项目,该部分将在下面介绍。

将自定义活动添加到你的 Unity 引擎项目

一个使用 VkQuality 的示例自定义活动包含在 插件包 中的 Assets/Plugins/Android/VkQualityTestActivity.java 中。要自定义该文件并在你的游戏中使用它,请执行以下步骤

  1. VkQualityTestActivity.java 文件复制到你的 Assets/Plugins/Android 目录。
  2. 将其重命名为适合你的游戏的名称(例如,MyGameActivity.java)。
  3. 在文本编辑器中打开该文件。
  4. 将类名从 VkQualityTestActivity 更改为你给文件起的名称(例如,MyGameActivity.java)。
  5. 将包名从 com.google.android.games.VkQualityTest 更改为与你的 Unity 项目设置 播放器类别中的 其他设置下的 包名称字段的值匹配(例如,com.mycompany.mygame)。
  6. 保存并关闭该文件。

添加一个引用自定义活动的自定义清单文件,并告诉 Unity 使用您的自定义清单文件。

  1. 将插件包的 Assets/Plugins/Android 目录中的 AndroidManifest.xml 文件复制到您项目的 Asset/Plugins/Android 目录中。
  2. 在文本编辑器中打开该文件。
  3. activity android:name 设置的值从 com.google.android.games.VkQualityTest.VkQualityTestActivity 更改为在前面的步骤中使用的包和活动名称(例如,com.mycompany.mygame.MyGameActivity)。
  4. 保存并关闭该文件。
  5. 打开 Unity 设置窗口,选择 Player 设置。展开 Publishing Settings 部分,选中 Custom Main Manifest 复选框。
Figure 3.The Custom Main Manifest option in the Unity Player settings.
图 3.Unity Player 设置中的 Custom Main Manifest 选项。

您的项目现在已设置为使用自定义活动,该活动在启动时调用 VkQuality 并根据 VkQuality 建议选择 Vulkan 或 OpenGL ES。

将 VkQuality 添加到现有的自定义活动中

如果您的游戏已经有一个覆盖默认 UnityPlayerActivity 的自定义活动,请通过添加以下代码来集成 VkQuality 建议。

首先,将 VkQuality 导入语句添加到自定义活动文件顶部的导入列表中。

Kotlin

import com.google.android.games.vkquality.VKQuality;

Java

import com.google.android.games.vkquality.VKQuality;

接下来,在您的 Activity 类主体中创建一些用于图形 API 选择的常量。

Kotlin

companion object {
  private const val OVERRIDE_NONE = 0
  private const val OVERRIDE_GLES = 1
  private const val OVERRIDE_VULKAN = 2

Java

private static final int OVERRIDE_NONE = 0;
private static final int OVERRIDE_GLES = 1;
private static final int OVERRIDE_VULKAN = 2;

创建一个变量来跟踪 API 选择。

Kotlin

private var apiOverride = OVERRIDE_NONE

Java

private int apiOverride = OVERRIDE_NONE;

将以下函数添加到您的 Activity 类中。

Kotlin

private fun CheckVkQuality() {
    val vkQuality = VKQuality(this)
    val startResult = vkQuality.StartVkQuality("")
    if (startResult == VKQuality.INIT_SUCCESS) {
        // In the current release, we can assume GetVkQuality is
        // ready as soon as StartVkQuality has returned success.
        val getResult = vkQuality.GetVkQuality()
        LogVkQualityResult(getResult)
        apiOverride =
            when (getResult) {
                VKQuality.RECOMMENDATION_VULKAN_BECAUSE_DEVICE_MATCH,
                VKQuality.RECOMMENDATION_VULKAN_BECAUSE_PREDICTION_MATCH,
                VKQuality.RECOMMENDATION_VULKAN_BECAUSE_FUTURE_ANDROID -> OVERRIDE_VULKAN
                VKQuality.RECOMMENDATION_GLES_BECAUSE_OLD_DEVICE,
                VKQuality.RECOMMENDATION_GLES_BECAUSE_OLD_DRIVER,
                VKQuality.RECOMMENDATION_GLES_BECAUSE_NO_DEVICE_MATCH,
                VKQuality.RECOMMENDATION_GLES_BECAUSE_PREDICTION_MATCH -> OVERRIDE_GLES
                else -> OVERRIDE_GLES
            }
        vkQuality.StopVkQuality()
    } else {
        Log.e("VKQUALITY", "VkQuality start failed with result: $startResult")
    }
}

Java

private void CheckVkQuality() {
  VKQuality vkQuality = new VKQuality(this);
  // An empty string specifies use of the default
  // built-in device list file.
  int startResult = vkQuality.StartVkQuality("");
  if (startResult == VKQuality.INIT_SUCCESS) {
      // In the current release, we can assume GetVkQuality is
      // ready as soon as StartVkQuality has returned success.
      int getResult = vkQuality.GetVkQuality();

      switch (getResult) {
          case VKQuality.RECOMMENDATION_VULKAN_BECAUSE_DEVICE_MATCH:
          case VKQuality.RECOMMENDATION_VULKAN_BECAUSE_PREDICTION_MATCH:
          case VKQuality.RECOMMENDATION_VULKAN_BECAUSE_FUTURE_ANDROID:
              apiOverride = OVERRIDE_VULKAN;
              break;
          case VKQuality.RECOMMENDATION_GLES_BECAUSE_OLD_DEVICE:
          case VKQuality.RECOMMENDATION_GLES_BECAUSE_OLD_DRIVER:
          case VKQuality.RECOMMENDATION_GLES_BECAUSE_NO_DEVICE_MATCH:
          case VKQuality.RECOMMENDATION_GLES_BECAUSE_PREDICTION_MATCH:
          default:
              apiOverride = OVERRIDE_GLES;
              break;
      }
      vkQuality.StopVkQuality();
  } else {
      Log.e("VKQUALITY", "VkQuality start failed with result: " + startResult);
  }
}

在调用基类实现之前,从 onCreate() 覆盖函数的顶部调用 CheckVkQuality 函数。

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
  CheckVkQuality()
  super.onCreate(savedInstanceState)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    CheckVkQuality();
    super.onCreate(savedInstanceState);
}

最后,添加 updateUnityCommandLineArguments() 函数的覆盖,该函数使用 apiOverride 的值将命令行参数传递给 Unity 引擎,指定要使用的图形 API。

Kotlin

override fun updateUnityCommandLineArguments(cmdLine: String): String {
  if (apiOverride == OVERRIDE_VULKAN) {
      Log.i("VKQUALITY", "Passing -force-vulkan")
      return appendCommandLineArgument(cmdLine, "-force-vulkan")
  } else if (apiOverride == OVERRIDE_GLES) {
      Log.i("VKQUALITY", "Passing -force-gles")
      return appendCommandLineArgument(cmdLine, "-force-gles")
  }
  Log.i("VKQUALITY", "No override passed")
  // let Unity pick the Graphics API based on PlayerSettings
  return cmdLine
}

private fun appendCommandLineArgument(cmdLine: String, arg: String?): String {
    return if (arg == null || arg.isEmpty()) cmdLine
    else if (cmdLine == null || cmdLine.isEmpty()) arg else "$cmdLine $arg"
}

Java

@Override protected String updateUnityCommandLineArguments(String cmdLine)
{
    if (apiOverride == OVERRIDE_VULKAN) {
        Log.i("VKQUALITY", "Passing -force-vulkan");
        return appendCommandLineArgument(cmdLine, "-force-vulkan");
    }
    else if (apiOverride == OVERRIDE_GLES) {
        Log.i("VKQUALITY", "Passing -force-gles");
        return appendCommandLineArgument(cmdLine, "-force-gles");
    }
    Log.i("VKQUALITY", "No override passed");
    // let Unity pick the Graphics API based on PlayerSettings
    return cmdLine;
}

private String appendCommandLineArgument(String cmdLine, String arg) {
    if (arg == null || arg.isEmpty())
        return cmdLine;
    else if (cmdLine == null || cmdLine.isEmpty())
        return arg;
    else
        return cmdLine + " " + arg;
}

您的自定义活动现在在启动时调用 VkQuality 并根据 VkQuality 建议选择 Vulkan 或 OpenGL ES。

使用自定义建议列表

通过将包含列表的文件名传递给 StartVkQuality() 来指定自定义建议列表文件,而不是传递空字符串。

Kotlin

val startResult = vkQuality.StartVkQuality("CUSTOM_FILE_NAME.vkq")

Java

int startResult = vkQuality.StartVkQuality("CUSTOM_FILE_NAME.vkq");

VkQuality 首先在您的应用程序的内部存储目录中查找该文件。如果该文件不在内部存储中,VkQuality 会尝试从您的应用捆绑包的资产中加载该文件。如果该文件不在这两个位置,VkQuality 会返回 ERROR_MISSING_DATA_FILE 枚举值。

要创建自定义建议列表文件,请使用位于 GitHub 存储库 中的 VkQuality 列表编辑器 工具。该工具的文档位于其 自述文件 中。