Skip to content

Commit 5816169

Browse files
authored
Add VERBOSE_SHADER_ERROR (#20448)
# Objective - Make it easier to debug shader def problems in shader libraries ## Solution - print context of where the shader module's entry point is and what the shader defs are ## Testing - intentionally broke a shader and ran 3d_scene, logs are added when env var is set. <img width="917" height="259" alt="{9D77F6EF-9813-4C18-90A9-51E81388D681}" src="https://github.com/user-attachments/assets/7ae42479-e548-40bf-8d26-ee61bab7c279" />
1 parent ef845e0 commit 5816169

File tree

1 file changed

+49
-2
lines changed

1 file changed

+49
-2
lines changed

crates/bevy_render/src/render_resource/pipeline_cache.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
Extract,
66
};
77
use alloc::{borrow::Cow, sync::Arc};
8-
use bevy_asset::{AssetEvent, AssetId, Assets};
8+
use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
99
use bevy_ecs::{
1010
event::EventReader,
1111
resource::Resource,
@@ -696,7 +696,12 @@ impl PipelineCache {
696696
PipelineCacheError::ProcessShaderError(err) => {
697697
let error_detail =
698698
err.emit_to_string(&self.shader_cache.lock().unwrap().composer);
699-
error!("failed to process shader:\n{}", error_detail);
699+
if std::env::var("VERBOSE_SHADER_ERROR")
700+
.is_ok_and(|v| !(v.is_empty() || v == "0" || v == "false"))
701+
{
702+
error!("{}", pipeline_error_context(cached_pipeline));
703+
}
704+
error!("failed to process shader error:\n{}", error_detail);
700705
return;
701706
}
702707
PipelineCacheError::CreateShaderModule(description) => {
@@ -746,6 +751,48 @@ impl PipelineCache {
746751
}
747752
}
748753

754+
fn pipeline_error_context(cached_pipeline: &CachedPipeline) -> String {
755+
fn format(
756+
shader: &Handle<Shader>,
757+
entry: &Option<Cow<'static, str>>,
758+
shader_defs: &[ShaderDefVal],
759+
) -> String {
760+
let source = match shader.path() {
761+
Some(path) => path.path().to_string_lossy().to_string(),
762+
None => String::new(),
763+
};
764+
let entry = match entry {
765+
Some(entry) => entry.to_string(),
766+
None => String::new(),
767+
};
768+
let shader_defs = shader_defs
769+
.iter()
770+
.flat_map(|def| match def {
771+
ShaderDefVal::Bool(k, v) if *v => Some(k.to_string()),
772+
ShaderDefVal::Int(k, v) => Some(format!("{k} = {v}")),
773+
ShaderDefVal::UInt(k, v) => Some(format!("{k} = {v}")),
774+
_ => None,
775+
})
776+
.collect::<Vec<_>>()
777+
.join(", ");
778+
format!("{source}:{entry}\nshader defs: {shader_defs}")
779+
}
780+
match &cached_pipeline.descriptor {
781+
PipelineDescriptor::RenderPipelineDescriptor(desc) => {
782+
let vert = &desc.vertex;
783+
let vert_str = format(&vert.shader, &vert.entry_point, &vert.shader_defs);
784+
let Some(frag) = desc.fragment.as_ref() else {
785+
return vert_str;
786+
};
787+
let frag_str = format(&frag.shader, &frag.entry_point, &frag.shader_defs);
788+
format!("vertex {vert_str}\nfragment {frag_str}")
789+
}
790+
PipelineDescriptor::ComputePipelineDescriptor(desc) => {
791+
format(&desc.shader, &desc.entry_point, &desc.shader_defs)
792+
}
793+
}
794+
}
795+
749796
#[cfg(all(
750797
not(target_arch = "wasm32"),
751798
not(target_os = "macos"),

0 commit comments

Comments
 (0)