Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove meshlet builder retry queue #16941

Merged
merged 2 commits into from
Dec 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 28 additions & 37 deletions crates/bevy_pbr/src/meshlet/from_mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy_render::{
};
use bevy_utils::HashMap;
use bitvec::{order::Lsb0, vec::BitVec, view::BitView};
use core::iter;
use core::{iter, ops::Range};
use half::f16;
use itertools::Itertools;
use meshopt::{
Expand Down Expand Up @@ -105,20 +105,22 @@ impl MeshletMesh {
let mut vertex_locks = vec![false; vertices.vertex_count];

// Build further LODs
let mut simplification_queue = Vec::from_iter(0..meshlets.len());
let mut retry_queue = Vec::new();
let mut simplification_queue = 0..meshlets.len();
while simplification_queue.len() > 1 {
// For each meshlet build a list of connected meshlets (meshlets that share a vertex)
let connected_meshlets_per_meshlet = find_connected_meshlets(
&simplification_queue,
simplification_queue.clone(),
&meshlets,
&position_only_vertex_remap,
position_only_vertex_count,
);

// Group meshlets into roughly groups of size TARGET_MESHLETS_PER_GROUP,
// grouping meshlets with a high number of shared vertices
let groups = group_meshlets(&connected_meshlets_per_meshlet, &simplification_queue);
let groups = group_meshlets(
&connected_meshlets_per_meshlet,
simplification_queue.clone(),
);

// Lock borders between groups to prevent cracks when simplifying
lock_group_borders(
Expand All @@ -131,9 +133,8 @@ impl MeshletMesh {

let next_lod_start = meshlets.len();
for group_meshlets in groups.into_iter() {
// If the group only has a single meshlet, we can't simplify it well, so retry later
// If the group only has a single meshlet we can't simplify it
if group_meshlets.len() == 1 {
retry_queue.push(group_meshlets[0]);
continue;
}

Expand All @@ -146,8 +147,7 @@ impl MeshletMesh {
vertex_stride,
&vertex_locks,
) else {
// Couldn't simplify the group enough, retry its meshlets later
retry_queue.extend_from_slice(&group_meshlets);
// Couldn't simplify the group enough
continue;
};

Expand Down Expand Up @@ -187,12 +187,8 @@ impl MeshletMesh {
);
}

// Set simplification queue to the list of newly created (and retrying) meshlets
simplification_queue.clear();
simplification_queue.extend(next_lod_start..meshlets.len());
if !simplification_queue.is_empty() {
simplification_queue.append(&mut retry_queue);
}
// Set simplification queue to the list of newly created meshlets
simplification_queue = next_lod_start..meshlets.len();
}

// Copy vertex attributes per meshlet and compress
Expand Down Expand Up @@ -252,50 +248,45 @@ fn compute_meshlets(indices: &[u32], vertices: &VertexDataAdapter) -> Meshlets {
}

fn find_connected_meshlets(
simplification_queue: &[usize],
simplification_queue: Range<usize>,
meshlets: &Meshlets,
position_only_vertex_remap: &[u32],
position_only_vertex_count: usize,
) -> Vec<Vec<(usize, usize)>> {
// For each vertex, build a list of all meshlets that use it
let mut vertices_to_meshlets = vec![Vec::new(); position_only_vertex_count];
for (meshlet_queue_id, meshlet_id) in simplification_queue.iter().enumerate() {
let meshlet = meshlets.get(*meshlet_id);
for meshlet_id in simplification_queue.clone() {
let meshlet = meshlets.get(meshlet_id);
for index in meshlet.triangles {
let vertex_id = position_only_vertex_remap[meshlet.vertices[*index as usize] as usize];
let vertex_to_meshlets = &mut vertices_to_meshlets[vertex_id as usize];
// Meshlets are added in order, so we can just check the last element to deduplicate,
// in the case of two triangles sharing the same vertex within a single meshlet
if vertex_to_meshlets.last() != Some(&meshlet_queue_id) {
vertex_to_meshlets.push(meshlet_queue_id);
if vertex_to_meshlets.last() != Some(&meshlet_id) {
vertex_to_meshlets.push(meshlet_id);
}
}
}

// For each meshlet pair, count how many vertices they share
let mut meshlet_pair_to_shared_vertex_count = <HashMap<_, _>>::default();
for vertex_meshlet_ids in vertices_to_meshlets {
for (meshlet_queue_id1, meshlet_queue_id2) in
vertex_meshlet_ids.into_iter().tuple_combinations()
{
for (meshlet_id1, meshlet_id2) in vertex_meshlet_ids.into_iter().tuple_combinations() {
let count = meshlet_pair_to_shared_vertex_count
.entry((
meshlet_queue_id1.min(meshlet_queue_id2),
meshlet_queue_id1.max(meshlet_queue_id2),
))
.entry((meshlet_id1.min(meshlet_id2), meshlet_id1.max(meshlet_id2)))
.or_insert(0);
*count += 1;
}
}

// For each meshlet, gather all other meshlets that share at least one vertex along with their shared vertex count
let mut connected_meshlets_per_meshlet = vec![Vec::new(); simplification_queue.len()];
for ((meshlet_queue_id1, meshlet_queue_id2), shared_count) in
meshlet_pair_to_shared_vertex_count
{
for ((meshlet_id1, meshlet_id2), shared_vertex_count) in meshlet_pair_to_shared_vertex_count {
// We record both id1->id2 and id2->id1 as adjacency is symmetrical
connected_meshlets_per_meshlet[meshlet_queue_id1].push((meshlet_queue_id2, shared_count));
connected_meshlets_per_meshlet[meshlet_queue_id2].push((meshlet_queue_id1, shared_count));
connected_meshlets_per_meshlet[meshlet_id1 - simplification_queue.start]
.push((meshlet_id2, shared_vertex_count));
connected_meshlets_per_meshlet[meshlet_id2 - simplification_queue.start]
.push((meshlet_id1, shared_vertex_count));
}

// The order of meshlets depends on hash traversal order; to produce deterministic results, sort them
Expand All @@ -309,15 +300,15 @@ fn find_connected_meshlets(
// METIS manual: https://github.com/KarypisLab/METIS/blob/e0f1b88b8efcb24ffa0ec55eabb78fbe61e58ae7/manual/manual.pdf
fn group_meshlets(
connected_meshlets_per_meshlet: &[Vec<(usize, usize)>],
simplification_queue: &[usize],
simplification_queue: Range<usize>,
) -> Vec<SmallVec<[usize; TARGET_MESHLETS_PER_GROUP]>> {
let mut xadj = Vec::with_capacity(simplification_queue.len() + 1);
let mut adjncy = Vec::new();
let mut adjwgt = Vec::new();
for connected_meshlets in connected_meshlets_per_meshlet {
xadj.push(adjncy.len() as i32);
for (connected_meshlet_queue_id, shared_vertex_count) in connected_meshlets {
adjncy.push(*connected_meshlet_queue_id as i32);
for (connected_meshlet_id, shared_vertex_count) in connected_meshlets {
adjncy.push((connected_meshlet_id - simplification_queue.start) as i32);
adjwgt.push(*shared_vertex_count as i32);
// TODO: Additional weight based on meshlet spatial proximity
}
Expand All @@ -336,8 +327,8 @@ fn group_meshlets(
.unwrap();

let mut groups = vec![SmallVec::new(); partition_count];
for (meshlet_queue_id, meshlet_group) in group_per_meshlet.into_iter().enumerate() {
groups[meshlet_group as usize].push(simplification_queue[meshlet_queue_id]);
for (i, meshlet_group) in group_per_meshlet.into_iter().enumerate() {
groups[meshlet_group as usize].push(i + simplification_queue.start);
}
groups
}
Expand Down
Loading