1use std::{marker::PhantomData, sync::Arc};
2
3use image::RgbaImage;
4use wgpu::util::DeviceExt;
5
6use super::Bind;
7
8pub trait TextureBindType {
10 fn binding_type(format: wgpu::TextureFormat) -> wgpu::BindingType;
11 fn texture_usages() -> wgpu::TextureUsages;
12}
13
14#[derive(Debug)]
15pub struct TextureType;
17#[derive(Debug)]
18pub struct StorageReadWriteTextureType;
22#[derive(Debug)]
23pub struct StorageReadOnlyTextureType;
27#[derive(Debug)]
28pub struct StorageWriteOnlyTextureType;
30
31impl TextureBindType for TextureType {
32 fn binding_type(_format: wgpu::TextureFormat) -> wgpu::BindingType {
33 wgpu::BindingType::Texture {
34 sample_type: wgpu::TextureSampleType::Float { filterable: true },
35 view_dimension: wgpu::TextureViewDimension::D2,
36 multisampled: false,
37 }
38 }
39 fn texture_usages() -> wgpu::TextureUsages {
40 wgpu::TextureUsages::TEXTURE_BINDING
41 }
42}
43impl TextureBindType for StorageReadWriteTextureType {
44 fn binding_type(format: wgpu::TextureFormat) -> wgpu::BindingType {
45 wgpu::BindingType::StorageTexture {
46 access: wgpu::StorageTextureAccess::ReadWrite,
47 format,
48 view_dimension: wgpu::TextureViewDimension::D2,
49 }
50 }
51 fn texture_usages() -> wgpu::TextureUsages {
52 wgpu::TextureUsages::STORAGE_BINDING
53 }
54}
55impl TextureBindType for StorageReadOnlyTextureType {
56 fn binding_type(format: wgpu::TextureFormat) -> wgpu::BindingType {
57 wgpu::BindingType::StorageTexture {
58 access: wgpu::StorageTextureAccess::ReadOnly,
59 format,
60 view_dimension: wgpu::TextureViewDimension::D2,
61 }
62 }
63 fn texture_usages() -> wgpu::TextureUsages {
64 wgpu::TextureUsages::STORAGE_BINDING
65 }
66}
67impl TextureBindType for StorageWriteOnlyTextureType {
68 fn binding_type(format: wgpu::TextureFormat) -> wgpu::BindingType {
69 wgpu::BindingType::StorageTexture {
70 access: wgpu::StorageTextureAccess::WriteOnly,
71 format,
72 view_dimension: wgpu::TextureViewDimension::D2,
73 }
74 }
75 fn texture_usages() -> wgpu::TextureUsages {
76 wgpu::TextureUsages::STORAGE_BINDING
77 }
78}
79
80pub type PlainTextureBind<I> = TextureBind<I, TextureType>;
82pub type StorageTextureBind<I> = TextureBind<I, StorageWriteOnlyTextureType>;
84pub type RgbaStorageTextureBind = TextureBind<RgbaImage, StorageWriteOnlyTextureType>;
86
87pub trait BindableImage {
89 fn from_vec(width: u32, height: u32, vec: Vec<u8>) -> Self;
90 fn size(&self) -> (u32, u32);
91 fn as_slice(&self) -> &[u8];
92 fn format() -> wgpu::TextureFormat;
93}
94
95impl BindableImage for RgbaImage {
96 fn from_vec(width: u32, height: u32, vec: Vec<u8>) -> Self {
97 RgbaImage::from_vec(width, height, vec).unwrap()
98 }
99
100 fn size(&self) -> (u32, u32) {
101 (self.width(), self.height())
102 }
103
104 fn as_slice(&self) -> &[u8] {
105 self.as_raw()
106 }
107
108 fn format() -> wgpu::TextureFormat {
109 wgpu::TextureFormat::Rgba8Unorm
110 }
111}
112
113pub struct TextureBind<I: BindableImage, Y: TextureBindType> {
115 pub texture: Arc<wgpu::Texture>,
116 view: wgpu::TextureView,
117 _img: PhantomData<I>,
118 _ty: PhantomData<Y>,
119}
120
121impl<I: BindableImage, Y: TextureBindType> Bind for TextureBind<I, Y> {
122 type Data = I;
123 type CreateInfo = (u32, u32);
124
125 fn binding_type() -> wgpu::BindingType {
126 Y::binding_type(I::format())
127 }
128
129 fn bind(&self) -> wgpu::BindingResource {
130 wgpu::BindingResource::TextureView(&self.view)
131 }
132
133 fn download(&self, device: &crate::Device) -> Self::Data {
134 let extent = self.texture.size();
135 let download_buffer = Arc::new(device.device.create_buffer(&wgpu::BufferDescriptor {
136 size: (extent.width
137 * extent.height
138 * extent.depth_or_array_layers
139 * self.texture.format().block_copy_size(None).unwrap_or(4)) as u64,
140 usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
141 mapped_at_creation: false,
142 label: None,
143 }));
144
145 let mut encoder = device
146 .device
147 .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
148 encoder.copy_texture_to_buffer(
149 wgpu::TexelCopyTextureInfo {
150 texture: &self.texture,
151 mip_level: 0,
152 origin: wgpu::Origin3d { x: 0, y: 0, z: 0 },
153 aspect: wgpu::TextureAspect::All,
154 },
155 wgpu::TexelCopyBufferInfo {
156 buffer: &download_buffer,
157 layout: wgpu::TexelCopyBufferLayout {
158 offset: 0,
159 bytes_per_row: Some(((extent.width * 4 + 255) / 256) * 256),
160 rows_per_image: None,
161 },
162 },
163 extent,
164 );
165 let command_buffer: wgpu::CommandBuffer = encoder.finish();
166 device.queue.submit(Some(command_buffer));
167
168 let buffer_content = Arc::new(std::sync::Mutex::new(Some(Vec::new())));
169 let buffer_content_clone = buffer_content.clone();
170 download_buffer
171 .clone()
172 .slice(..)
173 .map_async(wgpu::MapMode::Read, move |result| {
174 result.unwrap();
175 buffer_content_clone
176 .lock()
177 .unwrap()
178 .as_mut()
179 .unwrap()
180 .extend_from_slice(&download_buffer.slice(..).get_mapped_range());
181 });
182 device.device.poll(wgpu::Maintain::Wait);
183 let data = buffer_content.lock().unwrap().take().unwrap();
184 I::from_vec(extent.width, extent.height, data)
185 }
186
187 fn new_empty(device: &crate::Device, size: (u32, u32)) -> Self {
188 let texture = device.device.create_texture(&wgpu::TextureDescriptor {
189 label: Some(std::any::type_name::<I>()),
190 size: wgpu::Extent3d {
191 width: size.0,
192 height: size.1,
193 depth_or_array_layers: 1,
194 },
195 mip_level_count: 1,
196 sample_count: 1,
197 dimension: wgpu::TextureDimension::D2,
198 format: I::format(),
199 usage: wgpu::TextureUsages::COPY_SRC
200 | wgpu::TextureUsages::COPY_DST
201 | wgpu::TextureUsages::TEXTURE_BINDING
202 | Y::texture_usages(),
203 view_formats: &[],
204 });
205 let view = texture.create_view(&wgpu::TextureViewDescriptor {
206 label: Some(std::any::type_name::<I>()),
207 usage: None,
208 format: Some(I::format()),
209 dimension: Some(wgpu::TextureViewDimension::D2),
210 aspect: wgpu::TextureAspect::All,
211 base_mip_level: 0,
212 mip_level_count: None,
213 base_array_layer: 0,
214 array_layer_count: None,
215 });
216 Self {
217 texture: Arc::new(texture),
218 view,
219 _img: PhantomData,
220 _ty: PhantomData,
221 }
222 }
223
224 fn new_init(device: &crate::Device, inner: Self::Data) -> Self {
225 let size = inner.size();
226 let texture = device.device.create_texture_with_data(
227 &device.queue,
228 &wgpu::TextureDescriptor {
229 label: Some(std::any::type_name::<I>()),
230 size: wgpu::Extent3d {
231 width: size.0,
232 height: size.1,
233 depth_or_array_layers: 1,
234 },
235 mip_level_count: 1,
236 sample_count: 1,
237 dimension: wgpu::TextureDimension::D2,
238 format: I::format(),
239 usage: wgpu::TextureUsages::COPY_SRC
240 | wgpu::TextureUsages::COPY_DST
241 | wgpu::TextureUsages::TEXTURE_BINDING
242 | Y::texture_usages(),
243 view_formats: &[],
244 },
245 wgpu::util::TextureDataOrder::LayerMajor,
246 inner.as_slice(),
247 );
248 let view = texture.create_view(&wgpu::TextureViewDescriptor {
249 label: Some(std::any::type_name::<I>()),
250 usage: None,
251 format: Some(I::format()),
252 dimension: Some(wgpu::TextureViewDimension::D2),
253 aspect: wgpu::TextureAspect::All,
254 base_mip_level: 0,
255 mip_level_count: None,
256 base_array_layer: 0,
257 array_layer_count: None,
258 });
259 Self {
260 texture: Arc::new(texture),
261 view,
262 _img: PhantomData,
263 _ty: PhantomData,
264 }
265 }
266}