Skip to content

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
.init_resource::<renderer::PendingCommandBuffers>()
.insert_resource(app.world().resource::<AssetServer>().clone())
.insert_resource(RenderState::Initializing)
.add_systems(RenderRecovery, move |world: &mut World| {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure I understand why a new schedule is needed here? What's wrong with using Render?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this schedule runs Render, if it was Render it would infinite loop. the point is to gate running Render. notice RenderRecovery is private, also, so it cannot be circumvented. its an impl detail

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

@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
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-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: No status
Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

4 participants