130 lines
3.8 KiB
Rust
130 lines
3.8 KiB
Rust
use image::{DynamicImage, EncodableLayout};
|
|
use wgpu::{util::DeviceExt, *};
|
|
|
|
use crate::layout::{TextureUpdate, Textures};
|
|
|
|
pub struct GpuTextures {
|
|
device: Device,
|
|
queue: Queue,
|
|
views: Vec<TextureView>,
|
|
view_count: usize,
|
|
samplers: Vec<Sampler>,
|
|
null_view: TextureView,
|
|
no_views: Vec<TextureView>,
|
|
}
|
|
|
|
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::SetFree => self.view_count += 1,
|
|
TextureUpdate::Free(i) => self.free(i),
|
|
TextureUpdate::PushFree => self.push_free(),
|
|
}
|
|
}
|
|
changed
|
|
}
|
|
fn set(&mut self, i: u32, image: &DynamicImage) {
|
|
self.view_count += 1;
|
|
let view = self.create_view(image);
|
|
self.views[i as usize] = view;
|
|
}
|
|
fn free(&mut self, i: u32) {
|
|
self.view_count -= 1;
|
|
self.views[i as usize] = self.null_view.clone();
|
|
}
|
|
fn push(&mut self, image: &DynamicImage) {
|
|
self.view_count += 1;
|
|
let view = self.create_view(image);
|
|
self.views.push(view);
|
|
}
|
|
fn push_free(&mut self) {
|
|
self.view_count += 1;
|
|
self.views.push(self.null_view.clone());
|
|
}
|
|
|
|
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,
|
|
view_count: 0,
|
|
}
|
|
}
|
|
|
|
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 view_count(&self) -> usize {
|
|
self.view_count
|
|
}
|
|
}
|
|
|
|
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())
|
|
}
|