The Dependency property doesn’t track the dependencies that a job might have on data passed through a NativeArray or other similar containers. If you write a NativeArray in one job, and read that array in another, you must manually add the JobHandle of the first job as a dependency of the second. You can use JobHandle.CombineDependencies to do this.
But the last phrase confuses me. Why would I need to combineDependencies for this?
System Dependency → Job A (new handle) → Job B (Pass handle, returns handle) → Dependency = lastHandle
If you’re scheduling jobs consecutively you don’t need to. If Job B is running on a different system its ‘Dependency’ property doesn’t include that it depends on the Job A (since it doesn’t track NativeArrays), that’s why you combine
Sorry I don’t understand what you mean. Why do I need to combine? It’s a line… I don’t do paralell jobs (two handle paths) that I need to combine. And I’m very interested in undrestanding this.
You’ve assumed that Job B is scheduled just after Job A which is not always the case.
Consider this case:
SystemA Schedules JobA which uses some NativeArray
Some other systems run and schedule jobs…
SystemB Schedules JobB later in the frame which uses the same NativeArray
You need to include JobA’s dependency explicitly on JobB. SystemB’s Dependency property is not guaranteed to include JobA since it doesn’t know about NativeArrays
I though that Dependency is a simple JobHandle that represents the dependency of the systems that come before. If ECS finds that we read or write on something that another system writes to, the dependency is updated somehow. That’s what I though.
[Edit] Seems like it does with components only, but only if you don’t explicitly use handles and also if you use ForEach and WithCode…
So I’m passing that dependency to all my jobs, via copying the handle and passing to jobs, and also maybe creating a copy and passing then replacing…etc.
Now you say that seems like “NativeArrays” are not considered. I have no idea how to do all this…
Let’s do it this way:
SystemA
JobHandle handle = Dependency;
handle = JobA1.Schedule(handle)
handle = JobA2.Schedule(handle) <-- Writes to ARRAY
Dependency = handle;
SystemB Runs after A via [ExecuteAfter(SystemA)] both in the same group
JobHandle handle = Dependency;
handle = JobB1.Schedule(handle) <--- Reads Array. ERROR?
Dependency = handle
Can you tell me what I should do instead?
Is it something related to the docs: " By default, the system updates the Dependency property based on the components that each job reads and writes as you schedule jobs in a system.".
“If you use JobComponentSystem correctly then it is expected that any dependency chains will be setup correctly independent of the order in which you call JobComponentSystem.Update();”
“Now if you have shared containers that are not IComponentData etc.
Eg. some NativeArray<> being passed around then you have to also pass around the job handles manually.”
And that’s what I explicitly do.
I don’t even use Entities.ForEach or WithCode or any of those things that write on Dependencies. I use IJobEntities and IJob / IParallelJobFor
I exactly do that. Do the JobHandles stuff myself.
[Edit]
Important to note: The place that ARRAY is stored is a SINGLETON.
I found that singletons work differently, and you have to CompleteDependenciesBeforeRO() on it, but I guess it’s only if you don’t actually use any handles explicitly, which I do.
In your example SystemB runs after SystemA, since you didn’t use ECS components in the systems, Dependency property of SystemB doesn’t know that it depends on JobA1 or JobA2. You try to read the array and correctly get an error.
Solution 1: Use DynamicBuffer instead of NativeArray without any explicit dependency management and it works
Solution 2: Cache JobA2 handle on SystemA as a field, pass JobHandle.CombineDependencies(SystemBDependency, JobA2Handle) jobB when scheduling and it works
Solution 3: Don’t use Systems, use completely manual dependency management (if you aren’t using ECS components anyway)
Solution 2 worked. Thank you very much. I’m combining Dependency with the dependency of the other system, getting it via a parameter.
But I still don’t get it, so what I thought is:
The dependency on System A is assigned properly. Why is System B, that HAS to execute after A because of “executeAfter”, doesn’t receive a proper Dependecy with the stuff from System A?
Because why it should? Entities Dependency is not about systems but types systems using. If you not using component types - every system Dependency will be individual for it’s system (m_JobHandle), and will complete self from previous frame in BeforeOnUpdate. Only if you use component types you’ll have AddReader/Writer calls under the hood which will populate readers/writers job fences, in AfterOnUpdate they will be combined to system self handle (m_JobHandle) for proper self complete next frame. If no component types used in system then in AfterOnUpdate system will write read fence for Entity type only (for proper CompleteAllJobsAndInvalidateArrays behavior). But m_JobHandle itself is not shared. What Dependency do is on first get access to it in system (if you using component types) it’s under the hood gets reader writer fences and pass to system dependency, this is why, when you using component types, dependencies tracked properly across systems.