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

Get raw window handle only after Resume event #3639

Closed
wants to merge 3 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
17 changes: 1 addition & 16 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", "examples/android", "tools/ci", "errors"]

[features]
default = [
Expand Down Expand Up @@ -497,18 +497,3 @@ 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
5 changes: 2 additions & 3 deletions crates/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use bevy_render::{
},
render_resource::*,
renderer::RenderDevice,
texture::TextureCache,
texture::{TextureCache, DEFAULT_DEPTH_FORMAT},
view::{ExtractedView, Msaa, ViewDepthTexture},
RenderApp, RenderStage, RenderWorld,
};
Expand Down Expand Up @@ -384,8 +384,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 @@ -150,7 +150,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
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bevy_render::{
render_phase::{EntityRenderCommand, RenderCommandResult, TrackedRenderPass},
render_resource::{std140::AsStd140, *},
renderer::{RenderDevice, RenderQueue},
texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo},
texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo, DEFAULT_DEPTH_FORMAT},
view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms},
RenderApp, RenderStage,
};
Expand Down Expand Up @@ -527,7 +527,7 @@ impl SpecializedPipeline 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
35 changes: 12 additions & 23 deletions crates/bevy_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub mod prelude {
};
}

use bevy_utils::tracing::debug;
use bevy_utils::tracing::{debug, info};
pub use once_cell;

use crate::{
Expand Down Expand Up @@ -113,35 +113,23 @@ impl Plugin for RenderPlugin {
.get_resource::<options::WgpuOptions>()
.cloned()
.unwrap_or_default();

app.add_asset::<Shader>()
.init_asset_loader::<ShaderLoader>()
.register_type::<Color>();

if let Some(backends) = options.backends {
let instance = wgpu::Instance::new(backends);
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
};
let request_adapter_options = wgpu::RequestAdapterOptions {
power_preference: options.power_preference,
compatible_surface: surface.as_ref(),
..Default::default()
};
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
&instance,
&mut options,
&request_adapter_options,
));
debug!("Configured wgpu adapter Limits: {:#?}", &options.limits);
debug!("Configured wgpu adapter Features: {:#?}", &options.features);
let (device, adapter, queue) = futures_lite::future::block_on(
renderer::initialize_renderer(app, &instance, backends, &mut options),
);
info!("{:?}", adapter.get_info());
debug!("Configured wgpu adapter Limits: {:#?}", &adapter.limits());
debug!(
"Configured wgpu adapter Features: {:#?}",
&adapter.features()
);
app.insert_resource(device.clone())
.insert_resource(adapter.clone())
.insert_resource(queue.clone())
.insert_resource(options.clone())
.init_resource::<ScratchRenderWorld>()
Expand Down Expand Up @@ -170,6 +158,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(options)
.insert_resource(render_pipeline_cache)
Expand Down
95 changes: 84 additions & 11 deletions crates/bevy_render/src/renderer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod graph_runner;
mod render_device;

use bevy_utils::tracing::{info, info_span};
use bevy_utils::tracing::info_span;
pub use graph_runner::*;
pub use render_device::*;

Expand All @@ -12,7 +12,7 @@ use crate::{
};
use bevy_ecs::prelude::*;
use std::sync::Arc;
use wgpu::{CommandEncoder, Instance, Queue, RequestAdapterOptions};
use wgpu::{Adapter, 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 @@ -57,6 +57,8 @@ 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;
Expand All @@ -69,16 +71,86 @@ pub const DEFAULT_DISABLED_WGPU_FEATURES: wgpu::Features = wgpu::Features::MAPPA
/// 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: &mut WgpuOptions,
request_adapter_options: &RequestAdapterOptions<'_>,
) -> (RenderDevice, RenderQueue) {
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) {
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);

info!("{:?}", adapter.get_info());
for (i, adapter) in adapters.iter().enumerate() {
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)
}
}
Comment on lines +120 to +127
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it's a copy-pasted code from wgpu. But we should enumerate adapters here to make sure that we can use default texture format and default depth format as a render target for the selected adapter (for example, on my Android device Vulkan adapter can't use Depth32Float as a render target). request adapter just return first adapter which meets requirements of RequestAdapterOptions.

Copy link
Member

@mockersf mockersf Jan 17, 2022

Choose a reason for hiding this comment

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

that makes me sad... I think we should either:

  • switch from Depth32Float to Depth24Plus as the comment suggest, and which should be supported on Vulkan android (maybe with a cfg to check target architecture?)
  • upstream to wgpu a way to select an adapter based on the texture format it supports

Copy link
Contributor Author

Choose a reason for hiding this comment

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

switch from Depth32Float to Depth24Plus as the comment suggest, and which should be supported on Vulkan android (maybe with a cfg to check target architecture?)

As far as I know, only VK_FORMAT_D16_UNORM supported across all Vulkan powered devices (99% based on gpuinfo https://vulkan.gpuinfo.org/listoptimaltilingformats.php?platform=android)

upstream to wgpu a way to select an adapter based on the texture format it supports

request_adapter is implemented following by WebGPU spec. I don't think we can change it.

That's why wgpu-rs exposed enumerate_adapters function. It's allowed users to select adapter based on their options. Perhaps in the future, we will need to check if the adapter supports any other features.

Copy link
Member

Choose a reason for hiding this comment

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

Should we really be picking devices based on what texture / depth formats they support? That seems like a pretty trivial criteria relative to things like gpu features and performance. Wouldn't it make more sense to do runtime queries of supported formats and then pick the best one? Every device will support "something".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@cart I implemented this behavior because bevy uses Depth32Float as a default depth format and it's required for bevy_renderer. When I tested this on a real device, it have Depth32Float format on OpenGL adapter, but Vulkan adapter doesn't support it. (Android 8.0).

We can remove this part from PR. It unblocks some Android devices (maybe most of the devices, but definitely not all of them).

Copy link
Member

Choose a reason for hiding this comment

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

Yeah short term if we can move this forward without this behavior I think we should. I do acknowledge that this is a problem that needs solving, but I think it should be solved via querying supported depth formats at runtime after we've selected our device based on more substantial criteria.

Anything that currently consumes hard-coded Depth32Float constants could call something like RenderDevice::get_preferred_depth_format() instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Anything that currently consumes hard-coded Depth32Float constants could call something like RenderDevice::get_preferred_depth_format() instead.

Sorry, maybe I confused you. We can query depth format only from adapter (correct me, if I'am wrong). For example, on real device:

  1. Create instance with Vulkan and GL backend
  2. Enumerate adapters:
    1. Vulkan (Depth32Float is not available)
    2. OpenGL (Depth32Float is available)

What we should do in this case?

Copy link
Member

Choose a reason for hiding this comment

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

We would choose vulkan (if that is what wgpu recommends based on the wgpu config) and pick a different depth format supported by the device.

.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 Down Expand Up @@ -108,9 +180,10 @@ pub async fn initialize_renderer(
)
.await
.unwrap();
let adapter = Arc::new(adapter);
let device = Arc::new(device);
let queue = Arc::new(queue);
(RenderDevice::from(device), queue)
(RenderDevice::from(device), adapter, queue)
}

/// 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 @@ -43,6 +43,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
9 changes: 7 additions & 2 deletions crates/bevy_render/src/view/window.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
render_resource::TextureView,
renderer::{RenderDevice, RenderInstance},
renderer::{RenderAdapter, RenderDevice, RenderInstance},
texture::BevyDefault,
RenderApp, RenderStage, RenderWorld,
};
Expand Down Expand Up @@ -120,6 +120,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 +134,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
13 changes: 8 additions & 5 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,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 @@ -495,12 +497,12 @@ pub fn winit_runner_with(mut app: App) {
active = true;
}
event::Event::MainEventsCleared => {
handle_create_window_events(
&mut app.world,
event_loop,
&mut create_window_event_reader,
);
if active {
handle_create_window_events(
&mut app.world,
event_loop,
&mut create_window_event_reader,
);
app.update();
}
}
Expand Down Expand Up @@ -537,6 +539,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_resource_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 @@ -277,7 +277,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 @@ -299,18 +300,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
Loading