diff --git a/crates/anyrender_vello/src/window_renderer.rs b/crates/anyrender_vello/src/window_renderer.rs index f1331ab..f58a787 100644 --- a/crates/anyrender_vello/src/window_renderer.rs +++ b/crates/anyrender_vello/src/window_renderer.rs @@ -10,7 +10,7 @@ use vello::{ AaConfig, AaSupport, RenderParams, Renderer as VelloRenderer, RendererOptions, Scene as VelloScene, }; -use wgpu::{Features, Limits, PresentMode, TextureFormat, TextureUsages}; +use wgpu::{Features, Limits, PresentMode, SurfaceError, TextureFormat, TextureUsages}; use wgpu_context::{ DeviceHandle, SurfaceRenderer, SurfaceRendererConfiguration, TextureConfiguration, WGPUContext, }; @@ -207,7 +207,19 @@ impl WindowRenderer for VelloWindowRenderer { }); timer.record_time("cmd"); - let texture_view = render_surface.target_texture_view(); + match render_surface.ensure_current_surface_texture() { + Ok(_) => {} + Err(SurfaceError::Timeout | SurfaceError::Lost | SurfaceError::Outdated) => { + render_surface.clear_surface_texture(); + return; + } + Err(SurfaceError::OutOfMemory) => panic!("Out of memory"), + Err(SurfaceError::Other) => panic!("Unknown error getting surface"), + }; + + let texture_view = render_surface + .target_texture_view() + .expect("handled errorss from ensure_current_surface_texture above"); state .renderer .render_to_texture( @@ -227,7 +239,9 @@ impl WindowRenderer for VelloWindowRenderer { drop(texture_view); - render_surface.maybe_blit_and_present(); + render_surface + .maybe_blit_and_present() + .expect("handled errorss from ensure_current_surface_texture above"); timer.record_time("present"); render_surface diff --git a/crates/anyrender_vello_hybrid/src/window_renderer.rs b/crates/anyrender_vello_hybrid/src/window_renderer.rs index e6e216d..4e9b0c9 100644 --- a/crates/anyrender_vello_hybrid/src/window_renderer.rs +++ b/crates/anyrender_vello_hybrid/src/window_renderer.rs @@ -10,7 +10,7 @@ use vello_hybrid::{ RenderSettings, RenderSize, RenderTargetConfig, Renderer as VelloHybridRenderer, Scene as VelloHybridScene, }; -use wgpu::{CommandEncoderDescriptor, Features, Limits, PresentMode, TextureFormat}; +use wgpu::{CommandEncoderDescriptor, Features, Limits, PresentMode, SurfaceError, TextureFormat}; use wgpu_context::{DeviceHandle, SurfaceRenderer, SurfaceRendererConfiguration, WGPUContext}; use crate::{VelloHybridScenePainter, scene::ImageManager}; @@ -226,7 +226,19 @@ impl WindowRenderer for VelloHybridWindowRenderer { }); timer.record_time("cmd"); - let texture_view = render_surface.target_texture_view(); + match render_surface.ensure_current_surface_texture() { + Ok(_) => {} + Err(SurfaceError::Timeout | SurfaceError::Lost | SurfaceError::Outdated) => { + render_surface.clear_surface_texture(); + return; + } + Err(SurfaceError::OutOfMemory) => panic!("Out of memory"), + Err(SurfaceError::Other) => panic!("Unknown error getting surface"), + }; + + let texture_view = render_surface + .target_texture_view() + .expect("handled errorss from ensure_current_surface_texture above"); state .renderer @@ -247,7 +259,9 @@ impl WindowRenderer for VelloHybridWindowRenderer { drop(texture_view); - render_surface.maybe_blit_and_present(); + render_surface + .maybe_blit_and_present() + .expect("handled errorss from ensure_current_surface_texture above"); timer.record_time("present"); render_surface diff --git a/crates/wgpu_context/src/surface_renderer.rs b/crates/wgpu_context/src/surface_renderer.rs index 1c7c0c8..659c0d8 100644 --- a/crates/wgpu_context/src/surface_renderer.rs +++ b/crates/wgpu_context/src/surface_renderer.rs @@ -1,7 +1,7 @@ use crate::{DeviceHandle, WgpuContextError, util::create_texture}; use wgpu::{ CommandEncoderDescriptor, CompositeAlphaMode, Device, PresentMode, Queue, Surface, - SurfaceConfiguration, SurfaceTexture, TextureFormat, TextureUsages, TextureView, + SurfaceConfiguration, SurfaceError, SurfaceTexture, TextureFormat, TextureUsages, TextureView, TextureViewDescriptor, util::TextureBlitter, }; @@ -86,7 +86,7 @@ pub struct SurfaceRenderer<'s> { pub surface: Surface<'s>, pub config: SurfaceConfiguration, - current_surface_texture: Option, + current_surface_texture: Option>, intermediate_texture: Option>, } @@ -189,30 +189,46 @@ impl<'s> SurfaceRenderer<'s> { .configure(&self.device_handle.device, &self.config); } - fn ensure_current_surface_texture(&mut self) { + pub fn clear_surface_texture(&mut self) { + self.current_surface_texture = None; + } + + pub fn ensure_current_surface_texture(&mut self) -> Result<(), SurfaceError> { if self.current_surface_texture.is_none() { - self.current_surface_texture = Some( + let tex = self.surface.get_current_texture(); + if let Err(SurfaceError::Lost | SurfaceError::Outdated) = &tex { self.surface - .get_current_texture() - .expect("failed to get surface texture"), - ); + .configure(&self.device_handle.device, &self.config); + } + + self.current_surface_texture = Some(tex); } + + self.current_surface_texture + .as_ref() + .unwrap() + .as_ref() + .map(|_| ()) + .map_err(|err| err.clone()) } /// Get a target texture view to render to. /// /// If there is an intermediate texture, this is a view of that intermediate texture, otherwise /// it is a view of the surface texture. - pub fn target_texture_view(&mut self) -> TextureView { + pub fn target_texture_view(&mut self) -> Result { match &self.intermediate_texture { - Some(intermediate_texture) => intermediate_texture.texture_view.clone(), + Some(intermediate_texture) => Ok(intermediate_texture.texture_view.clone()), None => { - self.ensure_current_surface_texture(); - self.current_surface_texture + self.ensure_current_surface_texture()?; + Ok(self + .current_surface_texture + .as_ref() + .unwrap() .as_ref() .unwrap() .texture - .create_view(&TextureViewDescriptor::default()) + .create_view(&TextureViewDescriptor::default())) } } } @@ -222,15 +238,17 @@ impl<'s> SurfaceRenderer<'s> { /// /// Prior to calling this, [`Self::target_texture_view`] must have been called and some /// rendering work must have been scheduled to the resulting view. - pub fn maybe_blit_and_present(&mut self) { - self.ensure_current_surface_texture(); - let surface_texture = self.current_surface_texture.take().unwrap(); + pub fn maybe_blit_and_present(&mut self) -> Result<(), SurfaceError> { + self.ensure_current_surface_texture()?; + let surface_texture = self.current_surface_texture.take().unwrap().unwrap(); if let Some(its) = &self.intermediate_texture { self.blit_from_intermediate_texture_to_surface(&surface_texture, its); } surface_texture.present(); + + Ok(()) } /// Blit from the intermediate texture to the surface texture