use std::collections::HashMap;
use crate::backend::RenderError;
pub struct TexturePipeline {
textures: HashMap<u64, wgpu::Texture>,
bind_groups: HashMap<u64, wgpu::BindGroup>,
next_id: u64,
pub bind_group_layout: wgpu::BindGroupLayout,
sampler: wgpu::Sampler,
}
impl TexturePipeline {
pub fn new(device: &wgpu::Device) -> Self {
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("texture_bind_group_layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("texture_sampler"),
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
..Default::default()
});
Self {
textures: HashMap::new(),
bind_groups: HashMap::new(),
next_id: 1,
bind_group_layout,
sampler,
}
}
pub fn load(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
width: u32,
height: u32,
data: &[u8],
) -> Result<u64, RenderError> {
let expected_size = (width * height * 4) as usize;
if data.len() != expected_size {
return Err(RenderError::TextureError(format!(
"expected {} bytes, got {}",
expected_size,
data.len()
)));
}
let size = wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
};
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("user_texture"),
size,
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
queue.write_texture(
wgpu::TexelCopyTextureInfo {
texture: &texture,
mip_level: 0,
origin: wgpu::Origin3d::ZERO,
aspect: wgpu::TextureAspect::All,
},
data,
wgpu::TexelCopyBufferLayout {
offset: 0,
bytes_per_row: Some(4 * width),
rows_per_image: Some(height),
},
size,
);
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("texture_bind_group"),
layout: &self.bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&self.sampler),
},
],
});
let id = self.next_id;
self.next_id += 1;
self.textures.insert(id, texture);
self.bind_groups.insert(id, bind_group);
Ok(id)
}
pub fn get_bind_group(&self, id: u64) -> Option<&wgpu::BindGroup> {
self.bind_groups.get(&id)
}
}