示例#1
0
 public static void Execute(
     ref JobEntityBatchWrapper <T> jobWrapper,
     IntPtr additionalPtr,
     IntPtr bufferRangePatchData,
     ref JobRanges ranges,
     int jobIndex)
 {
     ExecuteInternal(ref jobWrapper, ref ranges, jobIndex);
 }
        internal static unsafe JobHandle ScheduleInternal <T>(
            ref T jobData,
            EntityQuery query,
            JobHandle dependsOn,
            ScheduleMode mode,
            int batchesPerChunk,
            bool isParallel = true)
            where T : struct, IJobEntityBatch
        {
            var queryImpl = query._GetImpl();
            var queryData = queryImpl->_QueryData;

            var cachedChunks = queryData->GetMatchingChunkCache();

            // Don't schedule the job if there are no chunks to work on
            var chunkCount = cachedChunks.Length;

            JobEntityBatchWrapper <T> jobEntityBatchWrapper = new JobEntityBatchWrapper <T>
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                // All IJobEntityBatch jobs have a EntityManager safety handle to ensure that BeforeStructuralChange throws an error if
                // jobs without any other safety handles are still running (haven't been synced).
                safety = new EntitySafetyHandle {
                    m_Safety = queryImpl->SafetyHandles->GetEntityManagerSafetyHandle()
                },
#endif

                MatchingArchetypes = queryData->MatchingArchetypes,
                CachedChunks       = cachedChunks,
                Filter             = queryImpl->_Filter,

                JobData      = jobData,
                JobsPerChunk = batchesPerChunk,
                IsParallel   = isParallel ? 1 : 0
            };

            var scheduleParams = new JobsUtility.JobScheduleParameters(
                UnsafeUtility.AddressOf(ref jobEntityBatchWrapper),
                isParallel
                ? JobEntityBatchProducer <T> .InitializeParallel()
                : JobEntityBatchProducer <T> .InitializeSingle(),
                dependsOn,
                mode);

            if (!isParallel)
            {
                return(JobsUtility.Schedule(ref scheduleParams));
            }
            else
            {
                return(JobsUtility.ScheduleParallelFor(ref scheduleParams, chunkCount * batchesPerChunk, 1));
            }
        }
            internal unsafe static void ExecuteInternal(
                ref JobEntityBatchWrapper <T> jobWrapper,
                ref JobRanges ranges,
                int jobIndex)
            {
                var chunks = jobWrapper.CachedChunks;

                bool isParallel  = jobWrapper.IsParallel == 1;
                bool isFiltering = jobWrapper.Filter.RequiresMatchesFilter;

                while (true)
                {
                    int beginBatchIndex = 0;
                    int endBatchIndex   = chunks.Length;

                    // If we are running the job in parallel, steal some work.
                    if (isParallel)
                    {
                        // If we have no range to steal, exit the loop.
                        if (!JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out beginBatchIndex, out endBatchIndex))
                        {
                            break;
                        }
                    }

                    // Do the actual user work.
                    for (int batchIndex = beginBatchIndex; batchIndex < endBatchIndex; ++batchIndex)
                    {
                        var chunkIndex        = batchIndex / jobWrapper.JobsPerChunk;
                        var batchIndexInChunk = batchIndex % jobWrapper.JobsPerChunk;
                        var chunk             = chunks.Ptr[chunkIndex];

                        if (isFiltering && chunk->MatchesFilter(jobWrapper.MatchingArchetypes.Ptr[chunks.PerChunkMatchingArchetypeIndex.Ptr[chunkIndex]], ref jobWrapper.Filter))
                        {
                            continue;
                        }

                        jobWrapper.JobData.Execute(ArchetypeChunk.EntityBatchFromChunk(chunk, jobWrapper.JobsPerChunk, batchIndexInChunk, chunks.EntityComponentStore), batchIndex);
                    }

                    // If we are not running in parallel, our job is done.
                    if (!isParallel)
                    {
                        break;
                    }
                }
            }
示例#4
0
            internal unsafe static void ExecuteInternal(
                ref JobEntityBatchWrapper <T> jobWrapper,
                ref JobRanges ranges,
                int jobIndex)
            {
                var batches = jobWrapper.Batches;

                bool isParallel = jobWrapper.IsParallel == 1;

                while (true)
                {
                    int beginBatchIndex = 0;
                    int endBatchIndex   = batches.Length;

                    // If we are running the job in parallel, steal some work.
                    if (isParallel)
                    {
                        // If we have no range to steal, exit the loop.
                        if (!JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out beginBatchIndex, out endBatchIndex))
                        {
                            break;
                        }
                    }

                    // Do the actual user work.
                    for (int batchIndex = beginBatchIndex; batchIndex < endBatchIndex; ++batchIndex)
                    {
                        jobWrapper.JobData.Execute(batches[batchIndex], batchIndex);
                    }

                    // If we are not running in parallel, our job is done.
                    if (!isParallel)
                    {
                        break;
                    }
                }
            }
示例#5
0
        internal static unsafe JobHandle ScheduleInternal <T>(
            ref T jobData,
            EntityQuery query,
            JobHandle dependsOn,
            ScheduleMode mode,
            int batchesPerChunk,
            bool isParallel = true)
            where T : struct, IJobEntityBatch
        {
            var queryImpl          = query._GetImpl();
            var filteredChunkCount = queryImpl->CalculateChunkCount();
            var batches            = new NativeArray <ArchetypeChunk>(filteredChunkCount * batchesPerChunk, Allocator.TempJob);

            var prefilterHandle = new PrefilterForJobEntityBatch
            {
                MatchingArchetypes   = queryImpl->_QueryData->MatchingArchetypes,
                Filter               = queryImpl->_Filter,
                BatchesPerChunk      = batchesPerChunk,
                EntityComponentStore = queryImpl->_Access->EntityComponentStore,
                Batches              = batches
            }.Schedule(dependsOn);

            JobEntityBatchWrapper <T> jobEntityBatchWrapper = new JobEntityBatchWrapper <T>
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                // All IJobEntityBatch jobs have a EntityManager safety handle to ensure that BeforeStructuralChange throws an error if
                // jobs without any other safety handles are still running (haven't been synced).
                safety = new EntitySafetyHandle {
                    m_Safety = queryImpl->SafetyHandles->GetEntityManagerSafetyHandle()
                },
#endif

                JobData = jobData,
                Batches = batches,

                JobsPerChunk = batchesPerChunk,
                IsParallel   = isParallel ? 1 : 0
            };

            var scheduleParams = new JobsUtility.JobScheduleParameters(
                UnsafeUtility.AddressOf(ref jobEntityBatchWrapper),
                isParallel
                ? JobEntityBatchProducer <T> .InitializeParallel()
                : JobEntityBatchProducer <T> .InitializeSingle(),
                prefilterHandle,
                mode);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            try
            {
#endif
            if (!isParallel)
            {
                return(JobsUtility.Schedule(ref scheduleParams));
            }
            else
            {
                return(JobsUtility.ScheduleParallelFor(ref scheduleParams, filteredChunkCount * batchesPerChunk, 1));
            }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        }

        catch (InvalidOperationException e)
        {
            prefilterHandle.Complete();
            batches.Dispose();
            throw e;
        }
#endif
        }
            internal unsafe static void ExecuteInternal(
                ref JobEntityBatchWrapper <T> jobWrapper,
                IntPtr bufferRangePatchData,
                ref JobRanges ranges,
                int jobIndex)
            {
                var chunks          = jobWrapper.CachedChunks;
                var prebuiltBatches = (ArchetypeChunk *)jobWrapper.PrebuiltBatchList.Ptr;

                bool isParallel  = jobWrapper.IsParallel == 1;
                bool isFiltering = jobWrapper.Filter.RequiresMatchesFilter;

                while (true)
                {
                    int beginBatchIndex = 0;
                    int endBatchIndex   = jobWrapper.UsePrebuiltBatchList == 1 ? jobWrapper.PrebuiltBatchList.Length : chunks.Length;

                    // If we are running the job in parallel, steal some work.
                    if (isParallel)
                    {
                        // If we have no range to steal, exit the loop.
                        if (!JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out beginBatchIndex, out endBatchIndex))
                        {
                            break;
                        }

                        JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobWrapper), 0, 0);
                    }

                    // Do the actual user work.
                    if (jobWrapper.UsePrebuiltBatchList == 1)
                    {
                        for (int batchIndex = beginBatchIndex; batchIndex < endBatchIndex; ++batchIndex)
                        {
                            var batch = prebuiltBatches[batchIndex];

                            if (isFiltering && !batch.m_Chunk->MatchesFilter(jobWrapper.MatchingArchetypes.Ptr[jobWrapper.PrebuiltBatchListMatchingArchetypeIndices.Ptr[batchIndex]], ref jobWrapper.Filter))
                            {
                                continue;
                            }

                            Assert.AreNotEqual(0, batch.Count);
                            jobWrapper.JobData.Execute(batch, batchIndex);
                        }
                    }
                    else
                    {
                        if (jobWrapper.JobsPerChunk == 1)
                        {
                            // 1 batch per chunk, with/without filtering
                            for (int batchIndex = beginBatchIndex; batchIndex < endBatchIndex; ++batchIndex)
                            {
                                var chunkIndex = batchIndex;
                                var chunk      = chunks.Ptr[chunkIndex];

                                if (isFiltering && !chunk->MatchesFilter(jobWrapper.MatchingArchetypes.Ptr[chunks.PerChunkMatchingArchetypeIndex.Ptr[chunkIndex]], ref jobWrapper.Filter))
                                {
                                    continue;
                                }

                                var batch = new ArchetypeChunk(chunk, chunks.EntityComponentStore);
                                Assert.AreNotEqual(0, batch.Count);
                                jobWrapper.JobData.Execute(batch, batchIndex);
                            }
                        }
                        else
                        {
                            // 2+ batches per chunk, with/without filtering
                            // This is the most general case; if only one code path survives, it should be this one.
                            for (int batchIndex = beginBatchIndex; batchIndex < endBatchIndex; ++batchIndex)
                            {
                                var chunkIndex        = batchIndex / jobWrapper.JobsPerChunk;
                                var batchIndexInChunk = batchIndex % jobWrapper.JobsPerChunk;
                                var chunk             = chunks.Ptr[chunkIndex];

                                if (isFiltering && !chunk->MatchesFilter(
                                        jobWrapper.MatchingArchetypes.Ptr[
                                            chunks.PerChunkMatchingArchetypeIndex.Ptr[chunkIndex]],
                                        ref jobWrapper.Filter))
                                {
                                    continue;
                                }

                                if (ArchetypeChunk.EntityBatchFromChunk(chunk, chunk->Count, jobWrapper.JobsPerChunk,
                                                                        batchIndexInChunk, chunks.EntityComponentStore, out var batch))
                                {
                                    jobWrapper.JobData.Execute(batch, batchIndex);
                                }
                            }
                        }
                    }

                    // If we are not running in parallel, our job is done.
                    if (!isParallel)
                    {
                        break;
                    }
                }
            }
        internal static unsafe JobHandle ScheduleInternal <T>(
            ref T jobData,
            EntityQuery query,
            JobHandle dependsOn,
            ScheduleMode mode,
            int batchesPerChunk,
            bool isParallel = true,
            NativeArray <Entity> limitToEntityArray = default(NativeArray <Entity>))
            where T : struct, IJobEntityBatch
        {
            var queryImpl = query._GetImpl();
            var queryData = queryImpl->_QueryData;

            var cachedChunks = queryData->GetMatchingChunkCache();

            // Don't schedule the job if there are no chunks to work on
            var chunkCount = cachedChunks.Length;

            var useEntityArray    = limitToEntityArray.IsCreated;
            var prebuiltBatchList = default(UnsafeList);
            var perBatchMatchingArchetypeIndex = default(UnsafeIntList);

            var batchCount = chunkCount * batchesPerChunk;

            if (useEntityArray)
            {
                prebuiltBatchList = new UnsafeList(Allocator.TempJob);
                perBatchMatchingArchetypeIndex = new UnsafeIntList(0, Allocator.TempJob);

                // Forces the creation of an EntityQueryMask, which is necessary to filter batches.
                var access = queryImpl->_Access;
                access->EntityQueryManager->GetEntityQueryMask(queryData, access->EntityComponentStore);

                ChunkIterationUtility.FindBatchesForEntityArrayWithQuery(
                    queryImpl->_Access->EntityComponentStore,
                    queryData,
                    ref queryImpl->_Filter,
                    (Entity *)limitToEntityArray.GetUnsafePtr(),
                    limitToEntityArray.Length,
                    ref prebuiltBatchList,
                    ref perBatchMatchingArchetypeIndex);

                batchCount = prebuiltBatchList.Length;
            }

            JobEntityBatchWrapper <T> jobEntityBatchWrapper = new JobEntityBatchWrapper <T>
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                // All IJobEntityBatch jobs have a EntityManager safety handle to ensure that BeforeStructuralChange throws an error if
                // jobs without any other safety handles are still running (haven't been synced).
                safety = new EntitySafetyHandle {
                    m_Safety = queryImpl->SafetyHandles->GetEntityManagerSafetyHandle()
                },
#endif

                MatchingArchetypes = queryData->MatchingArchetypes,
                CachedChunks       = cachedChunks,
                Filter             = queryImpl->_Filter,

                JobData      = jobData,
                JobsPerChunk = batchesPerChunk,
                IsParallel   = isParallel ? 1 : 0,

                UsePrebuiltBatchList = useEntityArray ? 1: 0,
                PrebuiltBatchList    = prebuiltBatchList,
                PrebuiltBatchListMatchingArchetypeIndices = perBatchMatchingArchetypeIndex
            };

            var scheduleParams = new JobsUtility.JobScheduleParameters(
                UnsafeUtility.AddressOf(ref jobEntityBatchWrapper),
                isParallel
                    ? JobEntityBatchProducer <T> .InitializeParallel()
                    : JobEntityBatchProducer <T> .InitializeSingle(),
                dependsOn,
                mode);

            var result = default(JobHandle);

            if (!isParallel)
            {
                result = JobsUtility.Schedule(ref scheduleParams);
            }
            else
            {
                result = JobsUtility.ScheduleParallelFor(ref scheduleParams, batchCount, 1);
            }

            if (useEntityArray)
            {
                result = prebuiltBatchList.Dispose(result);
                result = perBatchMatchingArchetypeIndex.Dispose(result);
            }

            return(result);
        }