use crate::numeric::usize_to_u64;
use vyre_driver::BackendError;
pub(crate) fn write_padded_prefix(
queue: &wgpu::Queue,
buffer: &wgpu::Buffer,
bytes: &[u8],
tail_offset_label: &'static str,
) -> Result<usize, BackendError> {
let aligned_len = bytes.len() & !3;
if aligned_len > 0 {
queue.write_buffer(buffer, 0, &bytes[..aligned_len]);
}
let tail_len = bytes.len() - aligned_len;
if tail_len == 0 {
return Ok(aligned_len);
}
let mut tail = [0u8; 4];
tail[..tail_len].copy_from_slice(&bytes[aligned_len..]);
queue.write_buffer(buffer, usize_to_u64(aligned_len, tail_offset_label)?, &tail);
Ok(aligned_len + 4)
}
pub(crate) fn write_padded_and_zero_fill(
queue: &wgpu::Queue,
buffer: &wgpu::Buffer,
bytes: &[u8],
allocation_len: u64,
) -> Result<(), BackendError> {
let allocation_len = usize::try_from(allocation_len).map_err(|source| {
BackendError::new(format!(
"GPU allocation length {allocation_len} cannot fit usize: {source}. Fix: split the dispatch input."
))
})?;
let zero_start = write_padded_prefix(queue, buffer, bytes, "GPU padded tail offset")?;
write_zero_fill(queue, buffer, zero_start, allocation_len)
}
fn write_zero_fill(
queue: &wgpu::Queue,
buffer: &wgpu::Buffer,
zero_start: usize,
allocation_len: usize,
) -> Result<(), BackendError> {
if allocation_len <= zero_start {
return Ok(());
}
static SCRATCH_ZEROS: [u8; 65_536] = [0u8; 65_536];
let mut offset = zero_start;
while offset < allocation_len {
let chunk = (allocation_len - offset).min(SCRATCH_ZEROS.len());
queue.write_buffer(
buffer,
usize_to_u64(offset, "GPU zero-fill offset")?,
&SCRATCH_ZEROS[..chunk],
);
offset += chunk;
}
Ok(())
}