Skip to content

Don't drop pending shader events on the reload frame in PipelineCache to fix pipelines never becoming ready on web - #25238

Closed
taearls wants to merge 2 commits into
bevyengine:mainfrom
taearls:24944/wasm-pipelines-no-longer-become-ready
Closed

Don't drop pending shader events on the reload frame in PipelineCache to fix pipelines never becoming ready on web#25238
taearls wants to merge 2 commits into
bevyengine:mainfrom
taearls:24944/wasm-pipelines-no-longer-become-ready

Conversation

@taearls

@taearls taearls commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Objective

Solution

The regression was in PipelineCache::extract_shaders. On any frame where
needs_shader_reload is set, the system takes a snapshot of every shader
currently in Assets<Shader> and re-registers it. Before this PR, it then
drained and discarded all pending AssetEvent<Shader> and returned early:

if cache.needs_shader_reload {
    cache.needs_shader_reload = false;
    for (id, shader) in shaders.iter() {
        // ...snapshot every shader currently in Assets...
        cache.set_shader(id, shader);
    }
    // Drain events so we don't double-process shaders we just loaded.
    for _ in events.read() {}
    return;
}

The intent behind the drain was to avoid double-processing shaders the snapshot
already handled. The problem: that snapshot is additive and only sees shaders
already present in Assets<Shader> at that instant
. If a shader finishes
loading asynchronously (very common on the web) its Added event is sitting in
this frame's buffer but the asset may not be in the snapshot yet — and a
Removed event has no representation in a snapshot that only ever adds. Throwing
the event buffer away on the reload frame means those events are lost, and any
pipeline waiting on that shader stays stuck in waiting_pipelines() indefinitely.

The fix is to stop discarding events: let the reload branch fall through to the
existing per-event loop instead of returning early.

if cache.needs_shader_reload {
    cache.needs_shader_reload = false;
    for (id, shader) in shaders.iter() {
        // ...snapshot every shader currently in Assets...
        cache.set_shader(id, shader);
    }
    // Fall through to the per-event loop below.
}

for event in events.read() {
    // Added / Modified / Removed handled as usual.
}

This is safe because the per-event loop is idempotent for the reload case: an
Added/Modified event just re-runs set_shader with the same data (harmless),
while Removed is now correctly honored on reload frames instead of being
silently dropped. The "double-process" the old comment worried about was never a
correctness issue.

Testing

  • Added a unit test (crates/bevy_shader/src/shader_cache.rs):
    set_shader_makes_a_missing_shader_loadable. It's device-free (ShaderCache<(), ()>,
    no GPU), so it runs in CI, and it exercises the exact cache operation the fix
    restores on the reload frame — a shader reports ShaderNotLoaded until
    set_shader applies it. cargo test -p bevy_shader passes.

@taearls taearls added A-Rendering Drawing game state to the screen O-Web Specific to web (WASM) builds S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 31, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Rendering Jul 31, 2026
@taearls
taearls requested a review from alice-i-cecile July 31, 2026 20:31
@kfc35 kfc35 added this to the 0.19.1 milestone Jul 31, 2026
@kfc35 kfc35 added P-Regression Functionality that used to work but no longer does. Add a test for this! C-Bug An unexpected or incorrect behavior labels Jul 31, 2026
@alice-i-cecile
alice-i-cecile requested a review from beicause August 1, 2026 04:13
@taearls
taearls marked this pull request as draft August 1, 2026 05:08
@taearls

taearls commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

I received some feedback on Discord that this PR in its current state doesn't resolve the issue it intended to fix. I'm converting this to a draft PR for now. I will look at this again this weekend and try to replicate this specifically on WGL2.

@beicause

beicause commented Aug 1, 2026

Copy link
Copy Markdown
Member

I fixed this in #25245. Just a friendly heads-up to avoid duplicate work.

@taearls

taearls commented Aug 1, 2026

Copy link
Copy Markdown
Contributor Author

Closing this draft PR in favor of #25245

@taearls taearls closed this Aug 1, 2026
@github-project-automation github-project-automation Bot moved this from Needs SME Triage to Done in Rendering Aug 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-Bug An unexpected or incorrect behavior O-Web Specific to web (WASM) builds P-Regression Functionality that used to work but no longer does. Add a test for this! S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

on 0.19.0 web firefox, demo loading screen, pipelines no longer become ready

3 participants