// Schedule all the jobs for the simulation step. // Enqueued callbacks can choose to inject additional jobs at defined sync points. public unsafe void ScheduleStepJobs(SimulationStepInput input, JobHandle inputDeps) { if (input.TimeStep < 0) { throw new ArgumentOutOfRangeException(); } if (input.ThreadCountHint <= 0) { throw new ArgumentOutOfRangeException(); } if (input.NumSolverIterations <= 0) { throw new ArgumentOutOfRangeException(); } // Dispose event streams from previous frame JobHandle handle = DisposeEventStreams(inputDeps); // Allocate storage for input velocities m_Storage.InputVelocityCount = input.World.NumDynamicBodies; m_Context = new Context { TimeStep = input.TimeStep, InputVelocities = m_Storage.InputVelocities }; if (input.World.NumDynamicBodies == 0) { // No need to do anything, since nothing can move FinalSimulationJobHandle = handle; FinalJobHandle = handle; return; } SimulationCallbacks callbacks = input.Callbacks ?? new SimulationCallbacks(); // Find all body pairs that overlap in the broadphase handle = input.World.CollisionWorld.Broadphase.ScheduleFindOverlapsJobs( out BlockStream dynamicVsDynamicBodyPairs, out BlockStream dynamicVsStaticBodyPairs, ref m_Context, handle); var postOverlapsHandle = handle; // Sort all overlapping and jointed body pairs into phases handle = m_Scheduler.ScheduleCreatePhasedDispatchPairsJob( ref input.World, ref dynamicVsDynamicBodyPairs, ref dynamicVsStaticBodyPairs, ref m_Context, handle); // Apply gravity and copy input velocities at this point (in parallel with the scheduler, but before the callbacks) var applyGravityAndCopyInputVelocitiesHandle = Solver.ScheduleApplyGravityAndCopyInputVelocitiesJob( ref input.World.DynamicsWorld, m_Storage.InputVelocities, input.TimeStep * input.Gravity, postOverlapsHandle); handle = JobHandle.CombineDependencies(handle, applyGravityAndCopyInputVelocitiesHandle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateDispatchPairs, this, ref input.World, handle); // Create contact points & joint Jacobians handle = NarrowPhase.ScheduleProcessBodyPairsJobs(ref input.World, input.TimeStep, input.NumSolverIterations, ref m_Context, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateContacts, this, ref input.World, handle); // Create contact Jacobians handle = Solver.ScheduleBuildContactJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, math.length(input.Gravity), ref m_Context, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateContactJacobians, this, ref input.World, handle); // Solve all Jacobians handle = Solver.ScheduleSolveJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, input.NumSolverIterations, ref m_Context, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostSolveJacobians, this, ref input.World, handle); // Integrate motions handle = Integrator.ScheduleIntegrateJobs(ref input.World.DynamicsWorld, input.TimeStep, handle); // Synchronize the collision world if (input.SynchronizeCollisionWorld) { handle = input.World.CollisionWorld.ScheduleUpdateDynamicLayer(ref input.World, input.TimeStep, input.Gravity, input.ThreadCountHint, handle); // TODO: timeStep = 0? } // Return the final simulation handle FinalSimulationJobHandle = handle; // Return the final handle, which includes disposing temporary arrays JobHandle *deps = stackalloc JobHandle[11] { FinalSimulationJobHandle, m_Context.DisposeOverlapPairs0, m_Context.DisposeOverlapPairs1, m_Context.DisposeBroadphasePairs0, m_Context.DisposeBroadphasePairs1, m_Context.DisposeContacts, m_Context.DisposeJacobians, m_Context.DisposeJointJacobians, m_Context.DisposeSolverSchedulerData, m_Context.DisposeProcessBodyPairs, m_Context.DisposePhasedDispatchPairs }; FinalJobHandle = JobHandleUnsafeUtility.CombineDependencies(deps, 11); }
// Schedule all the jobs for the simulation step. // Enqueued callbacks can choose to inject additional jobs at defined sync points. public void ScheduleStepJobs(SimulationStepInput input, JobHandle inputDeps, out JobHandle finalSimulationJobHandle, out JobHandle finalJobHandle) { // Dispose event streams from previous frame DisposeEventStreams(); m_Context = new Context(); if (input.World.NumDynamicBodies == 0) { // No need to do anything, since nothing can move finalSimulationJobHandle = new JobHandle(); finalJobHandle = new JobHandle(); return; } SimulationCallbacks callbacks = input.Callbacks ?? new SimulationCallbacks(); JobHandle handle = inputDeps; // We need to make sure that broadphase tree building is done before we schedule FindOverlapsJobs. handle.Complete(); // Find all body pairs that overlap in the broadphase handle = input.World.CollisionWorld.Broadphase.ScheduleFindOverlapsJobs( out BlockStream dynamicVsDynamicBroadphasePairsStream, out BlockStream staticVsDynamicBroadphasePairsStream, handle); handle.Complete(); // Need to know the total number of pairs before continuing // Create phased dispatch pairs for all interacting body pairs handle = m_Scheduler.ScheduleCreatePhasedDispatchPairsJob( ref input.World, ref dynamicVsDynamicBroadphasePairsStream, ref staticVsDynamicBroadphasePairsStream, ref m_Context, handle); handle.Complete(); // Need to know the total number of work items before continuing handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateDispatchPairs, this, handle); m_Context.CreateBodyPairsHandle = handle; // Create contact points & joint Jacobians handle = NarrowPhase.ScheduleProcessBodyPairsJobs(ref input.World, input.TimeStep, input.NumSolverIterations, ref m_Context, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateContacts, this, handle); m_Context.CreateContactsHandle = handle; // Create contact Jacobians handle = Solver.ScheduleBuildContactJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, ref m_Context, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateContactJacobians, this, handle); m_Context.CreateContactJacobiansHandle = handle; // Solve all Jacobians int numIterations = input.NumSolverIterations > 0 ? input.NumSolverIterations : 4; handle = Solver.ScheduleSolveJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, input.Gravity, numIterations, ref m_Context, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostSolveJacobians, this, handle); m_Context.SolveContactJacobiansHandle = handle; // Integration motions handle = Integrator.ScheduleIntegrateJobs(ref input.World.DynamicsWorld, input.TimeStep, input.Gravity, handle); handle = callbacks.Execute(SimulationCallbacks.Phase.PostIntegrateMotions, this, handle); m_Context.IntegrateMotionsHandle = handle; // Synchronize the collision world if (input.SynchronizeCollisionWorld) { handle = input.World.CollisionWorld.ScheduleUpdateDynamicLayer(ref input.World, input.TimeStep, input.ThreadCountHint, handle); // TODO: timeStep = 0? } // Return the final simulation handle finalSimulationJobHandle = handle; // Return the final handle, which includes disposing temporary arrays finalJobHandle = JobHandle.CombineDependencies(finalSimulationJobHandle, m_Context.DisposeBroadphasePairs, m_Context.DisposeContacts); finalJobHandle = JobHandle.CombineDependencies(finalJobHandle, m_Context.DisposeJacobians, m_Context.DisposeJointJacobians); finalJobHandle = JobHandle.CombineDependencies(finalJobHandle, m_Context.DisposeSolverSchedulerData); }