Skip to content

Commit 4454209

Browse files
committed
alpha.5 fixes
1 parent 848cd9b commit 4454209

6 files changed

Lines changed: 92 additions & 32 deletions

File tree

‎Cargo.lock‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "processing"
3-
version = "0.0.9-alpha.5"
3+
version = "0.0.9-alpha.6"
44
edition = "2024"
55
autoexamples = false
66

‎crates/processing_pyo3/Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "processing_pyo3"
3-
version = "0.0.9-alpha.5"
3+
version = "0.0.9-alpha.6"
44
edition = "2024"
55

66
[lints]

‎crates/processing_render/src/compute.rs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use bevy::{
2121
};
2222

2323
use bevy_naga_reflect::dynamic_shader::DynamicShader;
24+
use bevy_naga_reflect::reflect::ParameterCategory;
2425

2526
use crate::geometry::{Attribute, Geometry};
2627
use crate::material::custom::Shader;
@@ -385,6 +386,15 @@ pub fn dispatch(
385386
if !ready {
386387
return Err(ProcessingError::ResourceNotReady(name.to_string()));
387388
}
389+
// wgpu treats an incomplete bind group as fatal, so fail here instead
390+
if matches!(param.category(), ParameterCategory::Storage { .. })
391+
&& shader.buffer_handle(name).is_none()
392+
&& !mesh_bindings.iter().any(|(n, _)| n == name)
393+
{
394+
return Err(ProcessingError::InvalidArgument(format!(
395+
"nothing is bound to the shader's storage array `{name}`"
396+
)));
397+
}
388398
}
389399

390400
let mut bind_groups = Vec::new();

‎crates/processing_render/src/particles/emit.rs‎

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,81 @@
1+
use std::collections::HashSet;
12
use std::sync::Mutex;
23

34
use bevy::prelude::*;
45

56
use processing_core::app_mut;
67
use processing_core::error;
78

9+
use crate::compute::Compute;
810
use crate::geometry;
911
use crate::particles::grid::grid_build;
1012
use crate::particles::kernels::KernelRequires;
1113
use crate::particles::{Particles, particles_ensure_attribute};
1214
use crate::shader_value::ShaderValue;
1315
use crate::{buffer_write_element, compute_create, compute_dispatch, compute_set, shader_load};
16+
use bevy_naga_reflect::reflect::ParameterCategory;
1417

1518
const 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+
1779
pub 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

221274
pub 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();

‎crates/processing_render/src/particles/kernels/mod.rs‎

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,26 @@ use bevy::prelude::*;
88
use processing_core::app_mut;
99
use processing_core::error::{self, ProcessingError};
1010

11-
use crate::geometry::{BuiltinAttributes, Geometry};
11+
use crate::geometry::Geometry;
1212
use crate::shader_value::ShaderValue;
1313
use crate::{compute_create, compute_set, shader_load};
1414

1515
#[derive(Component, Default, Clone)]
1616
pub struct KernelRequires(pub Vec<Entity>);
1717

1818
pub(crate) fn set_requires(compute: Entity, names: &[&str]) -> error::Result<()> {
19+
let attrs = names
20+
.iter()
21+
.map(|name| {
22+
crate::geometry_attribute_find(*name)?.ok_or_else(|| {
23+
ProcessingError::InvalidArgument(format!("no attribute named `{name}`"))
24+
})
25+
})
26+
.collect::<error::Result<Vec<Entity>>>()?;
1927
app_mut(|app| {
20-
let world = app.world_mut();
21-
let attrs: Vec<Entity> = {
22-
let builtins = world.resource::<BuiltinAttributes>();
23-
names.iter().filter_map(|n| builtins.by_name(n)).collect()
24-
};
25-
world.entity_mut(compute).insert(KernelRequires(attrs));
28+
app.world_mut()
29+
.entity_mut(compute)
30+
.insert(KernelRequires(attrs));
2631
Ok(())
2732
})
2833
}
@@ -266,7 +271,8 @@ pub fn particles_kernel_orient() -> error::Result<Entity> {
266271
pub fn particles_kernel_field() -> error::Result<Entity> {
267272
let shader = shader_load("embedded://processing_render/particles/kernels/field.wgsl")?;
268273
let entity = compute_create(shader)?;
269-
set_requires(entity, &["position"])?;
274+
crate::geometry_attribute_create("weight", crate::geometry::AttributeFormat::Float)?;
275+
set_requires(entity, &["position", "weight"])?;
270276
compute_set(entity, "center", ShaderValue::Float3([0.0; 3]))?;
271277
compute_set(entity, "radius", ShaderValue::Float(1.0))?;
272278
compute_set(

0 commit comments

Comments
 (0)