@@ -2,19 +2,21 @@ use crate::{
2
2
render_resource:: {
3
3
AsModuleDescriptorError , BindGroupLayout , BindGroupLayoutId , ProcessShaderError ,
4
4
RawFragmentState , RawRenderPipelineDescriptor , RawVertexState , RenderPipeline ,
5
- RenderPipelineDescriptor , Shader , ShaderImport , ShaderProcessor ,
5
+ RenderPipelineDescriptor , Shader , ShaderImport , ShaderProcessor , ShaderReflectError ,
6
6
} ,
7
7
renderer:: RenderDevice ,
8
8
RenderWorld ,
9
9
} ;
10
10
use bevy_app:: EventReader ;
11
11
use bevy_asset:: { AssetEvent , Assets , Handle } ;
12
12
use bevy_ecs:: system:: { Res , ResMut } ;
13
- use bevy_utils:: { HashMap , HashSet } ;
13
+ use bevy_utils:: { tracing :: error , HashMap , HashSet } ;
14
14
use std:: { collections:: hash_map:: Entry , hash:: Hash , ops:: Deref , sync:: Arc } ;
15
15
use thiserror:: Error ;
16
16
use wgpu:: { PipelineLayoutDescriptor , ShaderModule , VertexBufferLayout } ;
17
17
18
+ use super :: ProcessedShader ;
19
+
18
20
#[ derive( Default ) ]
19
21
pub struct ShaderData {
20
22
pipelines : HashSet < CachedPipelineId > ,
@@ -52,7 +54,16 @@ impl ShaderCache {
52
54
. get ( handle)
53
55
. ok_or_else ( || RenderPipelineError :: ShaderNotLoaded ( handle. clone_weak ( ) ) ) ?;
54
56
let data = self . data . entry ( handle. clone_weak ( ) ) . or_default ( ) ;
55
- if shader. imports ( ) . len ( ) != data. resolved_imports . len ( ) {
57
+ let n_asset_imports = shader
58
+ . imports ( )
59
+ . filter ( |import| matches ! ( import, ShaderImport :: AssetPath ( _) ) )
60
+ . count ( ) ;
61
+ let n_resolved_asset_imports = data
62
+ . resolved_imports
63
+ . keys ( )
64
+ . filter ( |import| matches ! ( import, ShaderImport :: AssetPath ( _) ) )
65
+ . count ( ) ;
66
+ if n_asset_imports != n_resolved_asset_imports {
56
67
return Err ( RenderPipelineError :: ShaderImportNotYetAvailable ) ;
57
68
}
58
69
@@ -68,7 +79,12 @@ impl ShaderCache {
68
79
& self . shaders ,
69
80
& self . import_path_shaders ,
70
81
) ?;
71
- let module_descriptor = processed. get_module_descriptor ( ) ?;
82
+ let module_descriptor = match processed. get_module_descriptor ( ) {
83
+ Ok ( module_descriptor) => module_descriptor,
84
+ Err ( err) => {
85
+ return Err ( RenderPipelineError :: AsModuleDescriptorError ( err, processed) ) ;
86
+ }
87
+ } ;
72
88
entry. insert ( Arc :: new (
73
89
render_device. create_shader_module ( & module_descriptor) ,
74
90
) )
@@ -206,8 +222,8 @@ pub enum RenderPipelineError {
206
222
ShaderNotLoaded ( Handle < Shader > ) ,
207
223
#[ error( transparent) ]
208
224
ProcessShaderError ( #[ from] ProcessShaderError ) ,
209
- #[ error( transparent ) ]
210
- AsModuleDescriptorError ( # [ from ] AsModuleDescriptorError ) ,
225
+ #[ error( "{0}" ) ]
226
+ AsModuleDescriptorError ( AsModuleDescriptorError , ProcessedShader ) ,
211
227
#[ error( "Shader import not yet available." ) ]
212
228
ShaderImportNotYetAvailable ,
213
229
}
@@ -274,9 +290,13 @@ impl RenderPipelineCache {
274
290
match err {
275
291
RenderPipelineError :: ShaderNotLoaded ( _)
276
292
| RenderPipelineError :: ShaderImportNotYetAvailable => { /* retry */ }
277
- RenderPipelineError :: ProcessShaderError ( _)
278
- | RenderPipelineError :: AsModuleDescriptorError ( _) => {
279
- // shader could not be processed ... retrying won't help
293
+ // shader could not be processed ... retrying won't help
294
+ RenderPipelineError :: ProcessShaderError ( err) => {
295
+ error ! ( "failed to process shader: {}" , err) ;
296
+ continue ;
297
+ }
298
+ RenderPipelineError :: AsModuleDescriptorError ( err, source) => {
299
+ log_shader_error ( source, err) ;
280
300
continue ;
281
301
}
282
302
}
@@ -386,3 +406,47 @@ impl RenderPipelineCache {
386
406
}
387
407
}
388
408
}
409
+
410
+ fn log_shader_error ( source : & ProcessedShader , err : & AsModuleDescriptorError ) {
411
+ use codespan_reporting:: {
412
+ diagnostic:: { Diagnostic , Label } ,
413
+ files:: SimpleFile ,
414
+ term,
415
+ } ;
416
+
417
+ if let ProcessedShader :: Wgsl ( source) = source {
418
+ if let AsModuleDescriptorError :: ShaderReflectError ( err) = err {
419
+ match err {
420
+ ShaderReflectError :: WgslParse ( parse) => {
421
+ let msg = parse. emit_to_string ( source) ;
422
+ error ! ( "failed to process shader:\n {}" , msg) ;
423
+ }
424
+ ShaderReflectError :: Validation ( error) => {
425
+ let files = SimpleFile :: new ( "wgsl" , & source) ;
426
+ let config = term:: Config :: default ( ) ;
427
+ let mut writer = term:: termcolor:: Ansi :: new ( Vec :: new ( ) ) ;
428
+
429
+ let diagnostic = Diagnostic :: error ( ) . with_labels (
430
+ error
431
+ . spans ( )
432
+ . map ( |( span, desc) | {
433
+ Label :: primary ( ( ) , span. to_range ( ) . unwrap ( ) )
434
+ . with_message ( desc. to_owned ( ) )
435
+ } )
436
+ . collect ( ) ,
437
+ ) ;
438
+
439
+ term:: emit ( & mut writer, & config, & files, & diagnostic)
440
+ . expect ( "cannot write error" ) ;
441
+
442
+ let msg = writer. into_inner ( ) ;
443
+ let msg = String :: from_utf8_lossy ( & msg) ;
444
+
445
+ error ! ( "failed to process shader: \n {}" , msg) ;
446
+ }
447
+ ShaderReflectError :: GlslParse ( _) => { }
448
+ ShaderReflectError :: SpirVParse ( _) => { }
449
+ }
450
+ }
451
+ }
452
+ }
0 commit comments