Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed android instant crash #4139

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
- name: Install Cargo APK
run: cargo install --force cargo-apk
- name: Build APK
run: cargo apk build --example android
run: cd examples/android && cargo apk build

markdownlint:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -288,7 +288,7 @@ jobs:
source: './examples/'
targets: '[ "./Cargo.toml", "./examples/README.md" ]'
file-types: '[".rs"]'
exclude-folders: '["./examples/ios"]'
exclude-folders: '["./examples/ios", "./examples/android"]'
exclude-files: '[]'

check-unused-dependencies:
Expand Down
19 changes: 2 additions & 17 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ repository = "https://github.com/bevyengine/bevy"

[workspace]
exclude = ["benches", "crates/bevy_ecs_compile_fail_tests"]
members = ["crates/*", "examples/ios", "tools/ci", "errors"]
members = ["crates/*", "examples/ios", "tools/ci", "errors", "examples/android"]

[features]
default = [
Expand Down Expand Up @@ -542,19 +542,4 @@ path = "examples/window/transparent_window.rs"

[[example]]
name = "window_settings"
path = "examples/window/window_settings.rs"

# Android
[[example]]
crate-type = ["cdylib"]
name = "android"
path = "examples/android/android.rs"

[package.metadata.android]
apk_label = "Bevy Example"
assets = "assets"
res = "assets/android-res"
icon = "@mipmap/ic_launcher"
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
min_sdk_version = 16
target_sdk_version = 29
path = "examples/window/window_settings.rs"
4 changes: 2 additions & 2 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use std::ops::Range;
use bevy_app::{App, Plugin};
use bevy_core::FloatOrd;
use bevy_ecs::prelude::*;
use bevy_render::texture::DEFAULT_DEPTH_FORMAT;
use bevy_render::{
camera::{ActiveCameras, CameraPlugin, RenderTarget},
color::Color,
Expand Down Expand Up @@ -414,8 +415,7 @@ pub fn prepare_core_views_system(
mip_level_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float, /* PERF: vulkan docs recommend using 24
* bit depth for better performance */
format: DEFAULT_DEPTH_FORMAT,
usage: TextureUsages::RENDER_ATTACHMENT,
},
);
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ pub const MAX_POINT_LIGHT_SHADOW_MAPS: usize = 10;
pub const MAX_DIRECTIONAL_LIGHTS: usize = 1;
pub const POINT_SHADOW_LAYERS: u32 = (6 * MAX_POINT_LIGHT_SHADOW_MAPS) as u32;
pub const DIRECTIONAL_SHADOW_LAYERS: u32 = MAX_DIRECTIONAL_LIGHTS as u32;
pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float;
pub const SHADOW_FORMAT: TextureFormat = DEFAULT_DEPTH_FORMAT;

pub struct ShadowPipeline {
pub view_layout: BindGroupLayout,
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use bevy_ecs::{
};
use bevy_math::{Mat4, Size};
use bevy_reflect::TypeUuid;
use bevy_render::texture::DEFAULT_DEPTH_FORMAT;
use bevy_render::{
mesh::{GpuBufferInfo, Mesh, MeshVertexBufferLayout},
render_asset::RenderAssets,
Expand Down Expand Up @@ -477,7 +478,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
strip_index_format: None,
},
depth_stencil: Some(DepthStencilState {
format: TextureFormat::Depth32Float,
format: DEFAULT_DEPTH_FORMAT,
depth_write_enabled,
depth_compare: CompareFunction::Greater,
stencil: StencilState {
Expand Down
26 changes: 9 additions & 17 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,25 +122,16 @@ impl Plugin for RenderPlugin {

if let Some(backends) = options.backends {
let instance = wgpu::Instance::new(backends);
let surface = {
let windows = app.world.resource_mut::<bevy_window::Windows>();
let raw_handle = windows.get_primary().map(|window| unsafe {
let handle = window.raw_window_handle().get_handle();
instance.create_surface(&handle)
});
raw_handle
};
let request_adapter_options = wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
};
let (device, queue, adapter_info) = futures_lite::future::block_on(
renderer::initialize_renderer(&instance, &options, &request_adapter_options),
let (device, adapter, queue, adapter_info) = futures_lite::future::block_on(
renderer::initialize_renderer(app, &instance, backends, &options),
);
debug!("Configured wgpu adapter Limits: {:#?}", &adapter.limits());
debug!(
"Configured wgpu adapter Features: {:#?}",
&adapter.features()
);
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
debug!("Configured wgpu adapter Features: {:#?}", device.features());
app.insert_resource(device.clone())
.insert_resource(adapter.clone())
.insert_resource(queue.clone())
.insert_resource(adapter_info.clone())
.init_resource::<ScratchRenderWorld>()
Expand Down Expand Up @@ -169,6 +160,7 @@ impl Plugin for RenderPlugin {
.add_stage(RenderStage::Cleanup, SystemStage::parallel())
.insert_resource(instance)
.insert_resource(device)
.insert_resource(adapter)
.insert_resource(queue)
.insert_resource(adapter_info)
.insert_resource(render_pipeline_cache)
Expand Down
98 changes: 87 additions & 11 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
};
use bevy_ecs::prelude::*;
use std::sync::Arc;
use wgpu::{AdapterInfo, CommandEncoder, Instance, Queue, RequestAdapterOptions};
use wgpu::{Adapter, AdapterInfo, CommandEncoder, Instance, Queue};

/// Updates the [`RenderGraph`] with all of its nodes and then runs it to render the entire frame.
pub fn render_system(world: &mut World) {
Expand Down Expand Up @@ -72,24 +72,95 @@ pub fn render_system(world: &mut World) {
/// This queue is used to enqueue tasks for the GPU to execute asynchronously.
pub type RenderQueue = Arc<Queue>;

pub type RenderAdapter = Arc<Adapter>;

/// The GPU instance is used to initialize the [`RenderQueue`] and [`RenderDevice`],
/// aswell as to create [`WindowSurfaces`](crate::view::window::WindowSurfaces).
pub type RenderInstance = Instance;

/// Initializes the renderer by retrieving and preparing the GPU instance, device and queue
/// for the specified backend.
pub async fn initialize_renderer(
instance: &Instance,
#[cfg_attr(not(target_arch = "wasm32"), allow(unused))] app: &mut bevy_app::App,
instance: &wgpu::Instance,
#[cfg_attr(target_arch = "wasm32", allow(unused))] backends: wgpu::Backends,
options: &WgpuSettings,
request_adapter_options: &RequestAdapterOptions<'_>,
) -> (RenderDevice, RenderQueue, AdapterInfo) {
let adapter = instance
.request_adapter(request_adapter_options)
.await
.expect("Unable to find a GPU! Make sure you have installed required drivers!");
) -> (RenderDevice, RenderAdapter, RenderQueue, AdapterInfo) {
let adapter = {
#[cfg(not(target_arch = "wasm32"))]
{
use crate::texture::{BevyDefault as _, DEFAULT_DEPTH_FORMAT};
let mut adapters: Vec<wgpu::Adapter> = instance.enumerate_adapters(backends).collect();
let (mut integrated, mut discrete, mut virt, mut cpu, mut other) =
(None, None, None, None, None);

let adapter_info = adapter.get_info();
info!("{:?}", adapter_info);
for (i, adapter) in adapters.iter().enumerate() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced this is the right move. I just replied in the original thread here: https://github.com/bevyengine/bevy/pull/3639/files#r828534181

let default_texture_format_features =
adapter.get_texture_format_features(wgpu::TextureFormat::bevy_default());
let default_depth_format_features =
adapter.get_texture_format_features(DEFAULT_DEPTH_FORMAT);
if default_texture_format_features
.allowed_usages
.contains(wgpu::TextureUsages::RENDER_ATTACHMENT)
&& default_depth_format_features
.allowed_usages
.contains(wgpu::TextureUsages::RENDER_ATTACHMENT)
{
let info = adapter.get_info();
match info.device_type {
wgpu::DeviceType::IntegratedGpu => {
integrated = integrated.or(Some(i));
}
wgpu::DeviceType::DiscreteGpu => {
discrete = discrete.or(Some(i));
}
wgpu::DeviceType::VirtualGpu => {
virt = virt.or(Some(i));
}
wgpu::DeviceType::Cpu => {
cpu = cpu.or(Some(i));
}
wgpu::DeviceType::Other => {
other = other.or(Some(i));
}
}
}
}

let preferred_gpu_index = match options.power_preference {
wgpu::PowerPreference::LowPower => {
integrated.or(other).or(discrete).or(virt).or(cpu)
}
wgpu::PowerPreference::HighPerformance => {
discrete.or(other).or(integrated).or(virt).or(cpu)
}
}
.expect("Unable to find a GPU! Make sure you have installed required drivers!");

adapters.swap_remove(preferred_gpu_index)
}

#[cfg(target_arch = "wasm32")]
{
let surface = {
let world = app.world.cell();
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
let raw_handle = windows.get_primary().map(|window| unsafe {
let handle = window.raw_window_handle().get_handle();
instance.create_surface(&handle)
});
raw_handle
};
instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
})
.await
.expect("Unable to find a GPU! Make sure you have installed required drivers!")
}
};

#[cfg(feature = "wgpu_trace")]
let trace_path = {
Expand All @@ -104,6 +175,10 @@ pub async fn initialize_renderer(
// Maybe get features and limits based on what is supported by the adapter/backend
let mut features = wgpu::Features::empty();
let mut limits = options.limits.clone();

let adapter_info = adapter.get_info();
info!("{:?}", adapter_info);

if matches!(options.priority, WgpuSettingsPriority::Functionality) {
features = adapter.features() | wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
if adapter_info.device_type == wgpu::DeviceType::DiscreteGpu {
Expand Down Expand Up @@ -227,8 +302,9 @@ pub async fn initialize_renderer(
.await
.unwrap();
let device = Arc::new(device);
let adapter = Arc::new(adapter);
let queue = Arc::new(queue);
(RenderDevice::from(device), queue, adapter_info)
(RenderDevice::from(device), adapter, queue, adapter_info)
}

/// The context with all information required to interact with the GPU.
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_render/src/texture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ impl Plugin for ImagePlugin {
}
}

// PERF: vulkan docs recommend using 24 bit depth for better performance
pub const DEFAULT_DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;

pub trait BevyDefault {
fn bevy_default() -> Self;
}
Expand Down
8 changes: 7 additions & 1 deletion crates/bevy_render/src/view/window.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::renderer::RenderAdapter;
use crate::{
render_resource::TextureView,
renderer::{RenderDevice, RenderInstance},
Expand Down Expand Up @@ -120,6 +121,7 @@ pub fn prepare_windows(
_marker: NonSend<NonSendMarker>,
mut windows: ResMut<ExtractedWindows>,
mut window_surfaces: ResMut<WindowSurfaces>,
render_adapter: Res<RenderAdapter>,
render_device: Res<RenderDevice>,
render_instance: Res<RenderInstance>,
) {
Expand All @@ -133,8 +135,12 @@ pub fn prepare_windows(
render_instance.create_surface(&window.handle.get_handle())
});

let surface_format = surface
.get_preferred_format(&render_adapter)
.unwrap_or_else(TextureFormat::bevy_default);

let swap_chain_descriptor = wgpu::SurfaceConfiguration {
format: TextureFormat::bevy_default(),
format: surface_format,
width: window.physical_width,
height: window.physical_height,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ impl Plugin for WinitPlugin {
.set_runner(winit_runner)
.add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system());
let event_loop = EventLoop::new();
// TODO: Required for WebGL. Currently breaks only android initialization. Should be a part of init system
#[cfg(not(target_os = "android"))]
handle_initial_window_events(&mut app.world, &event_loop);
app.insert_non_send_resource(event_loop);
}
Expand Down Expand Up @@ -628,6 +630,7 @@ fn handle_create_window_events(
}
}

#[cfg(not(target_os = "android"))]
fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) {
let world = world.cell();
let mut winit_windows = world.get_non_send_mut::<WinitWindows>().unwrap();
Expand Down
9 changes: 3 additions & 6 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ When using `NDK (Side by side)`, the environment variable `ANDROID_NDK_ROOT` mus
To run on a device setup for Android development, run:

```sh
cargo apk run --example android
cd examples/android
cargo apk run
```

:warning: At this time Bevy does not work in Android Emulator.
Expand All @@ -309,18 +310,14 @@ Bevy by default targets Android API level 29 in its examples which is the <!-- m
[Play Store's minimum API to upload or update apps](https://developer.android.com/distribute/best-practices/develop/target-sdk). <!-- markdown-link-check-enable -->
Users of older phones may want to use an older API when testing.

To use a different API, the following fields must be updated in Cargo.toml:
To use a different API, the following fields must be updated in [Cargo.toml](./android/Cargo.toml):

```toml
[package.metadata.android]
target_sdk_version = >>API<<
min_sdk_version = >>API or less<<
```

Example | File | Description
--- | --- | ---
`android` | [`android/android.rs`](./android/android.rs) | The `3d/3d_scene.rs` example for Android

## iOS

### Setup
Expand Down
26 changes: 26 additions & 0 deletions examples/android/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "bevy_android_example"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]

[dependencies.bevy]
path = "../../"
features = ["bevy_winit", "render"]
default-features = false

[package.metadata.android]
assets = "../../assets"
resources = "../../assets/android-res"
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
min_sdk_version = 16
target_sdk_version = 29


[package.metadata.android.application]
label = "Bevy Example"
icon = "@mipmap/ic_launcher"
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use bevy::prelude::*;
#[bevy_main]
fn main() {
App::new()
.insert_resource(Msaa { samples: 2 })
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.run();
Expand Down