11//! Wrapper for extending a `Material` with `rust-gpu` shader functionality.
22
3- use std:: { any:: TypeId , marker:: PhantomData , sync:: RwLock } ;
3+ use std:: { any:: TypeId , marker:: PhantomData , path :: PathBuf , sync:: RwLock } ;
44
55use bevy:: {
66 pbr:: MaterialPipelineKey ,
77 prelude:: {
88 default, info, warn, CoreStage , Image , IntoSystemDescriptor , Material , MaterialPlugin ,
9- Plugin ,
9+ Plugin , Handle , Shader , Deref , DerefMut , Resource ,
1010 } ,
1111 reflect:: TypeUuid ,
1212 render:: render_resource:: { AsBindGroup , PreparedBindGroup , ShaderRef } ,
13- utils:: HashMap ,
13+ utils:: { HashMap , HashSet } ,
1414} ;
1515use once_cell:: sync:: Lazy ;
1616
1717use crate :: {
1818 load_rust_gpu_shader:: RustGpuShader ,
19- prelude:: { EntryPoint , Export , ExportHandle , RustGpuMaterial , SHADER_META } ,
19+ prelude:: { EntryPoint , RustGpuMaterial } ,
2020 systems:: { reload_materials, shader_events} ,
2121} ;
2222
6868 }
6969}
7070
71+ /// A resource to track `rust-gpu` shaders that have been reloaded on a given frame
72+ #[ derive( Debug , Default , Clone , Deref , DerefMut , Resource ) ]
73+ pub struct ChangedShaders ( pub HashSet < Handle < Shader > > ) ;
74+
7175/// Type-level RustGpu material settings
7276#[ derive( Debug , Default , Copy , Clone ) ]
7377pub struct RustGpuSettings {
8690 pub vertex_shader : Option < RustGpuShader > ,
8791 pub fragment_shader : Option < RustGpuShader > ,
8892 pub iteration : usize ,
89- #[ cfg( feature = "hot-rebuild" ) ]
90- pub export_handle : Option < ExportHandle > ,
9193}
9294
9395impl < M > Clone for RustGpuKey < M >
@@ -101,7 +103,6 @@ where
101103 vertex_shader : self . vertex_shader . clone ( ) ,
102104 fragment_shader : self . fragment_shader . clone ( ) ,
103105 iteration : self . iteration . clone ( ) ,
104- export_handle : self . export_handle . clone ( ) ,
105106 }
106107 }
107108}
@@ -154,10 +155,6 @@ pub struct RustGpu<M> {
154155
155156 /// Current reload iteration, used to drive hot-reloading.
156157 pub iteration : usize ,
157-
158- /// If `Some`, active entry points will be reported to this handle.
159- #[ cfg( feature = "hot-rebuild" ) ]
160- pub export_handle : Option < ExportHandle > ,
161158}
162159
163160impl < M > PartialEq for RustGpu < M >
@@ -237,8 +234,6 @@ where
237234 vertex_shader : self . vertex_shader . clone ( ) ,
238235 fragment_shader : self . fragment_shader . clone ( ) ,
239236 iteration : self . iteration ,
240- #[ cfg( feature = "hot-rebuild" ) ]
241- export_handle : self . export_handle . clone ( ) ,
242237 } ,
243238 } )
244239 }
@@ -329,7 +324,7 @@ where
329324
330325 #[ cfg( feature = "hot-reload" ) ]
331326 {
332- let metas = SHADER_META . read ( ) . unwrap ( ) ;
327+ let metas = crate :: prelude :: SHADER_META . read ( ) . unwrap ( ) ;
333328 if let Some ( vertex_meta) = metas. get ( & vertex_shader. 0 ) {
334329 info ! ( "Vertex meta is valid" ) ;
335330 info ! ( "Checking entry point {entry_point:}" ) ;
@@ -343,15 +338,25 @@ where
343338 }
344339
345340 #[ cfg( feature = "hot-rebuild" ) ]
346- if let Some ( sender) = & key. bind_group_data . export_handle {
341+ ' hot_rebuild: {
342+ let exports = crate :: prelude:: MATERIAL_EXPORTS . read ( ) . unwrap ( ) ;
343+ let Some ( export) = exports. get ( & std:: any:: TypeId :: of :: < Self > ( ) ) else {
344+ break ' hot_rebuild;
345+ } ;
346+
347+ let handles = crate :: prelude:: EXPORT_HANDLES . read ( ) . unwrap ( ) ;
348+ let Some ( handle) = handles. get ( export) else {
349+ break ' hot_rebuild;
350+ } ;
351+
347352 info ! ( "Entrypoint sender is valid" ) ;
348- sender
349- . send ( Export {
353+ handle
354+ . send ( crate :: prelude :: Export {
350355 shader : M :: Vertex :: NAME ,
351356 permutation : M :: Vertex :: permutation ( & shader_defs) ,
352357 } )
353358 . unwrap ( ) ;
354- }
359+ } ;
355360
356361 if apply {
357362 info ! ( "Applying vertex shader and entry point" ) ;
@@ -382,7 +387,7 @@ where
382387 #[ cfg( feature = "hot-reload" ) ]
383388 {
384389 info ! ( "Fragment meta is present" ) ;
385- let metas = SHADER_META . read ( ) . unwrap ( ) ;
390+ let metas = crate :: prelude :: SHADER_META . read ( ) . unwrap ( ) ;
386391 if let Some ( fragment_meta) = metas. get ( & fragment_shader. 0 ) {
387392 info ! ( "Fragment meta is valid" ) ;
388393 info ! ( "Checking entry point {entry_point:}" ) ;
@@ -396,14 +401,25 @@ where
396401 }
397402
398403 #[ cfg( feature = "hot-rebuild" ) ]
399- if let Some ( sender) = & key. bind_group_data . export_handle {
400- sender
401- . send ( Export {
404+ ' hot_rebuild: {
405+ let exports = crate :: prelude:: MATERIAL_EXPORTS . read ( ) . unwrap ( ) ;
406+ let Some ( export) = exports. get ( & std:: any:: TypeId :: of :: < Self > ( ) ) else {
407+ break ' hot_rebuild;
408+ } ;
409+
410+ let handles = crate :: prelude:: EXPORT_HANDLES . read ( ) . unwrap ( ) ;
411+ let Some ( handle) = handles. get ( export) else {
412+ break ' hot_rebuild;
413+ } ;
414+
415+ info ! ( "Entrypoint sender is valid" ) ;
416+ handle
417+ . send ( crate :: prelude:: Export {
402418 shader : M :: Fragment :: NAME ,
403419 permutation : M :: Fragment :: permutation ( & shader_defs) ,
404420 } )
405421 . unwrap ( ) ;
406- }
422+ } ;
407423
408424 if apply {
409425 info ! ( "Applying fragment shader and entry point" ) ;
@@ -431,4 +447,10 @@ where
431447 let mut settings = MATERIAL_SETTINGS . write ( ) . unwrap ( ) ;
432448 f ( & mut settings. entry ( TypeId :: of :: < Self > ( ) ) . or_default ( ) ) ;
433449 }
450+
451+ #[ cfg( feature = "hot-rebuild" ) ]
452+ pub fn export_to < P : Into < PathBuf > > ( path : P ) {
453+ let mut handles = crate :: prelude:: MATERIAL_EXPORTS . write ( ) . unwrap ( ) ;
454+ handles. insert ( std:: any:: TypeId :: of :: < Self > ( ) , path. into ( ) ) ;
455+ }
434456}
0 commit comments