use crate::UniformProvider;
use std::path::PathBuf;
use wgpu;
#[derive(Debug, Clone)]
pub struct PassDescription {
pub name: String,
pub inputs: Vec<String>,
pub workgroup_size: Option<[u32; 3]>,
pub resolution: Option<[u32; 2]>,
pub resolution_scale: Option<f32>,
}
impl PassDescription {
pub fn new(name: &str, inputs: &[&str]) -> Self {
Self {
name: name.to_string(),
inputs: inputs.iter().map(|s| s.to_string()).collect(),
workgroup_size: None,
resolution: None,
resolution_scale: None,
}
}
pub fn with_workgroup_size(mut self, size: [u32; 3]) -> Self {
self.workgroup_size = Some(size);
self
}
pub fn with_resolution(mut self, width: u32, height: u32) -> Self {
self.resolution = Some([width, height]);
self
}
pub fn with_resolution_scale(mut self, scale: f32) -> Self {
self.resolution_scale = Some(scale);
self
}
}
#[derive(Debug, Clone)]
pub struct StorageBufferSpec {
pub name: String,
pub size_bytes: u64,
}
impl StorageBufferSpec {
pub fn new(name: &str, size_bytes: u64) -> Self {
Self {
name: name.to_string(),
size_bytes,
}
}
}
#[derive(Debug)]
pub struct ComputeConfiguration {
pub entry_points: Vec<String>,
pub passes: Option<Vec<PassDescription>>,
pub custom_uniform_size: Option<u64>,
pub has_input_texture: bool,
pub has_mouse: bool,
pub has_fonts: bool,
pub has_audio: bool,
pub has_atomic_buffer: bool,
pub atomic_buffer_channels: u32,
pub audio_buffer_size: usize,
pub has_audio_spectrum: bool,
pub audio_spectrum_size: usize,
pub storage_buffers: Vec<StorageBufferSpec>,
pub workgroup_size: [u32; 3],
pub dispatch_once: bool,
pub texture_format: wgpu::TextureFormat,
pub label: String,
pub num_channels: Option<u32>,
pub hot_reload_path: Option<PathBuf>,
pub max_input_deps: usize,
}
pub struct ComputeShaderBuilder {
config: ComputeConfiguration,
}
impl ComputeShaderBuilder {
pub fn new() -> Self {
Self {
config: ComputeConfiguration {
entry_points: vec!["main".to_string()],
passes: None,
custom_uniform_size: None,
has_input_texture: false,
has_mouse: false,
has_fonts: false,
has_audio: false,
has_atomic_buffer: false,
atomic_buffer_channels: 3,
audio_buffer_size: 1024,
has_audio_spectrum: false,
audio_spectrum_size: 128,
storage_buffers: Vec::new(),
workgroup_size: [16, 16, 1],
dispatch_once: false,
texture_format: wgpu::TextureFormat::Rgba16Float,
label: "Compute Shader".to_string(),
num_channels: None,
hot_reload_path: None,
max_input_deps: 3,
},
}
}
pub fn with_entry_point(mut self, entry_point: &str) -> Self {
self.config.entry_points = vec![entry_point.to_string()];
self
}
pub fn with_multi_pass(mut self, passes: &[PassDescription]) -> Self {
self.config.passes = Some(passes.to_vec());
self.config.entry_points = passes.iter().map(|p| p.name.clone()).collect();
self.config.max_input_deps = passes
.iter()
.map(|p| p.inputs.len())
.max()
.unwrap_or(0)
.max(1);
self
}
pub fn with_custom_uniforms<T: UniformProvider>(mut self) -> Self {
self.config.custom_uniform_size = Some(std::mem::size_of::<T>() as u64);
self
}
pub fn with_input_texture(mut self) -> Self {
self.config.has_input_texture = true;
self
}
pub fn with_channels(mut self, num_channels: u32) -> Self {
self.config.num_channels = Some(num_channels);
self
}
pub fn with_mouse(mut self) -> Self {
self.config.has_mouse = true;
self
}
pub fn with_fonts(mut self) -> Self {
self.config.has_fonts = true;
self
}
pub fn with_audio(mut self, buffer_size: usize) -> Self {
self.config.has_audio = true;
self.config.audio_buffer_size = buffer_size;
self
}
pub fn with_audio_spectrum(mut self, spectrum_size: usize) -> Self {
self.config.has_audio_spectrum = true;
self.config.audio_spectrum_size = spectrum_size;
self
}
pub fn with_atomic_buffer(mut self, channels: u32) -> Self {
self.config.has_atomic_buffer = true;
self.config.atomic_buffer_channels = channels;
self
}
pub fn with_storage_buffer(mut self, buffer: StorageBufferSpec) -> Self {
self.config.storage_buffers.push(buffer);
self
}
pub fn with_storage_buffers(mut self, buffers: &[StorageBufferSpec]) -> Self {
self.config.storage_buffers.extend_from_slice(buffers);
self
}
pub fn with_workgroup_size(mut self, size: [u32; 3]) -> Self {
self.config.workgroup_size = size;
self
}
pub fn dispatch_once(mut self) -> Self {
self.config.dispatch_once = true;
self
}
pub fn with_texture_format(mut self, format: wgpu::TextureFormat) -> Self {
self.config.texture_format = format;
self
}
pub fn with_label(mut self, label: &str) -> Self {
self.config.label = label.to_string();
self
}
pub fn with_hot_reload(mut self, shader_path: &str) -> Self {
self.config.hot_reload_path = Some(PathBuf::from(shader_path));
self
}
pub fn build(self) -> ComputeConfiguration {
self.config
}
}
impl Default for ComputeShaderBuilder {
fn default() -> Self {
Self::new()
}
}