public static class IJobParallelForAppendExtensions
{
internal struct ParallelForAppendProducer<TJob, TValue> where TValue : unmanaged where TJob : struct, IJobParallelForAppend<TValue>
{
public unsafe struct JobWrapper
{
[NativeDisableUnsafePtrRestriction]
public UnsafeList<TValue>* AppendBuffer;
public TJob JobData;
}
internal static readonly SharedStatic<IntPtr> jobReflectionData = SharedStatic<IntPtr>.GetOrCreate<ParallelForAppendProducer<TJob, TValue>>();
[BurstDiscard]
public static unsafe void Initialize()
{
if (jobReflectionData.Data == IntPtr.Zero)
jobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(JobWrapper), typeof(TJob), (ExecuteJobFunction)Execute);
}
public delegate void ExecuteJobFunction(ref JobWrapper jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex);
public static unsafe void Execute(ref JobWrapper jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex)
{
TValue buf = default;
while (true)
{
int begin;
int end;
if (!JobsUtility.GetWorkStealingRange(ref ranges, jobIndex, out begin, out end))
break;
JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobWrapper), begin, end - begin);
var endThatCompilerCanSeeWillNeverChange = end;
for (var i = begin; i < endThatCompilerCanSeeWillNeverChange; ++i)
{
if (jobWrapper.JobData.Execute(i, ref buf))
{
int idx = Interlocked.Increment(ref jobWrapper.AppendBuffer->m_length) - 1;
jobWrapper.AppendBuffer->Ptr[idx] = buf;
}
}
}
}
}
public static void EarlyJobInit<TJob>() where TJob : struct
{
foreach (Type iType in typeof(TJob).GetInterfaces())
{
if (iType.IsGenericType && iType.GetGenericTypeDefinition() == typeof(IJobParallelForAppend<>))
{
Type[] genericArgs = iType.GetGenericArguments();
Type[] typeArgs = new Type[1 + genericArgs.Length];
typeArgs[0] = typeof(TJob);
Array.Copy(genericArgs, 0, typeArgs, 1, genericArgs.Length);
Type producerType = typeof(ParallelForAppendProducer<,>).MakeGenericType(typeArgs);
producerType.GetMethod("Initialize").Invoke(null, null);
break;
}
}
}
private static IntPtr GetReflectionData<TJob, TValue>() where TValue : unmanaged where TJob : struct, IJobParallelForAppend<TValue>
{
ParallelForAppendProducer<TJob, TValue>.Initialize();
var reflectionData = ParallelForAppendProducer<TJob, TValue>.jobReflectionData.Data;
// JobValidationInternal.CheckReflectionDataCorrect<T>(reflectionData);
return reflectionData;
}
public static unsafe JobHandle Schedule<TJob, TValue>(this TJob jobData, NativeList<TValue> buffer, int arrayLength, int innerloopBatchCount, JobHandle dependsOn = new JobHandle()) where TValue : unmanaged where TJob : struct, IJobParallelForAppend<TValue>
{
if (buffer.Capacity < buffer.Length + arrayLength)
{
buffer.SetCapacity(buffer.Length + arrayLength);
}
var jobWrapper = new ParallelForAppendProducer<TJob, TValue>.JobWrapper
{
AppendBuffer = buffer.GetUnsafeList(),
JobData = jobData
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData<TJob, TValue>(), dependsOn, ScheduleMode.Parallel);
return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, innerloopBatchCount);
}
public static unsafe void Run<TJob, TValue>(this TJob jobData, NativeList<TValue> buffer, int arrayLength) where TValue : unmanaged where TJob : struct, IJobParallelForAppend<TValue>
{
if (buffer.Capacity < buffer.Length + arrayLength)
{
buffer.SetCapacity(buffer.Length + arrayLength);
}
var jobWrapper = new ParallelForAppendProducer<TJob, TValue>.JobWrapper
{
AppendBuffer = buffer.GetUnsafeList(),
JobData = jobData
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData<TJob, TValue>(), new JobHandle(), ScheduleMode.Run);
JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, arrayLength);
}
public static unsafe JobHandle ScheduleByRef<TJob, TValue>(ref this TJob jobData, NativeList<TValue> buffer, int arrayLength, int innerloopBatchCount, JobHandle dependsOn = new JobHandle()) where TValue : unmanaged where TJob : struct, IJobParallelForAppend<TValue>
{
if (buffer.Capacity < buffer.Length + arrayLength)
{
buffer.SetCapacity(buffer.Length + arrayLength);
}
var jobWrapper = new ParallelForAppendProducer<TJob, TValue>.JobWrapper
{
AppendBuffer = buffer.GetUnsafeList(),
JobData = jobData
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData<TJob, TValue>(), dependsOn, ScheduleMode.Parallel);
return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, innerloopBatchCount);
}
public static unsafe void RunByRef<TJob, TValue>(ref this TJob jobData, NativeList<TValue> buffer, int arrayLength) where TValue : unmanaged where TJob : struct, IJobParallelForAppend<TValue>
{
if (buffer.Capacity < buffer.Length + arrayLength)
{
buffer.SetCapacity(buffer.Length + arrayLength);
}
var jobWrapper = new ParallelForAppendProducer<TJob, TValue>.JobWrapper
{
AppendBuffer = buffer.GetUnsafeList(),
JobData = jobData
};
var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobWrapper), GetReflectionData<TJob, TValue>(), new JobHandle(), ScheduleMode.Run);
JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, arrayLength);
}
}