1use crate::context::GpuContext;
7use crate::error::{GpuError, GpuResult};
8use bytemuck::{Pod, Zeroable};
9use std::marker::PhantomData;
10use std::sync::Arc;
11use tracing::{debug, trace};
12use wgpu::{
13 Buffer, BufferAsyncError, BufferDescriptor, BufferUsages, COPY_BUFFER_ALIGNMENT, MapMode,
14};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum BufferElementType {
26 F32,
28 F16,
30 U8,
32 U16,
34 U32,
36 I32,
38}
39
40impl BufferElementType {
41 pub fn byte_size(self) -> usize {
43 match self {
44 Self::F32 | Self::I32 | Self::U32 => 4,
45 Self::F16 | Self::U16 => 2,
46 Self::U8 => 1,
47 }
48 }
49
50 pub fn wgsl_type(self) -> &'static str {
55 match self {
56 Self::F32 => "f32",
57 Self::F16 => "f16",
58 Self::U32 => "u32",
59 Self::I32 => "i32",
60 Self::U8 => "u32", Self::U16 => "u32", }
63 }
64}
65
66pub fn f16_to_f32_slice(data: &[half::f16]) -> Vec<f32> {
75 data.iter().map(|h| f32::from(*h)).collect()
76}
77
78pub fn f32_to_f16_slice(data: &[f32]) -> Vec<half::f16> {
84 data.iter().map(|f| half::f16::from_f32(*f)).collect()
85}
86
87pub fn from_f16_slice_widening(
100 context: &GpuContext,
101 data: &[half::f16],
102) -> GpuResult<GpuBuffer<f32>> {
103 let f32_data = f16_to_f32_slice(data);
104 GpuBuffer::<f32>::from_data(
105 context,
106 &f32_data,
107 BufferUsages::STORAGE | BufferUsages::COPY_SRC | BufferUsages::COPY_DST,
108 )
109}
110
111pub fn from_f16_slice_native(context: &GpuContext, data: &[half::f16]) -> GpuResult<GpuBuffer<u8>> {
121 let bytes: &[u8] = bytemuck::cast_slice(data);
122 GpuBuffer::<u8>::from_data(
123 context,
124 bytes,
125 BufferUsages::STORAGE | BufferUsages::COPY_SRC | BufferUsages::COPY_DST,
126 )
127}
128
129pub fn read_f16_from_f32_buffer(buf: &GpuBuffer<f32>) -> GpuResult<Vec<half::f16>> {
138 let f32_vals = buf.read_blocking()?;
139 Ok(f32_to_f16_slice(&f32_vals))
140}
141
142pub struct GpuBuffer<T: Pod> {
147 buffer: Arc<Buffer>,
149 context: GpuContext,
151 len: usize,
153 usage: BufferUsages,
155 _phantom: PhantomData<T>,
157}
158
159impl<T: Pod> GpuBuffer<T> {
160 pub fn new(context: &GpuContext, len: usize, usage: BufferUsages) -> GpuResult<Self> {
166 let size = Self::calculate_size(len)?;
167
168 trace!("Creating GPU buffer: {} elements, {} bytes", len, size);
169
170 let buffer = context.device().create_buffer(&BufferDescriptor {
171 label: Some("GpuBuffer"),
172 size,
173 usage,
174 mapped_at_creation: false,
175 });
176
177 Ok(Self {
178 buffer: Arc::new(buffer),
179 context: context.clone(),
180 len,
181 usage,
182 _phantom: PhantomData,
183 })
184 }
185
186 pub fn from_data(context: &GpuContext, data: &[T], usage: BufferUsages) -> GpuResult<Self> {
192 let mut buffer = Self::new(context, data.len(), usage | BufferUsages::COPY_DST)?;
193 buffer.write(data)?;
194 Ok(buffer)
195 }
196
197 pub fn staging(context: &GpuContext, len: usize) -> GpuResult<Self> {
203 Self::new(
204 context,
205 len,
206 BufferUsages::MAP_READ | BufferUsages::COPY_DST,
207 )
208 }
209
210 fn calculate_size(len: usize) -> GpuResult<u64> {
212 let element_size = std::mem::size_of::<T>();
213 let size = len
214 .checked_mul(element_size)
215 .ok_or_else(|| GpuError::invalid_buffer("Buffer size overflow"))?;
216
217 let aligned_size = ((size as u64 + COPY_BUFFER_ALIGNMENT - 1) / COPY_BUFFER_ALIGNMENT)
219 * COPY_BUFFER_ALIGNMENT;
220
221 Ok(aligned_size)
222 }
223
224 pub fn write(&mut self, data: &[T]) -> GpuResult<()> {
231 if data.len() != self.len {
232 return Err(GpuError::invalid_buffer(format!(
233 "Data size mismatch: expected {}, got {}",
234 self.len,
235 data.len()
236 )));
237 }
238
239 if !self.usage.contains(BufferUsages::COPY_DST) {
240 return Err(GpuError::invalid_buffer(
241 "Buffer not writable (missing COPY_DST usage)",
242 ));
243 }
244
245 let bytes = bytemuck::cast_slice(data);
246 self.context.queue().write_buffer(&self.buffer, 0, bytes);
247
248 debug!("Wrote {} bytes to GPU buffer", bytes.len());
249 Ok(())
250 }
251
252 pub async fn read(&self) -> GpuResult<Vec<T>> {
258 if !self.usage.contains(BufferUsages::MAP_READ) {
259 return Err(GpuError::invalid_buffer(
260 "Buffer not readable (missing MAP_READ usage)",
261 ));
262 }
263
264 let buffer_slice = self.buffer.slice(..);
265
266 let (tx, rx) = futures::channel::oneshot::channel();
268 buffer_slice.map_async(MapMode::Read, move |result| {
269 let _ = tx.send(result);
270 });
271
272 self.context.poll(true);
274
275 rx.await
277 .map_err(|_| GpuError::buffer_mapping("Channel closed"))?
278 .map_err(|e| GpuError::buffer_mapping(Self::map_error_to_string(e)))?;
279
280 let data = buffer_slice.get_mapped_range();
282 let result: Vec<T> = bytemuck::cast_slice(&data).to_vec();
283
284 drop(data);
286 self.buffer.unmap();
287
288 debug!("Read {} elements from GPU buffer", result.len());
289 Ok(result)
290 }
291
292 pub async fn read_async(&self) -> GpuResult<Vec<T>> {
309 self.read().await
310 }
311
312 pub fn read_blocking(&self) -> GpuResult<Vec<T>> {
318 pollster::block_on(self.read())
319 }
320
321 pub fn copy_from(&mut self, source: &GpuBuffer<T>) -> GpuResult<()> {
327 if self.len != source.len {
328 return Err(GpuError::invalid_buffer(format!(
329 "Buffer size mismatch: {} != {}",
330 self.len, source.len
331 )));
332 }
333
334 if !source.usage.contains(BufferUsages::COPY_SRC) {
335 return Err(GpuError::invalid_buffer(
336 "Source buffer not copyable (missing COPY_SRC usage)",
337 ));
338 }
339
340 if !self.usage.contains(BufferUsages::COPY_DST) {
341 return Err(GpuError::invalid_buffer(
342 "Destination buffer not copyable (missing COPY_DST usage)",
343 ));
344 }
345
346 let mut encoder =
347 self.context
348 .device()
349 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
350 label: Some("Buffer Copy"),
351 });
352
353 let size = Self::calculate_size(self.len)?;
354 encoder.copy_buffer_to_buffer(&source.buffer, 0, &self.buffer, 0, size);
355
356 self.context.queue().submit(Some(encoder.finish()));
357
358 debug!("Copied {} elements between GPU buffers", self.len);
359 Ok(())
360 }
361
362 pub fn len(&self) -> usize {
364 self.len
365 }
366
367 pub fn is_empty(&self) -> bool {
369 self.len == 0
370 }
371
372 pub fn size_bytes(&self) -> u64 {
374 Self::calculate_size(self.len).unwrap_or(0)
375 }
376
377 pub fn buffer(&self) -> &Buffer {
379 &self.buffer
380 }
381
382 pub fn usage(&self) -> BufferUsages {
384 self.usage
385 }
386
387 fn map_error_to_string(error: BufferAsyncError) -> String {
389 error.to_string()
390 }
391}
392
393impl<T: Pod> Clone for GpuBuffer<T> {
394 fn clone(&self) -> Self {
395 Self {
396 buffer: Arc::clone(&self.buffer),
397 context: self.context.clone(),
398 len: self.len,
399 usage: self.usage,
400 _phantom: PhantomData,
401 }
402 }
403}
404
405impl<T: Pod> std::fmt::Debug for GpuBuffer<T> {
406 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
407 f.debug_struct("GpuBuffer")
408 .field("len", &self.len)
409 .field("size_bytes", &self.size_bytes())
410 .field("usage", &self.usage)
411 .field("type", &std::any::type_name::<T>())
412 .finish()
413 }
414}
415
416pub struct GpuRasterBuffer<T: Pod> {
421 bands: Vec<GpuBuffer<T>>,
423 width: u32,
425 height: u32,
427}
428
429impl<T: Pod + Zeroable> GpuRasterBuffer<T> {
430 pub fn new(
436 context: &GpuContext,
437 width: u32,
438 height: u32,
439 num_bands: usize,
440 usage: BufferUsages,
441 ) -> GpuResult<Self> {
442 let pixels_per_band = (width as usize)
443 .checked_mul(height as usize)
444 .ok_or_else(|| GpuError::invalid_buffer("Raster size overflow"))?;
445
446 let bands = (0..num_bands)
447 .map(|_| GpuBuffer::new(context, pixels_per_band, usage))
448 .collect::<GpuResult<Vec<_>>>()?;
449
450 debug!(
451 "Created GPU raster buffer: {}x{} with {} bands",
452 width, height, num_bands
453 );
454
455 Ok(Self {
456 bands,
457 width,
458 height,
459 })
460 }
461
462 pub fn from_bands(
468 context: &GpuContext,
469 width: u32,
470 height: u32,
471 bands_data: &[Vec<T>],
472 usage: BufferUsages,
473 ) -> GpuResult<Self> {
474 let expected_size = (width as usize) * (height as usize);
475
476 for (i, band) in bands_data.iter().enumerate() {
477 if band.len() != expected_size {
478 return Err(GpuError::invalid_buffer(format!(
479 "Band {} size mismatch: expected {}, got {}",
480 i,
481 expected_size,
482 band.len()
483 )));
484 }
485 }
486
487 let bands = bands_data
488 .iter()
489 .map(|data| GpuBuffer::from_data(context, data, usage))
490 .collect::<GpuResult<Vec<_>>>()?;
491
492 Ok(Self {
493 bands,
494 width,
495 height,
496 })
497 }
498
499 pub fn band(&self, index: usize) -> Option<&GpuBuffer<T>> {
501 self.bands.get(index)
502 }
503
504 pub fn band_mut(&mut self, index: usize) -> Option<&mut GpuBuffer<T>> {
506 self.bands.get_mut(index)
507 }
508
509 pub fn bands(&self) -> &[GpuBuffer<T>] {
511 &self.bands
512 }
513
514 pub fn num_bands(&self) -> usize {
516 self.bands.len()
517 }
518
519 pub fn dimensions(&self) -> (u32, u32) {
521 (self.width, self.height)
522 }
523
524 pub fn width(&self) -> u32 {
526 self.width
527 }
528
529 pub fn height(&self) -> u32 {
531 self.height
532 }
533
534 pub async fn read_all_bands(&self) -> GpuResult<Vec<Vec<T>>> {
540 let mut results = Vec::with_capacity(self.bands.len());
541
542 for band in &self.bands {
543 results.push(band.read().await?);
544 }
545
546 Ok(results)
547 }
548
549 pub fn read_all_bands_blocking(&self) -> GpuResult<Vec<Vec<T>>> {
555 pollster::block_on(self.read_all_bands())
556 }
557}
558
559impl<T: Pod> std::fmt::Debug for GpuRasterBuffer<T> {
560 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
561 f.debug_struct("GpuRasterBuffer")
562 .field("width", &self.width)
563 .field("height", &self.height)
564 .field("num_bands", &self.num_bands())
565 .field("type", &std::any::type_name::<T>())
566 .finish()
567 }
568}
569
570#[cfg(test)]
571#[allow(clippy::panic)]
572mod tests {
573 use super::*;
574
575 #[tokio::test]
576 async fn test_gpu_buffer_creation() {
577 if let Ok(context) = GpuContext::new().await {
578 let buffer: GpuBuffer<f32> = GpuBuffer::new(&context, 1024, BufferUsages::STORAGE)
579 .unwrap_or_else(|e| {
580 panic!("Failed to create buffer: {}", e);
581 });
582
583 assert_eq!(buffer.len(), 1024);
584 assert!(!buffer.is_empty());
585 }
586 }
587
588 #[tokio::test]
589 #[ignore]
590 async fn test_gpu_buffer_write_read() {
591 if let Ok(context) = GpuContext::new().await {
592 let data: Vec<f32> = (0..100).map(|i| i as f32).collect();
593
594 let buffer = GpuBuffer::from_data(
595 &context,
596 &data,
597 BufferUsages::STORAGE | BufferUsages::COPY_SRC | BufferUsages::COPY_DST,
598 )
599 .unwrap_or_else(|e| {
600 panic!("Failed to create buffer: {}", e);
601 });
602
603 let mut staging = GpuBuffer::staging(&context, 100).unwrap_or_else(|e| {
605 panic!("Failed to create staging buffer: {}", e);
606 });
607
608 staging.copy_from(&buffer).unwrap_or_else(|e| {
609 panic!("Failed to copy buffer: {}", e);
610 });
611
612 let result = staging.read().await.unwrap_or_else(|e| {
613 panic!("Failed to read buffer: {}", e);
614 });
615
616 assert_eq!(result.len(), data.len());
617 for (a, b) in result.iter().zip(data.iter()) {
618 assert!((a - b).abs() < 1e-6);
619 }
620 }
621 }
622
623 #[tokio::test]
624 async fn test_gpu_raster_buffer() {
625 if let Ok(context) = GpuContext::new().await {
626 let width = 64;
627 let height = 64;
628 let num_bands = 3;
629
630 let raster: GpuRasterBuffer<f32> =
631 GpuRasterBuffer::new(&context, width, height, num_bands, BufferUsages::STORAGE)
632 .unwrap_or_else(|e| {
633 panic!("Failed to create raster buffer: {}", e);
634 });
635
636 assert_eq!(raster.width(), width);
637 assert_eq!(raster.height(), height);
638 assert_eq!(raster.num_bands(), num_bands);
639 }
640 }
641}