1+ use std:: collections:: HashSet ;
12use std:: sync:: Mutex ;
23
34use bevy:: prelude:: * ;
45
56use processing_core:: app_mut;
67use processing_core:: error;
78
9+ use crate :: compute:: Compute ;
810use crate :: geometry;
911use crate :: particles:: grid:: grid_build;
1012use crate :: particles:: kernels:: KernelRequires ;
1113use crate :: particles:: { Particles , particles_ensure_attribute} ;
1214use crate :: shader_value:: ShaderValue ;
1315use crate :: { buffer_write_element, compute_create, compute_dispatch, compute_set, shader_load} ;
16+ use bevy_naga_reflect:: reflect:: ParameterCategory ;
1417
1518const WORKGROUP_SIZE : u32 = 64 ;
1619
20+ /// Creates every column `compute_entity` reads or writes that the system doesn't
21+ /// have yet: the kernel's declared requirements, plus any storage array the shader
22+ /// names after a known attribute. A storage array left unbound would make the
23+ /// bind group incomplete, which wgpu treats as fatal, so an unknown name is an error.
24+ fn ensure_columns ( particles_entity : Entity , compute_entity : Entity ) -> error:: Result < ( ) > {
25+ let ( required, missing) = app_mut ( |app| {
26+ let world = app. world ( ) ;
27+ let required = world
28+ . get :: < KernelRequires > ( compute_entity)
29+ . map ( |r| r. 0 . clone ( ) )
30+ . unwrap_or_default ( ) ;
31+ let compute = world
32+ . get :: < Compute > ( compute_entity)
33+ . ok_or ( error:: ProcessingError :: ComputeNotFound ) ?;
34+ let particles = world
35+ . get :: < Particles > ( particles_entity)
36+ . ok_or ( error:: ProcessingError :: ParticlesNotFound ) ?;
37+ let have: HashSet < & str > = particles
38+ . buffers
39+ . keys ( )
40+ . filter_map ( |& e| world. get :: < geometry:: Attribute > ( e) . map ( |a| a. name ) )
41+ . chain (
42+ particles
43+ . neighbor_lists
44+ . map ( |_| [ "neighbors" , "neighbor_count" ] )
45+ . into_iter ( )
46+ . flatten ( ) ,
47+ )
48+ . collect ( ) ;
49+ let missing: Vec < String > = compute
50+ . shader
51+ . reflection ( )
52+ . parameters ( )
53+ . filter ( |p| matches ! ( p. category( ) , ParameterCategory :: Storage { .. } ) )
54+ . filter_map ( |p| p. name ( ) . map ( str:: to_string) )
55+ . filter ( |name| {
56+ !have. contains ( name. as_str ( ) )
57+ && compute. shader . buffer_handle ( name) . is_none ( )
58+ && !compute. mesh_bindings . contains_key ( name)
59+ } )
60+ . collect ( ) ;
61+ Ok ( ( required, missing) )
62+ } ) ?;
63+
64+ for attr_entity in required {
65+ particles_ensure_attribute ( particles_entity, attr_entity) ?;
66+ }
67+ for name in missing {
68+ let attr = crate :: geometry_attribute_find ( name. as_str ( ) ) ?. ok_or_else ( || {
69+ error:: ProcessingError :: InvalidArgument ( format ! (
70+ "the shader uses a column named `{name}` that these particles don't have. \
71+ Create the column before applying it"
72+ ) )
73+ } ) ?;
74+ particles_ensure_attribute ( particles_entity, attr) ?;
75+ }
76+ Ok ( ( ) )
77+ }
78+
1779pub fn particles_emit_gpu (
1880 particles_entity : Entity ,
1981 count : u32 ,
@@ -23,16 +85,7 @@ pub fn particles_emit_gpu(
2385 return Ok ( ( ) ) ;
2486 }
2587
26- let required: Vec < Entity > = app_mut ( |app| {
27- Ok ( app
28- . world ( )
29- . get :: < KernelRequires > ( compute_entity)
30- . map ( |r| r. 0 . clone ( ) )
31- . unwrap_or_default ( ) )
32- } ) ?;
33- for attr_entity in required {
34- particles_ensure_attribute ( particles_entity, attr_entity) ?;
35- }
88+ ensure_columns ( particles_entity, compute_entity) ?;
3689
3790 let ( capacity, head, buffers) = app_mut ( |app| {
3891 let world = app. world ( ) ;
@@ -219,16 +272,7 @@ pub fn particles_gather(
219272}
220273
221274pub fn particles_apply ( particles_entity : Entity , compute_entity : Entity ) -> error:: Result < ( ) > {
222- let required: Vec < Entity > = app_mut ( |app| {
223- Ok ( app
224- . world ( )
225- . get :: < KernelRequires > ( compute_entity)
226- . map ( |r| r. 0 . clone ( ) )
227- . unwrap_or_default ( ) )
228- } ) ?;
229- for attr_entity in required {
230- particles_ensure_attribute ( particles_entity, attr_entity) ?;
231- }
275+ ensure_columns ( particles_entity, compute_entity) ?;
232276
233277 let ( capacity, buffers) = app_mut ( |app| {
234278 let world = app. world ( ) ;
0 commit comments