如需使用 Jetpack WebGPU,您的项目必须满足以下最低要求:
- Minimum API Level:需要 Android API 24 (Nougat) 或更高级别。
- 硬件:后端最好使用支持 Vulkan 1.1 及更高版本的设备。
- 兼容模式和 OpenGL ES 支持:通过在请求
GPUAdapter时将标准化的featureLevel选项设置为compatibility,即可在兼容模式下使用 WebGPU。
// 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”)。
- Package Name:验证软件包名称是否与您选择的命名空间一致(例如 com.example.webgpuapp)。
- 语言:选择 Kotlin。
- Minimum SDK:选择 API 24: Android 7.0 (Nougat) 或更高版本,这是此库的建议设置。
- Build Configuration Language:建议使用 Kotlin DSL (build.gradle.kts) 进行现代依赖项管理。
图 2. 从空白 activity 开始 完成:点击 Finish,然后等待 Android Studio 同步您的项目文件。
添加 WebGPU Jetpack 库
- 按照在应用中使用 Jetpack 库中的说明,将
google代码库添加到settings.gradle - 在应用或模块的 build.gradle 文件中添加所需工件的依赖项:
- 注意:请参阅 webgpu | Jetpack | Android 开发者,了解最新的库版本
androidx.webgpu 库包含 WebGPU NDK .so 库文件以及受管理的接口。
您可以通过更新 build.gradle 并使用 Android Studio 中的“同步项目”按钮将项目与 Gradle 文件同步来更新库版本。
高级架构
Android 应用中的 WebGPU 渲染在专用渲染线程上运行,以保持界面响应速度。
- 界面层:界面使用 Jetpack Compose 构建。WebGPU 绘制界面使用
AndroidExternalSurface集成到 Compose 层次结构中。 - 渲染逻辑:一种专用类(例如,WebGpuRenderer) 负责管理所有 WebGPU 对象并协调渲染循环。
- 着色器层:存储在 res 或字符串常量中的 WGSL 着色器代码。
分步说明:示例应用
本部分将逐步介绍在屏幕上渲染彩色三角形所需的基本步骤,演示核心 WebGPU 工作流。
主要 activity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
WebGpuSurface()
}
}
}
外部界面可组合项
创建一个名为 WebgpuSurface.kt 的新文件。此可组合项封装了 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()
}
}
}
}
}
设置渲染器
在 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 在 surface 被销毁时调用。
// Inside WebGpuRenderer class
fun cleanup() {
if (::webGpu.isInitialized) {
webGpu.close()
}
}
呈现的输出
示例应用结构
最好将渲染实现与界面逻辑分离,如示例应用所用的结构:
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))定义界面组件。它管理Surface生命周期范围,在 surface 准备就绪时初始化渲染器,并在其销毁时进行清理。 - WebGpuRenderer.kt:封装了所有特定于 WebGPU 的逻辑(设备创建、流水线设置)。它与界面分离,仅接收绘制所需的
[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 销毁:当用户离开或
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的内容,而不是每帧都创建新的缓冲区。 - 尽量减少状态变化:将共享同一流水线的绘制调用和绑定组分组,以尽量减少驱动程序开销并提高渲染效率。