From 2bb53ad6e7ea2689f2f56662e5840a8d363b3108 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 29 Mar 2024 04:02:24 +0100 Subject: Use a `StagingBelt` in `iced_wgpu` for regular buffer uploads --- wgpu/src/buffer.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'wgpu/src/buffer.rs') diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs index ef00c58f..f8828d46 100644 --- a/wgpu/src/buffer.rs +++ b/wgpu/src/buffer.rs @@ -61,12 +61,22 @@ impl Buffer { /// Returns the size of the written bytes. pub fn write( &mut self, - queue: &wgpu::Queue, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + belt: &mut wgpu::util::StagingBelt, offset: usize, contents: &[T], ) -> usize { let bytes: &[u8] = bytemuck::cast_slice(contents); - queue.write_buffer(&self.raw, offset as u64, bytes); + + belt.write_buffer( + encoder, + &self.raw, + offset as u64, + (bytes.len() as u64).try_into().expect("Non-empty write"), + device, + ) + .copy_from_slice(bytes); self.offsets.push(offset as u64); -- cgit From 5f1eb43161d70b4ef157aae1ebc2b5fb25eb5b27 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 29 Mar 2024 14:29:31 +0100 Subject: Split big `Buffer` writes into multiple chunks --- wgpu/src/buffer.rs | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'wgpu/src/buffer.rs') diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs index f8828d46..c9d6b828 100644 --- a/wgpu/src/buffer.rs +++ b/wgpu/src/buffer.rs @@ -1,6 +1,8 @@ use std::marker::PhantomData; use std::ops::RangeBounds; +pub const MAX_WRITE_SIZE: usize = 1024 * 100; + #[derive(Debug)] pub struct Buffer { label: &'static str, @@ -69,14 +71,38 @@ impl Buffer { ) -> usize { let bytes: &[u8] = bytemuck::cast_slice(contents); - belt.write_buffer( - encoder, - &self.raw, - offset as u64, - (bytes.len() as u64).try_into().expect("Non-empty write"), - device, - ) - .copy_from_slice(bytes); + if bytes.len() <= MAX_WRITE_SIZE { + belt.write_buffer( + encoder, + &self.raw, + offset as u64, + (bytes.len() as u64).try_into().expect("Non-empty write"), + device, + ) + .copy_from_slice(bytes); + } else { + let mut bytes_written = 0; + + let bytes_per_chunk = (bytes.len().min(MAX_WRITE_SIZE) as u64) + .try_into() + .expect("Non-empty write"); + + while bytes_written < bytes.len() { + belt.write_buffer( + encoder, + &self.raw, + (offset + bytes_written) as u64, + bytes_per_chunk, + device, + ) + .copy_from_slice( + &bytes[bytes_written + ..bytes_written + bytes_per_chunk.get() as usize], + ); + + bytes_written += bytes_per_chunk.get() as usize; + } + } self.offsets.push(offset as u64); -- cgit From 35af0aa84f76daddbb6d6959f9746bd09e306278 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 30 Mar 2024 13:50:40 +0100 Subject: Fix batched writes logic in `iced_wgpu::buffer` --- wgpu/src/buffer.rs | 59 +++++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 27 deletions(-) (limited to 'wgpu/src/buffer.rs') diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs index c9d6b828..463ea24a 100644 --- a/wgpu/src/buffer.rs +++ b/wgpu/src/buffer.rs @@ -1,7 +1,12 @@ use std::marker::PhantomData; +use std::num::NonZeroU64; use std::ops::RangeBounds; -pub const MAX_WRITE_SIZE: usize = 1024 * 100; +pub const MAX_WRITE_SIZE: usize = 100 * 1024; + +#[allow(unsafe_code)] +const MAX_WRITE_SIZE_U64: NonZeroU64 = + unsafe { NonZeroU64::new_unchecked(MAX_WRITE_SIZE as u64) }; #[derive(Debug)] pub struct Buffer { @@ -70,40 +75,40 @@ impl Buffer { contents: &[T], ) -> usize { let bytes: &[u8] = bytemuck::cast_slice(contents); + let mut bytes_written = 0; - if bytes.len() <= MAX_WRITE_SIZE { + // Split write into multiple chunks if necessary + while bytes_written + MAX_WRITE_SIZE < bytes.len() { belt.write_buffer( encoder, &self.raw, - offset as u64, - (bytes.len() as u64).try_into().expect("Non-empty write"), + (offset + bytes_written) as u64, + MAX_WRITE_SIZE_U64, device, ) - .copy_from_slice(bytes); - } else { - let mut bytes_written = 0; - - let bytes_per_chunk = (bytes.len().min(MAX_WRITE_SIZE) as u64) - .try_into() - .expect("Non-empty write"); - - while bytes_written < bytes.len() { - belt.write_buffer( - encoder, - &self.raw, - (offset + bytes_written) as u64, - bytes_per_chunk, - device, - ) - .copy_from_slice( - &bytes[bytes_written - ..bytes_written + bytes_per_chunk.get() as usize], - ); - - bytes_written += bytes_per_chunk.get() as usize; - } + .copy_from_slice( + &bytes[bytes_written..bytes_written + MAX_WRITE_SIZE], + ); + + bytes_written += MAX_WRITE_SIZE; } + // There will always be some bytes left, since the previous + // loop guarantees `bytes_written < bytes.len()` + let bytes_left = ((bytes.len() - bytes_written) as u64) + .try_into() + .expect("non-empty write"); + + // Write them + belt.write_buffer( + encoder, + &self.raw, + (offset + bytes_written) as u64, + bytes_left, + device, + ) + .copy_from_slice(&bytes[bytes_written..]); + self.offsets.push(offset as u64); bytes.len() -- cgit