use image::{DynamicImage, EncodableLayout}; use wgpu::{util::DeviceExt, *}; use crate::layout::{TextureUpdate, Textures}; pub struct GpuTextures { device: Device, queue: Queue, views: Vec, samplers: Vec, null_view: TextureView, no_views: Vec, } impl GpuTextures { pub fn update(&mut self, textures: &mut Textures) -> bool { let mut changed = false; for update in textures.updates() { changed = true; match update { TextureUpdate::Push(image) => self.push(image), TextureUpdate::Set(i, image) => self.set(i, image), TextureUpdate::Free(i) => self.free(i), } } changed } fn set(&mut self, i: u32, image: &DynamicImage) { let view = self.create_view(image); self.views[i as usize] = view; } fn free(&mut self, i: u32) { self.views[i as usize] = self.null_view.clone(); } fn push(&mut self, image: &DynamicImage) { let view = self.create_view(image); self.views.push(view); } fn create_view(&self, image: &DynamicImage) -> TextureView { let image = image.to_rgba8(); let (width, height) = image.dimensions(); let texture = self.device.create_texture_with_data( &self.queue, &TextureDescriptor { label: None, size: Extent3d { width, height, depth_or_array_layers: 1, }, mip_level_count: 1, sample_count: 1, dimension: TextureDimension::D2, format: TextureFormat::Rgba8Unorm, usage: TextureUsages::TEXTURE_BINDING, view_formats: &[], }, wgt::TextureDataOrder::MipMajor, image.as_bytes(), ); texture.create_view(&TextureViewDescriptor::default()) } pub fn new(device: &Device, queue: &Queue) -> Self { let null_view = null_texture_view(device); Self { device: device.clone(), queue: queue.clone(), views: Vec::new(), samplers: vec![default_sampler(device)], no_views: vec![null_view.clone()], null_view, } } pub fn views(&self) -> Vec<&TextureView> { if self.views.is_empty() { &self.no_views } else { &self.views } .iter() .by_ref() .collect() } pub fn samplers(&self) -> Vec<&Sampler> { self.samplers.iter().by_ref().collect() } } pub fn null_texture_view(device: &Device) -> TextureView { device .create_texture(&TextureDescriptor { label: Some("null"), size: Extent3d { width: 1, height: 1, depth_or_array_layers: 1, }, mip_level_count: 1, sample_count: 1, dimension: TextureDimension::D2, format: TextureFormat::Rgba8Unorm, usage: TextureUsages::TEXTURE_BINDING, view_formats: &[], }) .create_view(&TextureViewDescriptor::default()) } pub fn default_sampler(device: &Device) -> Sampler { device.create_sampler(&SamplerDescriptor::default()) }