From 85058997056adc177312e91ba6f08794765adc09 Mon Sep 17 00:00:00 2001 From: Matt Keeter Date: Fri, 11 Sep 2026 14:04:04 -0400 Subject: [PATCH] Add a single "copy config and data" operation --- fidget-wgpu/src/buf.rs | 40 +++++++++++++++++++++------- fidget-wgpu/src/color.rs | 33 ++++++----------------- fidget-wgpu/src/pixel/effects/mod.rs | 13 +++------ fidget-wgpu/src/voxel/effects/mod.rs | 12 +++------ 4 files changed, 47 insertions(+), 51 deletions(-) diff --git a/fidget-wgpu/src/buf.rs b/fidget-wgpu/src/buf.rs index 0ad9fb48..92199c36 100644 --- a/fidget-wgpu/src/buf.rs +++ b/fidget-wgpu/src/buf.rs @@ -2,9 +2,10 @@ //! //! This module is mostly internal to the crate, but is public because its types //! appear as return values and arguments. +use crate::Gpu; use fidget_core::render::{ImageSize, VoxelSize}; use fidget_raster::RenderSize; -use zerocopy::FromBytes; +use zerocopy::{FromBytes, IntoBytes}; /// Handle around a growable GPU buffer /// @@ -148,23 +149,44 @@ pub(crate) type FlexConfigBuffer = FlexBuffer>; impl FlexConfigBuffer where - C: zerocopy::IntoBytes + zerocopy::Immutable + Copy, - T: Copy, + C: zerocopy::IntoBytes + zerocopy::Immutable, + T: zerocopy::IntoBytes + zerocopy::Immutable + Copy, { - /// Writes a config value to the buffer - pub(crate) fn write_config(&self, c: &C, queue: &wgpu::Queue) { + pub(crate) fn write( + &mut self, + gpu: &Gpu, + c: &C, + data: &[T], + ) -> Result { + let r = self.grow_to_fit(&gpu.device, data.len().into())?; let config_len = std::mem::size_of::(); - let mut writer = queue + let data_len = std::mem::size_of_val(data); + let mut writer = gpu + .queue .write_buffer_with( - self.data(), + &self.data, 0, - (config_len as u64).try_into().unwrap(), + ((config_len + data_len) as u64).try_into().unwrap(), ) .unwrap(); - writer.copy_from_slice(c.as_bytes()); + writer.slice(..config_len).copy_from_slice(c.as_bytes()); + writer.slice(config_len..).copy_from_slice(data.as_bytes()); + Ok(match r { + std::cmp::Ordering::Equal => ConfigBufferWrite::BufferUnchanged, + std::cmp::Ordering::Less | std::cmp::Ordering::Greater => { + ConfigBufferWrite::BufferChanged + } + }) } } +#[derive(Copy, Clone, Debug)] +#[must_use] +pub(crate) enum ConfigBufferWrite { + BufferChanged, + BufferUnchanged, +} + impl FlexBuffer { pub(crate) fn new( device: &wgpu::Device, diff --git a/fidget-wgpu/src/color.rs b/fidget-wgpu/src/color.rs index 58fe6e13..ec472e5b 100644 --- a/fidget-wgpu/src/color.rs +++ b/fidget-wgpu/src/color.rs @@ -8,7 +8,7 @@ //! [`voxel::effects::ColorWorkspace`](crate::voxel::effects::ColorWorkspace) use crate::{ CopyVarsChanged, CopyVarsError, Gpu, - buf::{BufferSizeError, FlexBuffer, FlexConfigBuffer}, + buf::{BufferSizeError, ConfigBufferWrite, FlexBuffer, FlexConfigBuffer}, tag, voxel::VarsBufferTag, }; @@ -101,31 +101,18 @@ where Ok(()) } - pub(crate) fn copy_tape( + pub(crate) fn copy_config_and_tape( &mut self, gpu: &Gpu, + config: &C, bytecode: &[u32], ) -> Result<(), BufferSizeError> { - let r = self - .config - .grow_to_fit(&gpu.device, bytecode.len().into())?; - if !matches!(r, std::cmp::Ordering::Equal) { - self.bind_group = Default::default(); + match self.config.write(gpu, config, bytecode)? { + ConfigBufferWrite::BufferChanged => { + self.bind_group = Default::default() + } + ConfigBufferWrite::BufferUnchanged => (), } - let Ok(byte_count) = - (std::mem::size_of_val(bytecode) as u64).try_into() - else { - return Ok(()); - }; - let mut writer = gpu - .queue - .write_buffer_with( - self.config.data(), - std::mem::size_of::() as u64, - byte_count, - ) - .unwrap(); - writer.copy_from_slice(bytecode.as_bytes()); Ok(()) } @@ -152,10 +139,6 @@ where writer.copy_from_slice(shape_starts.as_bytes()); Ok(()) } - - pub(crate) fn copy_config(&mut self, gpu: &Gpu, config: &C) { - self.config.write_config(config, &gpu.queue) - } } /// Error type when constructing a [`ShapeColorBuffers`] diff --git a/fidget-wgpu/src/pixel/effects/mod.rs b/fidget-wgpu/src/pixel/effects/mod.rs index 73ff7159..92694576 100644 --- a/fidget-wgpu/src/pixel/effects/mod.rs +++ b/fidget-wgpu/src/pixel/effects/mod.rs @@ -527,14 +527,6 @@ impl ColorContext { CopyVarsError::BufferSize(b) => ColorError::VarBufferSize(b), CopyVarsError::MissingVar(v) => ColorError::MissingVar(v), })?; - - bufs.copy_tape(gpu, shape.bytecode()) - .map_err(ColorError::ConfigBufferSize)?; - bufs.copy_shape_starts(gpu, shape.shape_start()) - .expect("shape starts should always fit if shape bytecode fits"); - - // We'll write the config last, because writing the tape could have - // invalidated it. let config = ColorConfig { mat: mat4.data.as_slice().try_into().unwrap(), axes: shape.axes(), @@ -543,7 +535,10 @@ impl ColorContext { _pad: [0; 3], z: settings.z, }; - bufs.copy_config(gpu, &config); + bufs.copy_config_and_tape(gpu, &config, shape.bytecode()) + .map_err(ColorError::ConfigBufferSize)?; + bufs.copy_shape_starts(gpu, shape.shape_start()) + .expect("shape starts should always fit if shape bytecode fits"); let config_bg = bufs.config_bind_group(&gpu.device, &self.config_bind_group_layout); diff --git a/fidget-wgpu/src/voxel/effects/mod.rs b/fidget-wgpu/src/voxel/effects/mod.rs index 2fbb9b8f..7a4498c7 100644 --- a/fidget-wgpu/src/voxel/effects/mod.rs +++ b/fidget-wgpu/src/voxel/effects/mod.rs @@ -1306,20 +1306,16 @@ impl ColorContext { CopyVarsError::BufferSize(b) => ColorError::VarBufferSize(b), CopyVarsError::MissingVar(v) => ColorError::MissingVar(v), })?; - bufs.copy_tape(gpu, shape.bytecode()) - .map_err(ColorError::ConfigBufferSize)?; - bufs.copy_shape_starts(gpu, shape.shape_start()) - .expect("shape starts should always fit if shape bytecode fits"); - - // We'll write the config last, because writing the tape could have - // invalidated it. let config = ColorConfig { mat: mat.data.as_slice().try_into().unwrap(), axes: shape.axes(), image_size: [size.width(), size.height()], _pad: 0, }; - bufs.copy_config(gpu, &config); + bufs.copy_config_and_tape(gpu, &config, shape.bytecode()) + .map_err(ColorError::ConfigBufferSize)?; + bufs.copy_shape_starts(gpu, shape.shape_start()) + .expect("shape starts should always fit if shape bytecode fits"); let config_bg = bufs.config_bind_group(&gpu.device, &self.config_bind_group_layout);