Sin descripción
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IJobParallelForBatch.cs 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. using System;
  2. using Unity.Jobs.LowLevel.Unsafe;
  3. using Unity.Collections.LowLevel.Unsafe;
  4. using Unity.Collections;
  5. using System.Diagnostics;
  6. using Unity.Burst;
  7. namespace Unity.Jobs
  8. {
  9. /// <summary>
  10. /// Job type allowing for data to be operated on in parallel batches.
  11. /// </summary>
  12. /// <remarks>
  13. /// When scheduling an IJobParallelForBatch job the number of elements to work on is specified along with a batch size. Jobs will then run in parallel
  14. /// invoking Execute at a particular 'startIndex' of your working set and for a specified 'count' number of elements.
  15. /// </remarks>
  16. [JobProducerType(typeof(IJobParallelForBatchExtensions.JobParallelForBatchProducer<>))]
  17. public interface IJobParallelForBatch
  18. {
  19. /// <summary>
  20. /// Function operation on a "batch" of data contained within the job.
  21. /// </summary>
  22. /// <param name="startIndex">Starting index of job data to safely access.</param>
  23. /// <param name="count">Number of elements to operate on in the batch.</param>
  24. void Execute(int startIndex, int count);
  25. }
  26. /// <summary>
  27. /// Extension class for the IJobParallelForBatch job type providing custom overloads for scheduling and running.
  28. /// </summary>
  29. public static class IJobParallelForBatchExtensions
  30. {
  31. internal struct JobParallelForBatchProducer<T> where T : struct, IJobParallelForBatch
  32. {
  33. internal static readonly SharedStatic<IntPtr> jobReflectionData = SharedStatic<IntPtr>.GetOrCreate<JobParallelForBatchProducer<T>>();
  34. [BurstDiscard]
  35. internal static void Initialize()
  36. {
  37. if (jobReflectionData.Data == IntPtr.Zero)
  38. jobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(T), (ExecuteJobFunction)Execute);
  39. }
  40. internal delegate void ExecuteJobFunction(ref T jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex);
  41. public unsafe static void Execute(ref T jobData, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex)
  42. {
  43. while (true)
  44. {
  45. if (!JobsUtility.GetWorkStealingRange(
  46. ref ranges,
  47. jobIndex, out int begin, out int end))
  48. return;
  49. #if ENABLE_UNITY_COLLECTIONS_CHECKS
  50. JobsUtility.PatchBufferMinMaxRanges(bufferRangePatchData, UnsafeUtility.AddressOf(ref jobData), begin, end - begin);
  51. #endif
  52. jobData.Execute(begin, end - begin);
  53. }
  54. }
  55. }
  56. /// <summary>
  57. /// 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.
  58. /// </summary>
  59. /// <typeparam name="T"></typeparam>
  60. /// <remarks>
  61. /// When the Jobs 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.
  62. ///
  63. /// __Note__: While the Jobs package code generator handles this automatically for all closed job types, you must register those with generic arguments (like IJobParallelForBatch&amp;lt;MyJobType&amp;lt;T&amp;gt;&amp;gt;) manually for each specialization with [[Unity.Jobs.RegisterGenericJobTypeAttribute]].
  64. /// </remarks>
  65. public static void EarlyJobInit<T>()
  66. where T : struct, IJobParallelForBatch
  67. {
  68. JobParallelForBatchProducer<T>.Initialize();
  69. }
  70. static IntPtr GetReflectionData<T>()
  71. where T : struct, IJobParallelForBatch
  72. {
  73. JobParallelForBatchProducer<T>.Initialize();
  74. var reflectionData = JobParallelForBatchProducer<T>.jobReflectionData.Data;
  75. CollectionHelper.CheckReflectionDataCorrect<T>(reflectionData);
  76. return reflectionData;
  77. }
  78. /// <summary>
  79. /// Schedules a job that will execute the parallel batch job for all `arrayLength` elements in batches of `indicesPerJobCount`.
  80. /// The Execute() method for Job T will be provided the start index and number of elements to safely operate on.
  81. /// In cases where `indicesPerJobCount` is not a multiple of `arrayLength`, the `count` provided to the Execute method of Job T will be smaller than the `indicesPerJobCount` specified here.
  82. /// </summary>
  83. /// <param name="jobData">The job and data to schedule.</param>
  84. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  85. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch.</param>
  86. /// <param name="dependsOn">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.</param>
  87. /// <returns>JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.</returns>
  88. /// <typeparam name="T">Job type</typeparam>
  89. public static unsafe JobHandle Schedule<T>(this T jobData, int arrayLength, int indicesPerJobCount,
  90. JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch
  91. {
  92. var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), GetReflectionData<T>(), dependsOn, ScheduleMode.Single);
  93. return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, indicesPerJobCount);
  94. }
  95. /// <summary>
  96. /// Schedules a job that will execute the parallel batch job for all `arrayLength` elements in batches of `indicesPerJobCount`.
  97. /// The Execute() method for Job T will be provided the start index and number of elements to safely operate on.
  98. /// In cases where `indicesPerJobCount` is not a multiple of `arrayLength`, the `count` provided to the Execute method of Job T will be smaller than the `indicesPerJobCount` specified here.
  99. /// </summary>
  100. /// <param name="jobData">The job and data to schedule. In this variant, the jobData is
  101. /// passed by reference, which may be necessary for unusually large job structs.</param>
  102. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  103. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch.</param>
  104. /// <param name="dependsOn">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.</param>
  105. /// <returns>JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.</returns>
  106. /// <typeparam name="T">Job type</typeparam>
  107. public static unsafe JobHandle ScheduleByRef<T>(this ref T jobData, int arrayLength, int indicesPerJobCount,
  108. JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch
  109. {
  110. var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), GetReflectionData<T>(), dependsOn, ScheduleMode.Single);
  111. return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, indicesPerJobCount);
  112. }
  113. /// <summary>
  114. /// Schedules a job that will execute the parallel batch job for all `arrayLength` elements in batches of `indicesPerJobCount`.
  115. /// The Execute() method for Job T will be provided the start index and number of elements to safely operate on.
  116. /// In cases where `indicesPerJobCount` is not a multiple of `arrayLength`, the `count` provided to the Execute method of Job T will be smaller than the `indicesPerJobCount` specified here.
  117. /// </summary>
  118. /// <param name="jobData">The job and data to schedule.</param>
  119. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  120. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch.</param>
  121. /// <param name="dependsOn">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.</param>
  122. /// <returns>JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.</returns>
  123. /// <typeparam name="T">Job type</typeparam>
  124. public static unsafe JobHandle ScheduleParallel<T>(this T jobData, int arrayLength, int indicesPerJobCount,
  125. JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch
  126. {
  127. var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), GetReflectionData<T>(), dependsOn, ScheduleMode.Parallel);
  128. return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, indicesPerJobCount);
  129. }
  130. /// <summary>
  131. /// Schedules a job that will execute the parallel batch job for all `arrayLength` elements in batches of `indicesPerJobCount`.
  132. /// The Execute() method for Job T will be provided the start index and number of elements to safely operate on.
  133. /// In cases where `indicesPerJobCount` is not a multiple of `arrayLength`, the `count` provided to the Execute method of Job T will be smaller than the `indicesPerJobCount` specified here.
  134. /// </summary>
  135. /// <param name="jobData">The job and data to schedule. In this variant, the jobData is
  136. /// passed by reference, which may be necessary for unusually large job structs.</param>
  137. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  138. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch.</param>
  139. /// <param name="dependsOn">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.</param>
  140. /// <returns>JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.</returns>
  141. /// <typeparam name="T">Job type</typeparam>
  142. public static unsafe JobHandle ScheduleParallelByRef<T>(this ref T jobData, int arrayLength, int indicesPerJobCount,
  143. JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch
  144. {
  145. var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), GetReflectionData<T>(), dependsOn, ScheduleMode.Parallel);
  146. return JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, indicesPerJobCount);
  147. }
  148. /// <summary>
  149. /// Schedules a job that will execute the parallel batch job for all `arrayLength` elements in batches of `indicesPerJobCount`.
  150. /// The Execute() method for Job T will be provided the start index and number of elements to safely operate on.
  151. /// In cases where `indicesPerJobCount` is not a multiple of `arrayLength`, the `count` provided to the Execute method of Job T will be smaller than the `indicesPerJobCount` specified here.
  152. /// </summary>
  153. /// <param name="jobData">The job and data to schedule.</param>
  154. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  155. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch.</param>
  156. /// <param name="dependsOn">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.</param>
  157. /// <returns>JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.</returns>
  158. /// <typeparam name="T">Job type</typeparam>
  159. public static unsafe JobHandle ScheduleBatch<T>(this T jobData, int arrayLength, int indicesPerJobCount,
  160. JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch
  161. {
  162. return ScheduleParallel(jobData, arrayLength, indicesPerJobCount, dependsOn);
  163. }
  164. /// <summary>
  165. /// Schedules a job that will execute the parallel batch job for all `arrayLength` elements in batches of `indicesPerJobCount`.
  166. /// The Execute() method for Job T will be provided the start index and number of elements to safely operate on.
  167. /// In cases where `indicesPerJobCount` is not a multiple of `arrayLength`, the `count` provided to the Execute method of Job T will be smaller than the `indicesPerJobCount` specified here.
  168. /// </summary>
  169. /// <param name="jobData">The job and data to schedule. In this variant, the jobData is
  170. /// passed by reference, which may be necessary for unusually large job structs.</param>
  171. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  172. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch.</param>
  173. /// <param name="dependsOn">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.</param>
  174. /// <returns>JobHandle The handle identifying the scheduled job. Can be used as a dependency for a later job or ensure completion on the main thread.</returns>
  175. /// <typeparam name="T">Job type</typeparam>
  176. public static unsafe JobHandle ScheduleBatchByRef<T>(this ref T jobData, int arrayLength, int indicesPerJobCount,
  177. JobHandle dependsOn = new JobHandle()) where T : struct, IJobParallelForBatch
  178. {
  179. return ScheduleParallelByRef(ref jobData, arrayLength, indicesPerJobCount, dependsOn);
  180. }
  181. /// <summary>
  182. /// Executes the parallel batch job but on the main thread. See IJobParallelForBatchExtensions.Schedule for more information on how appending is performed.
  183. /// </summary>
  184. /// <param name="jobData">The job and data to schedule.</param>
  185. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  186. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch. This argument is ignored when using .Run()</param>
  187. /// <typeparam name="T">Job type</typeparam>
  188. /// <remarks>
  189. /// Unlike Schedule, since the job is running on the main thread no parallelization occurs and thus no `indicesPerJobCount` batch size is required to be specified.
  190. /// </remarks>
  191. public static unsafe void Run<T>(this T jobData, int arrayLength, int indicesPerJobCount) where T : struct, IJobParallelForBatch
  192. {
  193. var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), GetReflectionData<T>(), new JobHandle(), ScheduleMode.Run);
  194. JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, arrayLength);
  195. }
  196. /// <summary>
  197. /// Executes the parallel batch job but on the main thread. See IJobParallelForBatchExtensions.Schedule for more information on how appending is performed.
  198. /// </summary>
  199. /// <param name="jobData">The job and data to schedule. In this variant, the jobData is
  200. /// passed by reference, which may be necessary for unusually large job structs.</param>
  201. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  202. /// <param name="indicesPerJobCount">Number of elements to consider in a single parallel batch. This argument is ignored when using .RunByRef()</param>
  203. /// <typeparam name="T">Job type</typeparam>
  204. public static unsafe void RunByRef<T>(this ref T jobData, int arrayLength, int indicesPerJobCount) where T : struct, IJobParallelForBatch
  205. {
  206. var scheduleParams = new JobsUtility.JobScheduleParameters(UnsafeUtility.AddressOf(ref jobData), GetReflectionData<T>(), new JobHandle(), ScheduleMode.Run);
  207. JobsUtility.ScheduleParallelFor(ref scheduleParams, arrayLength, arrayLength);
  208. }
  209. /// <summary>
  210. /// Executes the parallel batch job but on the main thread. See IJobParallelForBatchExtensions.ScheduleBatch for more information on how appending is performed.
  211. /// </summary>
  212. /// <param name="jobData">The job and data to schedule.</param>
  213. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  214. /// <typeparam name="T">Job type</typeparam>
  215. /// <remarks>
  216. /// Unlike ScheduleBatch, since the job is running on the main thread no parallelization occurs and thus no `indicesPerJobCount` batch size is required to be specified.
  217. /// </remarks>
  218. public static unsafe void RunBatch<T>(this T jobData, int arrayLength) where T : struct, IJobParallelForBatch
  219. {
  220. Run(jobData, arrayLength, arrayLength);
  221. }
  222. /// <summary>
  223. /// Executes the parallel batch job but on the main thread. See IJobParallelForBatchExtensions.ScheduleBatch for more information on how appending is performed.
  224. /// </summary>
  225. /// <param name="jobData">The job and data to schedule. In this variant, the jobData is
  226. /// passed by reference, which may be necessary for unusually large job structs.</param>
  227. /// <param name="arrayLength">Total number of elements to consider when batching.</param>
  228. /// <typeparam name="T">Job type</typeparam>
  229. public static unsafe void RunBatchByRef<T>(this ref T jobData, int arrayLength) where T : struct, IJobParallelForBatch
  230. {
  231. RunByRef(ref jobData, arrayLength, arrayLength);
  232. }
  233. }
  234. }