656 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			656 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|  | using System; | ||
|  | using NUnit.Framework; | ||
|  | using UnityEngine.Scripting; | ||
|  | using Unity.Collections; | ||
|  | using Unity.Collections.LowLevel.Unsafe; | ||
|  | using Unity.Jobs; | ||
|  | using Unity.Jobs.LowLevel.Unsafe; | ||
|  | using Unity.Burst; | ||
|  | using System.Diagnostics; | ||
|  | using Unity.Collections.Tests; | ||
|  | 
 | ||
|  | [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.MyGenericJobDefer<int>))] | ||
|  | [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.MyGenericJobDefer<double>))] | ||
|  | [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.MyGenericJobDefer<float>))] | ||
|  | [assembly: RegisterGenericJobType(typeof(Unity.Jobs.Tests.ManagedJobs.GenericContainerJobDefer<NativeList<int>, int>))] | ||
|  | 
 | ||
|  | namespace Unity.Jobs.Tests.ManagedJobs | ||
|  | { | ||
|  |     internal enum JobRunType | ||
|  |     { | ||
|  |         Schedule, | ||
|  |         ScheduleByRef, | ||
|  |         Run, | ||
|  |         RunByRef, | ||
|  |     } | ||
|  | 
 | ||
|  | 	[JobProducerType(typeof(IJobTestExtensions.JobTestProducer<>))] | ||
|  |     internal interface IJobTest | ||
|  | 	{ | ||
|  | 		void Execute(); | ||
|  | 	} | ||
|  | 
 | ||
|  |     internal interface IJobTestInherit : IJob | ||
|  |     { | ||
|  |     } | ||
|  | 
 | ||
|  |     internal static class IJobTestExtensions | ||
|  | 	{ | ||
|  |         internal struct JobTestWrapper<T> where T : struct | ||
|  |         { | ||
|  |             internal T JobData; | ||
|  | 
 | ||
|  |             [NativeDisableContainerSafetyRestriction] | ||
|  |             internal NativeArray<byte> ProducerResourceToClean; | ||
|  |         } | ||
|  | 
 | ||
|  | 		internal struct JobTestProducer<T> where T : struct, IJobTest | ||
|  | 		{ | ||
|  | 			internal static readonly SharedStatic<IntPtr> s_JobReflectionData = SharedStatic<IntPtr>.GetOrCreate<JobTestProducer<T>>(); | ||
|  | 
 | ||
|  |             [BurstDiscard] | ||
|  |             internal static void Initialize() | ||
|  | 			{ | ||
|  | 				if (s_JobReflectionData.Data == IntPtr.Zero) | ||
|  | 					s_JobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(JobTestWrapper<T>), typeof(T), (ExecuteJobFunction)Execute); | ||
|  | 			} | ||
|  | 
 | ||
|  | 			public delegate void ExecuteJobFunction(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex); | ||
|  | 			public unsafe static void Execute(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) | ||
|  | 			{ | ||
|  | 				jobWrapper.JobData.Execute(); | ||
|  | 			} | ||
|  | 		} | ||
|  | 
 | ||
|  |         public static void EarlyJobInit<T>() | ||
|  |             where T : struct, IJobTest | ||
|  |         { | ||
|  |             JobTestProducer<T>.Initialize(); | ||
|  |         } | ||
|  | 
 | ||
|  |         static IntPtr GetReflectionData<T>() | ||
|  |             where T : struct, IJobTest | ||
|  |         { | ||
|  |             JobTestProducer<T>.Initialize(); | ||
|  |             var reflectionData = JobTestProducer<T>.s_JobReflectionData.Data; | ||
|  |             CollectionHelper.CheckReflectionDataCorrect<T>(reflectionData); | ||
|  |             return reflectionData; | ||
|  |         } | ||
|  | 
 | ||
|  |         public static unsafe JobHandle ScheduleTest<T>(this T jobData, NativeArray<byte> dataForProducer, JobHandle dependsOn = new JobHandle()) where T : struct, IJobTest | ||
|  | 		{ | ||
|  | 			JobTestWrapper<T> jobTestWrapper = new JobTestWrapper<T> | ||
|  | 			{ | ||
|  | 				JobData = jobData, | ||
|  | 				ProducerResourceToClean = dataForProducer | ||
|  | 			}; | ||
|  | 
 | ||
|  | 			var scheduleParams = new JobsUtility.JobScheduleParameters( | ||
|  | 				UnsafeUtility.AddressOf(ref jobTestWrapper), | ||
|  | 				GetReflectionData<T>(), | ||
|  | 				dependsOn, | ||
|  | 				ScheduleMode.Parallel | ||
|  | 			); | ||
|  | 
 | ||
|  | 			return JobsUtility.Schedule(ref scheduleParams); | ||
|  | 		} | ||
|  |     } | ||
|  | 
 | ||
|  |     [JobProducerType(typeof(IJobTestInheritProducerExtensions.JobTestProducer<>))] | ||
|  |     internal interface IJobTestInheritWithProducer : IJob | ||
|  |     { | ||
|  |         void Execute(bool empty); | ||
|  |     } | ||
|  | 
 | ||
|  |     internal static class IJobTestInheritProducerExtensions | ||
|  |     { | ||
|  |         internal struct JobTestWrapper<T> where T : struct | ||
|  |         { | ||
|  |             internal T JobData; | ||
|  |             internal byte Empty; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal struct JobTestProducer<T> where T : struct, IJobTestInheritWithProducer | ||
|  |         { | ||
|  |             internal static readonly SharedStatic<IntPtr> jobReflectionData = SharedStatic<IntPtr>.GetOrCreate<JobTestProducer<T>>(); | ||
|  | 
 | ||
|  |             [BurstDiscard] | ||
|  |             internal static void Initialize() | ||
|  |             { | ||
|  |                 if (jobReflectionData.Data == IntPtr.Zero) | ||
|  |                     jobReflectionData.Data = JobsUtility.CreateJobReflectionData(typeof(JobTestWrapper<T>), typeof(T), (ExecuteJobFunction)Execute); | ||
|  |             } | ||
|  | 
 | ||
|  |             public delegate void ExecuteJobFunction(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex); | ||
|  |             public unsafe static void Execute(ref JobTestWrapper<T> jobWrapper, IntPtr additionalPtr, IntPtr bufferRangePatchData, ref JobRanges ranges, int jobIndex) | ||
|  |             { | ||
|  |                 jobWrapper.JobData.Execute(jobWrapper.Empty != 0); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public static void EarlyJobInit<T>() | ||
|  |             where T : struct, IJobTestInheritWithProducer | ||
|  |         { | ||
|  |             JobTestProducer<T>.Initialize(); | ||
|  |         } | ||
|  | 
 | ||
|  |         static IntPtr GetReflectionData<T>() | ||
|  |             where T : struct, IJobTestInheritWithProducer | ||
|  |         { | ||
|  |             JobTestProducer<T>.Initialize(); | ||
|  |             var reflectionData = JobTestProducer<T>.jobReflectionData.Data; | ||
|  |             CollectionHelper.CheckReflectionDataCorrect<T>(reflectionData); | ||
|  |             return reflectionData; | ||
|  |         } | ||
|  | 
 | ||
|  |         unsafe public static JobHandle Schedule<T>(this T jobData, bool empty, JobHandle dependsOn = new JobHandle()) where T : struct, IJobTestInheritWithProducer | ||
|  |         { | ||
|  |             JobTestWrapper<T> jobTestWrapper = new JobTestWrapper<T> | ||
|  |             { | ||
|  |                 JobData = jobData, | ||
|  |                 Empty = (byte)(empty ? 1 : 0) | ||
|  |             }; | ||
|  | 
 | ||
|  |             var scheduleParams = new JobsUtility.JobScheduleParameters( | ||
|  |                 UnsafeUtility.AddressOf(ref jobTestWrapper), | ||
|  |                 GetReflectionData<T>(), | ||
|  |                 dependsOn, | ||
|  |                 ScheduleMode.Parallel | ||
|  |             ); | ||
|  | 
 | ||
|  |             return JobsUtility.Schedule(ref scheduleParams); | ||
|  |         } | ||
|  |     } | ||
|  |     internal struct MyGenericResizeJob<T> : IJob where T : unmanaged | ||
|  |     { | ||
|  | 		public int m_ListLength; | ||
|  | 		public NativeList<T> m_GenericList; | ||
|  | 		public void Execute() | ||
|  | 		{ | ||
|  | 			m_GenericList.Resize(m_ListLength, NativeArrayOptions.UninitializedMemory); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  |     internal struct MyGenericJobDefer<T> : IJobParallelForDefer where T: unmanaged | ||
|  | 	{ | ||
|  | 		public T m_Value; | ||
|  | 		[NativeDisableParallelForRestriction] | ||
|  | 		public NativeList<T> m_GenericList; | ||
|  | 		public void Execute(int index) | ||
|  | 		{ | ||
|  | 			m_GenericList[index] = m_Value; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  |     internal struct GenericContainerResizeJob<T, U> : IJob | ||
|  |         where T : unmanaged, INativeList<U> | ||
|  |         where U : unmanaged | ||
|  |     { | ||
|  |         public int m_ListLength; | ||
|  |         public T m_GenericList; | ||
|  |         public void Execute() | ||
|  |         { | ||
|  |             m_GenericList.Length = m_ListLength; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     internal struct GenericContainerJobDefer<T, U> : IJobParallelForDefer | ||
|  |         where T : unmanaged, INativeList<U> | ||
|  |         where U : unmanaged | ||
|  |     { | ||
|  |         public U m_Value; | ||
|  |         [NativeDisableParallelForRestriction] | ||
|  |         public T m_GenericList; | ||
|  | 
 | ||
|  |         public void Execute(int index) | ||
|  |         { | ||
|  |             m_GenericList[index] = m_Value; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     internal class JobTests : JobTestsFixture | ||
|  |     { | ||
|  |         public void ScheduleGenericContainerJob<T, U>(T container, U value) | ||
|  |             where T : unmanaged, INativeList<U> | ||
|  |             where U : unmanaged | ||
|  |         { | ||
|  |             var j0 = new GenericContainerResizeJob<T, U>(); | ||
|  |             var length = 5; | ||
|  |             j0.m_ListLength = length; | ||
|  |             j0.m_GenericList = container; | ||
|  |             var handle0 = j0.Schedule(); | ||
|  | 
 | ||
|  |             var j1 = new GenericContainerJobDefer<T, U>(); | ||
|  |             j1.m_Value = value; | ||
|  |             j1.m_GenericList = j0.m_GenericList; | ||
|  |             INativeList<U> iList = j0.m_GenericList; | ||
|  |             j1.Schedule((NativeList<U>)iList, 1, handle0).Complete(); | ||
|  | 
 | ||
|  |             Assert.AreEqual(length, j1.m_GenericList.Length); | ||
|  |             for (int i = 0; i != j1.m_GenericList.Length; i++) | ||
|  |                 Assert.AreEqual(value, j1.m_GenericList[i]); | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void ValidateContainerSafetyInGenericJob_ContainerIsGenericParameter() | ||
|  |         { | ||
|  |             var list = new NativeList<int>(1, RwdAllocator.ToAllocator); | ||
|  |             ScheduleGenericContainerJob(list, 5); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void GenericScheduleJobPair<T>(T value) where T : unmanaged | ||
|  |         { | ||
|  |             var j0 = new MyGenericResizeJob<T>(); | ||
|  |             var length = 5; | ||
|  |             j0.m_ListLength = length; | ||
|  |             j0.m_GenericList = new NativeList<T>(1, RwdAllocator.ToAllocator); | ||
|  |             var handle0 = j0.Schedule(); | ||
|  | 
 | ||
|  |             var j1 = new MyGenericJobDefer<T>(); | ||
|  |             j1.m_Value = value; | ||
|  |             j1.m_GenericList = j0.m_GenericList; | ||
|  |             j1.Schedule(j0.m_GenericList, 1, handle0).Complete(); | ||
|  | 
 | ||
|  |             Assert.AreEqual(length, j1.m_GenericList.Length); | ||
|  |             for (int i = 0; i != j1.m_GenericList.Length; i++) | ||
|  |                 Assert.AreEqual(value, j1.m_GenericList[i]); | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void ScheduleGenericJobPairFloat() | ||
|  |         { | ||
|  |             GenericScheduleJobPair(10f); | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void ScheduleGenericJobPairDouble() | ||
|  |         { | ||
|  |             GenericScheduleJobPair<double>(10.0); | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void ScheduleGenericJobPairInt() | ||
|  |         { | ||
|  |             GenericScheduleJobPair(20); | ||
|  |         } | ||
|  | 
 | ||
|  | #if ENABLE_UNITY_COLLECTIONS_CHECKS | ||
|  |         [Test] | ||
|  | 	    public void SchedulingGenericJobUnsafelyThrows() | ||
|  | 	    { | ||
|  | 		    var j0 = new MyGenericResizeJob<int>(); | ||
|  | 		    var length = 5; | ||
|  | 		    j0.m_ListLength = length; | ||
|  | 		    j0.m_GenericList = new NativeList<int>(1, RwdAllocator.ToAllocator); | ||
|  | 		    var handle0 = j0.Schedule(); | ||
|  | 		    var j1 = new MyGenericJobDefer<int>(); | ||
|  | 		    j1.m_Value = 6; | ||
|  | 		    j1.m_GenericList = j0.m_GenericList; | ||
|  | 		    Assert.Throws<InvalidOperationException>(()=>j1.Schedule(j0.m_GenericList, 1).Complete()); | ||
|  | 		    handle0.Complete(); | ||
|  | 	    } | ||
|  | #endif | ||
|  | 
 | ||
|  |         struct DontReferenceThisTypeOutsideOfThisTest { public int v; } | ||
|  |          | ||
|  |         [Test] | ||
|  |         [TestRequiresCollectionChecks] | ||
|  |         public void SchedulingGenericJobFromGenericContextUnsafelyThrows() | ||
|  |         { | ||
|  |             var list = new NativeList<DontReferenceThisTypeOutsideOfThisTest>(1, RwdAllocator.ToAllocator); | ||
|  |             ScheduleGenericJobUnsafely(list, new DontReferenceThisTypeOutsideOfThisTest { v = 5 }); | ||
|  |         } | ||
|  | 
 | ||
|  |         void ScheduleGenericJobUnsafely<T, U>(T container, U value) | ||
|  |             where T : unmanaged, INativeList<U> | ||
|  |             where U : unmanaged | ||
|  |         { | ||
|  |             var j0 = new GenericContainerResizeJob<T, U>(); | ||
|  |             var length = 5; | ||
|  |             j0.m_ListLength = length; | ||
|  |             j0.m_GenericList = container; | ||
|  |             var handle0 = j0.Schedule(); | ||
|  | 
 | ||
|  |             var j1 = new GenericContainerJobDefer<T, U>(); | ||
|  |             j1.m_Value = value; | ||
|  |             j1.m_GenericList = j0.m_GenericList; | ||
|  |             INativeList<U> iList = j0.m_GenericList; | ||
|  |             Assert.Throws<InvalidOperationException>(()=>j1.Schedule((NativeList<U>)iList, 1).Complete()); | ||
|  | 
 | ||
|  |             handle0.Complete();  // complete this so we can dispose the nativelist | ||
|  |         } | ||
|  | 
 | ||
|  |         /* | ||
|  | 	     * these two tests used to test that a job that inherited from both IJob and IJobParallelFor would work as expected | ||
|  | 	     * but that's probably crazy. | ||
|  | 	     */ | ||
|  |         /*[Test] | ||
|  |         public void Scheduling() | ||
|  |         { | ||
|  |             var job = data.Schedule(); | ||
|  |             job.Complete(); | ||
|  |             ExpectOutputSumOfInput0And1(); | ||
|  |         }*/ | ||
|  | 
 | ||
|  | 
 | ||
|  |         /*[Test] | ||
|  | 
 | ||
|  |         public void Scheduling_With_Dependencies() | ||
|  |         { | ||
|  |             data.input0 = input0; | ||
|  |             data.input1 = input1; | ||
|  |             data.output = output2; | ||
|  |             var job1 = data.Schedule(); | ||
|  | 
 | ||
|  |             // Schedule job2 with dependency against the first job | ||
|  |             data.input0 = output2; | ||
|  |             data.input1 = input2; | ||
|  |             data.output = output; | ||
|  |             var job2 = data.Schedule(job1); | ||
|  | 
 | ||
|  |             // Wait for completion | ||
|  |             job2.Complete(); | ||
|  |             ExpectOutputSumOfInput0And1And2(); | ||
|  |         }*/ | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void ForEach_Scheduling_With_Dependencies() | ||
|  |         { | ||
|  |             data.input0 = input0; | ||
|  |             data.input1 = input1; | ||
|  |             data.output = output2; | ||
|  |             var job1 = data.Schedule(output.Length, 1); | ||
|  | 
 | ||
|  |             // Schedule job2 with dependency against the first job | ||
|  |             data.input0 = output2; | ||
|  |             data.input1 = input2; | ||
|  |             data.output = output; | ||
|  |             var job2 = data.Schedule(output.Length, 1, job1); | ||
|  | 
 | ||
|  |             // Wait for completion | ||
|  |             job2.Complete(); | ||
|  |             ExpectOutputSumOfInput0And1And2(); | ||
|  |         } | ||
|  | 
 | ||
|  |         struct EmptyComputeParallelForJob : IJobParallelFor | ||
|  |         { | ||
|  |             public void Execute(int i) | ||
|  |             { | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void ForEach_Scheduling_With_Zero_Size() | ||
|  |         { | ||
|  |             var test = new EmptyComputeParallelForJob(); | ||
|  |             var job = test.Schedule(0, 1); | ||
|  |             job.Complete(); | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void Deallocate_Temp_NativeArray_From_Job() | ||
|  |         { | ||
|  |             TestDeallocateNativeArrayFromJob(RwdAllocator.ToAllocator); | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void Deallocate_Persistent_NativeArray_From_Job() | ||
|  |         { | ||
|  |             TestDeallocateNativeArrayFromJob(Allocator.Persistent); | ||
|  |         } | ||
|  | 
 | ||
|  |         private void TestDeallocateNativeArrayFromJob(Allocator label) | ||
|  |         { | ||
|  |             var tempNativeArray = CollectionHelper.CreateNativeArray<int>(expectedInput0, label); | ||
|  | 
 | ||
|  |             var copyAndDestroyJob = new CopyAndDestroyNativeArrayParallelForJob | ||
|  |             { | ||
|  |                 input = tempNativeArray, | ||
|  |                 output = output | ||
|  |             }; | ||
|  | 
 | ||
|  |             // NativeArray can safely be accessed before scheduling | ||
|  |             Assert.AreEqual(10, tempNativeArray.Length); | ||
|  | 
 | ||
|  |             tempNativeArray[0] = tempNativeArray[0]; | ||
|  | 
 | ||
|  |             var job = copyAndDestroyJob.Schedule(copyAndDestroyJob.input.Length, 1); | ||
|  | 
 | ||
|  |             job.Complete(); | ||
|  | 
 | ||
|  |             // Need to dispose because the allocator may be Allocator.Persistent. | ||
|  |             tempNativeArray.Dispose(); | ||
|  | 
 | ||
|  |             Assert.AreEqual(expectedInput0, copyAndDestroyJob.output.ToArray()); | ||
|  |         } | ||
|  | 
 | ||
|  | #if ENABLE_UNITY_COLLECTIONS_CHECKS | ||
|  |         public struct NestedDeallocateStruct | ||
|  |         { | ||
|  | 			public NativeArray<int> input; | ||
|  |         } | ||
|  | 
 | ||
|  |         public struct TestNestedDeallocate : IJob | ||
|  |         { | ||
|  |             public NestedDeallocateStruct nested; | ||
|  | 
 | ||
|  |             public NativeArray<int> output; | ||
|  | 
 | ||
|  |             public void Execute() | ||
|  |             { | ||
|  |                 for (int i = 0; i < nested.input.Length; ++i) | ||
|  |                     output[i] = nested.input[i]; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void TestNestedDeallocateOnJobCompletion() | ||
|  |         { | ||
|  |             var tempNativeArray = CollectionHelper.CreateNativeArray<int>(10, RwdAllocator.ToAllocator); | ||
|  |             var outNativeArray = CollectionHelper.CreateNativeArray<int>(10, RwdAllocator.ToAllocator); | ||
|  |             for (int i = 0; i < 10; i++) | ||
|  |                 tempNativeArray[i] = i; | ||
|  | 
 | ||
|  |             var job = new TestNestedDeallocate | ||
|  |             { | ||
|  |                 nested = new NestedDeallocateStruct() { input = tempNativeArray }, | ||
|  |                 output = outNativeArray | ||
|  |             }; | ||
|  | 
 | ||
|  |             var handle = job.Schedule(); | ||
|  |             handle.Complete(); | ||
|  | 
 | ||
|  |             RwdAllocator.Rewind(); | ||
|  | 
 | ||
|  | #if ENABLE_UNITY_COLLECTIONS_CHECKS | ||
|  |             // Ensure released safety handle indicating invalid buffer | ||
|  |             Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(tempNativeArray)); }); | ||
|  | 			Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(job.nested.input)); }); | ||
|  | #endif | ||
|  |         } | ||
|  | 
 | ||
|  |         public struct TestJobProducerJob : IJobTest | ||
|  |         { | ||
|  | 			public NativeArray<int> jobStructData; | ||
|  | 
 | ||
|  |             public void Execute() | ||
|  |             { | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void TestJobProducerCleansUp() | ||
|  |         { | ||
|  |             var tempNativeArray = CollectionHelper.CreateNativeArray<int>(10, RwdAllocator.ToAllocator); | ||
|  |             var tempNativeArray2 = CollectionHelper.CreateNativeArray<byte>(16, RwdAllocator.ToAllocator); | ||
|  | 
 | ||
|  |             var job = new TestJobProducerJob | ||
|  |             { | ||
|  |                 jobStructData = tempNativeArray, | ||
|  |             }; | ||
|  | 
 | ||
|  |             var handle = job.ScheduleTest(tempNativeArray2); | ||
|  |             handle.Complete(); | ||
|  | 
 | ||
|  |             RwdAllocator.Rewind(); | ||
|  | 
 | ||
|  | #if ENABLE_UNITY_COLLECTIONS_CHECKS | ||
|  |             // Check job data | ||
|  |             Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(tempNativeArray)); }); | ||
|  | 			Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(job.jobStructData)); }); | ||
|  | 			// Check job producer | ||
|  | 			Assert.Throws<ObjectDisposedException>(() => { AtomicSafetyHandle.CheckExistsAndThrow(NativeArrayUnsafeUtility.GetAtomicSafetyHandle(tempNativeArray2)); }); | ||
|  | #endif | ||
|  |         } | ||
|  | 
 | ||
|  |         public struct CopyJob : IJob | ||
|  |         { | ||
|  |             public NativeList<int> List1; | ||
|  |             public NativeList<int> List2; | ||
|  | 
 | ||
|  |             public void Execute() | ||
|  |             { | ||
|  |                 List1 = List2; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public unsafe void TestContainerCopy_EnsureSafetyHandlesCopyAndDisposeProperly() | ||
|  |         { | ||
|  |             var list1 = new NativeList<int>(10, RwdAllocator.ToAllocator); | ||
|  |             var list2 = new NativeList<int>(10, RwdAllocator.ToAllocator); | ||
|  |             list1.Add(1); | ||
|  |             list2.Add(2); | ||
|  | 
 | ||
|  |             var job = new CopyJob | ||
|  |             { | ||
|  |                 List1 = list1, | ||
|  |                 List2 = list2 | ||
|  |             }; | ||
|  | 
 | ||
|  |             job.Schedule().Complete(); | ||
|  | 
 | ||
|  |             list1.Dispose(); | ||
|  |             list2.Dispose(); | ||
|  |         } | ||
|  | #endif | ||
|  | 
 | ||
|  |         struct LargeJobParallelForDefer : IJobParallelForDefer | ||
|  |         { | ||
|  |             public FixedString4096Bytes StrA; | ||
|  |             public FixedString4096Bytes StrB; | ||
|  |             public FixedString4096Bytes StrC; | ||
|  |             public FixedString4096Bytes StrD; | ||
|  |             [NativeDisableParallelForRestriction] | ||
|  |             public NativeArray<int> TotalLengths; | ||
|  |             [ReadOnly] | ||
|  |             public NativeList<float> Unused; // Schedule() from NativeList.Length requires that the list be passed into the job | ||
|  | 
 | ||
|  |             public void Execute(int index) | ||
|  |             { | ||
|  |                 TotalLengths[0] = StrA.Length + StrB.Length + StrC.Length + StrD.Length; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public enum IterationCountMode | ||
|  |         { | ||
|  |             List, Pointer | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public unsafe void IJobParallelForDefer_LargeJobStruct_ScheduleRefWorks( | ||
|  |             [Values(IterationCountMode.List, IterationCountMode.Pointer)] IterationCountMode countMode) | ||
|  |         { | ||
|  |             using(var lengths = CollectionHelper.CreateNativeArray<int>(1, RwdAllocator.ToAllocator)) | ||
|  |             { | ||
|  |                 var dummyList = new NativeList<float>(RwdAllocator.ToAllocator); | ||
|  |                 dummyList.Add(5.0f); | ||
|  |                 var job = new LargeJobParallelForDefer | ||
|  |                 { | ||
|  |                     StrA = "A", | ||
|  |                     StrB = "BB", | ||
|  |                     StrC = "CCC", | ||
|  |                     StrD = "DDDD", | ||
|  |                     TotalLengths = lengths, | ||
|  |                     Unused = dummyList, | ||
|  |                 }; | ||
|  | 
 | ||
|  |                 if (countMode == IterationCountMode.List) | ||
|  |                 { | ||
|  |                     Assert.DoesNotThrow(() => job.ScheduleByRef(dummyList, 1).Complete()); | ||
|  |                 } | ||
|  |                 else if (countMode == IterationCountMode.Pointer) | ||
|  |                 { | ||
|  |                     var lengthArray = CollectionHelper.CreateNativeArray<int>(1, RwdAllocator.ToAllocator); | ||
|  |                     lengthArray[0] = 1; | ||
|  |                     Assert.DoesNotThrow(() => job.ScheduleByRef((int*)lengthArray.GetUnsafePtr(), 1).Complete()); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [BurstCompile(CompileSynchronously = true)] | ||
|  |         public struct InheritJob : IJobTestInherit | ||
|  |         { | ||
|  |             public NativeList<int> List1; | ||
|  |             public NativeList<int> List2; | ||
|  | 
 | ||
|  |             public void Execute() | ||
|  |             { | ||
|  |                 List1[0] = List2[0]; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void InheritInterfaceJobWorks() | ||
|  |         { | ||
|  |             var l1 = new NativeList<int>(4, RwdAllocator.ToAllocator); | ||
|  |             l1.Add(3); | ||
|  |             var l2 = new NativeList<int>(4, RwdAllocator.ToAllocator); | ||
|  |             l2.Add(17); | ||
|  |             var job = new InheritJob { List1 = l1, List2 = l2 }; | ||
|  |             job.Schedule().Complete(); | ||
|  | 
 | ||
|  |             Assert.IsTrue(l1[0] == 17); | ||
|  | 
 | ||
|  |             l2.Dispose(); | ||
|  |             l1.Dispose(); | ||
|  |         } | ||
|  | 
 | ||
|  |         [BurstCompile(CompileSynchronously = true)] | ||
|  |         public struct InheritWithProducerJob : IJobTestInheritWithProducer | ||
|  |         { | ||
|  |             public NativeList<int> List1; | ||
|  |             public NativeList<int> List2; | ||
|  | 
 | ||
|  |             public void Execute() | ||
|  |             { | ||
|  |                 List2[0] = List1[0]; | ||
|  |             } | ||
|  | 
 | ||
|  |             public void Execute(bool empty) | ||
|  |             { | ||
|  |                 List1[0] = List2[0]; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         [Test] | ||
|  |         public void InheritInterfaceWithProducerJobWorks() | ||
|  |         { | ||
|  |             var l1 = new NativeList<int>(4, RwdAllocator.ToAllocator); | ||
|  |             l1.Add(3); | ||
|  |             var l2 = new NativeList<int>(4, RwdAllocator.ToAllocator); | ||
|  |             l2.Add(17); | ||
|  |             var job = new InheritWithProducerJob { List1 = l1, List2 = l2 }; | ||
|  |             job.Schedule(false).Complete(); | ||
|  |             Assert.IsTrue(l1[0] == 17); | ||
|  | 
 | ||
|  |             l1[0] = 3; | ||
|  |             job.Schedule().Complete(); | ||
|  |             Assert.IsTrue(l2[0] == 3); | ||
|  | 
 | ||
|  |             l2.Dispose(); | ||
|  |             l1.Dispose(); | ||
|  |         } | ||
|  |     } | ||
|  | } |