summaryrefslogtreecommitdiffstats
path: root/src/bin
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2026-04-22 13:35:18 +0000
committers-ol <s+removethis@s-ol.nu>2026-05-14 14:46:13 +0000
commit9fd2105289ccc5a7c12af56bad4d33ef768d0f16 (patch)
treea4e6ff2c64fd0f1d4c73d74b3d62327630ff6206 /src/bin
parentadd tsv-video-buffer (diff)
downloadwgsl-view-9fd2105289ccc5a7c12af56bad4d33ef768d0f16.tar.gz
wgsl-view-9fd2105289ccc5a7c12af56bad4d33ef768d0f16.zip
samplers/textures as resources
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/wgsl_render.rs122
1 files changed, 55 insertions, 67 deletions
diff --git a/src/bin/wgsl_render.rs b/src/bin/wgsl_render.rs
index 29b5d5d..da28816 100644
--- a/src/bin/wgsl_render.rs
+++ b/src/bin/wgsl_render.rs
@@ -61,52 +61,35 @@ fn main() {
loop {
let frame_start = Instant::now();
- let handle_msg = |msg: rosc::OscMessage| {
- let path = &msg.addr;
-
- if path == "/shader" {
- match &msg.args[..] {
- [OscType::String(code)] => {
- if let Err(e) = renderer.load_shader(&device, code) {
- log::error!("shader error: {e}");
- }
- }
- _ => log::warn!("/shader: expected single string argument"),
+ let handle_msg = |msg: rosc::OscMessage| -> Result<(), String> {
+ let path: Vec<_> = msg.addr.strip_prefix("/").unwrap().split('/').collect();
+
+ match (&path[..], &msg.args[..]) {
+ (["shader"], [OscType::String(code)]) => renderer.load_shader(&device, code),
+ (["uniform", rest @ ..], args) => {
+ set_uniform(renderer.uniforms(), rest, args).map_err(|e| e.to_string())
+ }
+ (["texture", id], [OscType::String(tsv_name)]) => {
+ renderer.create_texture_resource(&device, id, tsv_name);
+ Ok(())
}
- } else if let Some(rest) = path.strip_prefix("/uniform/") {
- if let Err(e) = set_uniform(renderer.uniforms(), rest, &msg.args) {
- log::warn!("uniform error: {e}");
+ (["sampler", id], [OscType::String(filter), OscType::String(clamp)]) => {
+ let (filter_mode, address_mode) = parse_sampler_modes(filter, clamp)?;
+ renderer.create_sampler_resource(&device, id, filter_mode, address_mode);
+ Ok(())
}
- } else if let Some(tex_name) = path.strip_prefix("/texture/") {
- match &msg.args[..] {
- [OscType::String(tsv_name)] => {
- match renderer.uniforms().texture_slot_mut(tex_name) {
- Some(slot) => {
- slot.set_tsv_name(tsv_name.clone());
- log::info!("texture '{tex_name}' → tsv '{tsv_name}'");
- }
- None => log::warn!("texture '{tex_name}' not found"),
- }
- }
- _ => log::warn!("/texture/{tex_name}: expected string (TSV image name)"),
+ (["texture", id, "destroy"], []) => {
+ renderer.destroy_texture_resource(&device, id);
+ Ok(())
}
- } else if let Some(smp_name) = path.strip_prefix("/sampler/") {
- match &msg.args[..] {
- [OscType::String(filter), OscType::String(clamp)] => {
- if let Err(e) = configure_sampler(
- renderer.uniforms(),
- &device,
- smp_name,
- filter,
- clamp,
- ) {
- log::warn!("sampler error: {e}");
- }
- }
- _ => log::warn!("/sampler/{smp_name}: expected two strings (filter, clamp)"),
+ (["sampler", id, "destroy"], []) => {
+ renderer.destroy_sampler_resource(&device, id);
+ Ok(())
}
- } else {
- log::debug!("unhandled OSC: {path}");
+ (["binding", name], [OscType::String(target)]) => {
+ bind_resource(&mut renderer, &device, name, target)
+ }
+ _ => Err(format!("unhandled OSC message {} {:?}", msg.addr, msg.args)),
}
};
@@ -118,7 +101,7 @@ fn main() {
};
if dirty {
- gpu::refresh_textures(renderer.uniforms(), &device, &mut client, fence);
+ renderer.refresh_textures(&device, &mut client, fence);
renderer.render(&device, &queue);
device.poll(wgpu::PollType::wait_indefinitely()).unwrap();
@@ -146,13 +129,13 @@ fn main() {
/// Set a uniform value from OSC args, navigating the path.
fn set_uniform(
cache: &mut wgsl_view::uniform::UniformCache,
- path: &str,
+ path: &[&str],
args: &[OscType],
-) -> Result<(), Box<dyn std::error::Error>> {
- let mut parts = path.split('/');
- let name = parts.next().ok_or("missing uniform name")?;
+) -> Result<(), UniformError> {
+ let mut parts = path.iter();
+ let name = parts.next().ok_or(UniformError::NotFound)?;
- let mut uref = cache.get(name).ok_or("uniform not found")?;
+ let mut uref = cache.get(name).ok_or(UniformError::NotFound)?;
for component in parts {
uref = uref.field(component)?;
}
@@ -198,38 +181,43 @@ fn set_uniform(
.collect::<Result<_, _>>()?;
uref.set_u32(&values)?;
}
- _ => return Err(Box::new(UniformError::TypeMismatch)),
+ _ => return Err(UniformError::TypeMismatch),
}
Ok(())
}
-/// Configure a named sampler from string filter/clamp mode names.
-fn configure_sampler(
- cache: &mut wgsl_view::uniform::UniformCache,
- device: &wgpu::Device,
- name: &str,
+fn parse_sampler_modes(
filter: &str,
- clamp: &str,
-) -> Result<(), String> {
+ address: &str,
+) -> Result<(wgpu::FilterMode, wgpu::AddressMode), String> {
let filter_mode = match filter {
"linear" => wgpu::FilterMode::Linear,
"nearest" => wgpu::FilterMode::Nearest,
- _ => return Err(format!("unknown filter mode '{filter}' (linear|nearest)")),
+ _ => return Err(format!("unknown filter mode '{filter}'")),
};
- let address_mode = match clamp {
+ let address_mode = match address {
"clamp" => wgpu::AddressMode::ClampToEdge,
"repeat" => wgpu::AddressMode::Repeat,
"mirror" => wgpu::AddressMode::MirrorRepeat,
- _ => return Err(format!("unknown clamp mode '{clamp}' (clamp|repeat|mirror)")),
+ _ => return Err(format!("unknown address mode mode '{address}'")),
};
- let slot = cache
- .sampler_slot_mut(name)
- .ok_or_else(|| format!("sampler '{name}' not found"))?;
- slot.configure(device, filter_mode, address_mode);
- cache.rebuild_bind_group(device);
- log::info!("sampler '{name}' → {filter}, {clamp}");
- Ok(())
+ Ok((filter_mode, address_mode))
}
-
+fn bind_resource(
+ renderer: &mut Renderer,
+ device: &wgpu::Device,
+ name: &str,
+ target: &str,
+) -> Result<(), String> {
+ if let Some(id) = target.strip_prefix("/texture/") {
+ renderer.bind_texture_resource(device, name, id)?;
+ Ok(())
+ } else if let Some(id) = target.strip_prefix("/sampler/") {
+ renderer.bind_sampler_resource(device, name, id)?;
+ Ok(())
+ } else {
+ Err(format!("invalid binding target '{target}'"))
+ }
+}