forked from 1b-agent/opencadstudio-upstream
perf(wire): upload vertex buffers via mapped_at_creation
Step 1 of the wire pipeline cold-open optimization plan. Replaces `create_buffer_init` (intermediate staging-buffer memcpy) with a `mapped_at_creation` buffer the build path writes into directly. Cuts one alloc + one memcpy per wire buffer; on cold open with hundreds of MB of wire data this shows up immediately as lower peak memory and faster upload. Guarded against size-0 buffers by allocating a single-vertex placeholder when the wire is empty (the renderer already skips draws on vertex_count below the per-segment minimum). Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
1 parent
d3986e9cba
commit
522b123d82
1 file changed
+32
-11
@@ -25,7 +25,34 @@
|
||||
|
||||
use crate::scene::wire_model::WireModel;
|
||||
use iced::wgpu;
|
||||
use iced::wgpu::util::DeviceExt;
|
||||
|
||||
/// Allocate a VERTEX buffer with `mapped_at_creation` and write `data` directly
|
||||
/// into the mapped slice. Skips the intermediate staging copy that
|
||||
/// `create_buffer_init` performs and avoids holding a second `Vec` worth of
|
||||
/// memory during upload — meaningful on cold open where wire buffers can run
|
||||
/// into the hundreds of MB.
|
||||
fn vertex_buffer_mapped(
|
||||
device: &wgpu::Device,
|
||||
label: &str,
|
||||
data: &[WireVertex],
|
||||
) -> wgpu::Buffer {
|
||||
let bytes: &[u8] = bytemuck::cast_slice(data);
|
||||
// wgpu rejects size-0 buffers; the renderer already guards `vertex_count`
|
||||
// before issuing a draw, so a placeholder allocation is fine here.
|
||||
let size = bytes.len().max(std::mem::size_of::<WireVertex>()) as u64;
|
||||
let buf = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some(label),
|
||||
size,
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
mapped_at_creation: true,
|
||||
});
|
||||
{
|
||||
let mut view = buf.slice(..).get_mapped_range_mut();
|
||||
view[..bytes.len()].copy_from_slice(bytes);
|
||||
}
|
||||
buf.unmap();
|
||||
buf
|
||||
}
|
||||
|
||||
// ── Vertex layout ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -222,11 +249,8 @@ impl WireGpu {
|
||||
.chunks(MAX_VERTS)
|
||||
.enumerate()
|
||||
.map(|(i, chunk)| {
|
||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some(&format!("wire.batch.vbuf.{i}")),
|
||||
contents: bytemuck::cast_slice(chunk),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
});
|
||||
let label = format!("wire.batch.vbuf.{i}");
|
||||
let vertex_buffer = vertex_buffer_mapped(device, &label, chunk);
|
||||
Self {
|
||||
vertex_buffer,
|
||||
vertex_count: chunk.len() as u32,
|
||||
@@ -323,11 +347,8 @@ impl WireGpu {
|
||||
vertices.push(make(0.0, 1.0));
|
||||
}
|
||||
|
||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some(&format!("wire.vbuf.{}", wire.name)),
|
||||
contents: bytemuck::cast_slice(&vertices),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
});
|
||||
let label = format!("wire.vbuf.{}", wire.name);
|
||||
let vertex_buffer = vertex_buffer_mapped(device, &label, &vertices);
|
||||
|
||||
Self {
|
||||
vertex_buffer,
|
||||
|
||||
Reference in new issue
Block a user