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

Android: handle suspend / resume #9937

Merged
merged 4 commits into from
Oct 2, 2023
Merged
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
14 changes: 14 additions & 0 deletions crates/bevy_render/src/view/window/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ fn extract_windows(
screenshot_manager: Extract<Res<ScreenshotManager>>,
mut closed: Extract<EventReader<WindowClosed>>,
windows: Extract<Query<(Entity, &Window, &RawHandleWrapper, Option<&PrimaryWindow>)>>,
mut removed: Extract<RemovedComponents<RawHandleWrapper>>,
mut window_surfaces: ResMut<WindowSurfaces>,
) {
for (entity, window, handle, primary) in windows.iter() {
if primary.is_some() {
Expand Down Expand Up @@ -163,6 +165,11 @@ fn extract_windows(

for closed_window in closed.read() {
extracted_windows.remove(&closed_window.window);
window_surfaces.remove(&closed_window.window);
}
for removed_window in removed.read() {
extracted_windows.remove(&removed_window);
window_surfaces.remove(&removed_window);
}
// This lock will never block because `callbacks` is `pub(crate)` and this is the singular callsite where it's locked.
// Even if a user had multiple copies of this system, since the system has a mutable resource access the two systems would never run
Expand All @@ -187,6 +194,13 @@ pub struct WindowSurfaces {
configured_windows: HashSet<Entity>,
}

impl WindowSurfaces {
fn remove(&mut self, window: &Entity) {
self.surfaces.remove(window);
self.configured_windows.remove(window);
}
}

/// Creates and (re)configures window surfaces, and obtains a swapchain texture for rendering.
///
/// NOTE: `get_current_texture` in `prepare_windows` can take a long time if the GPU workload is
Expand Down
53 changes: 47 additions & 6 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ use bevy_window::{
WindowCloseRequested, WindowCreated, WindowDestroyed, WindowFocused, WindowMoved,
WindowResized, WindowScaleFactorChanged, WindowThemeChanged,
};
#[cfg(target_os = "android")]
use bevy_window::{PrimaryWindow, RawHandleWrapper};

#[cfg(target_os = "android")]
pub use winit::platform::android::activity::AndroidApp;
Expand Down Expand Up @@ -664,16 +666,55 @@ pub fn winit_runner(mut app: App) {
runner_state.is_active = false;
#[cfg(target_os = "android")]
{
// Android sending this event invalidates all render surfaces.
// TODO
// Upon resume, check if the new render surfaces are compatible with the
// existing render device. If not (which should basically never happen),
// then try to rebuild the renderer.
*control_flow = ControlFlow::Exit;
// Remove the `RawHandleWrapper` from the primary window.
// This will trigger the surface destruction.
let mut query = app.world.query_filtered::<Entity, With<PrimaryWindow>>();
let entity = query.single(&app.world);
app.world.entity_mut(entity).remove::<RawHandleWrapper>();
*control_flow = ControlFlow::Wait;
}
}
event::Event::Resumed => {
runner_state.is_active = true;
#[cfg(target_os = "android")]
{
// Get windows that are cached but without raw handles. Those window were already created, but got their
// handle wrapper removed when the app was suspended.
let mut query = app
.world
.query_filtered::<(Entity, &Window), (With<CachedWindow>, Without<bevy_window::RawHandleWrapper>)>();
if let Ok((entity, window)) = query.get_single(&app.world) {
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
let window = window.clone();

let (
_,
_,
_,
mut winit_windows,
mut adapters,
mut handlers,
accessibility_requested,
) = create_window_system_state.get_mut(&mut app.world);

let winit_window = winit_windows.create_window(
event_loop,
entity,
&window,
&mut adapters,
&mut handlers,
&accessibility_requested,
);

let wrapper = RawHandleWrapper {
window_handle: winit_window.raw_window_handle(),
display_handle: winit_window.raw_display_handle(),
};

app.world.entity_mut(entity).insert(wrapper);
}
*control_flow = ControlFlow::Poll;
}
}
event::Event::MainEventsCleared => {
if runner_state.is_active {
Expand Down