wgpu 与 Android App 集成

本文介绍了如何在Android应用中集成wgpu,包括配置开发环境、添加安卓构建目标、自定义窗口对象、定义FFI、实现cargo so子命令、编译为.so库文件以及自定义WGPUSurfaceView。通过这些步骤,可以实现在Android平台上进行图形渲染和使用着色器。
摘要由CSDN通过智能技术生成

开发环境配置

假设你的电脑上已经安装了 Android Studio,从菜单栏打开 SDK 管理器(Tools > SDK Manager > Android SDK > SDK Tools),勾选以下 3 个选项后点击 OK 按钮确认:

  • Android SDK Build-Tools
  • Android SDK Command-line Tools
  • NDK(Side by side)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wWm6NsMo-1672380557233)(https://upload-images.jianshu.io/upload_images/1787140-1585199b2e673d7b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

然后,设置如下两个系统环境变量:

export ANDROID_SDK_ROOT=$HOME/Library/Android/sdk
# 注意,此处需要替换为你电脑上安装的 NDK 的版本号
export NDK_HOME=$ANDROID_SDK_ROOT/ndk/23.1.7779620

添加安卓构建目标支持

到目前为止,Android 模拟器和虚拟设备还不支持 Vulkan 图形 API(仅支持 OpenGL ES),所以开发或调试 wgpu 程序在 Android 系统上的运行时,建议使用真机(各种云测平台的云真机也行)。

如果需要支持模拟器运行,还得加上 x86_64-linux-androidi686-linux-android 这两个构建目标的支持。需要注意的是,如果指定了 wgpu 项目使用 Vulkan 图形后端(Instance::new(wgpu::Backends::VULKAN)),则在模拟内运行时会崩溃:

rustup target add aarch64-linux-android armv7-linux-androideabi

自定义窗口对象

要实现一个 wgpu 里能使用的窗口对象,就必须实现 raw-window-handle 中 raw_window_handle() raw_display_handle() 这两个分别定义在 HasRawWindowHandle HasRawDisplayHandle trait 里的抽象接口。

实现 raw_display_handle() 最为简单, 只需要实例化一个空的 AndroidDisplayHandle 对象做为参数。查看 raw-window-handle 的源码就会发现,实现 raw_window_handle() 抽象接口需要用到 AndroidNdkWindowHandle 对象,此对象有一个叫 a_native_window 的字段,用来指向安卓 App 的 ANativeWindow 实例。
下面我们来一步步实现它。

先给项目添加必要的依赖:

[target.'cfg(target_os = "android")'.dependencies]
jni = "0.19"
# 星号表示不锁定特定版本,在项目构建及运行时始终保持使用最新版本
ndk-sys = "*"
raw-window-handle = "0.5"

然后定义一个 NativeWindow 结构体,它只有一个叫 a_native_window 的字段:

struct NativeWindow {
   
    a_native_window: *mut ndk_sys::ANativeWindow,
}
impl NativeWindow {
   
    // env 和 surface 都是安卓端传递过来的参数
    fn new(env: *mut JNIEnv, surface: jobject) -> Self {
   
        let a_native_window = unsafe {
   
            // 获取与安卓端 surface 对象关联的 ANativeWindow,以便能通过 Rust 与之交互。
            // 此函数在返回 ANativeWindow 的同时会自动将其引用计数 +1,以防止该对象在安卓端被意外释放。
            ndk_sys::ANativeWindow_fromSurface(env as *mut _, surface as *mut _)
        };
        Self {
    a_native_window }
    }
}

最后给 NativeWindow 实现 raw-window-handle 抽象接口:

unsafe impl HasRawWindowHandle for NativeWindow {
   
    fn raw_window_handle(&self) -> RawWindowHandle {
   
        let mut handle = AndroidNdkWindowHandle::empty();
        handle.a_native_window = self.a_native_window as *mut _ as *mut c_void;
        RawWindowHandle::AndroidNdk(handle)
    }
}

unsafe impl HasRawDisplayHandle for NativeWindow {
   
    fn raw_display_handle(&self) -> RawDisplayHandle {
   
        RawDisplayHandle::Android(AndroidDisplayHandle::empty())
    }
}

查看自定义窗口对象的完整源码!

定义 FFI

Rust 有一个关键字 extern(kotlin 中定义 JNI 函数时也有一个对应的关键字叫 external, 我们接下来会用到),当需要与其他语言编写的代码进行交互时,用于创建和使用外部函数接口(FFI,Foreign Function Interface)。FFI 是一种编程语言定义函数的方式,可以让不同的 ”外部“ 编程语言调用这些函数。

在 Rust 这一端,我们通过给公开函数添加 #[no_mangle] 属性来允许安卓端调用此函数:

#[no_mangle]
#[jni_fn("name.jinleili.wgpu.RustBridge")]
pub fn createWgpuCanvas(env: *mut JNIEnv, _: JClass, surface: job
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李金磊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值