VkQuality Unity 引擎外掛程式

Unity 引擎的 VkQuality 外掛程式會提供圖形 API (Vulkan 或 OpenGL ES) 的啟動時間建議,以便用於特定裝置上的遊戲。

VkQuality 針對 Vulkan 建議在比 Unity 引擎預設許可清單上更受限制的裝置組合。使用 VkQuality 可獲得 Vulkan 的效能優勢,同時只能在搭載較新版圖形驅動程式的新型裝置上使用 Vulkan,這將限制遊戲暴露於驅動程式的問題。VkQuality 只會提供品質建議,而非保證,因為在推薦裝置上仍有駕駛問題。VkQuality 支援自訂清單,可讓您為遊戲新增或移除裝置建議。

在 Unity 引擎遊戲中啟用 Vulkan

如要使用 VkQuality,遊戲必須在 Unity 專案設定中同時啟用 OpenGL ES 和 Vulkan 轉譯器。使用 Auto Graphics 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 級別等於或高於建議清單中的 Future API 級別,VkQuality 會建議使用 Vulkan。預設的推薦清單的 Future API 級別為 36,也就是說,在搭載 API 級別 36 以上的不相符裝置上,VkQuality 會傳回 RECOMMENDATION_VULKAN_BECAUSE_FUTURE_ANDROID 列舉常數。

如果在裝置許可清單或 GPU 建議清單中找不到相符項目,且裝置的 API 級別低於 Future 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 子目錄不存在,請建立這些子目錄)。
必要專案目錄中的 VkQuality .aar 檔案。
圖 1:所需專案目錄中的 VkQuality .aar 檔案。
  1. 在 Unity 的「Project」階層中選取 VkQuality-1.x.x 外掛程式檔案,在「Inspector」窗格中顯示其「Import Settings」。確認已勾選「Android」平台。
圖 2. VkQuality 外掛程式平台匯入設定。
圖 2. VkQuality 外掛程式平台匯入設定。

使用自訂活動呼叫 VkQuality

與一般 Unity 引擎外掛程式不同,必須在 Unity 引擎初始化之前執行 VkQuality,以取得圖形 API 建議。然後使用 Unity 播放器指令列引數功能,根據 VkQuality 建議設定 Graphs API。在 Android 中,傳遞指令列引數時,必須透過建立自訂活動,覆寫 UnityPlayerActivity 的預設行為。

如果遊戲已在使用自訂活動,請參閱「將 VkQuality 新增至現有自訂活動」一節。如要為遊戲建立新的自訂活動,請參閱下文的「在 Unity 專案中新增自訂活動」。

將自訂活動新增至 Unity 引擎專案

Assets/Plugins/Android/VkQualityTestActivity.java外掛程式套件內含使用 VkQuality 的自訂活動範例。如要自訂檔案並用於遊戲,請按照下列步驟操作:

  1. VkQualityTestActivity.java 檔案複製到 Assets/Plugins/Android 目錄。
  2. 將其重新命名為適合遊戲的名稱 (例如 MyGameActivity.java)。
  3. 使用文字編輯器開啟檔案。
  4. 將類別名稱從 VkQualityTestActivity 變更為您提供的檔案名稱 (例如 MyGameActivity.java)。
  5. 將套件名稱從 com.google.android.games.VkQualityTest 變更為符合 Unity 專案設定「Player」類別中的「Package Name」欄位值 (例如 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」(自訂主要資訊清單) 核取方塊。
圖 3:Unity Player 設定中的「自訂主要資訊清單」選項。
圖 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 List Editor 工具。該工具的說明文件位於其 README 中。