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,8 +168,8 @@ pub fn main() {
resized = false; 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( let mut encoder = device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None }, &wgpu::CommandEncoderDescriptor { label: None },
); );
@ -218,6 +218,15 @@ pub fn main() {
local_pool.run_until_stalled(); local_pool.run_until_stalled();
} }
Err(error) => match error {
wgpu::SwapChainError::Outdated => {
// Try rendering again next frame.
window.request_redraw();
}
_ => panic!("Swapchain error: {:?}", error),
},
}
}
_ => {} _ => {}
} }
}) })

View file

@ -40,6 +40,9 @@ pub trait Compositor: Sized {
/// Draws the output primitives to the next frame of the given [`SwapChain`]. /// 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 /// [`SwapChain`]: Self::SwapChain
fn draw<T: AsRef<str>>( fn draw<T: AsRef<str>>(
&mut self, &mut self,
@ -49,5 +52,5 @@ pub trait Compositor: Sized {
background_color: Color, background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output, output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T], overlay: &[T],
) -> mouse::Interaction; ) -> Result<mouse::Interaction, ()>;
} }

View file

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

View file

@ -311,15 +311,14 @@ async fn run_instance<A, E, C>(
viewport_version = current_viewport_version; viewport_version = current_viewport_version;
} }
let new_mouse_interaction = compositor.draw( if let Ok(new_mouse_interaction) = compositor.draw(
&mut renderer, &mut renderer,
&mut swap_chain, &mut swap_chain,
state.viewport(), state.viewport(),
state.background_color(), state.background_color(),
&primitive, &primitive,
&debug.overlay(), &debug.overlay(),
); ) {
debug.render_finished(); debug.render_finished();
if new_mouse_interaction != mouse_interaction { if new_mouse_interaction != mouse_interaction {
@ -332,6 +331,12 @@ async fn run_instance<A, E, C>(
// TODO: Handle animations! // TODO: Handle animations!
// Maybe we can use `ControlFlow::WaitUntil` for this. // 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::Event::WindowEvent {
event: window_event, event: window_event,