diff options
Diffstat (limited to 'src/uniform.rs')
| -rw-r--r-- | src/uniform.rs | 224 |
1 files changed, 95 insertions, 129 deletions
diff --git a/src/uniform.rs b/src/uniform.rs index 8f8b172..142c70c 100644 --- a/src/uniform.rs +++ b/src/uniform.rs @@ -409,16 +409,12 @@ pub struct TextureResource { height: u32, depth_or_array_layers: u32, view_dimension: wgpu::TextureViewDimension, - sample_type: wgpu::TextureSampleType, - multisampled: bool, } impl TextureResource { pub fn new(device: &wgpu::Device, id: String, tsv_name: String) -> Self { let format = wgpu::TextureFormat::Rgba8UnormSrgb; let view_dimension = wgpu::TextureViewDimension::D2; - let sample_type = wgpu::TextureSampleType::Float { filterable: true }; - let multisampled = false; let dimension = view_dimension_to_texture_dimension(view_dimension); let (texture, view) = create_input_texture(device, &id, 1, 1, 1, dimension, view_dimension, format); @@ -433,8 +429,6 @@ impl TextureResource { height: 1, depth_or_array_layers: 1, view_dimension, - sample_type, - multisampled, } } @@ -473,14 +467,6 @@ impl TextureResource { self.view_dimension } - pub fn sample_type(&self) -> wgpu::TextureSampleType { - self.sample_type - } - - pub fn multisampled(&self) -> bool { - self.multisampled - } - pub fn width(&self) -> u32 { self.width } @@ -525,8 +511,6 @@ impl TextureResource { self.height = height; self.depth_or_array_layers = depth_or_array_layers; self.view_dimension = view_dimension; - self.sample_type = wgpu::TextureSampleType::Float { filterable: true }; - self.multisampled = false; true } } @@ -585,12 +569,10 @@ impl SamplerResource { filter: wgpu::FilterMode, address_mode: wgpu::AddressMode, ) -> Self { - let mut this = Self { + Self { sampler: create_sampler(device, &id, filter, address_mode), id, - }; - this.configure(device, filter, address_mode); - this + } } pub fn id(&self) -> &str { @@ -633,70 +615,6 @@ fn create_sampler( }) } -pub struct ResourcePools { - textures: HashMap<String, TextureResource>, - samplers: HashMap<String, SamplerResource>, -} - -impl Default for ResourcePools { - fn default() -> Self { - Self::new() - } -} - -impl ResourcePools { - pub fn new() -> Self { - Self { - textures: HashMap::new(), - samplers: HashMap::new(), - } - } - - pub fn create_texture(&mut self, device: &wgpu::Device, id: &str, tsv_name: &str) { - self.textures.insert( - id.to_string(), - TextureResource::new(device, id.to_string(), tsv_name.to_string()), - ); - } - - pub fn destroy_texture(&mut self, id: &str) -> bool { - self.textures.remove(id).is_some() - } - - pub fn texture(&self, id: &str) -> Option<&TextureResource> { - self.textures.get(id) - } - - pub fn texture_mut(&mut self, id: &str) -> Option<&mut TextureResource> { - self.textures.get_mut(id) - } - - pub fn textures_mut(&mut self) -> impl Iterator<Item = &mut TextureResource> { - self.textures.values_mut() - } - - pub fn create_sampler( - &mut self, - device: &wgpu::Device, - id: &str, - filter: wgpu::FilterMode, - address_mode: wgpu::AddressMode, - ) { - self.samplers.insert( - id.to_string(), - SamplerResource::new(device, id.to_string(), filter, address_mode), - ); - } - - pub fn destroy_sampler(&mut self, id: &str) -> bool { - self.samplers.remove(id).is_some() - } - - pub fn sampler(&self, id: &str) -> Option<&SamplerResource> { - self.samplers.get(id) - } -} - struct TextureBindingSlot { name: String, binding: u32, @@ -748,13 +666,16 @@ fn image_multisampled(class: naga::ImageClass) -> bool { } /// Manages uniform buffer data and texture/sampler bindings for all globals in a shader. +/// Also owns the pooled texture and sampler resources. pub struct UniformCache { pub module: naga::Module, pub layouter: Layouter, uniforms: HashMap<String, UniformMember>, buffers: Vec<BufferState>, - textures: Vec<TextureBindingSlot>, - samplers: Vec<SamplerBindingSlot>, + texture_pool: HashMap<String, TextureResource>, + sampler_pool: HashMap<String, SamplerResource>, + texture_slots: Vec<TextureBindingSlot>, + sampler_slots: Vec<SamplerBindingSlot>, pub bind_group_layout: Option<wgpu::BindGroupLayout>, pub bind_group: Option<wgpu::BindGroup>, dirty: bool, @@ -786,8 +707,10 @@ impl UniformCache { layouter: Layouter::default(), uniforms: HashMap::new(), buffers: Vec::new(), - textures: Vec::new(), - samplers: Vec::new(), + texture_pool: HashMap::new(), + sampler_pool: HashMap::new(), + texture_slots: Vec::new(), + sampler_slots: Vec::new(), bind_group_layout: None, bind_group: None, dirty: false, @@ -804,8 +727,8 @@ impl UniformCache { let old_module = std::mem::take(&mut self.module); let old_uniforms = std::mem::take(&mut self.uniforms); let old_buffers = std::mem::take(&mut self.buffers); - let old_textures = std::mem::take(&mut self.textures); - let old_samplers = std::mem::take(&mut self.samplers); + let old_textures = std::mem::take(&mut self.texture_slots); + let old_samplers = std::mem::take(&mut self.sampler_slots); let mut new_uniforms: HashMap<String, UniformMember> = HashMap::new(); let mut new_buffers: Vec<BufferState> = Vec::new(); @@ -932,54 +855,96 @@ impl UniformCache { self.layouter = new_layouter; self.uniforms = new_uniforms; self.buffers = new_buffers; - self.textures = new_textures; - self.samplers = new_samplers; + self.texture_slots = new_textures; + self.sampler_slots = new_samplers; self.dirty = true; } - pub fn bind_texture_resource( + // --- Resource pool operations --- + + pub fn create_texture(&mut self, device: &wgpu::Device, id: &str, tsv_name: &str) { + self.texture_pool.insert( + id.to_string(), + TextureResource::new(device, id.to_string(), tsv_name.to_string()), + ); + self.build_bind_group(device); + } + + pub fn destroy_texture(&mut self, device: &wgpu::Device, id: &str) { + let removed = self.texture_pool.remove(id).is_some(); + let unbound = self.unbind_texture_resource(id); + if removed || unbound { + self.build_bind_group(device); + } + } + + pub fn textures_mut(&mut self) -> impl Iterator<Item = &mut TextureResource> { + self.texture_pool.values_mut() + } + + pub fn create_sampler( + &mut self, + device: &wgpu::Device, + id: &str, + filter: wgpu::FilterMode, + address_mode: wgpu::AddressMode, + ) { + self.sampler_pool.insert( + id.to_string(), + SamplerResource::new(device, id.to_string(), filter, address_mode), + ); + self.build_bind_group(device); + } + + pub fn destroy_sampler(&mut self, device: &wgpu::Device, id: &str) { + let removed = self.sampler_pool.remove(id).is_some(); + let unbound = self.unbind_sampler_resource(id); + if removed || unbound { + self.build_bind_group(device); + } + } + + pub fn bind_texture( &mut self, device: &wgpu::Device, - pools: &ResourcePools, - name: &str, + slot_name: &str, resource_id: &str, ) -> Result<(), String> { - if pools.texture(resource_id).is_none() { + if !self.texture_pool.contains_key(resource_id) { return Err(format!("texture '{resource_id}' not found")); } let slot = self - .textures + .texture_slots .iter_mut() - .find(|t| t.name == name) - .ok_or_else(|| format!("texture binding '{name}' not found"))?; + .find(|t| t.name == slot_name) + .ok_or_else(|| format!("texture binding '{slot_name}' not found in shader"))?; slot.resource_id = Some(resource_id.to_string()); - self.build_bind_group(device, pools); + self.build_bind_group(device); Ok(()) } - pub fn bind_sampler_resource( + pub fn bind_sampler( &mut self, device: &wgpu::Device, - pools: &ResourcePools, - name: &str, + slot_name: &str, resource_id: &str, ) -> Result<(), String> { - if pools.sampler(resource_id).is_none() { + if !self.sampler_pool.contains_key(resource_id) { return Err(format!("sampler '{resource_id}' not found")); } let slot = self - .samplers + .sampler_slots .iter_mut() - .find(|s| s.name == name) - .ok_or_else(|| format!("sampler binding '{name}' not found"))?; + .find(|s| s.name == slot_name) + .ok_or_else(|| format!("sampler binding '{slot_name}' not found in shader"))?; slot.resource_id = Some(resource_id.to_string()); - self.build_bind_group(device, pools); + self.build_bind_group(device); Ok(()) } - pub fn unbind_texture_resource(&mut self, id: &str) -> bool { + fn unbind_texture_resource(&mut self, id: &str) -> bool { let mut changed = false; - for slot in &mut self.textures { + for slot in &mut self.texture_slots { if slot.resource_id.as_deref() == Some(id) { slot.resource_id = None; changed = true; @@ -988,9 +953,9 @@ impl UniformCache { changed } - pub fn unbind_sampler_resource(&mut self, id: &str) -> bool { + fn unbind_sampler_resource(&mut self, id: &str) -> bool { let mut changed = false; - for slot in &mut self.samplers { + for slot in &mut self.sampler_slots { if slot.resource_id.as_deref() == Some(id) { slot.resource_id = None; changed = true; @@ -999,14 +964,15 @@ impl UniformCache { changed } - /// Rebuild the bind group (e.g. after a texture resize). - pub fn rebuild_bind_group(&mut self, device: &wgpu::Device, pools: &ResourcePools) { - self.build_bind_group(device, pools); + /// Rebuild the bind group after external changes (e.g. texture resize from TSV). + pub fn rebuild_bind_group(&mut self, device: &wgpu::Device) { + self.build_bind_group(device); } - fn build_bind_group(&mut self, device: &wgpu::Device, pools: &ResourcePools) { - let has_bindings = - !self.buffers.is_empty() || !self.textures.is_empty() || !self.samplers.is_empty(); + fn build_bind_group(&mut self, device: &wgpu::Device) { + let has_bindings = !self.buffers.is_empty() + || !self.texture_slots.is_empty() + || !self.sampler_slots.is_empty(); if !has_bindings { self.bind_group_layout = None; @@ -1029,7 +995,7 @@ impl UniformCache { }); } - for tex in &self.textures { + for tex in &self.texture_slots { layout_entries.push(wgpu::BindGroupLayoutEntry { binding: tex.binding, visibility: wgpu::ShaderStages::FRAGMENT, @@ -1042,7 +1008,7 @@ impl UniformCache { }); } - for smp in &self.samplers { + for smp in &self.sampler_slots { layout_entries.push(wgpu::BindGroupLayoutEntry { binding: smp.binding, visibility: wgpu::ShaderStages::FRAGMENT, @@ -1058,12 +1024,12 @@ impl UniformCache { let mut bg_entries: Vec<wgpu::BindGroupEntry> = Vec::new(); let fallback_textures_and_views: Vec<_> = self - .textures + .texture_slots .iter() .map(|tex| create_placeholder_texture(device, tex)) .collect(); let fallback_samplers: Vec<_> = self - .samplers + .sampler_slots .iter() .map(|smp| { if smp.binding_type == wgpu::SamplerBindingType::Comparison { @@ -1088,11 +1054,11 @@ impl UniformCache { }); } - for (idx, tex) in self.textures.iter().enumerate() { + for (idx, tex) in self.texture_slots.iter().enumerate() { let resource = tex .resource_id .as_deref() - .and_then(|id| pools.texture(id)) + .and_then(|id| self.texture_pool.get(id)) .filter(|res| texture_resource_matches(tex, res)); let texture_view = if let Some(resource) = resource { resource.view() @@ -1105,11 +1071,13 @@ impl UniformCache { }); } - for (idx, smp) in self.samplers.iter().enumerate() { + for (idx, smp) in self.sampler_slots.iter().enumerate() { let sampler = if smp.binding_type == wgpu::SamplerBindingType::Comparison { &fallback_samplers[idx] - } else if let Some(resource) = - smp.resource_id.as_deref().and_then(|id| pools.sampler(id)) + } else if let Some(resource) = smp + .resource_id + .as_deref() + .and_then(|id| self.sampler_pool.get(id)) { resource.sampler() } else { @@ -1164,8 +1132,6 @@ impl UniformCache { fn texture_resource_matches(slot: &TextureBindingSlot, resource: &TextureResource) -> bool { slot.view_dimension == resource.view_dimension() - && slot.sample_type == resource.sample_type() - && slot.multisampled == resource.multisampled() } fn create_placeholder_texture( |
