mod gaussian;
mod gaussian_transform;
mod model_transform;
pub use gaussian::*;
pub use gaussian_transform::*;
pub use model_transform::*;
use crate::{DownloadBufferError, FixedSizeBufferWrapperError};
use async_trait::async_trait;
#[async_trait]
pub trait BufferWrapper: Into<wgpu::Buffer> {
const DEFAULT_USAGES: wgpu::BufferUsages = wgpu::BufferUsages::from_bits_retain(
wgpu::BufferUsages::UNIFORM.bits() | wgpu::BufferUsages::COPY_DST.bits(),
);
fn buffer(&self) -> &wgpu::Buffer;
async fn download<T: bytemuck::NoUninit + bytemuck::AnyBitPattern>(
&self,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> Result<Vec<T>, DownloadBufferError>
where
Self: Send,
{
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Buffer Wrapper Download Encoder"),
});
let download = self.prepare_download(device, &mut encoder);
queue.submit(Some(encoder.finish()));
Self::map_download(&download, device).await
}
fn prepare_download(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
) -> wgpu::Buffer {
let download = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Buffer Wrapper Prepare Download Buffer"),
size: self.buffer().size(),
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
mapped_at_creation: false,
});
encoder.copy_buffer_to_buffer(self.buffer(), 0, &download, 0, download.size());
download
}
async fn map_download<T: bytemuck::NoUninit + bytemuck::AnyBitPattern>(
download: &wgpu::Buffer,
device: &wgpu::Device,
) -> Result<Vec<T>, DownloadBufferError> {
Self::map_download_with_poll_type(download, device, wgpu::PollType::wait_indefinitely())
.await
}
async fn map_download_with_poll_type<T: bytemuck::NoUninit + bytemuck::AnyBitPattern>(
download: &wgpu::Buffer,
device: &wgpu::Device,
poll_type: wgpu::PollType,
) -> Result<Vec<T>, DownloadBufferError> {
let (tx, rx) = oneshot::channel();
let buffer_slice = download.slice(..);
buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
if let Err(e) = tx.send(result) {
log::error!("Error occurred while sending buffer download data: {e:?}");
}
});
device.poll(poll_type)?;
rx.await??;
let edits = bytemuck::allocation::pod_collect_to_vec(&buffer_slice.get_mapped_range());
download.unmap();
Ok(edits)
}
}
impl BufferWrapper for wgpu::Buffer {
fn buffer(&self) -> &wgpu::Buffer {
self
}
}
pub trait FixedSizeBufferWrapper: BufferWrapper + TryFrom<wgpu::Buffer> {
type Pod;
fn pod_size() -> wgpu::BufferAddress {
std::mem::size_of::<Self::Pod>() as wgpu::BufferAddress
}
fn verify_buffer_size(buffer: &wgpu::Buffer) -> Result<(), FixedSizeBufferWrapperError> {
let expected_size = Self::pod_size();
let buffer_size = buffer.size();
if buffer_size != expected_size {
return Err(FixedSizeBufferWrapperError::BufferSizeMismatched {
buffer_size,
expected_size,
});
}
Ok(())
}
fn download_single(
&self,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> impl Future<Output = Result<Self::Pod, DownloadBufferError>> + Send
where
Self: Send + Sync,
Self::Pod: bytemuck::NoUninit + bytemuck::AnyBitPattern,
{
async move {
let vec = self.download::<Self::Pod>(device, queue).await?;
Ok(vec.into_iter().next().expect("downloaded single element"))
}
}
}