Allow late initialization of render state

This commit is contained in:
Maximilian Ammann 2022-04-23 18:37:12 +02:00
parent c289c184d3
commit 630a1e4bf7
3 changed files with 143 additions and 104 deletions

View File

@ -31,7 +31,7 @@ pub struct MapState<W> {
camera: ChangeObserver<camera::Camera>,
perspective: camera::Perspective,
render_state: RenderState,
render_state: Option<RenderState>,
scheduler: Scheduler,
message_receiver: mpsc::Receiver<TessellateMessage>,
shared_thread_state: SharedThreadState,
@ -46,7 +46,7 @@ impl<W> MapState<W> {
pub fn new(
window: W,
window_size: WindowSize,
render_state: RenderState,
render_state: Option<RenderState>,
scheduler: Scheduler,
style: Style,
) -> Self {
@ -100,7 +100,7 @@ impl<W> MapState<W> {
self.prepare_render();
// Render buffers
let result = self.render_state.render();
let result = self.render_state_mut().render();
#[cfg(all(feature = "enable-tracing", not(target_arch = "wasm32")))]
tracy_client::finish_continuous_frame!();
@ -170,13 +170,12 @@ impl<W> MapState<W> {
drop(_guard);
if let Some(view_region) = &view_region {
self.render_state
.upload_tile_geometry(view_region, &self.style, &self.tile_cache);
self.render_state.as_mut().expect("render state not yet initialized. Call reinitialize().").upload_tile_geometry(view_region, &self.style, &self.tile_cache);
self.render_state
.update_tile_view_pattern(view_region, &view_proj, self.zoom());
let zoom = self.zoom();
self.render_state_mut().update_tile_view_pattern(view_region, &view_proj, zoom);
self.render_state.update_metadata();
self.render_state_mut().update_metadata();
}
// TODO: Could we draw inspiration from StagingBelt (https://docs.rs/wgpu/latest/wgpu/util/struct.StagingBelt.html)?
@ -188,7 +187,7 @@ impl<W> MapState<W> {
self.try_failed = self.request_tiles_in_view(view_region);
}
self.render_state.update_globals(&view_proj, &self.camera);
self.render_state().update_globals(&view_proj, &self.camera);
}
self.camera.update_reference();
@ -253,7 +252,7 @@ impl<W> MapState<W> {
self.perspective.resize(width, height);
self.camera.resize(width, height);
self.render_state.resize(width, height)
self.render_state_mut().resize(width, height)
}
pub fn scheduler(&self) -> &Scheduler {
@ -289,11 +288,19 @@ impl<W> MapState<W> {
}
pub fn suspend(&mut self) {
self.render_state.suspend();
self.render_state_mut().suspend();
}
pub fn resume(&mut self) {
self.render_state.resume();
self.render_state_mut().resume();
}
pub fn render_state(&self) -> &RenderState {
self.render_state.as_ref().expect("render state not yet initialized. Call reinitialize().")
}
pub fn render_state_mut(&mut self) -> &'_ mut RenderState {
self.render_state.as_mut().unwrap()
}
}
@ -302,6 +309,18 @@ where
W: raw_window_handle::HasRawWindowHandle,
{
pub fn recreate_surface(&mut self) {
self.render_state.recreate_surface(&self.window);
self.render_state.as_mut().expect("render state not yet initialized. Call reinitialize().").recreate_surface(&self.window);
}
pub fn is_initialized(&self) -> bool {
self.render_state.is_some()
}
pub async fn reinitialize(&mut self) {
if self.render_state.is_none() {
let window_size = WindowSize::new(100, 100).unwrap(); // TODO get size
let render_state = RenderState::initialize(&self.window, window_size);
self.render_state = Some(render_state.await.unwrap())
}
}
}

View File

@ -68,11 +68,12 @@ impl RenderState {
pub async fn initialize<W: raw_window_handle::HasRawWindowHandle>(
window: &W,
window_size: WindowSize,
) -> Self {
) -> Option<Self> {
let sample_count = 4;
//let instance = wgpu::Instance::new(wgpu::Backends::GL);
let instance = wgpu::Instance::new(wgpu::Backends::all());
//let instance = wgpu::Instance::new(wgpu::Backends::all());
let instance = wgpu::Instance::new(wgpu::Backends::VULKAN);
let surface = unsafe { instance.create_surface(&window) };
let surface_config = wgpu::SurfaceConfiguration {
@ -101,7 +102,13 @@ impl RenderState {
} else if cfg!(target_os = "android") {
Limits {
max_storage_textures_per_shader_stage: 4,
..wgpu::Limits::default()
max_compute_workgroups_per_dimension: 0,
max_compute_workgroup_size_z: 0,
max_compute_workgroup_size_y: 0,
max_compute_workgroup_size_x: 0,
max_compute_workgroup_storage_size: 0,
max_compute_invocations_per_workgroup: 0,
..wgpu::Limits::downlevel_defaults()
}
} else {
Limits {
@ -125,8 +132,7 @@ impl RenderState {
},
None,
)
.await
.unwrap();
.await.ok()?;
surface.configure(&device, &surface_config);
@ -245,7 +251,7 @@ impl RenderState {
None
};
Self {
Some(Self {
instance,
surface,
device,
@ -270,7 +276,7 @@ impl RenderState {
tile_view_buffer,
TILE_VIEW_BUFFER_SIZE,
)),
}
})
}
pub fn recreate_surface<W: raw_window_handle::HasRawWindowHandle>(&mut self, window: &W) {

View File

@ -23,6 +23,20 @@ impl Runnable<winit::event_loop::EventLoop<()>> for MapState<winit::window::Wind
let mut input_controller = InputController::new(0.2, 100.0, 0.1);
event_loop.run(move |event, _, control_flow| {
#[cfg(target_os = "android")]
if !self.is_initialized() && event == Event::Resumed {
use tokio::runtime::Handle;
use tokio::task;
let state = task::block_in_place(|| {
Handle::current().block_on(async {
self.reinitialize().await;
})
});
return;
}
match event {
Event::DeviceEvent {
ref event,
@ -70,12 +84,12 @@ impl Runnable<winit::event_loop::EventLoop<()>> for MapState<winit::window::Wind
Ok(_) => {}
Err(wgpu::SurfaceError::Lost) => {
log::error!("Surface Lost");
},
}
// The system is out of memory, we should probably quit
Err(wgpu::SurfaceError::OutOfMemory) => {
log::error!("Out of Memory");
*control_flow = ControlFlow::Exit;
},
}
// All other errors (Outdated, Timeout) should be resolved by the next frame
Err(e) => eprintln!("{:?}", e),
};
@ -121,7 +135,7 @@ impl FromWindow for MapBuilder<winit::window::Window, winit::event_loop::EventLo
let size = window.inner_size();
(
window,
WindowSize::new(size.width, size.height).unwrap(),
WindowSize::new(100, 100).unwrap(),
event_loop,
)
}))