bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
36.61k stars 3.6k forks source link

Reduce number of copies in the Mesh API #15558

Open atlv24 opened 2 months ago

atlv24 commented 2 months ago

What problem does this solve or what need does it fill?

Currently, using the Mesh API incurs a lot of unnecessary memcpy. If you have a custom mesh representation, it's even worse because you have to build a Mesh copying all your data in, and then go through all the normal Mesh overhead.

Current state of Mesh copies:

  1. Mesh gets extracted which may involve a clone in extract_render_asset extracted_assets.push((id, asset.clone()));

  2. then it gets prepared into a GpuMesh, which interleave-copies the vertex data into a Vec<u8> in Mesh::get_vertex_buffer_data: let mut attributes_interleaved_buffer = vec![0; vertex_count * vertex_size];

  3. the interleave copy actually happens twice, the first time just to get the length and pre-allocate a slab 😬 mesh.get_vertex_buffer_data().len() as u64,

and then to fill in the buffer let vertex_data = mesh.get_vertex_buffer_data();

  1. which then gets passed by reference to wgpu create_buffer_with_data which immediately copies it yet again in DeviceExt::create_buffer_init: buffer.slice(..).get_mapped_range_mut()[..unpadded_size as usize].copy_from_slice(descriptor.contents); which then actually gets uploaded to the gpu

What solution would you like?

To solve 1: Retained render world will help here

To solve 2: introduce an api which both Mesh and custom mesh representations uses, that permits writing directly into a u8 buffer thats already mapped. this can be via a builder style api potentially.

To solve 3: a. length can be computed without copying, b. write directly into the slab instead of creating a vec and then copying

To solve 4: create_buffer_init() is a convenience function. If you want to minimize copies, then call create_buffer() with mapped_at_creation: true, then write into the mapping. - kpreid

What alternative(s) have you considered?

Not changing it

Additional context

i mostly want to expose an api that allows alternative mesh representations to exist easily within the renderer, and make Mesh use that api.

atlv24 commented 2 months ago

related https://github.com/bevyengine/bevy/issues/12263