using System;
using Unity.Jobs.LowLevel.Unsafe;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using System.Diagnostics;
using Unity.Burst;
using Unity.Mathematics;
namespace Unity.Jobs
{
///
/// **Obsolete.** Use instead.
///
[Obsolete("'JobParallelIndexListExtensions' has been deprecated; Use 'IJobFilterExtensions' instead.", false)]
public static class JobParallelIndexListExtensions
{
///
/// **Obsolete.**
///
///
///
///
///
///
///
///
[Obsolete("The signature for 'ScheduleAppend' has changed. 'innerloopBatchCount' is no longer part of this API.", false)]
public static unsafe JobHandle ScheduleAppend(this T jobData, NativeList indices, int arrayLength, int innerloopBatchCount, JobHandle dependsOn = new JobHandle()) where T : struct, IJobFilter
=> jobData.ScheduleAppend(indices, arrayLength, dependsOn);
///
/// **Obsolete.**
///
///
///
///
///
///
///
[Obsolete("The signature for 'ScheduleFilter' has changed. 'innerloopBatchCount' is no longer part of this API.")]
public static unsafe JobHandle ScheduleFilter(this T jobData, NativeList indices, int innerloopBatchCount, JobHandle dependsOn = new JobHandle()) where T : struct, IJobFilter
=> jobData.ScheduleFilter(indices, dependsOn);
}
///
/// **Obsolete.** Use instead.
///
[Obsolete("'IJobParallelForFilter' has been deprecated; use 'IJobFilter' instead. (UnityUpgradable) -> IJobFilter")]
public interface IJobParallelForFilter
{
///
///
///
///
///
bool Execute(int index);
}
///
/// Filters a list of indices.
///
///
/// IJobFilter allows for custom jobs to implement a bool Execute(int index) job function used to filter a list of indices.
/// For a provided list and index range, the list will be modified to append all indices for which Execute returns true or to exclude all indices for which Execute returns false
/// depending on if ScheduleAppend or Schedule is used, respectfully, for enqueuing the job with the job system.
///
[JobProducerType(typeof(IJobFilterExtensions.JobFilterProducer<>))]
public interface IJobFilter
{
///
/// Filter function. A list of indices is provided when scheduling this job type. The
/// Execute function will be called once for each index returning true or false if the job data at
/// the passed in index should be filtered or not.
///
/// Index to use when reading job data for the purpose of filtering
/// Returns true for data at index
bool Execute(int index);
}
///
/// Extension class for the IJobFilter job type providing custom overloads for scheduling and running.
///
public static class IJobFilterExtensions
{
internal struct JobFilterProducer where T : struct, IJobFilter
{
public struct JobWrapper
{
[NativeDisableParallelForRestriction]
public NativeList outputIndices;
public int appendCount;
public T JobData;
}
internal static readonly SharedStatic jobReflectionData = SharedStatic.GetOrCreate>();
[BurstDiscard]
internal static void Initialize()
{
if (jobReflectionData.Data == IntPtr.Zero)
jobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(JobWrapper), typeof(T), (ExecuteJobFunction)Execute);
}
public delegate void ExecuteJobFunction(ref JobWrapper jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex);
///
/// Job Producer method invoked by the Job System when running an IJobFilter Job.
///
/// IJobFilter wrapper type
/// unused
/// Buffer data JobRanges
/// unused
/// unused
public static void Execute(ref JobWrapper jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex)
{
if (jobWrapper.appendCount == -1)
ExecuteFilter(ref jobWrapper, bufferRangePatchData);
else
ExecuteAppend(ref jobWrapper, bufferRangePatchData);
}
public static unsafe void ExecuteAppend(ref JobWrapper jobWrapper, System.IntPtr bufferRangePatchData)
{
int oldLength = jobWrapper.outputIndices.Length;
jobWrapper.outputIndices.Capacity = math.max(jobWrapper.appendCount + oldLength, jobWrapper.outputIndices.Capacity);
int* outputPtr = (int*)jobWrapper.outputIndices.GetUnsafePtr();
int outputIndex = oldLength;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobWrapper),
0, jobWrapper.appendCount);
#endif
for (int i = 0; i != jobWrapper.appendCount; i++)
{
if (jobWrapper.JobData.Execute(i))
{
outputPtr[outputIndex] = i;
outputIndex++;
}
}
jobWrapper.outputIndices.ResizeUninitialized(outputIndex);
}
public static unsafe void ExecuteFilter(ref JobWrapper jobWrapper, System.IntPtr bufferRangePatchData)
{
int* outputPtr = (int*)jobWrapper.outputIndices.GetUnsafePtr();
int inputLength = jobWrapper.outputIndices.Length;
int outputCount = 0;
for (int i = 0; i != inputLength; i++)
{
int inputIndex = outputPtr[i];
#if ENABLE_UNITY_COLLECTIONS_CHECKS
JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobWrapper), inputIndex, 1);
#endif
if (jobWrapper.JobData.Execute(inputIndex))
{
outputPtr[outputCount] = inputIndex;
outputCount++;
}
}
jobWrapper.outputIndices.ResizeUninitialized(outputCount);
}
}
///
/// Gathers and caches reflection data for the internal job system's managed bindings. Unity is responsible for calling this method - don't call it yourself.
///
/// Job type
///
/// When the Collections package is included in the project, Unity generates code to call EarlyJobInit at startup. This allows Burst compiled code to schedule jobs because the reflection part of initialization, which is not compatible with burst compiler constraints, has already happened in EarlyJobInit.
///
/// __Note__: While the Jobs package code generator handles this automatically for all closed job types, you must register those with generic arguments (like IJobFilter<MyJobType<T>>) manually for each specialization with [[Unity.Jobs.RegisterGenericJobTypeAttribute]].
///
public static void EarlyJobInit()
where T : struct, IJobFilter
{
JobFilterProducer.Initialize();
}
static IntPtr GetReflectionData()
where T : struct, IJobFilter
{
JobFilterProducer.Initialize();
var reflectionData = JobFilterProducer.jobReflectionData.Data;
CollectionHelper.CheckReflectionDataCorrect(reflectionData);
return reflectionData;
}
///
/// Schedules a job that will execute the filter job for all integers in indices from index 0 until arrayLength. Each integer which passes the filter (i.e. true is returned from Execute()) will be appended to the indices list.
///
/// The job and data to schedule.
/// List of indices to be filtered. Filtered results will be appended to this list.
/// Number of indices to filter starting from index 0.
/// Dependencies are used to ensure that a job executes on workerthreads after the dependency has completed execution. Making sure that two jobs reading or writing to same data do not run in parallel.
/// JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.
/// Job type
public static unsafe JobHandle ScheduleAppend(this T jobData, NativeList indices, int arrayLength, JobHandle dependsOn = new JobHandle())
where T : struct, IJobFilter
{
return jobData.ScheduleAppendByRef(indices, arrayLength, dependsOn);
}
///
/// Schedules a job that will execute the filter job for all integers in indices from index 0 until arrayLength. Each integer which passes the filter (i.e. true is returned from Execute()) will be used to repopulate the indices list.
/// This has the effect of excluding all integer values that do not pass the filter.
///
/// The job and data to schedule.
/// List of indices to be filtered. Filtered results will be stored in this list.
/// Dependencies are used to ensure that a job executes on workerthreads after the dependency has completed execution. Making sure that two jobs reading or writing to same data do not run in parallel.
/// JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.
/// Job type
public static unsafe JobHandle ScheduleFilter(this T jobData, NativeList indices, JobHandle dependsOn = new JobHandle())
where T : struct, IJobFilter
{
return jobData.ScheduleFilterByRef(indices, dependsOn);
}
///
/// Executes the appending filter job, on the main thread. See IJobFilterExtensions.ScheduleAppend for more information on how appending is performed.
///
/// The job and data to schedule.
/// List of indices to be filtered and appended to.
/// Length of array the filter job will append to.
/// Job type
public static unsafe void RunAppend(this T jobData, NativeList indices, int arrayLength)
where T : struct, IJobFilter
{
jobData.RunAppendByRef(indices, arrayLength);
}
///
/// Executes the filter job, on the main thread. See IJobFilterExtensions.Schedule for more information on how appending is performed.
///
/// The job and data to schedule.
/// List of indices to be filtered. Filtered results will be stored in this list.
/// Job type
public static unsafe void RunFilter(this T jobData, NativeList indices)
where T : struct, IJobFilter
{
jobData.RunFilterByRef(indices);
}
///
/// Schedules a job that will execute the filter job for all integers in indices from index 0 until arrayLength. Each integer which passes the filter (i.e. true is returned from Execute()) will be appended to the indices list.
///
/// The job and data to schedule. In this variant, the jobData is
/// passed by reference, which may be necessary for unusually large job structs.
/// List of indices to be filtered. Filtered results will be appended to this list.
/// Number of indices to filter starting from index 0.
/// Dependencies are used to ensure that a job executes on workerthreads after the dependency has completed execution. Making sure that two jobs reading or writing to same data do not run in parallel.
/// JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.
/// Job type
public static unsafe JobHandle ScheduleAppendByRef(ref this T jobData, NativeList indices, int arrayLength, JobHandle dependsOn = new JobHandle())
where T : struct, IJobFilter
{
JobFilterProducer.JobWrapper jobWrapper = new JobFilterProducer.JobWrapper()
{
JobData = jobData,
outputIndices = indices,
appendCount = arrayLength
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData(), dependsOn, ScheduleMode.Single);
return JobsUtility.Schedule(ref scheduleParams);
}
///
/// Schedules a job that will execute the filter job for all integers in indices from index 0 until arrayLength. Each integer which passes the filter (i.e. true is returned from Execute()) will be used to repopulate the indices list.
/// This has the effect of excluding all integer values that do not pass the filter.
///
/// The job and data to schedule. In this variant, the jobData is
/// passed by reference, which may be necessary for unusually large job structs.
/// List of indices to be filtered. Filtered results will be stored in this list.
/// Dependencies are used to ensure that a job executes on workerthreads after the dependency has completed execution. Making sure that two jobs reading or writing to same data do not run in parallel.
/// JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.
/// Job type
public static unsafe JobHandle ScheduleFilterByRef(ref this T jobData, NativeList indices, JobHandle dependsOn = new JobHandle())
where T : struct, IJobFilter
{
JobFilterProducer.JobWrapper jobWrapper = new JobFilterProducer.JobWrapper()
{
JobData = jobData,
outputIndices = indices,
appendCount = -1
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData(), dependsOn, ScheduleMode.Single);
return JobsUtility.Schedule(ref scheduleParams);
}
///
/// Executes the appending filter job, on the main thread. See IJobFilterExtensions.ScheduleAppend for more information on how appending is performed.
///
/// The job and data to schedule.
/// List of indices to be filtered. Filtered results will be appended to this list.
/// Number of indices to filter starting from index 0.
/// Job type
public static unsafe void RunAppendByRef(ref this T jobData, NativeList indices, int arrayLength)
where T : struct, IJobFilter
{
JobFilterProducer.JobWrapper jobWrapper = new JobFilterProducer.JobWrapper()
{
JobData = jobData,
outputIndices = indices,
appendCount = arrayLength
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData(), new JobHandle(), ScheduleMode.Run);
JobsUtility.Schedule(ref scheduleParams);
}
///
/// Executes the filter job, on the main thread. See IJobFilterExtensions.Schedule for more information on how appending is performed.
///
/// The job and data to schedule. In this variant, the jobData is
/// passed by reference, which may be necessary for unusually large job structs.
/// List of indices to be filtered. Filtered results will be stored in this list.
/// Job type
public static unsafe void RunFilterByRef(ref this T jobData, NativeList indices)
where T : struct, IJobFilter
{
JobFilterProducer.JobWrapper jobWrapper = new JobFilterProducer.JobWrapper()
{
JobData = jobData,
outputIndices = indices,
appendCount = -1
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData(), new JobHandle(), ScheduleMode.Run);
JobsUtility.Schedule(ref scheduleParams);
}
}
}