Example #1
0
        public void AddComponentWithValidation(UnsafeMatchingArchetypePtrList archetypeList, EntityQueryFilter filter,
                                               ComponentType componentType, ComponentDependencyManager *dependencyManager)
        {
            AssertCanAddComponent(archetypeList, componentType);

            var chunks = ChunkIterationUtility.CreateArchetypeChunkArray(archetypeList, Collections.Allocator.TempJob, ref filter, dependencyManager);

            if (chunks.Length > 0)
            {
                //@TODO the fast path for a chunk that contains a single entity is only possible if the chunk doesn't have a Locked Entity Order
                //but we should still be allowed to add zero sized components to chunks with a Locked Entity Order, even ones that only contain a single entity

                /*
                 * if ((chunks.Length == 1) && (chunks[0].Count == 1))
                 * {
                 *  var entityPtr = (Entity*) chunks[0].m_Chunk->Buffer;
                 *  StructuralChange.AddComponentEntity(EntityComponentStore, entityPtr, componentType.TypeIndex);
                 * }
                 * else
                 * {
                 */
                AddComponent((ArchetypeChunk *)NativeArrayUnsafeUtility.GetUnsafePtr(chunks), chunks.Length, componentType);

                /*
                 * }
                 */
            }

            chunks.Dispose();
        }
Example #2
0
        public void RemoveComponentWithValidation(UnsafeMatchingArchetypePtrList archetypeList, EntityQueryFilter filter,
                                                  ComponentType componentType, ComponentDependencyManager *dependencyManager)
        {
            var chunks = ChunkIterationUtility.CreateArchetypeChunkArray(archetypeList, Collections.Allocator.TempJob, ref filter, dependencyManager);

            RemoveComponentWithValidation(chunks, componentType);
            chunks.Dispose();
        }
Example #3
0
            internal unsafe static void ExecuteInternal(
                ref JobEntityBatchIndexWrapper <T> jobWrapper,
                IntPtr bufferRangePatchData,
                ref JobRanges ranges,
                int jobIndex)
            {
                ChunkIterationUtility.UnpackPrefilterData(jobWrapper.PrefilterData, out var filteredChunks, out var entityIndices, out var batchCount);

                bool isParallel = jobWrapper.IsParallel == 1;

                while (true)
                {
                    int beginBatchIndex = 0;
                    int endBatchIndex   = batchCount;

                    // 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 batch = filteredChunks[batchIndex];
                        Assert.IsTrue(batch.Count > 0); // Empty batches are expected to be skipped by the prefilter job!
                        var entityOffset = entityIndices[batchIndex];

#if ENABLE_UNITY_COLLECTIONS_CHECKS
                        if (isParallel)
                        {
                            JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobWrapper), entityOffset, batch.Count);
                        }
#endif
                        jobWrapper.JobData.Execute(batch, batchIndex, entityOffset);
                    }

                    // If we are not running in parallel, our job is done.
                    if (!isParallel)
                    {
                        break;
                    }
                }
            }
            internal unsafe static void ExecuteInternal(
                ref JobEntityBatchIndexWrapper <T> jobWrapper,
                ref JobRanges ranges,
                int jobIndex)
            {
                ChunkIterationUtility.UnpackPrefilterData(jobWrapper.PrefilterData, out var filteredChunks, out var entityIndices, out var batchCount);

                bool isParallel = jobWrapper.IsParallel == 1;

                while (true)
                {
                    int beginBatchIndex = 0;
                    int endBatchIndex   = batchCount;

                    // 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(filteredChunks[batchIndex], batchIndex, entityIndices[batchIndex]);
                    }

                    // If we are not running in parallel, our job is done.
                    if (!isParallel)
                    {
                        break;
                    }
                }
            }
        public static unsafe void RunWithoutJobsInternal <T>(ref T jobData, ref EntityQuery query, Entity *limitToEntityArray, int limitToEntityArrayLength)
            where T : struct, IJobEntityBatch
        {
            var prebuiltBatchList = new UnsafeList(Allocator.TempJob);

            try
            {
                ChunkIterationUtility.FindFilteredBatchesForEntityArrayWithQuery(
                    query._GetImpl(),
                    limitToEntityArray, limitToEntityArrayLength,
                    ref prebuiltBatchList);

                ArchetypeChunk *chunks      = (ArchetypeChunk *)prebuiltBatchList.Ptr;
                int             chunkCounts = prebuiltBatchList.Length;
                for (int i = 0; i != chunkCounts; i++)
                {
                    jobData.Execute(chunks[i], i);
                }
            }
            finally
            {
                prebuiltBatchList.Dispose();
            }
        }
 public void Execute()
 {
     *OutChunkCount = ChunkIterationUtility.CalculateChunkCount(MatchingArchetypes, ref Filter);
 }
Example #7
0
 /// <summary>
 /// Calculates the total number of chunks this iterator can access.
 /// </summary>
 /// <returns>Number of chunks that can be accessed.</returns>
 internal int CalculateChunkCount()
 {
     return(ChunkIterationUtility.CalculateChunkCount(m_MatchingArchetypeList, ref m_Filter));
 }
Example #8
0
        internal void *GetCurrentChunkComponentDataPtr(bool isWriting, int indexInEntityQuery)
        {
            int indexInArchetype = CurrentMatchingArchetype->IndexInArchetype[indexInEntityQuery];

            return(ChunkIterationUtility.GetChunkComponentDataPtr(CurrentChunk, isWriting, indexInArchetype, m_GlobalSystemVersion));
        }
        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);
        }
Example #10
0
        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, IJobEntityBatchWithIndex
        {
            var queryImpl = query._GetImpl();
            var queryData = queryImpl->_QueryData;

            var batchCount                     = 0;
            var filteredChunkCount             = 0;
            var useEntityArray                 = limitToEntityArray.IsCreated;
            var prebuiltBatchList              = new UnsafeList(Allocator.TempJob);
            var perBatchMatchingArchetypeIndex = new UnsafeIntList(0, Allocator.TempJob);

            if (useEntityArray)
            {
                // 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;
            }
            else
            {
                filteredChunkCount = query.CalculateChunkCount();
                batchCount         = filteredChunkCount * batchesPerChunk;
            }

            // Allocate one buffer for all prefilter data and distribute it
            // We keep the full buffer as a "dummy array" so we can deallocate it later with [DeallocateOnJobCompletion]
            var sizeofBatchArray  = sizeof(ArchetypeChunk) * batchCount;
            var sizeofIndexArray  = sizeof(int) * batchCount;
            var prefilterDataSize = sizeofBatchArray + sizeofIndexArray + sizeof(int);

            var prefilterData      = (byte *)Memory.Unmanaged.Allocate(prefilterDataSize, 64, Allocator.TempJob);
            var prefilterDataArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray <byte>(prefilterData, prefilterDataSize, Allocator.TempJob);

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref prefilterDataArray, AtomicSafetyHandle.Create());
#endif

            var prefilterHandle = dependsOn;
            if (useEntityArray)
            {
                var prefilterJob = new PrefilterForJobEntityBatchWithIndex_EntityArray
                {
                    MatchingArchetypes             = queryImpl->_QueryData->MatchingArchetypes,
                    Filter                         = queryImpl->_Filter,
                    EntityComponentStore           = queryImpl->_Access->EntityComponentStore,
                    PrefilterData                  = prefilterData,
                    PrebuiltBatches                = prebuiltBatchList,
                    PerBatchMatchingArchetypeIndex = perBatchMatchingArchetypeIndex
                };

                if (mode != ScheduleMode.Run)
                {
                    prefilterHandle = prefilterJob.Schedule(dependsOn);
                }
                else
                {
                    prefilterJob.Run();
                }

                prefilterHandle = prebuiltBatchList.Dispose(prefilterHandle);
                prefilterHandle = perBatchMatchingArchetypeIndex.Dispose(prefilterHandle);
            }
            else
            {
                var prefilterJob = new PrefilterForJobEntityBatchWithIndex
                {
                    MatchingArchetypes   = queryImpl->_QueryData->MatchingArchetypes,
                    Filter               = queryImpl->_Filter,
                    BatchesPerChunk      = batchesPerChunk,
                    EntityComponentStore = queryImpl->_Access->EntityComponentStore,
                    PrefilterData        = prefilterData,
                    FilteredChunkCount   = filteredChunkCount
                };

                if (mode != ScheduleMode.Run)
                {
                    prefilterHandle = prefilterJob.Schedule(dependsOn);
                }
                else
                {
                    prefilterJob.Run();
                }
            }


            JobEntityBatchIndexWrapper <T> jobEntityBatchIndexWrapper = new JobEntityBatchIndexWrapper <T>
            {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
                // All IJobEntityBatchWithIndex 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,
                PrefilterData = prefilterDataArray,

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

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

#if UNITY_DOTSRUNTIME
            // This should just be a call to FinalizeScheduleChecked, but DOTSR requires the JobsUtility calls to be
            // in this specific function.
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            try
            {
#endif
            if (!isParallel)
            {
                return(JobsUtility.Schedule(ref scheduleParams));
            }
            else
            {
                return(JobsUtility.ScheduleParallelFor(ref scheduleParams, batchCount, 1));
            }
#if ENABLE_UNITY_COLLECTIONS_CHECKS
        }

        catch (InvalidOperationException e)
        {
            prefilterHandle.Complete();
            prefilterDataArray.Dispose();
            throw e;
        }
#endif
#else
            // We can't use try {} catch {} with 2020.2 as we will be burst compiling the schedule code.
            // Burst doesn't support exception handling.
            bool executedManaged = false;
            JobHandle result     = default;
            FinalizeScheduleChecked(isParallel, batchCount, prefilterHandle, prefilterDataArray, ref scheduleParams, ref executedManaged, ref result);

            if (executedManaged)
            {
                return(result);
            }

            return(FinalizeScheduleNoExceptions(isParallel, batchCount, ref scheduleParams));
#endif
        }