從 RenderScript 遷移

自 Android 12 起,RenderScript API 已淘汰。這類 API 會繼續運作一段時間,但裝置和元件製造商已停止提供硬體加速支援,後續版本也將完全移除 RenderScript 支援功能。

許多使用者會發現 C/C++ 的效能即可滿足他們的用途。如果您只仰賴 RenderScript 執行內建函式,可以使用 RenderScript 內建函式替換工具包取代這些用途,這樣不僅更易於使用,效能也可能翻倍!

如果確實需要完全利用 GPU 加速功能,建議您將指令碼遷移至 Vulkan

在 Android 平台上淘汰 RenderScript 後,我們也會移除 Android Gradle 外掛程式中的 RenderScript 支援功能。自 Android Gradle 外掛程式 7.2 版開始,RenderScript API 已淘汰。這類 API 仍可繼續運作,但會叫用警告,並將在未來的 AGP 版本中徹底移除。本指南將說明如何從 RenderScript 遷移。

從內建函式遷移

雖然 RenderScript 內建函式在 RenderScript 淘汰後仍會繼續運作,但可能只能在 CPU (而非 GPU) 上執行。

如果您的應用程式使用了內建函式,您可以使用獨立的替代程式庫;我們的測試結果顯示,與現有的 RenderScript CPU 實作相比,獨立替代程式庫的速度更快。

工具包中包含下列函式:

  • 混合
  • 模糊處理
  • 色彩矩陣
  • 卷積
  • 直方圖和 histogramDot
  • 對照表 (LUT) 函數和 LUT 3D
  • 調整大小
  • 從 YUV 轉換為 RGB

如需完整的詳細資料和限制條件,請參閱工具包的 README.mdToolkit.kt. 檔案。

請按照下列步驟下載、新增及使用資料庫:

  1. 從 GitHub 下載專案

  2. 找出並建構 renderscript-toolkit module

  3. 修改應用程式的 build.gradle 檔案,將程式庫新增至您的 Android Studio 專案。

  4. 叫用適當的工具包方法。

範例:從 ScriptIntrinsicBlur 函式遷移

如要取代 ScriptIntrinsicBlur 函式:

  • 如要模糊處理點陣圖,請呼叫 Toolkit.blur

    var blurredBitmap = Toolkit.blur(myBitmap, radius)
    
  • 如要模糊處理由位元組陣列表示的圖片,請指定每個像素的寬度、高度和位元組數。

    val outArray = Toolkit.blur(inputArray, bytesPerPixel, width, height, radius)
    

如果您指定的是 Android 12 (API 級別 31) 以上版本,請考慮使用 RenderEffect 類別,而不是 Toolkit.blur()

從指令碼遷移

如果 RenderScript 內建函式替換工具組 (其效能可能為 RenderScript 的 2 倍) 無法解決您的用途,建議您將 RenderScript 指令碼遷移至跨平台 Vulkan API。您通常不必採取這項措施,因為在大部分裝置上,指令碼已在 CPU 上執行 (而非在 GPU 上):在某些情況下,C/C++ 的運算速度可能比 RenderScript 或 Vulkan 更快,也可能足夠快,即使 Vulkan 或 RenderScript 的運作效果更好。

如要進一步瞭解如何遷移功能,請參考範例應用程式。此範例示範了如何在 RenderScript 中對點陣圖進行模糊處理並執行色彩矩陣轉換,以及如何在 Vulkan 中編寫等效的程式碼。

如果您的應用程式需要支援多種版本,請針對搭載 Android 6 (API 級別 23) 以下版本的裝置使用 RenderScript,而對 Android 7 (API 級別 24) 以上的版本則使用 Vulkan。如果 minSdkVersion 為 24 以上,則無須使用 RenderScript;Vulkan 可用於您支援的每部裝置。

Vulkan 不提供 Kotlin 或 Java API,因此無法將 RenderScript 直接對應至 Vulkan。您需要使用 NDK 編寫 Vulkan 程式碼,並建立 JNI 函式,才能從 Kotlin 或 Java 存取這個程式碼。

以下各節介紹了從 RenderScript 遷移的各個面向。範例應用程式幾乎涵蓋了上述所有考量因素。如要進一步瞭解這些因素,請比較 RenderScript 和 Vulkan 的對等程式碼。

初始化

請遵循下列步驟使用 NDK 建立 Vulkan 情境,而不要在 Kotlin 或 Java 中建立 RenderScript 情境物件。

  1. 建立 Vulkan 例項。

  2. 選擇支援運算佇列的 Vulkan 實體裝置。

  3. 建立 Vulkan 邏輯裝置,並取得運算佇列。

您可以選擇在 Android 上設定 Vulkan 驗證層,加快 Vulkan 應用程式的開發速度。

範例應用程式示範了如何在 VulkanContext.h 中初始化 Vulkan 情境。詳情請參閱 Vulkan 規格中的初始化裝置與佇列章節。

配置

您可以將 RenderScript 配置遷移至 Vulkan 儲存空間圖片Vulkan 儲存空間緩衝區。為了讓唯讀映像檔發揮最佳效能,請透過擷取作業使用取樣圖片,形式可以是合併的圖片取樣器或分開的取樣器取樣圖片繫結。

Vulkan 資源在 Vulkan 中配置。為避免在與其他 Android 元件互動時產生記憶體複製負荷,建議您使用VK_ANDROID_external_memory_android_hardware_buffer 擴充功能將 Android AHardwareBuffer匯入 Vulkan。這項擴充功能適用於所有支援 Vulkan 1.1 的 Android 裝置。如需詳細資訊,請參閱 FEATURE_VULKAN_HARDWARE_VERSION

範例應用程式示範了如何在 VulkanResources.h 中建立 Vulkan 資源。詳情請參閱 Vulkan 規格中的資源建立資源描述元章節。

指令碼

您的 RenderScript 指令碼必須轉換為 Vulkan 運算著色器。您可能還需要根據 RenderScript 全域變數的使用情況來調整程式碼。

撰寫 Vulkan 運算著色器

Vulkan 運算著色器通常是以 OpenGL 著色語言 (GLSL) 編寫,再編譯為 Standard Portable Intermediate Representation-V (SPIR-V) 格式。

如需瞭解如何將著色器整合到應用程式中的詳細資訊和操作說明,請參閱「Android 上的 Vulkan 著色器編譯器」。

調整指令碼全域變數

根據指令碼全域變數的特性,對於未在著色器中修改的全域變數,建議您使用特殊化常數、推送常數或統一緩衝區物件:

  • 特殊化常數:建議用於在不同核心叫用中大致一致的指令碼全域變數。變更特殊化常數值需要重新建立運算管線。
  • 推送常數:建議用於頻繁變更且小於 maxPushConstantsSize (保證大小下限為 128 個位元組) 的指令碼全域變數。
  • 統一緩衝區:建議用於頻繁變更且大於推送常數上限的指令碼全域變數。

對於在著色器中變更的全域變數,您可以使用 Vulkan 儲存空間影像Vulkan 儲存空間緩衝區

運算作業

您需要建立 Vulkan 運算管線,才能使 GPU 執行運算著色器。

建立 Vulkan 運算管線

範例應用程式中的 ComputePipeline.h 檔案示範了如何建立 Vulkan 運算管線。

如要在 Vulkan 中使用經過編譯的 SPIR-V 著色器,請依下列步驟建構 Vulkan 運算管線:

  1. 使用經過編譯的 SPIR-V 著色器建立著色器模組。
  2. 建立描述元集版面配置,以指定資源繫結 (詳情請參閱配置)。
  3. 根據描述元集版面配置建立描述元集。
  4. 根據描述元集版面配置建立管線版面配置。
  5. 使用著色器模組和管線版面配置建立運算管線。

詳情請參閱 Vulkan 規格中的運算管線一節。

開始運算作業

如要開始使用運算管線進行運算,請按照下列步驟操作:

  1. 使用 Vulkan 資源更新描述元集。
  2. 建立 Vulkan 指令緩衝區,並記錄下列指令:
    1. 繫結管線和描述元集。
    2. 調派運算工作群組。
  3. 將指令緩衝區提交至運算佇列。
  4. 在佇列中等候,或可選擇傳回同步處理圍欄。

如要鏈結多個核心 (例如使用 ScriptGroup 遷移程式碼),請將其記錄在一個指令緩衝區中,並與記憶體障礙進行同步處理。

範例應用程式示範了兩項運算工作:

  • HUE 輪替:具有單一運算著色器的簡易運算工作。如需程式碼範例,請參閱 ImageProcessor::rotateHue
  • 模糊處理:較為複雜的運算工作,依序執行兩個運算著色器。如需程式碼範例,請參閱 ImageProcessor::blur

如要進一步瞭解指令緩衝區或記憶體障礙,請參閱 Vulkan 規格中的指令緩衝區記憶體障礙章節。