don't panic when swapchain frame is outdated

This commit is contained in:
Billy Messenger 2020-12-16 10:03:51 -06:00
parent a42b3c6998
commit 4e391013c8
4 changed files with 140 additions and 108 deletions

View file

@ -168,55 +168,64 @@ pub fn main() {
resized = false;
}
let frame = swap_chain.get_current_frame().expect("Next frame");
match swap_chain.get_current_frame() {
Ok(frame) => {
let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None },
);
let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None },
);
let program = state.program();
let program = state.program();
{
// We clear the frame
let mut render_pass = scene.clear(
&frame.output.view,
&mut encoder,
program.background_color(),
);
{
// We clear the frame
let mut render_pass = scene.clear(
&frame.output.view,
&mut encoder,
program.background_color(),
);
// Draw the scene
scene.draw(&mut render_pass);
}
// Draw the scene
scene.draw(&mut render_pass);
// And then iced on top
let mouse_interaction = renderer.backend_mut().draw(
&mut device,
&mut staging_belt,
&mut encoder,
&frame.output.view,
&viewport,
state.primitive(),
&debug.overlay(),
);
// Then we submit the work
staging_belt.finish();
queue.submit(Some(encoder.finish()));
// Update the mouse cursor
window.set_cursor_icon(
iced_winit::conversion::mouse_interaction(
mouse_interaction,
),
);
// And recall staging buffers
local_pool
.spawner()
.spawn(staging_belt.recall())
.expect("Recall staging buffers");
local_pool.run_until_stalled();
}
Err(error) => match error {
wgpu::SwapChainError::Outdated => {
// Try rendering again next frame.
window.request_redraw();
}
_ => panic!("Swapchain error: {:?}", error),
},
}
// And then iced on top
let mouse_interaction = renderer.backend_mut().draw(
&mut device,
&mut staging_belt,
&mut encoder,
&frame.output.view,
&viewport,
state.primitive(),
&debug.overlay(),
);
// Then we submit the work
staging_belt.finish();
queue.submit(Some(encoder.finish()));
// Update the mouse cursor
window.set_cursor_icon(
iced_winit::conversion::mouse_interaction(
mouse_interaction,
),
);
// And recall staging buffers
local_pool
.spawner()
.spawn(staging_belt.recall())
.expect("Recall staging buffers");
local_pool.run_until_stalled();
}
_ => {}
}

View file

@ -40,6 +40,9 @@ pub trait Compositor: Sized {
/// Draws the output primitives to the next frame of the given [`SwapChain`].
///
/// This will return an error if drawing could not be completed on this frame.
/// If an error occurs, try calling this again on the next frame.
///
/// [`SwapChain`]: Self::SwapChain
fn draw<T: AsRef<str>>(
&mut self,
@ -49,5 +52,5 @@ pub trait Compositor: Sized {
background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T],
) -> mouse::Interaction;
) -> Result<mouse::Interaction, ()>;
}

View file

@ -100,7 +100,7 @@ impl iced_graphics::window::Compositor for Compositor {
width: u32,
height: u32,
) -> Self::SwapChain {
self.device.create_swap_chain(
let swap_chain = self.device.create_swap_chain(
surface,
&wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT,
@ -109,7 +109,9 @@ impl iced_graphics::window::Compositor for Compositor {
width,
height,
},
)
);
swap_chain
}
fn draw<T: AsRef<str>>(
@ -120,58 +122,71 @@ impl iced_graphics::window::Compositor for Compositor {
background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T],
) -> mouse::Interaction {
let frame = swap_chain.get_current_frame().expect("Next frame");
) -> Result<mouse::Interaction, ()> {
match swap_chain.get_current_frame() {
Ok(frame) => {
let mut encoder = self.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor {
label: Some("iced_wgpu encoder"),
},
);
let mut encoder = self.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor {
label: Some("iced_wgpu encoder"),
let _ =
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[
wgpu::RenderPassColorAttachmentDescriptor {
attachment: &frame.output.view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear({
let [r, g, b, a] =
background_color.into_linear();
wgpu::Color {
r: f64::from(r),
g: f64::from(g),
b: f64::from(b),
a: f64::from(a),
}
}),
store: true,
},
},
],
depth_stencil_attachment: None,
});
let mouse_interaction = renderer.backend_mut().draw(
&mut self.device,
&mut self.staging_belt,
&mut encoder,
&frame.output.view,
viewport,
output,
overlay,
);
// Submit work
self.staging_belt.finish();
self.queue.submit(Some(encoder.finish()));
// Recall staging buffers
self.local_pool
.spawner()
.spawn(self.staging_belt.recall())
.expect("Recall staging belt");
self.local_pool.run_until_stalled();
Ok(mouse_interaction)
}
Err(error) => match error {
wgpu::SwapChainError::Outdated => {
// Try again next frame.
Err(())
}
_ => panic!("Swapchain error: {:?}", error),
},
);
let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor {
attachment: &frame.output.view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear({
let [r, g, b, a] = background_color.into_linear();
wgpu::Color {
r: f64::from(r),
g: f64::from(g),
b: f64::from(b),
a: f64::from(a),
}
}),
store: true,
},
}],
depth_stencil_attachment: None,
});
let mouse_interaction = renderer.backend_mut().draw(
&mut self.device,
&mut self.staging_belt,
&mut encoder,
&frame.output.view,
viewport,
output,
overlay,
);
// Submit work
self.staging_belt.finish();
self.queue.submit(Some(encoder.finish()));
// Recall staging buffers
self.local_pool
.spawner()
.spawn(self.staging_belt.recall())
.expect("Recall staging belt");
self.local_pool.run_until_stalled();
mouse_interaction
}
}
}

View file

@ -311,27 +311,32 @@ async fn run_instance<A, E, C>(
viewport_version = current_viewport_version;
}
let new_mouse_interaction = compositor.draw(
if let Ok(new_mouse_interaction) = compositor.draw(
&mut renderer,
&mut swap_chain,
state.viewport(),
state.background_color(),
&primitive,
&debug.overlay(),
);
) {
debug.render_finished();
debug.render_finished();
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction,
));
if new_mouse_interaction != mouse_interaction {
window.set_cursor_icon(conversion::mouse_interaction(
new_mouse_interaction,
));
mouse_interaction = new_mouse_interaction;
}
mouse_interaction = new_mouse_interaction;
}
// TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this.
} else {
debug.render_finished();
// Rendering could not complete, try again next frame.
window.request_redraw();
}
}
event::Event::WindowEvent {
event: window_event,