Skip to content
Closed
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
7 changes: 4 additions & 3 deletions crates/bevy_render/src/render_resource/pipeline_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -758,9 +758,10 @@ impl PipelineCache {
shader.shader_defs.extend(cache.global_shader_defs.clone());
cache.set_shader(id, shader);
}
// Drain events so we don't double-process shaders we just loaded.
for _ in events.read() {}
return;
// Fall through to the per-event loop below rather than draining and
// returning: a shader whose Added/Modified event is in this frame's
// buffer but which the snapshot above missed (e.g. async-loaded on
// web) must still be applied, not dropped. See #24944.
}

for event in events.read() {
Expand Down
53 changes: 53 additions & 0 deletions crates/bevy_shader/src/shader_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,56 @@ pub enum ShaderCacheError {
#[error("Could not create shader module: {0}")]
CreateShaderModule(String),
}

#[cfg(test)]
mod tests {
use super::*;
use bevy_asset::{uuid::Uuid, AssetId};

/// A GPU-free [`ShaderCache`]: both the module type and the device type are
/// `()`, and `load_module` is never reached on the paths under test.
fn test_cache() -> ShaderCache<(), ()> {
ShaderCache::new(
(),
Features::empty(),
DownlevelFlags::empty(),
|_d, _s, _v| Ok(()),
)
}

fn shader_id(n: u128) -> AssetId<Shader> {
AssetId::Uuid {
uuid: Uuid::from_u128(n),
}
}

/// A shader absent from the cache reports [`ShaderCacheError::ShaderNotLoaded`];
/// once [`ShaderCache::set_shader`] applies it, `get` no longer does. This is
/// the cache operation `PipelineCache::extract_shaders` performs for an
/// `Added`/`Modified` shader event — the path #24944 restored on the reload
/// frame.
#[test]
fn set_shader_makes_a_missing_shader_loadable() {
let id = shader_id(24944);
let mut cache = test_cache();

assert!(
matches!(
cache.get(0, id, &[]),
Err(ShaderCacheError::ShaderNotLoaded(_))
),
"a shader not yet in the cache should report ShaderNotLoaded",
);

cache.set_shader(
id,
Shader::from_wgsl("@compute @workgroup_size(1) fn main() {}", "s.wgsl"),
);

let result = cache.get(0, id, &[]);
assert!(
!matches!(result, Err(ShaderCacheError::ShaderNotLoaded(_))),
"after set_shader the shader is loaded, so get must not report ShaderNotLoaded; got {result:?}",
);
}
}