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

Allow Mesh-related queue phase systems to parallelize #11804

Merged
merged 8 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
43 changes: 36 additions & 7 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ use bevy_render::{
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
};
use bevy_utils::{tracing::error, HashMap, HashSet};
use std::hash::Hash;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicU32, Ordering};
use std::{hash::Hash, num::NonZeroU32};

use self::{irradiance_volume::IrradianceVolume, prelude::EnvironmentMapLight};

Expand Down Expand Up @@ -236,9 +237,7 @@ where
.after(prepare_materials::<M>),
queue_material_meshes::<M>
.in_set(RenderSet::QueueMeshes)
.after(prepare_materials::<M>)
// queue_material_meshes only writes to `material_bind_group_id`, which `queue_shadows` doesn't read
.ambiguous_with(render::queue_shadows::<M>),
.after(prepare_materials::<M>),
),
);
}
Expand Down Expand Up @@ -466,7 +465,7 @@ pub fn queue_material_meshes<M: Material>(
msaa: Res<Msaa>,
render_meshes: Res<RenderAssets<Mesh>>,
render_materials: Res<RenderMaterials<M>>,
mut render_mesh_instances: ResMut<RenderMeshInstances>,
render_mesh_instances: Res<RenderMeshInstances>,
render_material_instances: Res<RenderMaterialInstances<M>>,
render_lightmaps: Res<RenderLightmaps>,
mut views: Query<(
Expand Down Expand Up @@ -592,7 +591,7 @@ pub fn queue_material_meshes<M: Material>(
let Some(material_asset_id) = render_material_instances.get(visible_entity) else {
continue;
};
let Some(mesh_instance) = render_mesh_instances.get_mut(visible_entity) else {
let Some(mesh_instance) = render_mesh_instances.get(visible_entity) else {
continue;
};
let Some(mesh) = render_meshes.get(mesh_instance.mesh_asset_id) else {
Expand Down Expand Up @@ -646,7 +645,9 @@ pub fn queue_material_meshes<M: Material>(
}
};

mesh_instance.material_bind_group_id = material.get_bind_group_id();
mesh_instance
.material_bind_group_id
.set(material.get_bind_group_id());

match material.properties.alpha_mode {
AlphaMode::Opaque => {
Expand Down Expand Up @@ -795,6 +796,34 @@ pub struct PreparedMaterial<T: Material> {
#[derive(Component, Clone, Copy, Default, PartialEq, Eq, Deref, DerefMut)]
pub struct MaterialBindGroupId(Option<BindGroupId>);

/// An atomic version of [`MaterialBindGroupId`] that can be read from and written to
/// safely from multiple threads.
#[derive(Default)]
pub struct AtomicMaterialBindGroupId(AtomicU32);

impl AtomicMaterialBindGroupId {
/// Stores a value atomically. Uses [`Ordering::Relaxed`] so there is zero guarentee of ordering
/// relative to other operations.
///
/// See also: [`AtomicU32::store`].
pub fn set(&self, id: MaterialBindGroupId) {
let id = if let Some(id) = id.0 {
NonZeroU32::from(id).get()
} else {
0
};
self.0.store(id, Ordering::Relaxed);
}

/// Loads a value atomically. Uses [`Ordering::Relaxed`] so there is zero guarentee of ordering
/// relative to other operations.
///
/// See also: [`AtomicU32::load`].
pub fn get(&self) -> MaterialBindGroupId {
MaterialBindGroupId(NonZeroU32::new(self.0.load(Ordering::Relaxed)).map(BindGroupId::from))
}
}

impl<T: Material> PreparedMaterial<T> {
pub fn get_bind_group_id(&self) -> MaterialBindGroupId {
MaterialBindGroupId(Some(self.bind_group.id()))
Expand Down
13 changes: 7 additions & 6 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
MaterialBindGroupId, NotShadowCaster, NotShadowReceiver, PreviousGlobalTransform, Shadow,
ViewFogUniformOffset, ViewLightProbesUniformOffset, ViewLightsUniformOffset,
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS,
AtomicMaterialBindGroupId, MaterialBindGroupId, NotShadowCaster, NotShadowReceiver,
PreviousGlobalTransform, Shadow, ViewFogUniformOffset, ViewLightProbesUniformOffset,
ViewLightsUniformOffset, CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT,
MAX_DIRECTIONAL_LIGHTS,
};
use bevy_app::{Plugin, PostUpdate};
use bevy_asset::{load_internal_asset, AssetId, Handle};
Expand Down Expand Up @@ -248,7 +249,7 @@ bitflags::bitflags! {
pub struct RenderMeshInstance {
pub transforms: MeshTransforms,
pub mesh_asset_id: AssetId<Mesh>,
pub material_bind_group_id: MaterialBindGroupId,
pub material_bind_group_id: AtomicMaterialBindGroupId,
pub shadow_caster: bool,
pub automatic_batching: bool,
}
Expand Down Expand Up @@ -319,7 +320,7 @@ pub fn extract_meshes(
mesh_asset_id: handle.id(),
transforms,
shadow_caster: !not_shadow_caster,
material_bind_group_id: MaterialBindGroupId::default(),
material_bind_group_id: AtomicMaterialBindGroupId::default(),
automatic_batching: !no_automatic_batching,
},
));
Expand Down Expand Up @@ -477,7 +478,7 @@ impl GetBatchData for MeshPipeline {
maybe_lightmap.map(|lightmap| lightmap.uv_rect),
),
mesh_instance.automatic_batching.then_some((
mesh_instance.material_bind_group_id,
mesh_instance.material_bind_group_id.get(),
mesh_instance.mesh_asset_id,
maybe_lightmap.map(|lightmap| lightmap.image),
)),
Expand Down
12 changes: 12 additions & 0 deletions crates/bevy_render/src/render_resource/resource_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ macro_rules! define_atomic_id {
}))
}
}

impl From<$atomic_id_type> for core::num::NonZeroU32 {
fn from(value: $atomic_id_type) -> Self {
value.0
}
}

impl From<core::num::NonZeroU32> for $atomic_id_type {
fn from(value: core::num::NonZeroU32) -> Self {
Self(value)
}
}
};
}

Expand Down