Skip to content

Render Recovery#22761

Merged
alice-i-cecile merged 19 commits intobevyengine:mainfrom
atlv24:ad/render-error-handling
Feb 5, 2026
Merged

Render Recovery#22761
alice-i-cecile merged 19 commits intobevyengine:mainfrom
atlv24:ad/render-error-handling

Conversation

@atlv24
Copy link
Contributor

@atlv24 atlv24 commented Feb 1, 2026

Objective

Solution

  • Use wgpu::Device::set_device_lost_callback and wgpu::Device::on_uncaptured_error to listen for errors.
  • Add a state machine for the renderer
  • Update it on error
  • Add a RenderErrorHandler to let users specify behavior on error by returning a specific RenderErrorPolicy
  • This lets us for example ignore validation errors, delete responsible entities, or reload the renderer if the device was lost.

Testing

    .insert_resource(bevy_render::error_handler::RenderErrorHandler(|_, _, _| {
        bevy_render::error_handler::RenderErrorPolicy::StopRendering
    }))
    .insert_resource(bevy_render::error_handler::RenderErrorHandler(|_, _, _| {
        bevy_render::error_handler::RenderErrorPolicy::Recover(default())
    }))

Note: no release note yet, as recovery does not exactly work well: this PR gets us to the point of being able to care about it, but we currently instantly crash on recover due to gpu resources not existing anymore. We need to build more resilience before publicizing imo.

@atlv24 atlv24 added A-Rendering Drawing game state to the screen S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 1, 2026
@github-project-automation github-project-automation bot moved this to Needs SME Triage in Rendering (2026 Proposal) Feb 1, 2026
@atlv24 atlv24 force-pushed the ad/render-error-handling branch from b896165 to c848450 Compare February 1, 2026 01:27
pub(crate) fn update(main_world: &mut World, render_world: &mut World) -> bool {
match render_world.resource::<RenderState>() {
RenderState::Initializing => {
render_world.insert_resource(RenderState::Ready);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we really just instantly transition from Initializing into Ready?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the transition into Ready should be done by RenderStartup itself (in case it has its own fallibility).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its better to keep all the state-machine-y things in the function together

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with keeping this together for now, but I suspect we may need to refactor this later.

@IQuick143 IQuick143 added C-Feature A new feature, making something new possible P-Crash A sudden unexpected crash D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes labels Feb 1, 2026
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
@valaphee
Copy link
Contributor

valaphee commented Feb 3, 2026

This should also solve #21407

@IQuick143
Copy link
Contributor

It's not quite solving it yet, but it gets us close.

render_app.set_extract(move |main_world, render_world| {
if should_run_startup {
render_app.set_extract(|main_world, render_world| {
if error_handler::update_state(main_world, render_world) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of update_state makes it quite hard to understand what this method call is doing. I would prefer a rename, but would accept a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it used to be called update and i asked for a bikeshed and thats what we came up with, but im open to better name suggestions. it updates the state machine that handles the renderer and device lifecycle. i'll add a comment for now saying as much

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like check_render_device_lifecycle? IMO we should try and capture a) renderer / device b) lifecycle and c) some form of check or "should run" or something to indicate that it returns a bool that should be used.

@alice-i-cecile
Copy link
Member

No blocking feedback, and wgpu maintainers were reasonably happy with this. I'm not equipped to give a full approval here though; I don't know the domain well enough.

Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, the logic of everything is great and it does what it's supposed to.

I don't like how it feels like it does 4 different things at once but I haven't managed to untangle it.

I think it might feel mildly better to name the new module render_state and error handling just happens to be part of handling the state instead of the state being managed by something called error_handler. I would also just move the RenderStartup to be inside the state machine itself because that state machine is already aware of it so it feels a bit unnecessary to keep them separate. The update_state function already does a bunch of things and mutates the world so it seems appropriate for it to just run the schedule when it needs to. Especially if we start running it on recovery.

With that said, I think the current state of things works and we can rename it later. I don't want to block work on naming things.

@IceSentry IceSentry added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 5, 2026
@atlv24
Copy link
Contributor Author

atlv24 commented Feb 5, 2026

I've done the renames requested, although im not sure i agree with them. The point of calling it error_handler was more for the user facing api:

bevy::render::error_handler::{RenderErrorHandler, RenderErrorPolicy}

vs

bevy::render::render_state::{RenderErrorHandler, RenderErrorPolicy}

@atlv24
Copy link
Contributor Author

atlv24 commented Feb 5, 2026

Im just gonna make the mod private and re-export from the top level instead

@atlv24
Copy link
Contributor Author

atlv24 commented Feb 5, 2026

nah... it was just better before im gonna keep error_handler for now my bad

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Feb 5, 2026
Merged via the queue into bevyengine:main with commit 71dd9ea Feb 5, 2026
38 checks passed
@github-project-automation github-project-automation bot moved this to Done in Rendering Feb 5, 2026
@github-project-automation github-project-automation bot moved this from Needs SME Triage to Done in Rendering (2026 Proposal) Feb 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes P-Crash A sudden unexpected crash S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

6 participants