use crate::alloc_prelude::*;
use crate::counters::Counters;
use crate::dynamics::{
CCDSolver, ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet,
RigidBodySet,
};
use crate::geometry::{
BroadPhaseBvh, BroadPhasePairEvent, ColliderHandle, ColliderSet, ContactManifoldIndex,
NarrowPhase,
};
use crate::math::Vector;
use crate::pipeline::{EventHandler, PhysicsHooks};
mod quarantine;
pub use quarantine::Quarantine;
mod solve;
mod substep;
#[cfg(test)]
mod test;
#[cfg(test)]
mod test_staged;
pub struct PhysicsPipeline {
pub counters: Counters,
joint_constraint_indices: Vec<ContactManifoldIndex>,
joint_selection_primed: bool,
broad_phase_events: Vec<BroadPhasePairEvent>,
end_step_collider_aabbs: Vec<(ColliderHandle, crate::geometry::Aabb)>,
quarantine: Quarantine,
#[cfg(feature = "parallel")]
active_body_handles: Vec<crate::dynamics::RigidBodyHandle>,
sleep_observations: Vec<(u32, bool)>,
staged_solver: crate::dynamics::StagedIslandSolver,
#[cfg(feature = "parallel")]
deferred_bvh:
std::sync::Mutex<Option<std::sync::mpsc::Receiver<crate::geometry::DeferredBvhOptimize>>>,
deferred_bvh_inline: Option<crate::geometry::DeferredBvhOptimize>,
#[cfg(all(feature = "parallel", not(feature = "unsync-callbacks")))]
thread_pool: Option<std::sync::Arc<rayon::ThreadPool>>,
}
impl Default for PhysicsPipeline {
fn default() -> Self {
PhysicsPipeline::new()
}
}
#[allow(dead_code)]
fn check_pipeline_send_sync() {
fn do_test<T: Sync>() {}
do_test::<PhysicsPipeline>();
}
impl PhysicsPipeline {
pub fn new() -> PhysicsPipeline {
PhysicsPipeline {
counters: Counters::new(true),
#[cfg(feature = "parallel")]
active_body_handles: vec![],
sleep_observations: Vec::new(),
staged_solver: crate::dynamics::StagedIslandSolver::new(),
#[cfg(feature = "parallel")]
deferred_bvh: std::sync::Mutex::new(None),
deferred_bvh_inline: None,
#[cfg(all(feature = "parallel", not(feature = "unsync-callbacks")))]
thread_pool: None,
joint_constraint_indices: vec![],
joint_selection_primed: false,
broad_phase_events: vec![],
end_step_collider_aabbs: vec![],
quarantine: Quarantine::default(),
}
}
fn join_deferred_bvh_optimize(&mut self, broad_phase: &mut BroadPhaseBvh) {
#[cfg(feature = "parallel")]
if let Some(rx) = self.deferred_bvh.get_mut().unwrap().take() {
let task = rx.recv().expect("the deferred BVH optimization task died");
broad_phase.finish_deferred_optimize(task);
return;
}
if let Some(mut task) = self.deferred_bvh_inline.take() {
task.run();
broad_phase.finish_deferred_optimize(task);
}
}
pub fn step(
&mut self,
gravity: Vector,
integration_parameters: &IntegrationParameters,
islands: &mut IslandManager,
broad_phase: &mut BroadPhaseBvh,
narrow_phase: &mut NarrowPhase,
bodies: &mut RigidBodySet,
colliders: &mut ColliderSet,
impulse_joints: &mut ImpulseJointSet,
multibody_joints: &mut MultibodyJointSet,
ccd_solver: &mut CCDSolver,
hooks: &dyn PhysicsHooks,
events: &dyn EventHandler,
) {
#[cfg(all(feature = "parallel", not(feature = "unsync-callbacks")))]
if let Some(pool) = self.thread_pool.clone() {
return pool.install(|| {
self.step_inner(
gravity,
integration_parameters,
islands,
broad_phase,
narrow_phase,
bodies,
colliders,
impulse_joints,
multibody_joints,
ccd_solver,
hooks,
events,
)
});
}
self.step_inner(
gravity,
integration_parameters,
islands,
broad_phase,
narrow_phase,
bodies,
colliders,
impulse_joints,
multibody_joints,
ccd_solver,
hooks,
events,
)
}
}
#[cfg(all(feature = "parallel", not(feature = "unsync-callbacks")))]
impl PhysicsPipeline {
pub fn configure_thread_pool(
&mut self,
num_threads: usize,
) -> Result<(), rayon::ThreadPoolBuildError> {
let builder = rayon::ThreadPoolBuilder::new()
.num_threads(num_threads)
.thread_name(|i| alloc::format!("rapier-worker-{i}"));
self.thread_pool = Some(std::sync::Arc::new(builder.build()?));
Ok(())
}
pub fn thread_pool(&self) -> Option<std::sync::Arc<rayon::ThreadPool>> {
self.thread_pool.clone()
}
pub fn set_thread_pool(&mut self, pool: Option<std::sync::Arc<rayon::ThreadPool>>) {
self.thread_pool = pool;
}
pub fn clear_thread_pool(&mut self) {
self.thread_pool = None;
}
pub fn num_threads(&self) -> Option<usize> {
self.thread_pool
.as_ref()
.map(|pool| pool.current_num_threads())
}
}