Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions _release-content/release-notes/render-recovery.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Render Recovery"
authors: ["@atlv24"]
pull_requests: [22761, 23350, 23349, 23433, 23458, 23444, 23459, 23461, 23463, 22714, 22759, 16481]
pull_requests: [22761, 23350, 23349, 23433, 23458, 23444, 23459, 23461, 23463, 22714, 22759, 16481, 24131]
---

You can now recover from rendering errors such as device loss by reloading the renderer:
Expand All @@ -21,4 +21,4 @@ app.insert_resource(RenderErrorHandler(

NOTE: this is just an example showing the different errors and policies available, and not a recommendation for how to handle errors.

The default error handler behaves identically to how Bevy behaved before: validation errors are ignored, and other errors crash/hang the application.
The default error handler will quit the application on any RenderError.
29 changes: 22 additions & 7 deletions crates/bevy_render/src/error_handler.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloc::sync::Arc;
use bevy_app::AppExit;
use bevy_ecs::{
resource::Resource,
world::{Mut, World},
Expand All @@ -19,6 +20,11 @@ use crate::{
pub enum RenderErrorPolicy {
/// Pretends nothing happened and continues rendering.
/// This discards the error after logging it to console.
/// WARNING: Using this policy could cause hazardous rapid flashing
/// if the conditions causing the error remain unaddressed, since
/// rendering will attempt to continue executing.
/// When choosing to use this policy, be sure to test that the application
/// remains safe to use.
Ignore,
/// Keeps the app alive, but stops rendering further.
/// This keeps the error state, and will continue polling the [`RenderErrorHandler`]
Expand All @@ -32,9 +38,11 @@ pub enum RenderErrorPolicy {
///
/// The handler has access to both the main world and the render world in that order.
/// By the time this is invoked, the error has already been logged. The error is provided
/// for the decision-making reason of how to appropriately respond to it. Not all errors
/// are equally severe: validation errors may be ignored for example, while device lost errors
/// require recovery to continue rendering.
/// for the decision-making reason of how to appropriately respond to it.
///
/// Note that failing to address the source of an error and continuing to render may cause rapid flashing.
/// Be sure to thoroughly test your error handler to ensure you application remains safe
/// to use.
#[derive(Resource)]
pub struct RenderErrorHandler(
pub for<'a> fn(&'a RenderError, &'a mut World, &'a mut World) -> RenderErrorPolicy,
Expand All @@ -60,13 +68,20 @@ impl RenderErrorHandler {

impl Default for RenderErrorHandler {
fn default() -> Self {
// This is what we've always done historically,
// but we could choose a new default once recovery works better.
Self(|_, _, _| RenderErrorPolicy::Ignore)
// Quit the application for any `RenderError`.
// These `RenderError`s originate from wgpu. Ignoring a wgpu OutOfMemory
// or wgpu Validation error without addressing the root cause can
// create a rendering loop that delivers hazardous strobing effects.
// We can choose a new default once recovery works better.
Self(|error, main_world, _| {
bevy_log::error!("Quitting the application due to {:?} RenderError", error.ty);
main_world.write_message(AppExit::error());
RenderErrorPolicy::StopRendering
})
}
}

/// An error encountered during rendering.
/// An error encountered during rendering. These errors come from wgpu.
#[derive(Debug)]
pub struct RenderError {
pub ty: ErrorType,
Expand Down
Loading