Skip to content
Open
Show file tree
Hide file tree
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
25 changes: 13 additions & 12 deletions crates/bevy_mesh/src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ impl Indices {
/// Extend the indices with indices from an iterator.
/// Semantically equivalent to calling [`push`](Indices::push) for each element in the iterator,
/// but more efficient.
///
/// [`Indices::U16`] will be converted to [`Indices::U32`] if there is primitive restart value [`u16::MAX`] or any value greater than [`u16::MAX`].
impl Extend<u32> for Indices {
fn extend<T: IntoIterator<Item = u32>>(&mut self, iter: T) {
let mut iter = iter.into_iter();
Expand All @@ -131,18 +133,17 @@ impl Extend<u32> for Indices {
Indices::U16(indices) => {
indices.reserve(iter.size_hint().0);
while let Some(index) = iter.next() {
match u16::try_from(index) {
Ok(index) => indices.push(index),
Err(_) => {
let new_vec = indices
.iter()
.map(|&index| u32::from(index))
.chain(iter::once(index))
.chain(iter)
.collect::<Vec<u32>>();
*self = Indices::U32(new_vec);
break;
}
if index < u16::MAX as u32 {
indices.push(index as u16);
} else {
let new_vec = indices
.iter()
.map(|&index| u32::from(index))
.chain(iter::once(index))
.chain(iter)
.collect::<Vec<u32>>();
*self = Indices::U32(new_vec);
break;
}
}
}
Expand Down
23 changes: 21 additions & 2 deletions crates/bevy_mesh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ bitflags! {
#[derive(Clone, Debug)]
pub struct BaseMeshPipelineKey: u64 {
const MORPH_TARGETS = 1 << (u64::BITS - 1);
const INDEX_FORMAT_RESERVED_BITS = Self::INDEX_FORMAT_MASK_BITS << Self::INDEX_FORMAT_SHIFT_BITS;
const INDEX_FORMAT_NONE = 0 << Self::INDEX_FORMAT_SHIFT_BITS;
const INDEX_FORMAT_U32 = 1 << Self::INDEX_FORMAT_SHIFT_BITS;
const INDEX_FORMAT_U16 = 2 << Self::INDEX_FORMAT_SHIFT_BITS;
}
}

Expand All @@ -69,11 +73,26 @@ impl BaseMeshPipelineKey {
pub const PRIMITIVE_TOPOLOGY_SHIFT_BITS: u64 =
(u64::BITS - 1 - Self::PRIMITIVE_TOPOLOGY_MASK_BITS.count_ones()) as u64;

pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self {
pub const INDEX_FORMAT_MASK_BITS: u64 = 0b11;
pub const INDEX_FORMAT_SHIFT_BITS: u64 =
Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS - Self::INDEX_FORMAT_MASK_BITS.count_ones() as u64;

pub fn from_primitive_topology_and_index(
primitive_topology: PrimitiveTopology,
indices: Option<wgpu_types::IndexFormat>,
) -> Self {
let index_bits = match indices {
None => BaseMeshPipelineKey::INDEX_FORMAT_NONE,
Some(indices) => match indices {
wgpu_types::IndexFormat::Uint16 => BaseMeshPipelineKey::INDEX_FORMAT_U16,
wgpu_types::IndexFormat::Uint32 => BaseMeshPipelineKey::INDEX_FORMAT_U32,
},
}
.bits();
let primitive_topology_bits = ((primitive_topology as u64)
& Self::PRIMITIVE_TOPOLOGY_MASK_BITS)
<< Self::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
Self::from_bits_retain(primitive_topology_bits)
Self::from_bits_retain(primitive_topology_bits | index_bits)
}

pub fn primitive_topology(&self) -> PrimitiveTopology {
Expand Down
4 changes: 0 additions & 4 deletions crates/bevy_pbr/src/meshlet/material_pipeline_prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,6 @@ pub fn prepare_material_meshlet_meshes_main_opaque_pass(
view_key |= MeshPipelineKey::DISTANCE_FOG;
}

view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);

for material_id in render_material_instances
.instances
.values()
Expand Down Expand Up @@ -297,8 +295,6 @@ pub fn prepare_material_meshlet_meshes_prepass(
view_key |= MeshPipelineKey::MOTION_VECTOR_PREPASS;
}

view_key |= MeshPipelineKey::from_primitive_topology(PrimitiveTopology::TriangleList);

for material_id in render_material_instances
.instances
.values()
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_pbr/src/prepass/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ impl PrepassPipeline {
layout: bind_group_layouts,
primitive: PrimitiveState {
topology: mesh_key.primitive_topology(),
strip_index_format: mesh_key.strip_index_format(),
unclipped_depth,
..default()
},
Expand Down
41 changes: 39 additions & 2 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2268,11 +2268,22 @@ impl MeshPipelineKey {
1 << ((self.bits() >> Self::MSAA_SHIFT_BITS) & Self::MSAA_MASK_BITS)
}

pub fn from_primitive_topology(primitive_topology: PrimitiveTopology) -> Self {
pub fn from_primitive_topology_and_index(
primitive_topology: PrimitiveTopology,
indices: Option<IndexFormat>,
) -> Self {
let index_bits = match indices {
None => BaseMeshPipelineKey::INDEX_FORMAT_NONE,
Some(indices) => match indices {
IndexFormat::Uint16 => BaseMeshPipelineKey::INDEX_FORMAT_U16,
IndexFormat::Uint32 => BaseMeshPipelineKey::INDEX_FORMAT_U32,
},
}
.bits();
let primitive_topology_bits = ((primitive_topology as u64)
& BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_MASK_BITS)
<< BaseMeshPipelineKey::PRIMITIVE_TOPOLOGY_SHIFT_BITS;
Self::from_bits_retain(primitive_topology_bits)
Self::from_bits_retain(primitive_topology_bits | index_bits)
}

pub fn primitive_topology(&self) -> PrimitiveTopology {
Expand All @@ -2288,6 +2299,24 @@ impl MeshPipelineKey {
_ => PrimitiveTopology::default(),
}
}

pub fn index_format(&self) -> Option<IndexFormat> {
let index_bits = self.bits() & BaseMeshPipelineKey::INDEX_FORMAT_RESERVED_BITS.bits();
match index_bits {
x if x == BaseMeshPipelineKey::INDEX_FORMAT_U16.bits() => Some(IndexFormat::Uint16),
x if x == BaseMeshPipelineKey::INDEX_FORMAT_U32.bits() => Some(IndexFormat::Uint32),
x if x == BaseMeshPipelineKey::INDEX_FORMAT_NONE.bits() => None,
_ => unreachable!(),
}
}

pub fn strip_index_format(&self) -> Option<IndexFormat> {
if self.primitive_topology().is_strip() {
self.index_format()
} else {
None
}
}
}

// Ensure that we didn't overflow the number of bits available in `MeshPipelineKey`.
Expand All @@ -2305,6 +2334,13 @@ const_assert_eq!(
0
);

// Ensure that the reserved bits don't overlap with the indices type bits
const_assert_eq!(
BaseMeshPipelineKey::INDEX_FORMAT_RESERVED_BITS.bits()
& MeshPipelineKey::ALL_RESERVED_BITS.bits(),
0
);

fn is_skinned(layout: &MeshVertexBufferLayoutRef) -> bool {
layout.0.contains(Mesh::ATTRIBUTE_JOINT_INDEX)
&& layout.0.contains(Mesh::ATTRIBUTE_JOINT_WEIGHT)
Expand Down Expand Up @@ -2711,6 +2747,7 @@ impl SpecializedMeshPipeline for MeshPipeline {
cull_mode: Some(Face::Back),
unclipped_depth: false,
topology: key.primitive_topology(),
strip_index_format: key.strip_index_format(),
..default()
},
depth_stencil: Some(DepthStencilState {
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_pbr/src/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,10 @@ pub fn specialize_wireframes(
};

let mut mesh_key = *view_key;
mesh_key |= MeshPipelineKey::from_primitive_topology(mesh.primitive_topology());
mesh_key |= MeshPipelineKey::from_primitive_topology_and_index(
mesh.primitive_topology(),
mesh.index_format(),
);

if render_visibility_ranges.entity_has_crossfading_visibility_ranges(*visible_entity) {
mesh_key |= MeshPipelineKey::VISIBILITY_RANGE_DITHER;
Expand Down
20 changes: 18 additions & 2 deletions crates/bevy_render/src/mesh/allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ struct SlabAllocation {
allocation: Allocation,
/// The number of slots that this allocation takes up.
slot_count: u32,
/// The number of padding elements that this allocation takes up.
padding_elem_count: u32,
}

/// Holds information about all slabs scheduled to be allocated or reallocated.
Expand Down Expand Up @@ -448,7 +450,8 @@ impl MeshAllocator {
range: (slab_allocation.allocation.offset
* general_slab.element_layout.elements_per_slot)
..((slab_allocation.allocation.offset + slab_allocation.slot_count)
* general_slab.element_layout.elements_per_slot),
* general_slab.element_layout.elements_per_slot)
- slab_allocation.padding_elem_count,
})
}

Expand Down Expand Up @@ -722,14 +725,22 @@ impl MeshAllocator {
) {
let data_element_count = data_byte_len.div_ceil(layout.size) as u32;
let data_slot_count = data_element_count.div_ceil(layout.elements_per_slot);
let padding_elem_count = data_slot_count * layout.elements_per_slot - data_element_count;

// If the mesh data is too large for a slab, give it a slab of its own.
if data_slot_count as u64 * layout.slot_size()
>= settings.large_threshold.min(settings.max_slab_size)
{
self.allocate_large(mesh_id, layout);
} else {
self.allocate_general(mesh_id, data_slot_count, layout, slabs_to_grow, settings);
self.allocate_general(
mesh_id,
data_slot_count,
padding_elem_count,
layout,
slabs_to_grow,
settings,
);
}
}

Expand All @@ -739,6 +750,7 @@ impl MeshAllocator {
&mut self,
mesh_id: &AssetId<Mesh>,
data_slot_count: u32,
padding_elem_count: u32,
layout: ElementLayout,
slabs_to_grow: &mut SlabsToReallocate,
settings: &MeshAllocatorSettings,
Expand Down Expand Up @@ -779,6 +791,7 @@ impl MeshAllocator {
slab_allocation: SlabAllocation {
allocation,
slot_count: data_slot_count,
padding_elem_count,
},
});
break;
Expand All @@ -795,6 +808,7 @@ impl MeshAllocator {
settings,
layout,
data_slot_count,
padding_elem_count,
);

self.slabs.insert(new_slab_id, Slab::General(new_slab));
Expand Down Expand Up @@ -922,6 +936,7 @@ impl GeneralSlab {
settings: &MeshAllocatorSettings,
layout: ElementLayout,
data_slot_count: u32,
padding_elem_count: u32,
) -> GeneralSlab {
let initial_slab_slot_capacity = (settings.min_slab_size.div_ceil(layout.slot_size())
as u32)
Expand All @@ -945,6 +960,7 @@ impl GeneralSlab {
slab_allocation: SlabAllocation {
slot_count: data_slot_count,
allocation,
padding_elem_count,
},
});
}
Expand Down
28 changes: 21 additions & 7 deletions crates/bevy_render/src/mesh/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ impl RenderMesh {
pub fn indexed(&self) -> bool {
matches!(self.buffer_info, RenderMeshBufferInfo::Indexed { .. })
}

#[inline]
pub fn index_format(&self) -> Option<IndexFormat> {
match self.buffer_info {
RenderMeshBufferInfo::Indexed { index_format, .. } => Some(index_format),
RenderMeshBufferInfo::NonIndexed => None,
}
}
}

/// The index/vertex buffer info of a [`RenderMesh`].
Expand Down Expand Up @@ -172,18 +180,24 @@ impl RenderAsset for RenderMesh {
None => None,
};

let buffer_info = match mesh.indices() {
Some(indices) => RenderMeshBufferInfo::Indexed {
count: indices.len() as u32,
index_format: indices.into(),
},
None => RenderMeshBufferInfo::NonIndexed,
let (buffer_info, index_format) = match mesh.indices() {
Some(indices) => (
RenderMeshBufferInfo::Indexed {
count: indices.len() as u32,
index_format: indices.into(),
},
Some(indices.into()),
),
None => (RenderMeshBufferInfo::NonIndexed, None),
};

let mesh_vertex_buffer_layout =
mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);

let key_bits = BaseMeshPipelineKey::from_primitive_topology(mesh.primitive_topology());
let key_bits = BaseMeshPipelineKey::from_primitive_topology_and_index(
mesh.primitive_topology(),
index_format,
);
#[cfg(feature = "morph")]
let key_bits = if mesh.morph_targets().is_some() {
key_bits | BaseMeshPipelineKey::MORPH_TARGETS
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_sprite_render/src/mesh2d/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,10 @@ pub fn specialize_material2d_meshes<M: Material2d>(
continue;
};
let mesh_key = *view_key
| Mesh2dPipelineKey::from_primitive_topology(mesh.primitive_topology())
| Mesh2dPipelineKey::from_primitive_topology_and_index(
mesh.primitive_topology(),
mesh.index_format(),
)
| material_2d.properties.mesh_pipeline_key_bits;

let pipeline_id = pipelines.specialize(
Expand Down
Loading
Loading