summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/integration/src/main.rs99
-rw-r--r--graphics/src/window.rs2
-rw-r--r--graphics/src/window/compositor.rs26
-rw-r--r--wgpu/src/window/compositor.rs126
-rw-r--r--winit/src/application.rs38
5 files changed, 181 insertions, 110 deletions
diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs
index b4f580a4..6f319466 100644
--- a/examples/integration/src/main.rs
+++ b/examples/integration/src/main.rs
@@ -172,55 +172,66 @@ 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();
+
+ {
+ // 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);
+ }
+
+ // 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(),
+ );
- let program = state.program();
+ // Then we submit the work
+ staging_belt.finish();
+ queue.submit(Some(encoder.finish()));
- {
- // We clear the frame
- let mut render_pass = scene.clear(
- &frame.output.view,
- &mut encoder,
- program.background_color(),
- );
+ // Update the mouse cursor
+ window.set_cursor_icon(
+ iced_winit::conversion::mouse_interaction(
+ mouse_interaction,
+ ),
+ );
- // Draw the scene
- scene.draw(&mut render_pass);
- }
+ // And recall staging buffers
+ local_pool
+ .spawner()
+ .spawn(staging_belt.recall())
+ .expect("Recall staging buffers");
- // 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();
+ local_pool.run_until_stalled();
+ }
+ Err(error) => match error {
+ wgpu::SwapChainError::OutOfMemory => {
+ panic!("Swapchain error: {}. Rendering cannot continue.", error)
+ }
+ _ => {
+ // Try rendering again next frame.
+ window.request_redraw();
+ }
+ },
+ }
}
_ => {}
}
diff --git a/graphics/src/window.rs b/graphics/src/window.rs
index 3e74db5f..365ddfbc 100644
--- a/graphics/src/window.rs
+++ b/graphics/src/window.rs
@@ -4,7 +4,7 @@ mod compositor;
#[cfg(feature = "opengl")]
mod gl_compositor;
-pub use compositor::Compositor;
+pub use compositor::{Compositor, SwapChainError};
#[cfg(feature = "opengl")]
pub use gl_compositor::GLCompositor;
diff --git a/graphics/src/window/compositor.rs b/graphics/src/window/compositor.rs
index 7d5d789b..de2a6990 100644
--- a/graphics/src/window/compositor.rs
+++ b/graphics/src/window/compositor.rs
@@ -1,6 +1,9 @@
use crate::{Color, Error, Viewport};
+
use iced_native::mouse;
+
use raw_window_handle::HasRawWindowHandle;
+use thiserror::Error;
/// A graphics compositor that can draw to windows.
pub trait Compositor: Sized {
@@ -52,5 +55,26 @@ pub trait Compositor: Sized {
background_color: Color,
output: &<Self::Renderer as iced_native::Renderer>::Output,
overlay: &[T],
- ) -> mouse::Interaction;
+ ) -> Result<mouse::Interaction, SwapChainError>;
+}
+
+/// Result of an unsuccessful call to [`Compositor::draw`].
+#[derive(Clone, PartialEq, Eq, Debug, Error)]
+pub enum SwapChainError {
+ /// A timeout was encountered while trying to acquire the next frame.
+ #[error(
+ "A timeout was encountered while trying to acquire the next frame"
+ )]
+ Timeout,
+ /// The underlying surface has changed, and therefore the swap chain must be updated.
+ #[error(
+ "The underlying surface has changed, and therefore the swap chain must be updated."
+ )]
+ Outdated,
+ /// The swap chain has been lost and needs to be recreated.
+ #[error("The swap chain has been lost and needs to be recreated")]
+ Lost,
+ /// There is no more memory left to allocate a new frame.
+ #[error("There is no more memory left to allocate a new frame")]
+ OutOfMemory,
}
diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs
index 68ebf234..b60efd25 100644
--- a/wgpu/src/window/compositor.rs
+++ b/wgpu/src/window/compositor.rs
@@ -141,59 +141,79 @@ 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");
-
- let mut encoder = self.device.create_command_encoder(
- &wgpu::CommandEncoderDescriptor {
- label: Some("iced_wgpu encoder"),
+ ) -> Result<mouse::Interaction, iced_graphics::window::SwapChainError> {
+ match swap_chain.get_current_frame() {
+ Ok(frame) => {
+ let mut encoder = self.device.create_command_encoder(
+ &wgpu::CommandEncoderDescriptor {
+ label: Some("iced_wgpu encoder"),
+ },
+ );
+
+ let _ =
+ encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ label: Some(
+ "iced_wgpu::window::Compositor render pass",
+ ),
+ color_attachments: &[wgpu::RenderPassColorAttachment {
+ view: &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::Timeout => {
+ Err(iced_graphics::window::SwapChainError::Timeout)
+ }
+ wgpu::SwapChainError::Outdated => {
+ Err(iced_graphics::window::SwapChainError::Outdated)
+ }
+ wgpu::SwapChainError::Lost => {
+ Err(iced_graphics::window::SwapChainError::Lost)
+ }
+ wgpu::SwapChainError::OutOfMemory => {
+ Err(iced_graphics::window::SwapChainError::OutOfMemory)
+ }
},
- );
-
- let _ = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
- label: Some("iced_wgpu::window::Compositor render pass"),
- color_attachments: &[wgpu::RenderPassColorAttachment {
- view: &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
+ }
}
}
diff --git a/winit/src/application.rs b/winit/src/application.rs
index 5d1aabf9..1d32a5f3 100644
--- a/winit/src/application.rs
+++ b/winit/src/application.rs
@@ -366,27 +366,43 @@ async fn run_instance<A, E, C>(
viewport_version = current_viewport_version;
}
- let new_mouse_interaction = compositor.draw(
+ match compositor.draw(
&mut renderer,
&mut swap_chain,
state.viewport(),
state.background_color(),
&primitive,
&debug.overlay(),
- );
+ ) {
+ Ok(new_mouse_interaction) => {
+ 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.
+ }
+ Err(error) => match error {
+ // This is an unrecoverable error.
+ window::SwapChainError::OutOfMemory => {
+ panic!("{}", error);
+ }
+ _ => {
+ debug.render_finished();
+
+ // Try rendering again next frame.
+ window.request_redraw();
+ }
+ },
}
-
- // TODO: Handle animations!
- // Maybe we can use `ControlFlow::WaitUntil` for this.
}
event::Event::WindowEvent {
event: event::WindowEvent::MenuEntryActivated(entry_id),