summaryrefslogtreecommitdiffstats
path: root/src/uniform.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/uniform.rs')
-rw-r--r--src/uniform.rs224
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(