example-runner-wgpu: transition from ndk-glue to android-activity.

This commit is contained in:
Eduard-Mihai Burtescu 2023-03-22 18:29:05 +02:00 committed by Eduard-Mihai Burtescu
parent a9472a0743
commit 9cd0b2759f
9 changed files with 154 additions and 159 deletions

View File

@ -116,7 +116,7 @@ jobs:
echo "::endgroup::"
echo "::group::Build WGPU example for Android"
cargo apk build -p example-runner-wgpu --features use-installed-tools --no-default-features
cargo apk build -p example-runner-wgpu --lib --features use-installed-tools --no-default-features
echo "::endgroup::"
lint:

165
Cargo.lock generated
View File

@ -77,6 +77,24 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
[[package]]
name = "android_log-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e"
[[package]]
name = "android_logger"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8619b80c242aa7bd638b5c7ddd952addeecb71f69c75e33f1d47b2804f8f883a"
dependencies = [
"android_log-sys",
"env_logger",
"log",
"once_cell",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@ -157,7 +175,7 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"hermit-abi 0.1.19",
"libc",
"winapi",
]
@ -310,7 +328,7 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim 0.8.0",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
@ -558,41 +576,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "darling"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim 0.10.0",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "derivative"
version = "2.2.0"
@ -670,12 +653,12 @@ dependencies = [
[[package]]
name = "env_logger"
version = "0.9.0"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"atty",
"humantime",
"is-terminal",
"log",
"regex",
"termcolor",
@ -731,13 +714,13 @@ dependencies = [
name = "example-runner-wgpu"
version = "0.0.0"
dependencies = [
"android_logger",
"bytemuck",
"cfg-if",
"console_error_panic_hook",
"console_log",
"env_logger",
"futures",
"ndk-glue",
"shared",
"spirv-builder",
"structopt",
@ -794,12 +777,6 @@ dependencies = [
"miniz_oxide 0.4.4",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
@ -1069,6 +1046,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "hexf-parse"
version = "0.2.1"
@ -1081,12 +1064,6 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "indexmap"
version = "1.9.2"
@ -1139,6 +1116,18 @@ dependencies = [
"windows-sys 0.45.0",
]
[[package]]
name = "is-terminal"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e"
dependencies = [
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys 0.45.0",
]
[[package]]
name = "itertools"
version = "0.10.5"
@ -1464,35 +1453,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
[[package]]
name = "ndk-glue"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f"
dependencies = [
"libc",
"log",
"ndk",
"ndk-context",
"ndk-macro",
"ndk-sys",
"once_cell",
"parking_lot 0.12.1",
]
[[package]]
name = "ndk-macro"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
dependencies = [
"darling",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ndk-sys"
version = "0.4.1+23.1.7779620"
@ -1568,7 +1528,7 @@ version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"hermit-abi 0.1.19",
"libc",
]
@ -1688,17 +1648,6 @@ dependencies = [
"ttf-parser",
]
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core 0.8.5",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
@ -1706,21 +1655,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.7",
]
[[package]]
name = "parking_lot_core"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall 0.2.10",
"smallvec",
"winapi",
"parking_lot_core",
]
[[package]]
@ -2387,12 +2322,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "structopt"
version = "0.3.25"
@ -2793,7 +2722,7 @@ dependencies = [
"js-sys",
"log",
"naga",
"parking_lot 0.11.2",
"parking_lot",
"profiling",
"raw-window-handle 0.5.1",
"smallvec",
@ -2817,7 +2746,7 @@ dependencies = [
"codespan-reporting",
"log",
"naga",
"parking_lot 0.11.2",
"parking_lot",
"profiling",
"raw-window-handle 0.5.1",
"rustc-hash",
@ -2855,7 +2784,7 @@ dependencies = [
"metal",
"naga",
"objc",
"parking_lot 0.11.2",
"parking_lot",
"profiling",
"range-alloc",
"raw-window-handle 0.5.1",

34
android.nix Normal file
View File

@ -0,0 +1,34 @@
# HACK(eddyb) this is a minimal setup to allow testing the Android build on NixOS.
#
# Tested in `NIXPKGS_ACCEPT_ANDROID_SDK_LICENSE=1 nix-shell android.nix --pure`,
# by running the following commands (x64 target is for the Android Emulator):
# rustup target add aarch64-linux-android x86_64-linux-android
# cargo apk build -p example-runner-wgpu --target aarch64-linux-android
# cargo apk build -p example-runner-wgpu --target x86_64-linux-android
#
# (you can also replace `cargo apk build` with `cargo apk run` to launch it,
# via `adb`, into either the Android Emulator, or a physical Android device)
let
pkgs = import <nixpkgs> {};
in with pkgs; mkShell rec {
# Workaround for https://github.com/NixOS/nixpkgs/issues/60919.
# NOTE(eddyb) needed only in debug mode (warnings about needing optimizations
# turn into errors due to `-Werror`, for at least `spirv-tools-sys`).
hardeningDisable = [ "fortify" ];
# Allow cargo to download crates (even inside `nix-shell --pure`).
SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt";
nativeBuildInputs = [ rustup cargo-apk jdk ];
ANDROID_SDK_ROOT = let
androidComposition = androidenv.composeAndroidPackages {
abiVersions = [ "arm64-v8a" "x86_64" ];
includeNDK = true;
platformVersions = [ "30" ];
};
in "${androidComposition.androidsdk}/libexec/android-sdk";
ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle";
}

View File

@ -22,19 +22,19 @@ shared = { path = "../../shaders/shared" }
futures = { version = "0.3", default-features = false, features = ["std", "executor"] }
# Vulkan SDK or MoltenVK needs to be installed for `vulkan-portability` to work on macOS
wgpu = { git = "https://github.com/gfx-rs/wgpu", features = ["spirv", "vulkan-portability"] }
winit = "0.28.3"
winit = { version = "0.28.3", features = ["android-native-activity"] }
structopt = "0.3"
strum = { version = "0.23.0", default_features = false, features = ["std", "derive"] }
bytemuck = "1.6.3"
[target.'cfg(not(any(target_os = "android", target_arch = "wasm32")))'.dependencies]
env_logger = "0.10.0"
spirv-builder = { workspace = true, features = ["watch"] }
[target.'cfg(target_os = "android")'.dependencies]
ndk-glue = "0.7.0"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
env_logger = "0.9.0"
android_logger = "0.11.0"
# NOTE(eddyb) `winit` feature `android-native-activity` is always enabled above,
# to avoid specifying the dependency twice, but only applies to android builds.
[target.'cfg(target_arch = "wasm32")'.dependencies]
web-sys = "0.3.60"

View File

@ -25,7 +25,11 @@ fn main() -> Result<(), Box<dyn Error>> {
&& dir.ends_with(profile)
&& dir.pop();
assert!(ok);
let dir = dir.join("spirv-builder");
// NOTE(eddyb) this needs to be distinct from the `--target-dir` value that
// `spirv-builder` generates in a similar way from `$OUT_DIR` and `$PROFILE`,
// otherwise repeated `cargo build`s will cause build script reruns and the
// rebuilding of `rustc_codegen_spirv` (likely due to common proc macro deps).
let dir = dir.join("example-runner-wgpu-builder");
let status = std::process::Command::new("cargo")
.args([
"run",

View File

@ -1,3 +1,10 @@
#[cfg(target_os = "android")]
const _: () = panic!(
"executable not applicable for Android targets, \
make sure to pass `--lib` when building with `cargo-apk`"
);
fn main() {
#[cfg(not(target_os = "android"))]
example_runner_wgpu::main();
}

View File

@ -1,22 +1,14 @@
use wgpu::util::DeviceExt;
use super::Options;
use std::{convert::TryInto, future::Future, time::Duration};
fn block_on<T>(future: impl Future<Output = T>) -> T {
cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
wasm_bindgen_futures::spawn_local(future)
} else {
futures::executor::block_on(future)
}
}
}
use std::{convert::TryInto, time::Duration};
pub fn start(options: &Options) {
env_logger::init();
let shader_binary = crate::maybe_watch(options.shader, None);
block_on(start_internal(options, shader_binary));
futures::executor::block_on(start_internal(options, shader_binary));
}
pub async fn start_internal(

View File

@ -369,17 +369,41 @@ fn create_pipeline(
}
#[allow(clippy::match_wild_err_arm)]
pub fn start(options: &Options) {
pub fn start(
#[cfg(target_os = "android")] android_app: winit::platform::android::activity::AndroidApp,
options: &Options,
) {
let mut event_loop_builder = EventLoopBuilder::with_user_event();
cfg_if::cfg_if! {
if #[cfg(target_os = "android")] {
android_logger::init_once(
android_logger::Config::default()
.with_min_level("info".parse().unwrap()),
);
use winit::platform::android::EventLoopBuilderExtAndroid;
event_loop_builder.with_android_app(android_app);
} else if #[cfg(target_arch = "wasm32")] {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
} else {
env_logger::init();
}
}
let event_loop = event_loop_builder.build();
// Build the shader before we pop open a window, since it might take a while.
let event_loop = EventLoopBuilder::with_user_event().build();
let proxy = event_loop.create_proxy();
let initial_shader = maybe_watch(
options.shader,
Some(Box::new(move |res| match proxy.send_event(res) {
Ok(it) => it,
// ShaderModuleDescriptor is not `Debug`, so can't use unwrap/expect
Err(_err) => panic!("Event loop dead"),
})),
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
{
let proxy = event_loop.create_proxy();
Some(Box::new(move |res| match proxy.send_event(res) {
Ok(it) => it,
// ShaderModuleDescriptor is not `Debug`, so can't use unwrap/expect
Err(_err) => panic!("Event loop dead"),
}))
},
);
let window = winit::window::WindowBuilder::new()
@ -390,8 +414,6 @@ pub fn start(options: &Options) {
cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init().expect("could not initialize logger");
use winit::platform::web::WindowExtWebSys;
// On wasm, append the canvas to the document body
web_sys::window()

View File

@ -73,7 +73,10 @@
use structopt::StructOpt;
use strum::{Display, EnumString};
// NOTE(eddyb) while this could theoretically work on the web, it needs more work.
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
mod compute;
mod graphics;
#[derive(EnumString, Display, PartialEq, Eq, Copy, Clone)]
@ -86,7 +89,9 @@ pub enum RustGPUShader {
fn maybe_watch(
shader: RustGPUShader,
on_watch: Option<Box<dyn FnMut(wgpu::ShaderModuleDescriptor<'static>) + Send + 'static>>,
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))] on_watch: Option<
Box<dyn FnMut(wgpu::ShaderModuleDescriptor<'static>) + Send + 'static>,
>,
) -> wgpu::ShaderModuleDescriptor<'static> {
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
{
@ -145,10 +150,6 @@ fn maybe_watch(
}
}
fn is_compute_shader(shader: RustGPUShader) -> bool {
shader == RustGPUShader::Compute
}
#[derive(StructOpt)]
#[structopt(name = "example-runner-wgpu")]
pub struct Options {
@ -156,14 +157,20 @@ pub struct Options {
shader: RustGPUShader,
}
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
pub fn main() {
env_logger::init();
#[cfg_attr(target_os = "android", export_name = "android_main")]
pub fn main(
#[cfg(target_os = "android")] android_app: winit::platform::android::activity::AndroidApp,
) {
let options: Options = Options::from_args();
if is_compute_shader(options.shader) {
compute::start(&options);
} else {
graphics::start(&options);
#[cfg(not(any(target_os = "android", target_arch = "wasm32")))]
if options.shader == RustGPUShader::Compute {
return compute::start(&options);
}
graphics::start(
#[cfg(target_os = "android")]
android_app,
&options,
);
}