如要使用 Jetpack WebGPU,專案必須符合下列最低需求:
- 最低 API 級別:必須為 Android API 24 (Nougat) 以上版本。
- 硬體:後端最好使用支援 Vulkan 1.1 以上版本的裝置。
- 相容性模式和 OpenGL ES 支援:如要使用 WebGPU 搭配相容性模式,請在要求
GPUAdapter時,將標準化featureLevel選項設為compatibility。
// Example of requesting an adapter with "compatibility" mode enabled:
val adapter = instance.requestAdapter(
GPURequestAdapterOptions(featureLevel = FeatureLevel.Compatibility))
安裝與設定
需求條件:
Android Studio:從官方網站下載最新版 Android Studio,然後按照 Android Studio 安裝指南中的說明操作。
建立新專案
安裝 Android Studio 後,請按照下列步驟設定 WebGPU 專案:
- 建立新專案:開啟 Android Studio,然後點選「New Project」。
選取範本:在 Android Studio 中選擇「Empty Activity」範本,然後按一下「Next」。
圖 1.在 Android Studio 中建立新專案 設定專案:
- 名稱:為專案命名 (例如 「JetpackWebGPUSample」)。
- 套件名稱:確認套件名稱與您選擇的命名空間相符 (例如 com.example.webgpuapp)。
- 「Language」(程式語言):選取「Kotlin」。
- 「Minimum SDK」:選取「API 24: Android 7.0 (Nougat)」以上版本,這是建議用於這個程式庫的版本。
- 建構設定語言:建議使用 Kotlin DSL (build.gradle.kts) 管理新式依附元件。
圖 2.從空白活動開始 完成:按一下「Finish」,然後等待 Android Studio 同步處理專案檔案。
新增 WebGPU Jetpack 程式庫
- 按照「在應用程式中使用 Jetpack 程式庫」一文的說明,將
google存放區新增至settings.gradle。 - 在應用程式或模組的 build.gradle 檔案中,新增您需要的構件依附元件:
- 注意:請參閱 webgpu | Jetpack | Android 開發人員,瞭解最新程式庫版本
androidx.webgpu 程式庫包含 WebGPU NDK .so 程式庫檔案,以及受管理程式碼介面。
如要更新程式庫版本,請更新 build.gradle,然後在 Android Studio 中使用「Sync Project」按鈕,將專案與 Gradle 檔案同步。
高階架構
Android 應用程式中的 WebGPU 算繪作業會在專屬的算繪執行緒上執行,以維持 UI 的回應性。
- 使用者介面層:使用 Jetpack Compose 建構使用者介面。WebGPU 繪圖介面會使用
AndroidExternalSurface整合至 Compose 階層。 - 算繪邏輯:專門類別 (例如 WebGpuRenderer) 負責管理所有 WebGPU 物件,並協調算繪迴圈。
- 著色器層:儲存在 res 或字串常數中的 WGSL 著色器程式碼。
逐步操作說明:範例應用程式
本節將逐步說明在畫面上算繪彩色三角形的必要步驟,示範 WebGPU 的核心工作流程。
主要活動
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WebGpuSurface()
}
}
}
外部介面可組合項
建立名為 WebgpuSurface.kt 的新檔案。這個 Composable 會包裝 AndroidExternalSurface,在 Compose 和算繪器之間提供橋接功能。
@Composable
fun WebGpuSurface(modifier: Modifier = Modifier) {
// Create and remember a WebGpuRenderer instance.
val renderer = remember { WebGpuRenderer() }
AndroidExternalSurface(
modifier = modifier.fillMaxSize(),
) {
// This block is called when the surface is created or resized.
onSurface { surface, width, height ->
// Run the rendering logic on a background thread.
withContext(Dispatchers.Default) {
try {
// Initialize the renderer with the surface
renderer.init(surface, width, height)
// Render a frame.
renderer.render()
} finally {
// Clean up resources when the surface is destroyed.
renderer.cleanup()
}
}
}
}
}
設定 Renderer
在 WebGpuRenderer.kt 中建立 WebGpuRenderer 類別。這個類別會處理與 GPU 通訊的繁重工作。
首先,定義類別結構和變數:
class WebGpuRenderer() {
private lateinit var webGpu: WebGpu
private lateinit var renderPipeline: GPURenderPipeline
}
初始化:接著,實作 init 函式,建立 WebGPU 執行個體並設定介面。這個函式是由我們稍早建立的外部介面可組合函式內的 AndroidExternalSurface 範圍呼叫。
注意:init 函式會使用 createWebGpu,這是輔助方法 (androidx.webgpu.helper 的一部分),可簡化設定程序。這個公用程式會建立 WebGPU 執行個體、選取介面卡,並要求裝置。
// Inside WebGpuRenderer class
suspend fun init(surface: Surface, width: Int, height: Int) {
// 1. Create Instance & Device
webGpu = createWebGpu(surface)
val device = webGpu.device
// 2. Setup Pipeline (compile shaders)
initPipeline(device)
// 3. Configure the Surface
webGpu.webgpuSurface.configure(
GPUSurfaceConfiguration(
device,
width,
height,
TextureFormat.RGBA8Unorm,
)
)
}
androidx.webgpu 程式庫包含 JNI 和 .so 檔案,這些檔案會由建構系統自動連結及管理。輔助方法
createWebGpu 負責載入已組合的 libwebgpu_c_bundled.so。
管道設定
現在我們有了裝置,需要告訴 GPU 如何繪製三角形。 我們建立的「管道」包含著色器程式碼 (以 WGSL 編寫),即可達成這個目標。
將這個私有輔助函式新增至 WebGpuRenderer 類別,編譯著色器並建立算繪管道。
// Inside WebGpuRenderer class
private fun initPipeline(device: GPUDevice) {
val shaderCode = """
@vertex fn vs_main(@builtin(vertex_index) vertexIndex : u32) ->
@builtin(position) vec4f {
const pos = array(vec2f(0.0, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
return vec4f(pos[vertexIndex], 0, 1);
}
@fragment fn fs_main() -> @location(0) vec4f {
return vec4f(1, 0, 0, 1);
}
"""
// Create Shader Module
val shaderModule = device.createShaderModule(
GPUShaderModuleDescriptor(shaderSourceWGSL = GPUShaderSourceWGSL(shaderCode))
)
// Create Render Pipeline
renderPipeline = device.createRenderPipeline(
GPURenderPipelineDescriptor(
vertex = GPUVertexState(
shaderModule,
), fragment = GPUFragmentState(
shaderModule, targets = arrayOf(GPUColorTargetState(TextureFormat.RGBA8Unorm))
), primitive = GPUPrimitiveState(PrimitiveTopology.TriangleList)
)
)
}
繪製影格
管道準備就緒後,我們現在可以實作算繪函式。這個函式會從畫面取得下一個可用紋理、記錄繪圖指令,並將這些指令提交至 GPU。
將這個方法新增至 WebGpuRenderer 類別:
// Inside WebGpuRenderer class
fun render() {
if (!::webGpu.isInitialized) {
return
}
val gpu = webGpu
// 1. Get the next available texture from the screen
val surfaceTexture = gpu.webgpuSurface.getCurrentTexture()
// 2. Create a command encoder
val commandEncoder = gpu.device.createCommandEncoder()
// 3. Begin a render pass (clearing the screen to blue)
val renderPass = commandEncoder.beginRenderPass(
GPURenderPassDescriptor(
colorAttachments = arrayOf(
GPURenderPassColorAttachment(
GPUColor(0.0, 0.0, 0.5, 1.0),
surfaceTexture.texture.createView(),
loadOp = LoadOp.Clear,
storeOp = StoreOp.Store,
)
)
)
)
// 4. Draw
renderPass.setPipeline(renderPipeline)
renderPass.draw(3) // Draw 3 vertices
renderPass.end()
// 5. Submit and Present
gpu.device.queue.submit(arrayOf(commandEncoder.finish()))
gpu.webgpuSurface.present()
}
清除資源
實作清除函式,當表面遭到刪除時,WebGpuSurface 會呼叫該函式。
// Inside WebGpuRenderer class
fun cleanup() {
if (::webGpu.isInitialized) {
webGpu.close()
}
}
顯示的輸出內容
範例應用程式結構
建議您將算繪實作項目與 UI 邏輯分離,如範例應用程式所用的結構:
app/src/main/
├── java/com/example/app/
│ ├── MainActivity.kt // Entry point
│ ├── WebGpuSurface.kt // Composable Surface
│ └── WebGpuRenderer.kt // Pure WebGPU logic
- MainActivity.kt:應用程式進入點。這會將內容設為
WebGpuSurface可組合項。 - WebGpuSurface.kt:使用
[AndroidExternalSurface](/reference/kotlin/androidx/compose/foundation/package-summary#AndroidExternalSurface(androidx.compose.ui.Modifier,kotlin.Boolean,androidx.compose.ui.unit.IntSize,androidx.compose.foundation.AndroidExternalSurfaceZOrder,kotlin.Boolean,kotlin.Function1))定義 UI 元件。這個類別會管理Surface生命週期範圍,在表面準備就緒時初始化算繪器,並在表面遭到刪除時進行清理。 - WebGpuRenderer.kt:封裝所有 WebGPU 專屬邏輯 (裝置建立、管道設定)。與 UI 解耦,只接收繪製所需的
[Surface](/reference/android/view/Surface.html)和尺寸。
生命週期與資源管理
生命週期管理作業是由 Jetpack Compose 內 [AndroidExternalSurface](/reference/kotlin/androidx/compose/foundation/package-summary#AndroidExternalSurface(androidx.compose.ui.Modifier,kotlin.Boolean,androidx.compose.ui.unit.IntSize,androidx.compose.foundation.AndroidExternalSurfaceZOrder,kotlin.Boolean,kotlin.Function1)) 提供的 Kotlin 協同程式範圍處理。
- 介面建立:在
onSurfacelambda 區塊的開頭初始化Device和Surface設定。Surface可用時,這段程式碼會立即執行。 - 介面終止:使用者離開或系統終止
Surface時,系統會取消 lambda 區塊。系統會執行finally區塊,呼叫renderer.cleanup()以防止記憶體流失。 - 調整大小:如果表面尺寸變更,
AndroidExternalSurface可能會重新啟動區塊或直接處理更新 (視設定而定),因此算繪器一律會寫入有效的緩衝區。
偵錯與驗證
WebGPU 具有驗證輸入結構和擷取執行階段錯誤的機制。
- Logcat:驗證錯誤會列印到 Android Logcat。
- 錯誤範圍:您可以將 GPU 指令封裝在
[device.pushErrorScope()](/reference/kotlin/androidx/webgpu/GPUDevice#pushErrorScope(kotlin.Int))和 `device.popErrorScope() 區塊中,擷取特定錯誤。
device.pushErrorScope(ErrorFilter.Validation)
// ... potentially incorrect code ...
device.popErrorScope { status, type, message ->
if (status == PopErrorScopeStatus.Success && type != ErrorType.NoError) {
Log.e("WebGPU", "Validation Error: $message")
}
}
效能提升秘訣
使用 WebGPU 程式設計時,請注意下列事項,避免效能瓶頸:
- 避免在每個影格建立物件:在應用程式設定期間,將管道 (
GPURenderPipeline)、繫結群組版面配置和著色器模組執行個體化一次,盡量重複使用。 - 最佳化緩衝區用量:透過
GPUQueue.writeBuffer更新現有GPUBuffers的內容,而非在每個影格建立新的緩衝區。 - 減少狀態變化:將共用相同管道的繪圖呼叫分組,並繫結群組,以盡量減少驅動程式的負擔,並提升算繪效率。