#GetSingletonRW.ValueRO vs GetSingleton

1 messages · Page 1 of 1 (latest)

hollow dragon
#

What happens with dependencies with both?
Can somebody summarize the differences since the documentation says nothing at all?

https://docs.unity3d.com/Packages/com.unity.entities@1.2/manual/components-singleton.html

So my singleton component has NativeList inside of it, so I guess it is recommended to use the RW version.

GetSingleton is supposed to return a read only version of it. Does it consider write dependencies by itself? Or since it's native containers it doesn't?

GetSingletonRW returns a reference to the data. So we use that if we want to access the native containers otherwise, GetSingleton is enough?

Do the dependencies work with the reference ? Only if they are passed to Jobs I guess??

waxen mist
#

If you want to Add, Remove, Clear, ... elements of the NativeList in a IComponentData, you can use GetSingleton. If you want to replace said NativeList with another NativeList, you have to use GetSingletonRW.
The reason for this is NativeContainers use pointers.

hollow dragon
# waxen mist If you want to Add, Remove, Clear, ... elements of the NativeList in a IComponen...

That's not what the docs say. https://docs.unity3d.com/Packages/com.unity.entities@1.2/manual/components-singleton.html
At the end it recommends using RW when having NativeContainers inside a singleton... and only in that case

But I don't understand the last phrase. "Only use to access a NativeContainer in a component. This is because native containers have their own safety mechanisms compatible with Jobs Debugger, separate from ECS component safety mechanisms."

In that case, why do I need to use the RW version? If it's the native containers the ones that have safety mechanisms? Both GetSingleton and GetSingletonRW do exactly the same inside ECS code, unless you have safety checks enabled, in that case, both check anyway.

Does it mean that I have to use these inside jobs so that I get dependency errors output, at least?

If you have errors, then you have to fix the dependencies by hand (It doesn't tell you if you have to use EntityManager.CompleteDependencyBeforeRW specifially or not)

tepid quest
hollow dragon
# tepid quest `GetSingleton` will register RO dependency `GetSingletonRW` will register RW dep...

EHm...Not sure about any of that. As the docs say , singletons don't manage dependencies, you have to do it manually.

Nothing about dependencies in GetSingleton...I don't see anything in GetSingletonRW either... Are you sure ?

` [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(BurstCompatibleComponentData) })]
public RefRW<T> GetSingletonRW<T>() where T : unmanaged, IComponentData
{
var typeIndex = TypeManager.GetTypeIndex<T>();

        GetSingletonChunkAndEntity(typeIndex, out var indexInArchetype, out var chunk, out var entityIndexInChunk);

        var archetype = _Access->EntityComponentStore->GetArchetype(chunk);
        var data = ChunkDataUtility.GetComponentDataRW(chunk, archetype, entityIndexInChunk,
            indexInArchetype, _Access->EntityComponentStore->GlobalSystemVersion);

#if (UNITY_EDITOR || DEVELOPMENT_BUILD) && !DISABLE_ENTITIES_JOURNALING
if (Hint.Unlikely(_Access->EntityComponentStore->m_RecordToJournal != 0))
RecordSingletonJournalRW(chunk, typeIndex, EntitiesJournaling.RecordType.GetComponentDataRW, data, UnsafeUtility.SizeOf<T>());
#endif
return new RefRW<T>(data);
}`

#

(I removed the code when checks are enabled, shouldn't affect dependencies)

tepid quest
hollow dragon
#

"singleton API calls don't ensure that running jobs are completed first. The Jobs Debugger logs an error on invalid access, and you either need to manually complete dependencies with EntityManager.CompleteDependencyBeforeRO or EntityManager.CompleteDependencyBeforeRW, or you need to restructure the data dependencies.

You should also be careful if you use GetSingletonRW to get read/write access to components. Because a reference to component data is returned, it's possible to modify data while jobs are also reading or writing it. "

tepid quest
#

practically it'll new EntityQueryBuilder(Allocator.Temp).WithAll/RW<T>().Build(ref systemState); and store it to generated field, which will then be used to obtain singleton. Build(ref SystemState) is what actually registers dependency

hollow dragon
#

Also my singleton has NativeContainers inside (that complicates it even more)

tepid quest
hollow dragon
#

¿¿

#

I'm seriously confused about all this. I've been having conversations with a lot of people and each of them say a different thing. I don't understand the documentation, there's only a paragraph about singletons.

hollow dragon
tepid quest
#

if you put native container inside singleton component - singleton management itself kind of takes care of dependency management for you

tepid quest
hollow dragon
#

Ehm... so I can't use singletons on jobs?

tepid quest
#

Why not?

hollow dragon
#

Maybe I can get the singleton and pass the references to the native containers to the jobs?

tepid quest
#

put it in a field and that's it

#

or that

#

doesn't really matter

#

same thing technically

#

So basically in the simplest you need to follow very simple concept

hollow dragon
#

WEll. Basically all SystemAPI calls have to be done outside jobs, that's that

tepid quest
#

if you put native container in singleton - you are responsible for ensuring you pass those native containers correctly.

if you use SystemAPI.GetSingleton - this will register RO dependency on singleton type. Thus making sure that job can safely read native containers inside.
If you use SystemAPI.GetSingletonRW - this will register RW dependency on singleton type. Thus making sure that job can safely read and write native containers inside.

The only annoying part of this - RefRW<T> returned by RW overload will throw if you attempt to use it on main thread (if there are jobs that are already scheduled with any dependency on that singleton). So what you need to do instead - just register dependency manually in system OnCreate and then use GetSingleton instead. Once dependency registered, it's stuck on system forever.

#

so if you want to use singleton with native container in a job for RW purposes you need:
OnCreate() { this.GetComponentTypeHandle<T>(); } - to register RW dependency (or there are utilities in different libraries that implement a cleaner way to do same thing)
OnUpdate() { new MyJob { mySingleton = SystemAPI.GetSingleton<T>() }.Schedule(); }

hollow dragon
#

I'm very very confused.

I got this code . It's a terrible design, but let's see...

It's a very very simplified version

OnUpdate():
var receivedData = receivedDataSingleton.dataList[0];
SystemAPI.SetSingleton(receivedData);
receivedDataSingleton.dataList.RemoveAt(0);

Received data singleton is a singleton that contains a NativeList<OtherSingleton>.
I just take the first, replace a singleton with it.

  • I'm removing stuff from the list
  • I'm using systemAPI that can't be done on a job
#

(let me read what you wrote)

#

SO... how would you do this using GetSingleton

tepid quest
#

tbh, I don't get what exactly you are doing

hollow dragon
tepid quest
hollow dragon
tepid quest
#

eventually they just call _query12452151.GetSingleton<T>();

hollow dragon
#

ok....

tepid quest
hollow dragon
#

In that case... I guess it's good to have
this.GetComponentTypeHandle<T>();
on every system that will write or read from it

#

How do I mark if it reads or write?

tepid quest
hollow dragon
#

If I only read... what should I do?

tepid quest
#

RW dependency forces jobs to run sequentially, disallowing parallel execution

hollow dragon
#

this.GetComponentTypeHandle<T>(readonly: true); ?

tepid quest
#

as it registers RO dependency via query creation

hollow dragon
#

Even when I have Native Containers inside of it??

tepid quest
#

native container inside don't change anything

hollow dragon
#

Because there's jobs that can be writing to them at the same time, and the dependency system is not aware of any of that

#

That's why it says that we use: CompleteDependenciesBeforeRO()

What's that used for then?

tepid quest
#

all you do here is like making yourself a promise, that you only work with native containers inside singleton only if you treat dependency of that singleton correctly

hollow dragon
#

This code is not mine xD

tepid quest
hollow dragon
#

is a project I'm working on and I need to solve all the dependencies

#

OK I get it.

tepid quest
#

so SystemA writes to SingletonKek (contains nativearray inside)
while SystemB reads from SingletonKek

SystemB jobs must wait until SystemA jobs complete

hollow dragon
#

I'm more worried about reading something that is being written, to be honest.

#

Yeah but...

#

what happens with the jobs in B?

#

if it's a normal job... should I pass Dependency?

#

erhm... I guess I use normal jobs dependencies

#

But I need to do Combine Dependencies with the jobs that modify the native containers, right?

tepid quest
#

ofc, if you don't pass, job will start right away and you can easily run into safety exceptions that track down when multiple jobs access same native containers

#

but when you use IJobEntity it's all actually generated for you if you use overloads without parameters

hollow dragon
#

ok So what you mean is that I'll have normal job errors

#

We don't use IJobEntity that much

#

🤷‍♀️

tepid quest
#

then make sure you pass state.Dependency

hollow dragon
#

We use regular jobs because it's all Native Containers, and the dependencies are a mess

tepid quest
#

and write it back as well

hollow dragon
#

ok got it. But when you modify native containers in components, you have to explicitly manage the dependencies,

#

that's what I've learned so far

tepid quest
#

state.Dependency = new MyJob().Schedule(state.Dependency);

hollow dragon
#

Yeah. That's it

#

ok

hollow dragon
#

IComponentData

#

Some of our components contain NativeContainers, just like the singletons

tepid quest
#

I mean, singleton are also that. But you usually refer to them as singleton

hollow dragon
#

it's all lists everywhere

tepid quest
#

this is much more complicated route

hollow dragon
#

Yeah. Any component really.

tepid quest
#

not only you have to explicitly disable safety for that

hollow dragon
#

............. IT's a mess

tepid quest
#

you also have to maintain disposal

hollow dragon
#

But I worry about singletons only now. I can't fix it all

#

Of course, we use ECS without really using ECS to be honest. taht's how I see it

#

We don't take advantage of a lot of things, I guess.

#

Well. Thanks a lot for your time. I need to read everything again and think about it.

#

I wish docs had more information about all this. It's really difficult

tepid quest
#

My only suggestion - rework all native containers inside components (that aren't singletons) into DynamicBuffer<T>

#

they are component-lists which are fully supported by safety system

hollow dragon
#

ok . Will take notes about it

#

thanks a lot ^_^

hollow dragon
# tepid quest you also have to maintain disposal

I have just one question regarding the previous conversation.

For example, is this correct? I'm not doing any GetComponentLookup(isReadOnly : true) in on create for the singleton.... You said it wasn't necessary. Why is there an option for isReadOnly then? Is it another purpose?

        EntityManager.CompleteDependencyBeforeRO<MySingletonWithNativeContainers>();
        var number = SystemAPI.GetSingleton<MySingletonWithNativeContainers>().dataList.Length;
        CallToManagedCode(number);

If I'm forced to do this without jobs, should I call CompleteDependencies this way?? Is there anything else I need?

tepid quest
#

it registers RO dependency

#

thus when you only need RO, simply calling SystemAPI.GetSingleton in OnUpdate is enough to have RO dependency setup

tepid quest
hollow dragon
#

What is the CompleteDependencyBeforeRO used for then?

tepid quest
#

EntityManager.CompleteDependencyBeforeRO<MySingletonWithNativeContainers>(); this code will complete ALL jobs that have RW dependency. But not RO.

hollow dragon
#

Yeah. I'm very fluent with jobs. My problem is the ECS concepts and dependencies generated automatically / Code gen

tepid quest
#

RO jobs will continue running

tepid quest
#

what it does is fetches dependency written by last system, that has it registered

#

and then calls .Complete on it

#

that's it

#

in github link above it is explained what written by last system means

hollow dragon
#

Yeah I still have to read all that stuff, but I didn't have time.

I'm confused about all this.
I don't know how to write my question :D....

#

If I'm doing GetSingleton() a dependency is created. It is RO. But ... if I use it in main thread code.... I have to complete! right?

#

So that is good. I have to do this:
EntityManager.CompleteDependencyBeforeRO<MySingletonWithNativeContainers>();

tepid quest
#

which is very clever system

hollow dragon
#

haha

#

What I don't understand is... The dependencies are just the same as with regular jobs.

#

Dependency carries the JobHandle. that's all

tepid quest
#

yep

#

that's it

hollow dragon
#

but when I do that code, I need to complete!! It's main thread

#

So instead of doing Dependency.Complete() It's better that I call that other function that is more specific to RW , don't I?

#

(I'll read what you tell me, yes)

tepid quest
#

So, another thing you really need to understand is codegen behind SystemAPI

hollow dragon
#

Yeah. SystemAPI is destroying my code. Because I can't use it in jobs.

tepid quest
#

because in actually those methods don't do one thing, they generate code in multiple places: fields, OnCreate method body, OnUpdate method body

#

you don't need it

#

and maybe it's best if you avoid it

#

because this way you can learn how actual code works

hollow dragon
#

Avoid what? Using CompleteDependency?

tepid quest
#

avoid using SystemAPI

hollow dragon
#

It's not systemAPI, it's EntityManager...

tepid quest
#

That's not the code I'm refererring to

hollow dragon
#

Yeah. For example SystemAPI. SetSingleton does GetSingletonRW().ValueRW = newSingleton; Is that what you mean? But there's more checks inside...

#

I could do that in a job

tepid quest
#

anything SystemAPI is codegen

#

code is literally just throw new Exception();

#

codegenerators will then create actual code out of real api

hollow dragon
#

OK. But I still don't know if I'm doing right. If the code that uses the singleton is not inside jobs, and if has to be written to (RW) , then I declare the Lookup on OnCreate() to tell the system to depend on the singleton as RW, then use GetSingleton.

Is that right? I don't have to call CompleteDependencyBeforeRO()? I'm not completely sure

#

The system now has that dependency... but I don't use Dependency property at all. In that case I should complete. That's my question. Do I complete? How do I complete?

tepid quest
#

When you do main thread code, you don't need ANY dependencies registered whatsoever, because they are only used by jobs

#

All you care about is sync point, so it ensures no other job runs while you are doing your thing outside of job system

#

So calling is mandatory CompleteDependencyBefore

#

One of the best times to do it - before you schedule any job in a frame.

hollow dragon
#

OK that's what I was asking. Right that makes a lot of sense

#

cool

tepid quest
#

This way all it'd do is just ensure last job (with this dependency) from previous frame is complete

hollow dragon
#

...................ugh that opened new questions

#

Does CompleteDependencyBeforeRW() work with Singletons with NativeContainers?

tepid quest
#

native containers aren't related to any of this API whatsoever, you can have literally anything inside those singletons

#

even raw pointers

hollow dragon
#

ok

#

So if I work with native containers I need to assign Dependency correctly at the end of each system, by hand

tepid quest
#

and singletons aren't any special. They are just components that exist only at 1 quantity

#

singleton API simply provides sugar checks to ensure it is indeed this way and throw otherwise

hollow dragon
#

So......... if my system receives a good dependency ........................ why do we need to register the dependency by hand on OnCreate?? ............

hollow dragon
#

Is it so that the ECS manager organizes the systems correctly?

#

haha. OK

#

Thanks a lot. I'll read it

#

🙏

#

Thanks a lot.

hollow dragon
# tepid quest so if you want to use singleton with native container in a job for RW purposes y...

Hey ! I read what you sent me. That article, everythign... I had one follow up question .

About exactly this that I mention. My colleagues are confused why you use GetSingleton after delcaring the dependency on OnCreate using... getComponentLookup(),
You said to use this approach only if you pass the singleton to jobs. If you do main thread any of that is needed. You just call the CompleteBeforeRW/RO and do whatever you want in the main thread.

GetSingleton returns a copy of all values (and references to the native containers inside). What's the problem with RW if you are using Jobs? What if you want to write to the value types in the job? You can't use GetSingleton.

What is wrong by using GetSingletonRW in main thread vs jobs?

#

I wish I had 4 or 5 versions of the same code so you told me which one is the correct way 😄

tepid quest
hollow dragon
#

........... ehm............. so on the main thread you can't do

CompleteBeforeRW()
GetSingletonRW().ValueRW.... do something with it?

#

it doesn't work?

tepid quest
#

you can, but the whole point is you have to call CompleteBeforeRW() for it

#

which force completes all jobs running

hollow dragon
#

Of course I have, it's main thread!

#

But would that work? I know it's bad, by sadly some of my systems can't be jobified at the moment

tepid quest
#

what I mean is that you use GetSingleton so you can pass singleton copy (with native containers) to job without sync points

hollow dragon
#

I know I know. But I want to clear it up:

Main Thread only system : Use CompleteBeforeRW/RO then you can use GetSingleton() to read. GetSingletonRW().ValueRW to write. (GetSingletonRW().ValueRO also for read??)

Jobified System: USe GetSingleton() to pass to jobs, and declare GetComponentLookup in Oncreate()
or Use GetSingletonRW() to pass to jobs and not declare anything on top?

#

So the first one, is that one the way to do it?

#

Second one, I'm not sure. I'm getting confused by the GetComponentLookup delcaration, seriously

#

And two people told me to do the same, but I still don't know it's purpose, if GetSingletonRW effectively declares the dependency anyway in codegen.

tepid quest
#

and declare GetComponentLookup in Oncreate() only if you want to write (since GetSingleton wouldn't register RW)

hollow dragon
#

But I can't write on what GetSingleton returns!

#

It returns a copy of the value types. I can use it for the native containers...

tepid quest
#

without sync point at least

#

and just syncing before scheduling ruins the whole purpose of jobs

hollow dragon
#

Why can't you pass the RefRW to a job?

tepid quest
#

do you call CompleteDependencyBefore?

hollow dragon
#

No

tepid quest
hollow dragon
#

It just creates a query on OnCreate and calls query.GetSingletonRW ........... why can't we pass that to a job?

#

And use ValueRW inside the job

hollow dragon
#

right?

tepid quest
hollow dragon
#

Ok. I get it. I get it.

#

So the GetComponentLookup is a HACK for singletons with NativeContainers. that's it

royal prairie
hollow dragon
#

It doesn't force you to complete

#

Yes I'm starting to grasp it. I had no idea you can't use SingletonRW wihtout completing, ALWAYS.

royal prairie
#

What Issue is saying only about the singleton component and how you interact with it on its own, not correlate to any native container it contains

hollow dragon
#

So a hack is to declare it as RW on OnCreate , then use GetSingleton and pass it to jobs which modify those NativeColletions. The system doesnt' care about it, the dependencies are correct

#

I'll try this all out. But we use a thousand GetSingletonRW and we don't complete before in a lot of them. Probably becuase no job was writing on them before hand

royal prairie
#

I think the best you should do here is providing a reproducible sample so the community can inspect to better understand your case and your claims.

hollow dragon
#

By the way , RequireForUpdate<...> doesn't show up in the final generated code . Job calls either. Why's that?

#

Is it needed, really, if we already did SystemAPI.GetSingleton in OnUpdate?

tepid quest
hollow dragon
#

Because that's the point of all of this...

tepid quest
#

That part is actually bit more complicated

#

but only a bit

hollow dragon
tepid quest
#

not really

#

GetSingleton returns copy

#

so changes to copy will only remain on copy

hollow dragon
#

That's what I'm saying...

#

In that case you have to use GetSingletonRW!

tepid quest
#

but you can actually use that lookup

tepid quest
#

it's a pointer, which aren't allowed unless they are a valid native container

hollow dragon
#

Ah. taht's the bit that I don't know about. I'm not that fluent with ECS, and I haven't created my codebase myself, so I'm working with other people's code

tepid quest
hollow dragon
#

ok. So how do you change a value type on the singleton then?. Maybe that's unrelated to this thread.

tepid quest
#

SystemAPI.GetSingletonEntity
SystemAPI.GetComponentLookup is what you'd need to obtain both

#

but I personally prefer to just create NativeReference instead

#

and put it alongside other singleton native collections

somber parcel
tepid quest
#

so you had to disable safety to fit, thus not having any safety whatsoever for that singleton and never knowing if you actually have a problem

somber parcel
#

fair, makes sense

hollow dragon
#

Hey guys. Bringing up this again with a simple example.
Surprisingly enough I'm still confused.

I want NO sync points. I want to jobify this system completely and I'm not able to do it.

How would you completely jobify this? I tried using EntityQuery with the singleton, but anything I do I'm forced to use RW which, as you guys said, needs a mandatory CompleteBeforeRW.
It's funny I still don't know how to do this simple thing with singletons. Just update the value type of the singleton by 1.

#

`using EM.DOTS.Components;
using EM.DOTS.EcsStructure.Attributes;
using EM.GameUtils;
using EM.Systems.Groups;
using Unity.Burst;
using Unity.Entities;
using Unity.Jobs;

namespace MyNamespace
{
[UpdateInGroup(typeof(MyGroup)), OrderFirst = true)]
public partial struct IncreaseSimFrame : ISystem
{
[BurstCompile]
public void OnCreate(ref SystemState state)
{
state.EntityManager.CreateSingleton(new CurrentSimFrame { simFrame = -1 });
}

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        state.EntityManager.CompleteDependencyBeforeRW<CurrentSimFrame>();

        ref var currentSimFrame = ref SystemAPI.GetSingletonRW<CurrentSimFrame>().ValueRW;
        var newSimTick = currentSimFrame.simTick + 1;
        
        SystemAPI.SetSingleton(new CurrentSimFrame
        {
            simFrame = currentSimFrame.simFrame + 1,
        });
    }
}

}`

#

Apart from that, is this version correct? I don't see any difference between using Complete or not.

tepid quest
#

kinda same as Time

#

state.EntityManager.CompleteDependencyBeforeRW<CurrentSimFrame>(); in short - just don't call this

hollow dragon
# tepid quest kinda same as `Time`

OK, got it. But how would you jobify this?. How can I SET SINGLETON without using RW? It does ValueRW = Something else, so I need to do that inside the Job without SystemAPI, ....so I need to use GetSingletonRW, and since you guys told me it is mandatory to call Complete if you use RW at any point (which I'm not sure yet about it because I've seen code here that uses RW and doesn't complete).... how am I going to do any of this on a job?

tepid quest
#

besides it is not mandatory to call complete on anything

#

assuming you never schedule job that accesses CurrentSimFrame from entities - you never need to sync it, because no job ever tries to even read/write it

#

and simply a field with this CurrentSimFrame in a job - is just a copy assigned on main thread

somber parcel
#

but then everywhere else that gets the singleton needs to either complete the query or schedule a job just to get the singleton, which would just be slower and more messy

#

Which is why it's easier to just have IncreaseSimFrame "own" the singleton, and pass it into a job as a value. So let's say you have something like this:

    [UpdateInGroup(typeof(MyGroup)), OrderFirst = true)]
    public partial struct IncreaseSimFrame : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.EntityManager.CreateSingleton(new CurrentSimFrame { simFrame = -1 });
        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            ref var currentSimFrame = ref SystemAPI.GetSingletonRW<CurrentSimFrame>().ValueRW;
            currentSimFrame.simFrame++;
        }
    }

    [UpdateInGroup(typeof(MyGroup)))]
    public partial struct SomeOtherSystem : ISystem
    {
        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            var currSimFrame = SystemAPI.GetSingleton<CurrentSimFrame>();
            state.Dependency = new MagicJob(){
                CurrentSimFrame = currSimFrame;
            }
        }
    }
}

The reason you wouldn't need to call CompleteDependency here is two-fold:

  1. You never schedule a job that has CurrentSimFrame as the type of entity it loops over
  2. CurrentSimFrame is a pure struct without any reference types in it like NativeArray

The second being the most important, because there's no reference types in it, the job will get a copy of CurrentSimFrame as it was when the job was scheduled. That means that even if IncreaseSimFrame runs again before the job started or while the job is running, the job won't be reading the new value of IncreaseSimFrame.

And because of this, CompleteBeforeRW would probably not even create a sync point, since no jobs actually have a dependency on it.

tepid quest
#

GetSingletonRW does not sync

#

.ValueRW only makes a safety check for any jobs that access safety handle (the same one shared with ComponentTypeHandle or ComponentLookup of same type)

#

so if you were using IJE or any of mentioned lookup/handles - it would throw, but since nothing herer actually does it - it's not

somber parcel
tepid quest
#

you call GetSingleton in that system - it registers component type to system

#

so state.Dependency will have it

#

so if you were to call CompleteDependencyBeforeRW - MagicJob will be part of it

somber parcel
#

hmm, let me test

somber parcel
#

Yup, you're right. It tags all jobs in the system as having it as a dependency, interesting. So if a job was scheduled inside IncreaseSimFrame then that would also need to complete before MagicJob gets to start, no matter if CompleteDependency is called or not

#

I wonder what the best way to have it not care about it for scheduling is then. Maybe SharedStatic specifically being read from within OnUpdate of the system? Though I guess in most scenarios this won't actually be an issue

tepid quest
hollow dragon
# tepid quest why do you want to jobify this?

Because the Dependency of the system will include the change of the value and chain it with the rest, doesn't it?. Otherwise it is executed in...what order and when? The rest of the code uses this a lot.

I'm still really bad at understanding what's the connection between jobs inside sytems and systems dependency. I assume Dependency is just a JobHandle and you need to create a chain of jobs in order. So if I use GetSingletonRW or register the WRITE on this system and I don't jobify it... the rest of the systems that read or write on it execute after this system, then?

#

I'm not sure what happens with main thread code inbetween systems, to be honest.

hollow dragon
hollow dragon
hollow dragon
# somber parcel but then everywhere else that gets the singleton needs to either complete the qu...

agh... ok guys, I'm lost here then. I'm completely confused, again, and this is the tenth time xD ......... To be honest I'm not sure when Complete() is called at all in the ECS world. So if this system is one of the first that is executed, and a lot of jobs and main threaded code use this singleton... what happens if I keep it main thread? Is it executed before? Should I mark the singleton as Written on this system so that the rest are aware of it? I'm so confused...

#

Thanks a lot, btw, for that code

somber parcel
# hollow dragon agh... ok guys, I'm lost here then. I'm completely confused, again, and this is ...

If the system that writes to the singleton is set to run before all other systems that use the singleton, then:

  • If you call CompleteDependencyBeforeRW then all jobs from the previous frame that use the singleton will be forced to complete before that call finishes.
  • If you don't call CompleteDependencyBeforeRW then the system doesn't affect previously scheduled jobs
  • If you have a job in the system that has a RW dependency then all jobs from the previous frame will be forced to finish before that job starts.

Previous frame here meaning last time the systemgroup was run. If the system group runs multiple times in a single "update" then each time it runs counts as a frame. And if you put the system that modifies the singleton at the end of the systemgroup then it follows the same logic, but with jobs in the same frame instead

tepid quest
#

and reading copy of component inside job is not something that needs a sync point

hollow dragon
tepid quest
somber parcel
#

You can also check with the timeline view in the profiler to get an idea of how well your program parallelizes

hollow dragon
#

Hey guys! 🙂

@tepid quest Sorry for pinging you. just FYI, passing GetSingletonRW() or ValueRW/RO directly to a job can be done without any additional change. It works. You were not sure about it.

So after a lot of discussion with my team, they told me to remove the "hacks" adding GetComponentLookup on OnCreate. Seems like it's not needed at all and I have to restore all the GetSingletonRWs everywhere.
So the summary for me is this:

Normal Singletons with only Value Types

  • Main Threaded code: GetSingleton (copy) for read, SetSingleton (replace) for writing. If the singleton was passed to jobs in systems before, use CompleteBeforeRO or RW.

  • Jobified code: Pass GetSingleton for read, pass GetSingletonRW.ValueRW to the jobs so we mimic what SetSingleton does inside of them (ValueRW = other instance)

Singletons with Native Containers

  • Main Threaded code: same as normal but taking care of those NativeArrays and completing if there were jobs before.

  • Jobified code: Pass GetSingleton if we only read. Pass GetSingletonRW.ValueRW if we write on them so that is is registered as RW.

No need for any hack whatsoever. Is that still (add GetComponentLookup or such on OnCreate, then use GetSingleton)
Anything wrong here?

tepid quest
hollow dragon
#

It doesn't. But GetSingletonRW().ValueRW doesn't return RefRW. But you can pass both.

somber parcel
hollow dragon
#

Is that ok? Is any hack needed for that?

#

Why is that hack needed and people keep mentioning it while it makes no sense to do it anymore? (Imho)

hollow dragon
tepid quest
somber parcel
#

Yea, that's what I'm on about too. If you're doing this then it copies:

ref var someSingleton = SystemAPI.GetSingletonRW<SomeSingleton>().ValueRW;
state.Dependency = new SomeJob {
  SomeSingleton = someSingleton;
}.Schedule();
hollow dragon
somber parcel
#

If the field inside SomeJob is public SomeSingleton SomeSingleton; then that field isn't a ref

#

Which is fine if you're editing native arrays, but for value types it wouldn't modify the singleton

hollow dragon
hollow dragon
#

What about value types ? (last question)

#

If SetSingleton does SingletonRW.ValueRW = newComponentData
How do I do that inside a job?

tepid quest
#

ref var refVar = ref SystemAPI.GetSingletonRW<SomeSingleton>().ValueRW;
new SomeJob { field = refVar }.Run(); Assume SomeJob writes different value to field 100%
field.Equals(refVar); false

somber parcel
hollow dragon
somber parcel
#

Then you can just pass the full RefRW<SomeSingleton> instead I believe

hollow dragon
#

ok. Well. I haven't tried, maybe it needs an attribute to ignore the unsafety, right? It's void*

somber parcel
#

possibly, but if it's a singular job then then it should be safe since the job is tagged with RW on the singleton and isn't parallel

#

I guess that would technically be true for a job scheduled with .Schedule too

hollow dragon
tepid quest
#

but if ValueRW works, then hacks with GetComponentLookup are probably obsolete

#

I remember when using GetSingletonRW().ValueRW would cause throw because of some safety handle collision

#

but maybe it's no longer a case

#

need to check

hollow dragon
# tepid quest need to check

I finally tested with a simple project and just 2 systems. I pass the RefRW.ValueRW in system 2 after system 1 modifies it and it doesn't do anything wrong. It works modifying the Native Arrays inside the singleton without any problem. So seems like all that hack thing is obsolete, indeed.