Beispiel #1
0
        public JobHandle GetDependency(int *readerTypes, int readerTypesCount, int *writerTypes, int writerTypesCount)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (readerTypesCount * kMaxReadJobHandles + writerTypesCount > m_JobDependencyCombineBufferCount)
            {
                throw new ArgumentException("Too many readers & writers in GetDependency");
            }
#endif

            var count = 0;
            for (var i = 0; i != readerTypesCount; i++)
            {
                m_JobDependencyCombineBuffer[count++] = m_ComponentSafetyHandles[readerTypes[i] & TypeManager.ClearFlagsMask].WriteFence;
            }

            for (var i = 0; i != writerTypesCount; i++)
            {
                var writerType = writerTypes[i] & TypeManager.ClearFlagsMask;

                m_JobDependencyCombineBuffer[count++] = m_ComponentSafetyHandles[writerType].WriteFence;

                var numReadFences = m_ComponentSafetyHandles[writerType].NumReadFences;
                for (var j = 0; j != numReadFences; j++)
                {
                    m_JobDependencyCombineBuffer[count++] = m_ReadJobFences[writerType * kMaxReadJobHandles + j];
                }
            }

            return(JobHandleUnsafeUtility.CombineDependencies(m_JobDependencyCombineBuffer,
                                                              count));
        }
Beispiel #2
0
        public static unsafe JobHandle CombineDependencies(JobHandle a, JobHandle b, JobHandle c, JobHandle d)
        {
            var array = stackalloc JobHandle[4] {
                a, b, c, d
            };

            return(JobHandleUnsafeUtility.CombineDependencies(array, 4));
        }
        JobHandle CombineReadDependencies(ushort typeArrayIndex)
        {
            var combined = JobHandleUnsafeUtility.CombineDependencies(
                m_ReadJobFences + typeArrayIndex * kMaxReadJobHandles, m_DependencyHandles[typeArrayIndex].NumReadFences);

            m_ReadJobFences[typeArrayIndex * kMaxReadJobHandles] = combined;
            m_DependencyHandles[typeArrayIndex].NumReadFences    = 1;

            return(combined);
        }
Beispiel #4
0
        private JobHandle CombineReadDependencies(int typeWithoutFlags)
        {
            var combined = JobHandleUnsafeUtility.CombineDependencies(
                m_ReadJobFences + typeWithoutFlags * kMaxReadJobHandles, m_ComponentSafetyHandles[typeWithoutFlags].NumReadFences);

            m_ReadJobFences[typeWithoutFlags * kMaxReadJobHandles]   = combined;
            m_ComponentSafetyHandles[typeWithoutFlags].NumReadFences = 1;

            return(combined);
        }
        public JobHandle AddDependency(int *readerTypes, int readerTypesCount, int *writerTypes, int writerTypesCount,
                                       JobHandle dependency)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            JobHandle *combinedDependencies      = null;
            var        combinedDependenciesCount = 0;
#endif

            for (var i = 0; i != writerTypesCount; i++)
            {
                var writer = writerTypes[i];
                m_ComponentSafetyHandles[writer].WriteFence = dependency;
            }


            for (var i = 0; i != readerTypesCount; i++)
            {
                var reader = readerTypes[i];
                m_ReadJobFences[reader * kMaxReadJobHandles + m_ComponentSafetyHandles[reader].NumReadFences] =
                    dependency;
                m_ComponentSafetyHandles[reader].NumReadFences++;

                if (m_ComponentSafetyHandles[reader].NumReadFences == kMaxReadJobHandles)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    var combined = CombineReadDependencies(reader);
                    if (combinedDependencies == null)
                    {
                        JobHandle *temp = stackalloc JobHandle[readerTypesCount];
                        combinedDependencies = temp;
                    }

                    combinedDependencies[combinedDependenciesCount++] = combined;
#else
                    CombineReadDependencies(reader);
                    #endif
                }
            }

            if (readerTypesCount != 0 || writerTypesCount != 0)
            {
                m_HasCleanHandles = false;
            }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (combinedDependencies != null)
            {
                return(JobHandleUnsafeUtility.CombineDependencies(combinedDependencies, combinedDependenciesCount));
            }
            return(dependency);
#else
            return(dependency);
#endif
        }
        public JobHandle AddDependency(int *readerTypes, int readerTypesCount, int *writerTypes, int writerTypesCount,
                                       JobHandle dependency)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            JobHandle *combinedDependencies      = null;
            var        combinedDependenciesCount = 0;
#endif
            if (readerTypesCount == 0 && writerTypesCount == 0)
            {
                ushort entityTypeArrayIndex = GetTypeArrayIndex(EntityTypeIndex);
                // if no dependency types are provided add read dependency to the Entity type
                // to ensure these jobs are still synced by CompleteAllJobsAndInvalidateArrays
                m_ReadJobFences[entityTypeArrayIndex * kMaxReadJobHandles +
                                m_DependencyHandles[entityTypeArrayIndex].NumReadFences] = dependency;
                m_DependencyHandles[entityTypeArrayIndex].NumReadFences++;

                if (m_DependencyHandles[entityTypeArrayIndex].NumReadFences == kMaxReadJobHandles)
                {
                    //@TODO: Check dynamically if the job debugger is enabled?
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    return(CombineReadDependencies(entityTypeArrayIndex));
#else
                    CombineReadDependencies(entityTypeArrayIndex);
#endif
                }
                return(dependency);
            }

            for (var i = 0; i != writerTypesCount; i++)
            {
                m_DependencyHandles[GetTypeArrayIndex(writerTypes[i])].WriteFence = dependency;
            }


            for (var i = 0; i != readerTypesCount; i++)
            {
                var reader = GetTypeArrayIndex(readerTypes[i]);
                m_ReadJobFences[reader * kMaxReadJobHandles + m_DependencyHandles[reader].NumReadFences] =
                    dependency;
                m_DependencyHandles[reader].NumReadFences++;

                if (m_DependencyHandles[reader].NumReadFences == kMaxReadJobHandles)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    var combined = CombineReadDependencies(reader);
                    if (combinedDependencies == null)
                    {
                        JobHandle *temp = stackalloc JobHandle[readerTypesCount];
                        combinedDependencies = temp;
                    }

                    combinedDependencies[combinedDependenciesCount++] = combined;
#else
                    CombineReadDependencies(reader);
#endif
                }
            }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (combinedDependencies != null)
            {
                return(JobHandleUnsafeUtility.CombineDependencies(combinedDependencies, combinedDependenciesCount));
            }
            return(dependency);
#else
            return(dependency);
#endif
        }
Beispiel #7
0
        public JobHandle AddDependency(int *readerTypes, int readerTypesCount, int *writerTypes, int writerTypesCount,
                                       JobHandle dependency)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            JobHandle *combinedDependencies      = null;
            var        combinedDependenciesCount = 0;
#endif
            m_HasCleanHandles = false;

            if (readerTypesCount == 0 && writerTypesCount == 0)
            {
                // if no dependency types are provided add read dependency to the Entity type
                // to ensure these jobs are still synced by CompleteAllJobsAndInvalidateArrays
                m_ReadJobFences[EntityTypeIndex * kMaxReadJobHandles +
                                m_ComponentSafetyHandles[EntityTypeIndex].NumReadFences] = dependency;
                m_ComponentSafetyHandles[EntityTypeIndex].NumReadFences++;

                if (m_ComponentSafetyHandles[EntityTypeIndex].NumReadFences == kMaxReadJobHandles)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    return(CombineReadDependencies(EntityTypeIndex));
#else
                    CombineReadDependencies(EntityTypeIndex);
#endif
                }
                return(dependency);
            }

            for (var i = 0; i != writerTypesCount; i++)
            {
                var writer = writerTypes[i] & TypeManager.ClearFlagsMask;
                m_ComponentSafetyHandles[writer].WriteFence = dependency;
            }


            for (var i = 0; i != readerTypesCount; i++)
            {
                var reader = readerTypes[i] & TypeManager.ClearFlagsMask;
                m_ReadJobFences[reader * kMaxReadJobHandles + m_ComponentSafetyHandles[reader].NumReadFences] =
                    dependency;
                m_ComponentSafetyHandles[reader].NumReadFences++;

                if (m_ComponentSafetyHandles[reader].NumReadFences == kMaxReadJobHandles)
                {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                    var combined = CombineReadDependencies(reader);
                    if (combinedDependencies == null)
                    {
                        JobHandle *temp = stackalloc JobHandle[readerTypesCount];
                        combinedDependencies = temp;
                    }

                    combinedDependencies[combinedDependenciesCount++] = combined;
#else
                    CombineReadDependencies(reader);
#endif
                }
            }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            if (combinedDependencies != null)
            {
                return(JobHandleUnsafeUtility.CombineDependencies(combinedDependencies, combinedDependenciesCount));
            }
            return(dependency);
#else
            return(dependency);
#endif
        }
Beispiel #8
0
        // 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);
        }
Beispiel #9
0
        // Schedule all the jobs for the simulation step.
        // Enqueued callbacks can choose to inject additional jobs at defined sync points.
        // threadCountHint defines which simulation type will be called:
        //     - threadCountHint > 0 will result in default multithreaded simulation
        //     - threadCountHint <=0 will result in a very small number of jobs (1 per physics step phase) that are scheduled sequentially
        // Behavior doesn't change regardless of the threadCountHint provided.
        public unsafe SimulationJobHandles ScheduleStepJobs(SimulationStepInput input, SimulationCallbacks callbacksIn, JobHandle inputDeps, int threadCountHint = 0)
        {
            if (input.TimeStep < 0)
            {
                throw new ArgumentOutOfRangeException();
            }
            if (input.NumSolverIterations <= 0)
            {
                throw new ArgumentOutOfRangeException();
            }

            bool singleThreadedSim = (threadCountHint <= 0);

            // Dispose and reallocate input velocity buffer, if dynamic body count has increased.
            // Dispose previous collision and trigger event data streams.
            // New event streams are reallocated later when the work item count is known.
            JobHandle handle = SimulationContext.ScheduleReset(ref input.World, inputDeps, false);

            SimulationContext.TimeStep = input.TimeStep;

            StepContext = new StepContext();

            if (input.World.NumDynamicBodies == 0)
            {
                // No need to do anything, since nothing can move
                m_StepHandles = new SimulationJobHandles(handle);
                return(m_StepHandles);
            }

            SimulationCallbacks callbacks = callbacksIn ?? new SimulationCallbacks();

            // Find all body pairs that overlap in the broadphase
            var handles = input.World.CollisionWorld.ScheduleFindOverlapsJobs(
                out NativeStream dynamicVsDynamicBodyPairs, out NativeStream dynamicVsStaticBodyPairs, handle, threadCountHint);

            handle = handles.FinalExecutionHandle;
            var disposeHandle1     = handles.FinalDisposeHandle;
            var postOverlapsHandle = handle;

            // Sort all overlapping and jointed body pairs into phases
            handles = m_Scheduler.ScheduleCreatePhasedDispatchPairsJob(
                ref input.World, ref dynamicVsDynamicBodyPairs, ref dynamicVsStaticBodyPairs, handle,
                ref StepContext.PhasedDispatchPairs, out StepContext.SolverSchedulerInfo, threadCountHint);
            handle = handles.FinalExecutionHandle;
            var disposeHandle2 = handles.FinalDisposeHandle;

            // 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, SimulationContext.InputVelocities, input.TimeStep * input.Gravity, singleThreadedSim ? handle : postOverlapsHandle, threadCountHint);

            handle = JobHandle.CombineDependencies(handle, applyGravityAndCopyInputVelocitiesHandle);
            handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateDispatchPairs, this, ref input.World, handle);

            // Create contact points & joint Jacobians
            handles = NarrowPhase.ScheduleCreateContactsJobs(ref input.World, input.TimeStep,
                                                             ref StepContext.Contacts, ref StepContext.Jacobians, ref StepContext.PhasedDispatchPairs, handle,
                                                             ref StepContext.SolverSchedulerInfo, threadCountHint);
            handle = handles.FinalExecutionHandle;
            var disposeHandle3 = handles.FinalDisposeHandle;

            handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateContacts, this, ref input.World, handle);

            // Create contact Jacobians
            handles = Solver.ScheduleBuildJacobiansJobs(ref input.World, input.TimeStep, input.Gravity, input.NumSolverIterations,
                                                        handle, ref StepContext.PhasedDispatchPairs, ref StepContext.SolverSchedulerInfo,
                                                        ref StepContext.Contacts, ref StepContext.Jacobians, threadCountHint);
            handle = handles.FinalExecutionHandle;
            var disposeHandle4 = handles.FinalDisposeHandle;

            handle = callbacks.Execute(SimulationCallbacks.Phase.PostCreateContactJacobians, this, ref input.World, handle);

            // Solve all Jacobians
            handles = Solver.ScheduleSolveJacobiansJobs(ref input.World.DynamicsWorld, input.TimeStep, input.NumSolverIterations,
                                                        ref StepContext.Jacobians, ref SimulationContext.CollisionEventDataStream, ref SimulationContext.TriggerEventDataStream,
                                                        ref StepContext.SolverSchedulerInfo, handle, threadCountHint);
            handle = handles.FinalExecutionHandle;
            var disposeHandle5 = handles.FinalDisposeHandle;

            handle = callbacks.Execute(SimulationCallbacks.Phase.PostSolveJacobians, this, ref input.World, handle);

            // Integrate motions
            handle = Integrator.ScheduleIntegrateJobs(ref input.World.DynamicsWorld, input.TimeStep, handle, threadCountHint);

            // Synchronize the collision world
            if (input.SynchronizeCollisionWorld)
            {
                handle = input.World.CollisionWorld.ScheduleUpdateDynamicTree(ref input.World, input.TimeStep, input.Gravity, handle, threadCountHint);  // TODO: timeStep = 0?
            }

            // Return the final simulation handle
            m_StepHandles.FinalExecutionHandle = handle;

            // Different dispose logic for single threaded simulation compared to "standard" threading (multi threaded)
            if (singleThreadedSim)
            {
                handle = dynamicVsDynamicBodyPairs.Dispose(handle);
                handle = dynamicVsStaticBodyPairs.Dispose(handle);
                handle = StepContext.PhasedDispatchPairs.Dispose(handle);
                handle = StepContext.Contacts.Dispose(handle);
                handle = StepContext.Jacobians.Dispose(handle);
                handle = StepContext.SolverSchedulerInfo.ScheduleDisposeJob(handle);

                m_StepHandles.FinalDisposeHandle = handle;
            }
            else
            {
                // Return the final handle, which includes disposing temporary arrays
                JobHandle *deps = stackalloc JobHandle[5]
                {
                    disposeHandle1,
                    disposeHandle2,
                    disposeHandle3,
                    disposeHandle4,
                    disposeHandle5
                };
                m_StepHandles.FinalDisposeHandle = JobHandleUnsafeUtility.CombineDependencies(deps, 5);
            }

            return(m_StepHandles);
        }