Skip to main content

scry_gpu/
buffer.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! GPU buffer abstraction.
3//!
4//! Buffers are the primary way to move data between CPU and GPU.
5//! They wrap backend-specific storage and expose a typed, safe interface.
6
7use crate::backend::{BackendBuffer, BackendBufferOps};
8use crate::error::Result;
9
10/// Trait for types that can be bound as a GPU buffer in a dispatch call.
11///
12/// This is object-safe so that `&[&dyn GpuBuf]` can hold mixed buffer types.
13#[allow(private_interfaces)]
14pub trait GpuBuf {
15    #[doc(hidden)]
16    fn raw(&self) -> &BackendBuffer;
17}
18
19/// A typed GPU buffer.
20///
21/// `Buffer<T>` owns a region of GPU memory containing `len` elements of type `T`.
22/// Data is moved to the GPU on creation ([`Device::upload`]) and read back on demand
23/// ([`Buffer::download`]).
24///
25/// [`Device::upload`]: crate::Device::upload
26pub struct Buffer<T: bytemuck::Pod> {
27    pub(crate) inner: BackendBuffer,
28    pub(crate) len: usize,
29    pub(crate) _marker: std::marker::PhantomData<T>,
30}
31
32impl<T: bytemuck::Pod> Buffer<T> {
33    /// Number of `T` elements in this buffer.
34    pub const fn len(&self) -> usize {
35        self.len
36    }
37
38    /// Whether the buffer is empty.
39    pub const fn is_empty(&self) -> bool {
40        self.len == 0
41    }
42
43    /// Size in bytes.
44    pub const fn byte_size(&self) -> u64 {
45        match self.len.checked_mul(std::mem::size_of::<T>()) {
46            Some(s) => s as u64,
47            None => u64::MAX,
48        }
49    }
50
51    /// Copy buffer contents back to the CPU.
52    ///
53    /// This blocks until the transfer is complete.
54    pub fn download(&self) -> Result<Vec<T>> {
55        let bytes = self.inner.read_back()?;
56        let elements = bytemuck::cast_slice(&bytes).to_vec();
57        Ok(elements)
58    }
59}
60
61#[allow(private_interfaces)]
62impl<T: bytemuck::Pod> GpuBuf for Buffer<T> {
63    fn raw(&self) -> &BackendBuffer {
64        &self.inner
65    }
66}
67
68impl<T: bytemuck::Pod> std::fmt::Debug for Buffer<T> {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        f.debug_struct("Buffer")
71            .field("len", &self.len)
72            .field("byte_size", &self.byte_size())
73            .field("type", &std::any::type_name::<T>())
74            .finish_non_exhaustive()
75    }
76}