Faster MeshletMesh deserialization#14193
Conversation
crates/bevy_pbr/src/meshlet/asset.rs
Outdated
| reader.read_to_end(&mut compressed_asset_data).await?; | ||
|
|
||
| // Convert compressed data back to an asset | ||
| let reader = &mut FrameDecoder::new(Cursor::new(compressed_asset_data)); |
There was a problem hiding this comment.
Does LZ4 compression actually help? You might have to use delta encoding (i.e. instead of storing indices you'd store the wrapping difference from the previous index) if you want it to have much impact
There was a problem hiding this comment.
It did when I used bincode, I should probably double check again.
Nanite has a whole bunch of tricks they use for compressing disk and in-memory asset data, but they're low priority for me vs runtime performance at the moment, and I don't really have much experience with this field https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf.
There was a problem hiding this comment.
9.73mb without compression, 4.97mb with.
crates/bevy_pbr/src/meshlet/asset.rs
Outdated
| let compressed_asset_data_len = async_read_u64(reader).await? as usize; | ||
|
|
||
| // Load compressed asset data | ||
| let mut compressed_asset_data = Vec::with_capacity(compressed_asset_data_len); |
There was a problem hiding this comment.
I wish I could directly wrap Bevy's &mut dyn Reader in a FrameDecoder, rather than read to a Vec first, but it's not possible as Reader doesn't implement the typical std::io::Read sync trait - only Bevy's custom async traits :(
@cart any thoughts?
There was a problem hiding this comment.
We can make adapters like so:
struct AsyncWriteSyncAdapter<'a>(&'a mut Writer);
impl Write for AsyncWriteSyncAdapter<'_> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
block_on(self.0.write(buf))
}
fn flush(&mut self) -> std::io::Result<()> {
block_on(self.0.flush())
}
}
struct AsyncReadSyncAdapter<'a>(&'a mut dyn Reader);
impl Read for AsyncReadSyncAdapter<'_> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
block_on(self.0.read(buf))
}
}There was a problem hiding this comment.
Not having to allocate an intermediate vec was a nice perf/memory win.
pcwalton
left a comment
There was a problem hiding this comment.
Looks fine, just a couple of suggestions.
# Objective - #14193 changed the bunny meshlet url but didn't update example metadata ## Solution - Also update the url there
Objective
Solution
Testing
Changelog
MeshletMeshloading speedMeshletMeshdisk format has changed, andMESHLET_MESH_ASSET_VERSIONhas been bumpedMeshletMeshfields are now privateMeshletMeshSaverLoadtoMeshletMeshSaverLoaderMeshlet,MeshletBoundingSpheres, andMeshletBoundingSpheretypes are now privateMeshletMeshSaveOrLoadError::SerializationOrDeserializationMeshletMeshSaveOrLoadError::WrongFileTypeMigration Guide
MeshletMeshassets, as the disk format has changed, andMESHLET_MESH_ASSET_VERSIONhas been bumpedMeshletMeshfields are now privateMeshletMeshSaverLoadis now namedMeshletMeshSaverLoaderMeshlet,MeshletBoundingSpheres, andMeshletBoundingSpheretypes are now privateMeshletMeshSaveOrLoadError::SerializationOrDeserializationhas been removedMeshletMeshSaveOrLoadError::WrongFileType, match on this variant if you match onMeshletMeshSaveOrLoadError