Repository: bevyengine/bevy
File: crates/bevy_render/src/error_handler.rs (Rust)

Code before:
            return Some(RenderError {
                ty,
                description,
                source: Some(WgpuWrapper::new(source)),
            });
        }
        None
    }
}

/// We need both the main and render world to properly handle errors, so we wedge ourselves into Extract.
/// Returns true if `RenderStartup` should be run.
pub(crate) fn update_state(main_world: &mut World, render_world: &mut World) -> bool {
    if let Some(error) = render_world.resource::<DeviceErrorHandler>().poll() {
        render_world.insert_resource(RenderState::Errored(error));
    }
    match render_world.resource::<RenderState>() {
        RenderState::Initializing => {
            render_world.insert_resource(RenderState::Ready);
            return true;
        }
        RenderState::Ready => {
            // all is well
        }
        RenderState::Errored(error) => {
            match main_world.resource::<RenderErrorHandler>().0(error) {
                RenderErrorPolicy::Ignore => {
                    // Pretend that didn't happen.
                    render_world.insert_resource(RenderState::Ready);
                }
                RenderErrorPolicy::Panic => {
                    panic!("Rendering error {error:?}");
                }
                RenderErrorPolicy::Shutdown => {
                    // error was already logged by `DeviceErrorHandler`
                    main_world.write_message(AppExit::error());
                }
                RenderErrorPolicy::StopRendering => {
                    // do nothing
                }
                RenderErrorPolicy::Recover(render_creation) => {
                    assert!(insert_future_resources(&render_creation, main_world));
                    render_world.insert_resource(RenderState::Reinitializing);
                }
            }
        }
        RenderState::Reinitializing => {
            if let Some(render_resources) = main_world
                .get_resource::<FutureRenderResources>()
                .unwrap()
                .clone()

Review comment (suggestion):
If someone could figure out how to work the lifetimes so we can pass the render world or main world to this handler, (ideally both, even) that would be sweet. im inclined to leave it to a followup

Code after:
    /// Checks to see if any errors have been caught, and returns an appropriate `RenderState`
    pub(crate) fn poll(&self) -> Option<RenderError> {
        // Device lost is more important so we let it take precedence; every error gets logged anyways.
        if let Some((_, description)) = self.device_lost.lock().unwrap().take() {
            return Some(RenderError {
                ty: ErrorType::DeviceLost,
                description,
                source: None,
            });
        }
        if let Some(error) = self.uncaptured.lock().unwrap().take() {
            let (ty, description, source) = match error.into_inner() {
                wgpu::Error::OutOfMemory { source } => {
                    (ErrorType::OutOfMemory, "".to_string(), source)
                }
                wgpu::Error::Validation {
                    source,
                    description,
                } => (ErrorType::Validation, description, source),
                wgpu::Error::Internal {
                    source,
                    description,
                } => (ErrorType::Internal, description, source),
            };
            return Some(RenderError {
                ty,
                description,
                source: Some(WgpuWrapper::new(source)),
            });
        }
        None
    }
}

/// Updates the state machine that handles the renderer and device lifecycle.
/// Polls the [`DeviceErrorHandler`] and fires the [`RenderErrorHandler`] if needed.
///
/// Runs [`crate::RenderStartup`] after every time a [`RenderDevice`] is acquired.
///
/// We need both the main and render world to properly handle errors, so we wedge ourselves into [extract](bevy_app::SubApp::set_extract).
pub(crate) fn update_state(main_world: &mut World, render_world: &mut World) {
    if let Some(error) = render_world.resource::<DeviceErrorHandler>().poll() {
        render_world.insert_resource(RenderState::Errored(error));
    };

    // Remove the render state so we can provide both worlds to the `RenderErrorHandler`.
    let state = render_world.remove_resource::<RenderState>().unwrap();

    match &state {
        RenderState::Initializing => {
            render_world.run_schedule(RenderStartup);