// Schedule jobs to build Jacobians from the contacts stored in the simulation context internal static SimulationJobHandles ScheduleBuildJacobiansJobs(ref PhysicsWorld world, float timeStep, float3 gravity, int numSolverIterations, JobHandle inputDeps, ref NativeList <DispatchPairSequencer.DispatchPair> dispatchPairs, ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo, ref NativeStream contacts, ref NativeStream jacobians, int threadCountHint = 0) { SimulationJobHandles returnHandles = default; if (threadCountHint <= 0) { returnHandles.FinalExecutionHandle = new BuildJacobiansJob { ContactsReader = contacts.AsReader(), JacobiansWriter = jacobians.AsWriter(), TimeStep = timeStep, Gravity = gravity, NumSolverIterations = numSolverIterations, World = world, DispatchPairs = dispatchPairs.AsDeferredJobArray(), SolverSchedulerInfo = solverSchedulerInfo }.Schedule(inputDeps); } else { var buildJob = new BuildJacobiansJob { ContactsReader = contacts.AsReader(), JacobiansWriter = jacobians.AsWriter(), TimeStep = timeStep, InvTimeStep = timeStep > 0.0f ? 1.0f / timeStep : 0.0f, GravityAcceleration = math.length(gravity), NumSolverIterations = numSolverIterations, World = world, DispatchPairs = dispatchPairs.AsDeferredJobArray(), SolverSchedulerInfo = solverSchedulerInfo }; JobHandle handle = buildJob.ScheduleUnsafeIndex0(solverSchedulerInfo.NumWorkItems, 1, inputDeps); returnHandles.FinalDisposeHandle = JobHandle.CombineDependencies( dispatchPairs.Dispose(handle), contacts.Dispose(handle)); returnHandles.FinalExecutionHandle = handle; } return(returnHandles); }
// Schedules a set of jobs to iterate the provided dispatch pairs and create contacts based on them. internal static SimulationJobHandles ScheduleCreateContactsJobs(ref PhysicsWorld world, float timeStep, ref NativeStream contacts, ref NativeStream jacobians, ref NativeList <DispatchPairSequencer.DispatchPair> dispatchPairs, JobHandle inputDeps, ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo, bool multiThreaded = true) { SimulationJobHandles returnHandles = default; if (!multiThreaded) { contacts = new NativeStream(1, Allocator.TempJob); jacobians = new NativeStream(1, Allocator.TempJob); returnHandles.FinalExecutionHandle = new CreateContactsJob { World = world, TimeStep = timeStep, DispatchPairs = dispatchPairs.AsDeferredJobArray(), ContactsWriter = contacts.AsWriter() }.Schedule(inputDeps); } else { var numWorkItems = solverSchedulerInfo.NumWorkItems; var contactsHandle = NativeStream.ScheduleConstruct(out contacts, numWorkItems, inputDeps, Allocator.TempJob); var jacobiansHandle = NativeStream.ScheduleConstruct(out jacobians, numWorkItems, inputDeps, Allocator.TempJob); var processHandle = new ParallelCreateContactsJob { World = world, TimeStep = timeStep, DispatchPairs = dispatchPairs.AsDeferredJobArray(), SolverSchedulerInfo = solverSchedulerInfo, ContactsWriter = contacts.AsWriter() }.ScheduleUnsafeIndex0(numWorkItems, 1, JobHandle.CombineDependencies(contactsHandle, jacobiansHandle)); returnHandles.FinalExecutionHandle = processHandle; } return(returnHandles); }
// Schedule jobs to solve the Jacobians stored in the simulation context internal static unsafe SimulationJobHandles ScheduleSolveJacobiansJobs(ref DynamicsWorld dynamicsWorld, float timestep, int numIterations, ref NativeStream jacobians, ref NativeStream collisionEvents, ref NativeStream triggerEvents, ref DispatchPairSequencer.SolverSchedulerInfo solverSchedulerInfo, JobHandle inputDeps, int threadCountHint = 0) { SimulationJobHandles returnHandles = default; if (threadCountHint <= 0) { collisionEvents = new NativeStream(1, Allocator.Persistent); triggerEvents = new NativeStream(1, Allocator.Persistent); returnHandles.FinalExecutionHandle = new SolverJob { CollisionEventsWriter = collisionEvents.AsWriter(), JacobiansReader = jacobians.AsReader(), NumIterations = numIterations, Timestep = timestep, TriggerEventsWriter = triggerEvents.AsWriter(), MotionVelocities = dynamicsWorld.MotionVelocities, Phases = solverSchedulerInfo.PhaseInfo }.Schedule(inputDeps); return(returnHandles); } JobHandle handle; int numPhases = solverSchedulerInfo.NumPhases; // Use persistent allocator to allow these to live until the start of next step { NativeArray <int> workItemList = solverSchedulerInfo.NumWorkItems; //TODO: Change this to Allocator.TempJob when https://github.com/Unity-Technologies/Unity.Physics/issues/7 is resolved JobHandle collisionEventStreamHandle = NativeStream.ScheduleConstruct(out collisionEvents, workItemList, inputDeps, Allocator.Persistent); JobHandle triggerEventStreamHandle = NativeStream.ScheduleConstruct(out triggerEvents, workItemList, inputDeps, Allocator.Persistent); handle = JobHandle.CombineDependencies(collisionEventStreamHandle, triggerEventStreamHandle); float invNumIterations = math.rcp(numIterations); var phaseInfoPtrs = (DispatchPairSequencer.SolverSchedulerInfo.SolvePhaseInfo *)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(solverSchedulerInfo.PhaseInfo); for (int solverIterationId = 0; solverIterationId < numIterations; solverIterationId++) { bool lastIteration = solverIterationId == numIterations - 1; for (int phaseId = 0; phaseId < numPhases; phaseId++) { var job = new SolverJob { JacobiansReader = jacobians.AsReader(), PhaseIndex = phaseId, Phases = solverSchedulerInfo.PhaseInfo, MotionVelocities = dynamicsWorld.MotionVelocities, StepInput = new StepInput { InvNumSolverIterations = invNumIterations, IsLastIteration = lastIteration, Timestep = timestep, InvTimestep = timestep > 0.0f ? 1.0f / timestep : 0.0f } }; // Only initialize event writers for last solver iteration jobs if (lastIteration) { job.CollisionEventsWriter = collisionEvents.AsWriter(); job.TriggerEventsWriter = triggerEvents.AsWriter(); } // NOTE: The last phase must be executed on a single job since it // int.MaxValue can't be used as batchSize since 19.1 overflows in that case... bool isLastPhase = phaseId == numPhases - 1; int batchSize = isLastPhase ? (int.MaxValue / 2) : 1; int *numWorkItems = &(phaseInfoPtrs[phaseId].NumWorkItems); handle = job.Schedule(numWorkItems, batchSize, handle); } } } // Dispose processed data returnHandles.FinalDisposeHandle = JobHandle.CombineDependencies( jacobians.Dispose(handle), solverSchedulerInfo.ScheduleDisposeJob(handle)); returnHandles.FinalExecutionHandle = handle; return(returnHandles); }