Пример #1
0
        // TODO: We need to make a public version of ScheduleReset for use with
        // local simulation calling StepImmediate and chaining jobs over a number
        // of steps. This becomes a problem if new bodies are added to the world
        // between simulation steps.
        // A public version could take the form:
        //         public JobHandle ScheduleReset(ref PhysicsWorld world, JobHandle inputDeps = default)
        //         {
        //             return ScheduleReset(ref world, inputDeps, true);
        //         }
        // However, to make that possible we need a why to allocate InputVelocities within a job.
        // The core simulation does not chain jobs across multiple simulation steps and so
        // will not hit this issue.
        internal JobHandle ScheduleReset(SimulationStepInput stepInput, JobHandle inputDeps, bool allocateEventDataStreams)
        {
            m_NumDynamicBodies = stepInput.World.NumDynamicBodies;
            if (!m_InputVelocities.IsCreated || m_InputVelocities.Length < m_NumDynamicBodies)
            {
                // TODO: can we find a way to setup InputVelocities within a job?
                if (m_InputVelocities.IsCreated)
                {
                    m_InputVelocities.Dispose();
                }
                m_InputVelocities = new NativeArray <Velocity>(m_NumDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            }

            // Solver stabilization data
            if (stepInput.SolverStabilizationHeuristicSettings.EnableSolverStabilization)
            {
                if (!m_SolverStabilizationMotionData.IsCreated || m_SolverStabilizationMotionData.Length < m_NumDynamicBodies)
                {
                    if (m_SolverStabilizationMotionData.IsCreated)
                    {
                        m_SolverStabilizationMotionData.Dispose();
                    }
                    m_SolverStabilizationMotionData = new NativeArray <Solver.StabilizationMotionData>(m_NumDynamicBodies, Allocator.Persistent, NativeArrayOptions.ClearMemory);
                }
                else if (m_NumDynamicBodies > 0)
                {
                    unsafe
                    {
                        UnsafeUtility.MemClear(m_SolverStabilizationMotionData.GetUnsafePtr(), m_NumDynamicBodies * UnsafeUtility.SizeOf <Solver.StabilizationMotionData>());
                    }
                }
            }

            var handle = inputDeps;

            if (CollisionEventDataStream.IsCreated)
            {
                handle = CollisionEventDataStream.Dispose(handle);
            }
            if (TriggerEventDataStream.IsCreated)
            {
                handle = TriggerEventDataStream.Dispose(handle);
            }
            if (allocateEventDataStreams)
            {
                if (!WorkItemCount.IsCreated)
                {
                    WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent);
                }
                handle = NativeStream.ScheduleConstruct(out CollisionEventDataStream, WorkItemCount, handle, Allocator.Persistent);
                handle = NativeStream.ScheduleConstruct(out TriggerEventDataStream, WorkItemCount, handle, Allocator.Persistent);
            }
            return(handle);
        }
Пример #2
0
        public static JobHandle ScheduleConstruct <U>(bool runInParallel, out NativeStream dataStream, NativeList <U> forEachCountFromList, Allocator allocator, JobHandle dependsOn = default)
            where U : unmanaged
        {
            JobExtensions.CheckDependencies(runInParallel, dependsOn);
            if (runInParallel)
            {
                return(NativeStream.ScheduleConstruct(out dataStream, forEachCountFromList, dependsOn, allocator));
            }

            dependsOn.Complete();
            dataStream = new NativeStream(forEachCountFromList.Length, allocator);
            return(default);
Пример #3
0
    public void ScheduleCreateThrows()
    {
        var list = new NativeList <int>(Allocator.Persistent);

        list.Add(2);

        NativeStream stream;
        var          jobHandle = NativeStream.ScheduleConstruct(out stream, list, default(JobHandle));

        Assert.Throws <InvalidOperationException>(() => Debug.Log(stream.ForEachCount));

        jobHandle.Complete();

        Assert.AreEqual(1, stream.ForEachCount);

        stream.Dispose();
        list.Dispose();
    }
Пример #4
0
        // 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, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                contacts  = new NativeStream(1, Allocator.TempJob);
                jacobians = new NativeStream(1, Allocator.TempJob);
                returnHandles.FinalExecutionHandle = new CreateContactsJob
                {
                    World               = world,
                    TimeStep            = timeStep,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo,
                    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 CreateContactsJob
                {
                    World               = world,
                    TimeStep            = timeStep,
                    DispatchPairs       = dispatchPairs.AsDeferredJobArray(),
                    SolverSchedulerInfo = solverSchedulerInfo,
                    ContactsWriter      = contacts.AsWriter()
                }.ScheduleUnsafeIndex0(numWorkItems, 1, JobHandle.CombineDependencies(contactsHandle, jacobiansHandle));


                returnHandles.FinalExecutionHandle = processHandle;
            }

            return(returnHandles);
        }
Пример #5
0
        internal static JobHandle ScheduleProcessBodyPairsJobs(ref PhysicsWorld world, float timeStep, int numIterations, ref Simulation.Context context, JobHandle inputDeps)
        {
            var numWorkItems         = context.SolverSchedulerInfo.NumWorkItems;
            var contactsHandle       = NativeStream.ScheduleConstruct(out context.Contacts, numWorkItems, inputDeps, Allocator.TempJob);
            var jointJacobiansHandle = NativeStream.ScheduleConstruct(out context.JointJacobians, numWorkItems, inputDeps, Allocator.TempJob);
            var jacobiansHandle      = NativeStream.ScheduleConstruct(out context.Jacobians, numWorkItems, inputDeps, Allocator.TempJob);

            var processHandle = new ProcessBodyPairsJob
            {
                World               = world,
                TimeStep            = timeStep,
                NumIterations       = numIterations,
                PhasedDispatchPairs = context.PhasedDispatchPairs.AsDeferredJobArray(),
                SolverSchedulerInfo = context.SolverSchedulerInfo,
                ContactWriter       = context.Contacts.AsWriter(),
                JointJacobianWriter = context.JointJacobians.AsWriter(),
            }.ScheduleUnsafeIndex0(numWorkItems, 1, JobHandle.CombineDependencies(contactsHandle, jointJacobiansHandle, jacobiansHandle));


            context.DisposeProcessBodyPairs = NativeListUtilityTemp.DisposeHotFix(ref context.PhasedDispatchPairs, processHandle);

            return(processHandle);
        }
Пример #6
0
        // TODO: We need to make a public version of ScheduleReset for use with
        // local simulation calling StepImmediate and chaining jobs over a number
        // of steps. This becomes a problem if new bodies are added to the world
        // between simulation steps.
        // A public version could take the form:
        //         public JobHandle ScheduleReset(ref PhysicsWorld world, JobHandle inputDeps = default)
        //         {
        //             return ScheduleReset(ref world, inputDeps, true);
        //         }
        // However, to make that possible we need a why to allocate InputVelocities within a job.
        // The core simulation does not chain jobs across multiple simulation steps and so
        // will not hit this issue.
        internal JobHandle ScheduleReset(ref PhysicsWorld world, JobHandle inputDeps, bool allocateEventDataStreams)
        {
            m_Bodies = world.Bodies;

            int numDynamicBodies = world.NumDynamicBodies;

            if (InputVelocities.Length < numDynamicBodies)
            {
                // TODO: can we find a way to setup InputVelocities within a job?
                if (InputVelocities.IsCreated)
                {
                    InputVelocities.Dispose();
                }
                InputVelocities = new NativeArray <Velocity>(numDynamicBodies, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            }

            var handle = inputDeps;

            if (CollisionEventDataStream.IsCreated)
            {
                handle = CollisionEventDataStream.Dispose(handle);
            }
            if (TriggerEventDataStream.IsCreated)
            {
                handle = TriggerEventDataStream.Dispose(handle);
            }
            if (allocateEventDataStreams)
            {
                if (!WorkItemCount.IsCreated)
                {
                    WorkItemCount = new NativeArray <int>(new int[] { 1 }, Allocator.Persistent);
                }
                handle = NativeStream.ScheduleConstruct(out CollisionEventDataStream, WorkItemCount, handle, Allocator.Persistent);
                handle = NativeStream.ScheduleConstruct(out TriggerEventDataStream, WorkItemCount, handle, Allocator.Persistent);
            }
            return(handle);
        }
Пример #7
0
        // Schedule some jobs to solve the Jacobians stored in the simulation context
        internal static unsafe JobHandle ScheduleSolveJacobiansJobs(ref DynamicsWorld dynamicsWorld, float timestep, int numIterations, ref Simulation.Context context, JobHandle inputDeps)
        {
            JobHandle handle;

            int numPhases = context.SolverSchedulerInfo.NumPhases;

            // Use persistent allocator to allow these to live until the start of next step
            {
                NativeArray <int> workItemList = context.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 context.CollisionEventStream, workItemList, inputDeps, Allocator.Persistent);
                JobHandle triggerEventStreamHandle   = NativeStream.ScheduleConstruct(out context.TriggerEventStream, workItemList, inputDeps, Allocator.Persistent);

                handle = JobHandle.CombineDependencies(collisionEventStreamHandle, triggerEventStreamHandle);

                float invNumIterations = math.rcp(numIterations);

                var phaseInfoPtrs = (Scheduler.SolverSchedulerInfo.SolvePhaseInfo *)NativeArrayUnsafeUtility.GetUnsafeBufferPointerWithoutChecks(context.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
                        {
                            JacobianReader   = context.Jacobians.AsReader(),
                            PhaseIndex       = phaseId,
                            Phases           = context.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 = context.CollisionEventStream.AsWriter();
                            job.TriggerEventsWriter   = context.TriggerEventStream.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
            context.DisposeJacobians           = context.Jacobians.Dispose(handle);
            context.DisposeJointJacobians      = context.JointJacobians.Dispose(handle);
            context.DisposeSolverSchedulerData = context.SolverSchedulerInfo.ScheduleDisposeJob(handle);

            return(handle);
        }
Пример #8
0
        // Schedule a set of jobs which will write all overlapping body pairs to the given steam,
        // where at least one of the bodies is dynamic. The results are unsorted.
        public SimulationJobHandles ScheduleFindOverlapsJobs(out NativeStream dynamicVsDynamicPairsStream, out NativeStream staticVsDynamicPairsStream,
                                                             JobHandle inputDeps, int threadCountHint = 0)
        {
            SimulationJobHandles returnHandles = default;

            if (threadCountHint <= 0)
            {
                dynamicVsDynamicPairsStream        = new NativeStream(1, Allocator.TempJob);
                staticVsDynamicPairsStream         = new NativeStream(1, Allocator.TempJob);
                returnHandles.FinalExecutionHandle = new FindOverlapsJob
                {
                    Broadphase = this,
                    DynamicVsDynamicPairsWriter = dynamicVsDynamicPairsStream.AsWriter(),
                    StaticVsDynamicPairsWriter  = staticVsDynamicPairsStream.AsWriter()
                }.Schedule(inputDeps);

                return(returnHandles);
            }

            var dynamicVsDynamicNodePairIndices = new NativeList <int2>(Allocator.TempJob);
            var staticVsDynamicNodePairIndices  = new NativeList <int2>(Allocator.TempJob);

            JobHandle allocateDeps = new AllocateDynamicVsStaticNodePairs
            {
                dynamicVsDynamicNodePairIndices = dynamicVsDynamicNodePairIndices,
                staticVsDynamicNodePairIndices  = staticVsDynamicNodePairIndices,
                dynamicBranchCount = m_DynamicTree.BranchCount,
                staticBranchCount  = m_StaticTree.BranchCount
            }.Schedule(inputDeps);

            // Build pairs of branch node indices
            JobHandle dynamicVsDynamicPairs = new DynamicVsDynamicBuildBranchNodePairsJob
            {
                Ranges          = m_DynamicTree.Ranges,
                NumBranches     = m_DynamicTree.BranchCount,
                NodePairIndices = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            JobHandle staticVsDynamicPairs = new StaticVsDynamicBuildBranchNodePairsJob
            {
                DynamicRanges      = m_DynamicTree.Ranges,
                StaticRanges       = m_StaticTree.Ranges,
                NumStaticBranches  = m_StaticTree.BranchCount,
                NumDynamicBranches = m_DynamicTree.BranchCount,
                NodePairIndices    = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            //@TODO: We only need a dependency on allocateDeps, but the safety system doesn't understand that we can not change length list in DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            //       if this is a performance issue we can use [NativeDisableContainerSafetyRestriction] on DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            JobHandle dynamicConstruct = NativeStream.ScheduleConstruct(out dynamicVsDynamicPairsStream, dynamicVsDynamicNodePairIndices, dynamicVsDynamicPairs, Allocator.TempJob);
            JobHandle staticConstruct  = NativeStream.ScheduleConstruct(out staticVsDynamicPairsStream, staticVsDynamicNodePairIndices, staticVsDynamicPairs, Allocator.TempJob);

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle dynamicVsDynamicHandle = new DynamicVsDynamicFindOverlappingPairsJob
            {
                DynamicTree     = m_DynamicTree,
                PairWriter      = dynamicVsDynamicPairsStream.AsWriter(),
                NodePairIndices = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(dynamicVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(dynamicVsDynamicPairs, dynamicConstruct));

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle staticVsDynamicHandle = new StaticVsDynamicFindOverlappingPairsJob
            {
                StaticTree      = m_StaticTree,
                DynamicTree     = m_DynamicTree,
                PairWriter      = staticVsDynamicPairsStream.AsWriter(),
                NodePairIndices = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(staticVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(staticVsDynamicPairs, staticConstruct));

            // Dispose node pair lists
            var disposeOverlapPairs0 = NativeListUtilityTemp.DisposeHotFix(ref dynamicVsDynamicNodePairIndices, dynamicVsDynamicHandle);
            var disposeOverlapPairs1 = NativeListUtilityTemp.DisposeHotFix(ref staticVsDynamicNodePairIndices, staticVsDynamicHandle);

            returnHandles.FinalDisposeHandle   = JobHandle.CombineDependencies(disposeOverlapPairs0, disposeOverlapPairs1);
            returnHandles.FinalExecutionHandle = JobHandle.CombineDependencies(dynamicVsDynamicHandle, staticVsDynamicHandle);

            return(returnHandles);
        }
Пример #9
0
        // Schedule a set of jobs which will write all overlapping body pairs to the given steam,
        // where at least one of the bodies is dynamic. The results are unsorted.
        internal JobHandle ScheduleFindOverlapsJobs(out NativeStream dynamicVsDynamicPairsStream, out NativeStream staticVsDynamicPairsStream, ref Simulation.Context context, JobHandle inputDeps)
        {
            var dynamicVsDynamicNodePairIndices = new NativeList <int2>(Allocator.TempJob);
            var staticVsDynamicNodePairIndices  = new NativeList <int2>(Allocator.TempJob);

            JobHandle allocateDeps = new AllocateDynamicVsStaticNodePairs
            {
                dynamicVsDynamicNodePairIndices = dynamicVsDynamicNodePairIndices,
                staticVsDynamicNodePairIndices  = staticVsDynamicNodePairIndices,
                dynamicBranchCount = m_DynamicTree.m_BranchCount,
                staticBranchCount  = m_StaticTree.m_BranchCount
            }.Schedule(inputDeps);

            // Build pairs of branch node indices
            JobHandle dynamicVsDynamicPairs = new DynamicVsDynamicBuildBranchNodePairsJob
            {
                Ranges          = m_DynamicTree.Ranges,
                NumBranches     = m_DynamicTree.m_BranchCount,
                NodePairIndices = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            JobHandle staticVsDynamicPairs = new StaticVsDynamicBuildBranchNodePairsJob
            {
                DynamicRanges      = m_DynamicTree.Ranges,
                StaticRanges       = m_StaticTree.Ranges,
                NumStaticBranches  = m_StaticTree.m_BranchCount,
                NumDynamicBranches = m_DynamicTree.m_BranchCount,
                NodePairIndices    = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(allocateDeps);

            //@TODO: We only need a dependency on allocateDeps, but the safety system doesn't understand that we can not change length list in DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            //       if this is a performance issue we can use [NativeDisableContainerSafetyRestriction] on DynamicVsDynamicBuildBranchNodePairsJob & StaticVsDynamicBuildBranchNodePairsJob
            JobHandle dynamicConstruct = NativeStream.ScheduleConstruct(out dynamicVsDynamicPairsStream, dynamicVsDynamicNodePairIndices, dynamicVsDynamicPairs, Allocator.TempJob);
            JobHandle staticConstruct  = NativeStream.ScheduleConstruct(out staticVsDynamicPairsStream, staticVsDynamicNodePairIndices, staticVsDynamicPairs, Allocator.TempJob);

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle dynamicVsDynamicHandle = new DynamicVsDynamicFindOverlappingPairsJob
            {
                DynamicNodes       = m_DynamicTree.Nodes,
                BodyFilters        = m_BodyFilters,
                DynamicNodeFilters = m_DynamicTree.NodeFilters,
                PairWriter         = dynamicVsDynamicPairsStream.AsWriter(),
                NodePairIndices    = dynamicVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(dynamicVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(dynamicVsDynamicPairs, dynamicConstruct));

            // Write all overlaps to the stream (also deallocates nodePairIndices)
            JobHandle staticVsDynamicHandle = new StaticVsDynamicFindOverlappingPairsJob
            {
                StaticNodes        = m_StaticTree.Nodes,
                DynamicNodes       = m_DynamicTree.Nodes,
                BodyFilters        = m_BodyFilters,
                StaticNodeFilters  = m_StaticTree.NodeFilters,
                DynamicNodeFilters = m_DynamicTree.NodeFilters,
                PairWriter         = staticVsDynamicPairsStream.AsWriter(),
                NodePairIndices    = staticVsDynamicNodePairIndices.AsDeferredJobArray()
            }.Schedule(staticVsDynamicNodePairIndices, 1, JobHandle.CombineDependencies(staticVsDynamicPairs, staticConstruct));

            // Dispose node pair lists
            context.DisposeOverlapPairs0 = NativeListUtilityTemp.DisposeHotFix(ref dynamicVsDynamicNodePairIndices, dynamicVsDynamicHandle);
            context.DisposeOverlapPairs1 = NativeListUtilityTemp.DisposeHotFix(ref staticVsDynamicNodePairIndices, staticVsDynamicHandle);

            return(JobHandle.CombineDependencies(dynamicVsDynamicHandle, staticVsDynamicHandle));
        }