#archived-dots
1 messages ยท Page 12 of 1
so a setcomponentdata call on a section entity could then fail if the section isn't fully loaded when its called correct?
when you call load subscene
it gives you an async handle
you need to wait till that is done before doing anything
yeah im in the process of doing that now but issue mentioned it didn't work like that so I just wanted to clarify before I continued
alternatively you shouldn't even do this at all
you should just be doing this with jobs/queries
when the entity exists
the job will run
if not
it won't run
Ah I guess I could make a spawnvehiclesystem that handles this you're right
thank you for the suggestion
Are entities that are part of loading subscene present in a world?
or are they loaded only on last frame of loading?
as in, all at the same time?
They are all loaded at once
I wonder if you can load subscene from build in editor
not as authoring, but as just entities
So one of my auto converted entities has children entities, is there a way to take the root entity and copy it and it will copy all children as well? cause EntityManager.Instantiate just copies the root entity.
Hmm I thought it should work
With linked entity
But tbh I avoid hierarchies so I'm not that familiar with it
Its not a linked entity according to the inspector
there aren't any linked entity components being added when its converted
LinkedEntityGroup buffer
is created during normal conversion for all children in Transform hierarchy
during instantiation of prefab
all entities that belong to that group are copied
ill read into it
but in this case I was able to solve my problem with a mesh combine tool xd
Imagine: IBlobComponent...
Well, a blob ref is just a pointer... Reinterpret as a BlobType** ugh. Disgusting. But it works.
Burst does not like generic double pointers sadly.
why would you ever do that?
do what?
reinterpret as blobassetreference<T> is the next best thing
using a pointer pointer for blobs
A BAR is a pointer itself. By reinterpreting as a pointer pointer, you remove Unity's annoying message of requiring use of a ref to access blob data.
hehe, i see. you can also get the ptr to the blob and save just the ptr. double ptr is performance hell
Shape<Circle>** comes from a ICD containing a single BAR of a Shape<Circle>.
The first pointer is the NA component data. The second pointer is the blob.
yeah funky setup
But it works
in that case all good
Burst throws an error if it's a generic double pointer sadly
i didn't mean it like that. just haven't seen nativearrays with it
A NativeArray<BlobAssetReference<BlobType>> => BlobType**.
The redirection of the second pointer breaks vectorization sadly. It is random access.
What it does is reduce memory usage and increase chunk capacity. I've shaved off nearly 88 bytes (22 floats) from every entity.
you moved those bytes to the blob?
yep
yeah blobs are great for that
Hrm. No difference in performance though. The actual chunk iteration jobs are sub 0.1ms and singlethreaded.
oh nice, my blobs are taking quite the hit. but they are muuuch more than just 22 floats. i'd have to check how much size they take
hm, seems i need internal access to find that out
around 350-500 bytes ๐
You storing a book per entity?
good lord, not per entity ๐ it's my spell definition database
and yeah, it's a shit ton of data
anyone remember this? unity said the want to make some cap on chunk capacity or smth
yes
and still going with 16k chunks? how does this work then when the capacity would be very high? empty chunk space?
it's 128
and imo it's actually somewhat of a problem
i'm hoping that it's only for archetypes with enable bits... but i feel like this won't be the case
128 components per entity?
i remembered the mention about this while looking at my capacities and I'm just not getting it - why? enabled bits might be the best answer. yeah, i also hope this is just for enabled bits archetypes. i'd hate the idea of such an arbitrary cap
Wait, what? Why
One related change we did make for 1.0 is putting an artificial cap of 128 entities per chunk, to simplify and optimize the enabled-bits processing code (128 bits = one 16-byte SIMD register). Previously you could have a chunk capacity as high as 2048 under pathological conditions, but in practice almost every archetype we've seen is already comfortably below the new capacity limit, so we don't expect this to result in too many additional chunks.
where is this?
I guess... I can see the reasoning
dont suppose anyone encountered a physics bug when you destroy physics colliders+joints entities, the physics system does like 10x more work(!) and theres an immediate death spiral?
Death spiral is just fixed step. As for destruction, how are you doing so? Just delete entity?
yeah just destroy entity via entitymanager.destroy. theres a minor step of removing some system state component but I dont understand this at all
Do you know what job is taking so long? I really only know the BVH builder but I'm 99% sure there's no spiral-able issue in their BVH world reconstruction
Possibly if the destroyed entity's AABB somehow persists but 0'ed out. That'll cause the midpoint split to end up in a neverending loop.
it definitely feels like something like that is happening
I swear there are less physics entities in the below profiler than the top ๐ฅฒ
maybe the only wrinkle is that Im relying on LinkedEntityGroup to destroy the ragdoll rather than doing it manually? I dont ever recall getting this before in previous ragdoll experiments but now that Im thinking about it, Im not sure if I ever actually destoyed entity ragdolls before
Possibly. The create contacts job is the one killing your simulation.
My hypothesis is that when you destroy an entity with a LEG, the target entity is destroyed but the linked children persist until the next frame, or end of frame.
During that time, physics attempts to reconstruct a joint but one of the entities are invalid. And it moves forward with the invalid data, resulting in a broken while loop (maybe)
yeah it doesnt last forever but its a good few seconds of terrible performance after the fact before it settles down. definitely gonna need to do some experiments. Im a bit worried it seems the havok guys havent really been active in a while if this is really a bug and not some dumb implementation thing on my part
When you program your own physics engine, all the bug are both your implementation and your fault.
Join me in making it crystal clear who to blame when the physics engine explodes. Roll your own engine.
this is specifically why I didnt write my own engine ๐
my code already explodes enough when using off the shelf parts!
Ha, I think I broke live conversion personally. Thankfully pressing the clear cache is simple enough
this is getting nerdy AF ๐
Using ref, disgusting
You can halve the width of that function by using direct pointer access
You can probably make that generic...
open for input. i looked at generics and datatypes yesterday. wasn't that great, so, wdym?
Just looks like repeated code. Replace the <short>, <half>, <float>, etc with a <T> and you can just copy paste the method name instead of the code.
But for this short of actual code, it's on the edge of worth generifying
T doesn't work for simple data types
and yeah, i'm changing the unsafeUtility methods. figured as I'm using byte ptr and byte index it doesn't work anyway
ref *(float*)((byte*)statChangeValuePtr[statChangeByteIndex]) I guess that isnt much better...
changed it to this
That first line, the short value, wont work.
Adding to a pointer changes the target of the pointer, you still need to pull the actual data out
*((short*)Ptr + Index) (dont need the parenthesis around the second.
(original was better)
oh right, *(short*) should work
Yep, I think you need parenthesis around the Ptr+Idx or else it'll be adding the number index to the short pulled from ptr
yeah, i liked the verbose nature of it but the index gets multiplied by the size of the data type so sadly not an option
Soon, my secret goal of making everyone write c++ will be achieved.
if another c# dev jumps in, or just enzi in 6 months time what version is going to make sense faster to them
yeah, i'm aware. already have that.
because i'm already just looking at it and thinking, wtf you doing mate
i looked at some unsafeUtility method but couldn't find one which is not using a sizeof multiplier
and i'll probably inline method this because you are right. this gets hard to figure out and any slight change will make it explode ๐
I just make everything either a float or int. Easier for everyone that way. Value type switches are just more headaches than it's worth unless you generify everything
eh, most programming task are too easy anyway. need some challenge ๐คฃ
and i'm certainly not mad enough to write my own physics engine
that's for sure!
As you said, it's a challenge. And really makes me think in SIMD. Simple mathematics is too slow. Must do 4 at once.
(i've already done that in flash AS3 ๐ฉ )
Pointer madness.
Having to write unsafe everywhere is not fun
make the top class/struct unsafe. done ๐
So big.
this whole thing turned out to be quite the nice case for codegen. i have to create so many index lookups. doing that by hand. ooff
yep, that's a big one ๐
is this series still relevant with 0.51+ ? https://www.youtube.com/playlist?list=PL-05SQhI5rIYuRbANfxjt7G2C9oFch0al
probably 90%
And the 10% will make you very confused.
Trying to get an idea of the workflow, starting point, etc of dots. I already know how to use burst/jobs quite well so that is not an issue
That's great. Basically, entities are your automatically managed NAs and the IJobs replaced with IJobEntityBatch to get NSlices of the bigger NA.
https://dots-tutorial.moetsi.com/ Since you already have your feet wet, I recommend this up to date tutorial.
It touches basically all aspects of DOTS ecosystem currently. From the basic entity all the way to UI and VR integration.
Alright cool, thankyou. This along with a few other sources is likely what I'll need to get started on porting my multiplayer project to ECS. It's not necessary to use DOTS, but it's going on servers, and reducing the pref cost of each instance running saves money and resources in the long run.
my strong advice is don't port an existing project to entities
if you want performance on an existing project, just stick with jobs + burst
It's getting completely rewritten, but the assets are being reused/modified to work with DOTS
oh if you're writing from scratch then sure ok go ahead
hm, does it make any difference if I add 2 short or 2 half values as long as they are 16 bit? i'm not sure if i can generalize this on bit level or if i should stick to data types
2 shorts are fine. Integer addition doesnt care about bit count. 2 halves definitely not.
that's what i thought. hm, well okay then ๐
You must re-expand the halfs to floats before operating any math on it. Floats have 2 components, the exponent and mantissa, and can not be added like an int.
Unless you want to implement half arithmetic. It's just like floats but halve the bitshifts.
i was expecting var statChangeHalfValue = *(half*) changeValuePtr; ref var tmpHalfValue = ref *(half*) valuePtr; tmpHalfValue += statChangeHalfValue; to fail as I can't find the + operator for it
There's an implicit cast to float.
ok then
Check. Implicit casting is sneaky.
God, I forgot how amazing swizzling is.
It's been too long since I had to hammer out any shaders but burst is keeping me sharp
quick question regarding the dots workflow: is it better than prior to 0.51? I am not a fan of all the boilerplate or custom tools that need to be made first just to do something simple in earlier versions
depends how fast you want your code to be
^
It's easier to use with far less boilerplate if you use the code-generation version but you're not gonna see the maximum burst performance using them
you can still get great performance boosts from burst and easy multi threading from jobs
and will be potentially a lot faster than gamoebjects
but yeah, you won't get max performance without writing it yourself
Rendering honestly is the largest bottleneck. Using the code gen Entities.ForEach or IJobEntity will give you objectively far better performance on a larger scale than GOs.
You just wont get performance to support thousands to tens of thousands simultaneously
So what is the alternative to using the Entities.ForEach/IJobEntity that isn't codegen?
writing the jobs yourself with IJobEntityBatch
that's what all the code gen turns into
oh, so just native Jobs/Burst
Basically
Im kind of bothered that IConvertGameObjectToEntity exists. DOTS workflow should not incorporate the concept of GameObjects
The only link between the two should be the ability to share data, ie; cache value from GameObject, queue job, await computation, apply results (just like normal jobs currently not using entites)
and really the only use as of right now that GOs serve in a DOTS-based project is for UI/ease of use/setup. If unity can cut down on that reliance, DOTS will be much better overall
GOs are the human facing interface.
They're not evil. I've grown to like them quite a lot as an authoring tool despite going completely DOTS with no GOs during play.
GOs in DOTS are just a skin. They're a launching platform for 100s to 1,000s of entities.
This single monobehavior is 24 different components when authored.
Dont think of GO's as good or bad. They're just a well fleshed out inspector tool in DOTS.
I don't hate GOs, I like their ease-of-use and wide range of uses. The bothersome part is that you can take an GameObject, use it as a "template" and create an entity from it. Instead, an entity should be created from some sort of custom entity editor much like the current GO inspector for components etc.
The GO inspector is the custom entity editor.
These GOs wont exist during gameplay. They only exist inside the editor. You ship the entities found in the DOTS Hierarchy.
So if they invented EntityObjects and they existed in scene and could be prefabs and used the exact same inspector that'd be fine?!
Why spend years re-inventing the wheel
No, instead it would be a list/collection of prefab entities you can use that are created using the editor to instantiate during runtime. Since Entities are data-driven, it makes more sense for them to be "prefabs" in a storage sense in the editor project folder. When you need to create a new entity, referencing the entity prefab would be the go-to.
For entites/GameObjects that exist in the scene, Im fine with them technically being GameObjects, but presented to the user they should come with obvious entity restrictions and not this hacky ConvertToEntity script that gets added when the checkbox is selected.
That's called a subscene.
^
Subscenes are DOTS's prefab and authoring tool all in one. You can nest subscenes. You can edit subscenes. You can selectively activate (load) or deactivate them.
DOTS honestly should have it's own editor
you need to watch the 1.0 talk
Watch that. I've gone from a subscene hater to holy shit I cant live without them
unlisted... go figure that is the reason I couldn't find any context about that video
part of their gdc 2022 playlist
I dont know why unity unlists that talk. It's possibly the most solid demonstration of DOTS 1.0 so far.
but yeah it's weird it's unlisted
It singlehandedly re-kindled my hope in DOTS. Being a salty old vet in these coding trenches.
I generally follow development in the forums, so seeing this video is a huge refreshment if it turns out to be what I hope it covers
3mins in and they're using a foreach Query which cleans up the workflow quite a lot IMO
That's the preliminary on-main-thread entities foreach using the IAspect<> Interface coming with 1.0.
If they somehow can extend that to scheduled jobs, that will be fantastic but the foreach IAspect on the mainthread is still nice to see.
GOs are custom editor
Conversion workflow with gos is great
Subscenes make it so no gos make it to the build
Im liking the light humor and the way examples are presented to solving issues. My favorite so far is the ability to manipulate entites and have the changes reflect it edit mode as well (dirty.) I also like that there is now less abstraction between authoring mode, and runtime mode
cool, watched it all and Im liking what Im seeing so far
Great. 1.0 is probably months away so now is a good time to get familiar with the basics of DOTS. It wont change much with 1.0.
(although 2022 LTS is their goal according to the very small blurb at the end of the 2022.2 beta features list)
Got physics working. Only discrete collisions though.
Can't wait for jornal
Journal?
Ability to track structural changes history
Is that not already in entities? I havent used it before
I wasn't able to find anything about using it
yeah you can see a lot of info through debugger now
its great
look at entity field, can look it up in every world
all it's components etc
was such a great addition
bruh
I barely have systembase to attach breakpoint xD
hmmm
Does Rider support journal?
So I have an entity that I am converting from a gameobject. It has one of unities physic authoring scripts. Physics Shape attached. Later after it is converted to an entity and spawned with entitymanager I add a PhysicsVelocity component to it. The moment I do the entities Translation and LW all get NaN as the values. What am I missing?
I suggest you to create entity through authoring and see it yourself in inspector
then create it manually in code
yes
how do you access it?
a good way to see how to use it is turn on break points on exception
I can't find that journal anywhere in debug options
hmm so I am not missing any components. This problem appears to be from copying an entity. If I do not copy the entity and just create a new one the problem doesn't persist. Maybe the colliders are being reused and its causing this not sure, but I know how to fix it now at least.
Maybe the colliders are being reused and its causing this not sure, but I know how to fix it now at least.
collider is definitely re-used
if you want to make something that's static -> dynamic
convert it as a dynamic
and remove the component
it needs to setup a bunch of other stuff
they said sometime during the 2022.2 beta
likely this year imo
have you ensured your translation/rotation (scale?)are correct?
if you'll have invalid rotation
you'll certainly have NaN errors
Yes they are just 0
what do you mean by debug options?
journaling records are automatically attached to the stack of any exception
0,0,0,0 rotation is invalid
its 0 0 0 1
there's no window - you have to break point
They are
yeah, normal breakpoints didn't show
and I had no idea about exceptions
Its cause the colliders being copied so the rigiddbody doesn't know how to behave
but any exception you have from entities should attach journaling info
(turn journaling off and compare)
you can inspect entities in normal break points
oh
that's not really journaling info, but just another very useful feature
Is there a helper method cause I am not finding any info how to do this anywhere
I have this weird exception triggered on entity from subscene (I assume) which is not meant to be destroyed at all
How can I breakpoint this code with journal?
you can see it should be debugging the journal info out for you already
mine literally shows this info in the exception
ArgumentException: The entity does not exist. Entity (190:1) was previously destroyed by Beyond.Environment.Corruption.CorruptionSystem.
or if done via ECB
ArgumentException: The entity does not exist. Entity (190:1) was previously destroyed by Unity.Entities.BeginPresentationEntityCommandBufferSystem. This command was requested from Beyond.Environment.Corruption.CorruptionSystem.
this is from journaling
Does the new input system work in jobs?
yeah, I created generic components for each action
Started<>
Performed<>
Canceled<>
and everytime action is pressed - there's singleton component
with it
bruuuuh
how can I solve this problem?
I have trigger events
which sometimes need to be disabled only for query
which is basically based on write group
private struct JumpInteractionJob : ITriggerEventsJob
{
public EntityCommandBuffer buffer;
[NativeDisableUnsafePtrRestriction] public EntityQuery kek;
public void Execute(TriggerEvent triggerEvent)
{
if (kek.Matches(triggerEvent.EntityA) && kek.Matches(triggerEvent.EntityB))
{
Interact(triggerEvent.EntityA);
Interact(triggerEvent.EntityB);
}
}
private void Interact(in Entity e) { buffer.AddComponent<InteractedTag>(e); }
}
Current implementation doesn't work
because EntityQuery methods aren't allowed in jobs
cast entityquery to entity array and build a hashset
hmm
I wonder if I can do opposite
get all filtered entities
so this way I will have very small hashset
Im getting memory leaks with a super simple test SystemBase that modifies a cube GameObject in a subscene
It seems it has something to do with subscenes
there's a second memory leak error that points to AsyncLoadSceneOperation.cs
nvm, I forgot the subscene had the ConvertToEntity enabled... ๐
weird how that checkbox exists in the first place.
it's ignored afaik
in subscene
Ignored as in it shouldn't be used?
yeah it doesnt make much sense to convert the subscene itself
internally the subscene is a GameObject, so that's why it's showing up in the first place (and also why it can actually convert a subscene, but not without errors)
they use some kind of hooks
to inject subscenes into world
they are not meant to be converted through normal interface
Yeah I was messing around last night and left that checked... forgot to uncheck it and I remembered the error I had last night was because of it ๐
is EntityManager usable inside of a burstified job? or at least a normal job? The docs claim you cant, but source code says otherwise
no
I was thinking about a similar idea the other day. How's it working for you? I assume you are relying heavily on RequireSingletonForUpdate which is why you went the singleton route.
yeah, I do rely on singleton for updates
works out fine, since it's literally same thing as
normal calls
from new input system
the only thing that bothers me is that it can be codegened
into a very nice wrapper
which generates all components manually, creates system that registers for all callbacks
and etc
Yeah, I guess I'm wondering if its worth splitting input into one component per action like that. I use a single big component for all my input right now. I can definitely see the benefits of the more granular approach, but wasn't sure if it was overkill.
codegened from an ActionMap?
yeah
you have list of actions
you generate tags for buttons
special components for values
so for example if you want to generate that for moving mouse, which gives Vector2 value
you simply make such component
literally same as OOP new input system
and fully burstable
potentially
it can be even improved more
by creating single system to handle all of them
yeah sounds like a nice setup. Wonder if unity will provide a better way to work with input in dots
Do you mean a single system for populating the tags and components, also codegened?
I already have single system
which is hand written atm
and looks horrible to manage
it simply resets archetype of input entity
yeah same for me, but all editing the same component instead of one per input event
so all input components are gone
meanwhile adding components to that entity is done by new input system callbacks
By new input system callbacks do you mean the codegened c# interface that looks like OnMyInput(InputAction.CallbackContext context)?
yeah
I haven't really dug into how new input system works outside of that
so potentially can be made even faster
yeah that's what I'm using too. Thought it has been around for a while so making sure I didn't miss some new thing there
I'm still using the old input system. I have that control system wired from years back in my first unity project and it works even today
old input system is not that cool with custom bindings to centralized actions
WASD, the only bindings you ever need
what if user wants ESDF?
or uses gamepad
sucks to be them
there's really nothing more that i hate more and that's html and css. say hello to ui toolkit
they're deliberately making it HTML and CSS because that's what game UI designers are familiar with
i can't even make this dropdown and textfield in 2 columns and i made the froggy flex tutorial a few times. ...ugh
webdev hacks are everywhere
flex is at least better thand oldschool css. doesn't help when theui builder is just weird
(I'm fat fingering on mobile again.)
i'm sure if i get around it, it'll be great. much better than the old way of building editor ui
anyone has experience in ui toolkit for editor ui? there's some controls but i don't know how to style them. everything's greyed out
like the textfield. can't make the label smaller
Might be better off asking in #๐งฐโui-toolkit
I only played with it to render text and such, not actually build a UI
can probably just give it some classes
yep, custom selector .my-text-field > .unity-base-field__label - this UI builder is very unintuitive. i had to find out now that min-width of this label is set to 150px. doesn't really show me. shame, hope this gets better. it also says when hovering over some class. double click to create selector but nothing is happening. you have to type it in ๐
is it still RenderMesh we use to draw 2d sprites?
nah, 2d is drawn through hybrid go
oh okay i was about to add the hybrid v2 thingy and universal RP, is that needed
and ig this would be able to fix my problem with mesh and material being a managed type cuz hybrid go is non-burstable anyway
unless you implement your own renderer yeah
Best way to get a specific entity? Such as the local player that is in the same chunk of NPCs/other players.
or should the local player(s) be tagged to separate it
var packedEnablerCounts = enablerCounts.Reinterpret<int4>();
for (int j = 0; j < enablerCounts.Length; j++)
{
bool valid = packedEnablerCounts[j] > new int4(0,0,0,0);
}```
how could i do something like this?
i want that bool4 to be turned into a bool "valid" that is true if all evaluations of the bool4 are true.
math.all
if you handle that local player seperately in a lot of ways id say it makes sense to have a tag.
thanks! im not very familiar with element wise operations on vectors. that saved me a ton of time
yeah np. math has a LOT of cool features that I wish the normal Mathf library had
this starts to look like something
tutorials are all over the place for ui toolkit. some make it harder than it actually is
Is my only option to use a job to evaluate the values of the entity(s) before passing it off to the HUD? Example: health value for each local player (split screen)
Entities.ForEach doesn't have an ability to await it like .Complete() for jobs, so parsing data is not possible.
Entities.ForEach returns a jobhandle. you can .Complete() that. It is the same as with jobs
i dont know how other people are getting their data to UI but i use unbursted Systems to write to monobehaviour world. im not using UI Toolkit for runtime yet
No it doesn't, the only type that is returned is a ForEachLambdaJobDescription
ah well it only does if you use .Schedule() or ScheduleParallel()
else there is no reason to await since its synchronous with .Run
That's what I'm using. Can you provide a snippet of it returning the JobHandle ?
{
})
.Schedule(Dependency);```
Where Dependency is the Systems Dependency jobhandle.
^ if you don't pass in a handle it's handled for you via code gen
Is you pass in a handle it'll return a handle and you can manage it yourself
Ok thanks I think that will work, but I think im going to stick to using jobs instead of using ForEach. Too many restrictions that shouldn't exist atm
yep
var packedEnablerCounts = enablerCounts.AsNativeArray().Reinterpret<int4>();
for (int j = 0; j < enablerCounts.Length; j++)
{
var isValid = math.all(packedEnablerCounts[j] > new int4(0, 0, 0, 0));
var didChange = possibilities[j].valid != isValid;
possibilities[j] = new Possibility
{
valid = isValid
};
if (didChange)
{
//do some expensive stuff
}
}```
how should i go about getting rid of that branch at the bottom to make that loop SIMD compatible?
write to a didChangeArray and do an extra loop over that outside of this faster loop?
That would be faster yes. The isValid is converted from a 4-wide bool4, so it already breaks SIMD vector intrinsics
ok my physics performance woes were due to an extra PhysicsStep(didnt realize had two). two will annihilate performance in certain scenarios(but not all apparently)
so id have to first create an bool4 isValid in a SIMDed Loop and then in another do the reduction to bool isValid? that second loop must be able to use SIMD too somehow right?
thats the physics deathspiral Tertle talks about alot. with standard settings going below 60fps guarantees a bad time
imo it should error having more than one PhysicsStep to protect dummies like me, but it only manifested under certain obscure circumstances, enabling a ragdoll one way but not another. ๐คทโโ๏ธ
you can only really make the top vectorized. the bottom would require another loop. something that could work, would be to use left shift (math.compress) and tzcnt to count the number that can be skipped. having said that, i don't think this will be worth it much if this runs every frame anyway. just let it branch. the expensive part will probably still be scalar so you can make only ns improvements with the intro
@robust scaffold might have some better ideas
its not a performance bottleneck atm. i just thought the datalayout fits perfectly here to try to learn some easy SIMD. gotta start somewhere
i do have some other places where SIMD should actually do alot for performance but those im not touching right now ๐
try it, i also think skipping is a nice way to utilize some simd
first time i hear about skipping. so give me some time to google it ๐
Huh, depends on what you're trying to do
Early returns and code skips are great but it really depends on what you're trying to do.
i need to message neighborcells of this cell running the code about changes to the possibility array. Changes to possibilities can only occur if in all 4 directions (the int4) the enabler count is positive.
So you want to run // do some expensive stuff only if packedEnablerCounts[j] has values other than 0?
yes AND if possibilities[j].valid was also false before.
Does the expensive stuff depend on the specific value in PEC[j] and return a int4?
no. its something like Get the neighbor cell from Grid and a struct containing the changed PossibilityIndex ( j ) to a dynamic buffer
If the expensive stuff computes only a single float or int, you're gonna be hard pressed to SIMD it
This looks like a simple bit check
Instead of an if (int4 > int4.zero), try instead just a byte and then toggle on bit flags.
Not everything needs to be SIMD with SOA format.
The code blurb I just posted above calculates the maximum distance out of 4 points simultaneously using SIMD. That's a easy situation to SIMD. If you're just using a flag check, you dont need a math.all()
Use a byte and save chunk memory.
hmm sry i dont think i understood it. i just dont know the tools i have to my disposal at all. its so hard to find good learning resources on it
Im pretty sure the top still wont work:
public void Execute () {
for (int i = 0; i < 100; i++) {
Unity.Burst.CompilerServices.Loop.ExpectVectorized();
bool changed = math.all(vals[i] > int4.zero);
if (changed) results[i] = vals[i];
}
}
that's expecting loop unrolling and something very different. automatic loop unrolling will never work with scalar branches
What values do you expect packedEnablerCounts[j] to be?
Expect vectorized is very basic. Look at the burst inspector to tell if it's really vectorized. Look for VP operations.
Is there an alternative to the automatic loop unrolling? I've been really wanting more control over how a loop gets vectorzied... but never looked into it
There's manual unrolling. But it is painful and I do not recommend.
that depends on the TileRuleset of the WaveFunctionCollapse. id practically expect not more than 10k
You can probably help burst by instead doing: results[i] = math.select(results[i], vals[i], math.all(vals[i] > int4.zero))
I would imagine a WFC algo can be SIMD'ed since I've seen compute shaders generate them as well. But short of giving me a code snippet, all I can say is that doing so is not for the faint of heart.
as far as i understood it the compute shader versions have to do alot more work due to the parallelization. They calculate every tile every frame. Im doing a version where i do have parallel propagation without the need to update everything
its not good for my heart thats true
well, in a performance-critical environment it can matter (especially since I have a library that aims for the most absolute top performance possible using burst.) Got any sources on how to force Burst to acknowledge the manual unrolling?
I dont know the specifics of the algo but it should be possible.
Manual unrolling is called writing the assembly by hand. Reinterpret your NAs to v256 and write out all the VP operations manually.
Let me tell you, I took a shot at doing this by hand for a sweep and clear algo on a tree and, while it worked, manual vectorization means having to manually support all instruction sets.
That article describes manual vectorization for Neon, which is AMD chips. The code wont work on Intel for example. You'll need to write out the intel intrinsics as well. And if you want to support mobile, those as well.
Oh screw that im not writing manual assembly. I was hoping it was just some unity limbo you had to go through :/
Work with burst, not against. Vectorization means working with float4s or straight floats.
the "old" naive brutefore way of wfc would benefit alot from SIMD im sure.
the newer more performant way generates lookup datastructures before the actual algo starts. you dont have to (or cant) loop linerally over arrays alot actually.
reading up on WFC, from my initial impression, you can probably calculate the entropy on the four neighboring tiles simultaneously using SIMD then collapse the wavefunction using math.cmin() to select the minimum and left pack / compress to conduct logic using the lowest entropy.
The lowest entropy probably cant be done in SIMD unless you're gonna use SIMD first to obtain lowest neighboring entropy and write back to the source array and a second pass that operates on 4 tiles at once to calculate the resulting tile.
you are mixing the collapse with the propagation step though. for collapse you take the global lowest entropy cell. you never need to calculate the lowest entropy of neighbors
This is just from some random article on the topic. I imagine you know the specifics.
but you are not wrong in that the entropy can be done in parallel. there is actually only one really good article i found on WFC that explains the overlapping model combined with the performance improvements. the other articles simplify quite alot. if you are curious : https://www.gridbugs.org/wave-function-collapse/
(Edit 2022-05-03: I found out that the Wave Function Collapse algorithm was heavily inspired by an existing algorithm called "Model Synthesis". I've added a section to further reading with links to the author's website for more information.) Wave Function Collapse is a procedural generation algorithm which produces images by arranging a collecti...
Hrm yea. Seems right.
im still intruiged about the math.compress and tzcnt @viral sonnet mentioned
what does the compress do with an int4?
so it packs every int4 that is 0 to the right of the array?
This is my usage of compress to obtain overlapping AABBs when querying a BVH tree for broadphase physics.
The first compress uses a bool mask of 4 possible leaves containing entities and left packs a compIdx and compDat (name of an arrays of ints) of the two halves of an entity struct.
ah so the bool4 defines which ones are packed left i see
and that enables me to avoid branching because i can just sort everything i want to skip to the end?
Yes. But make sure this is appropriate for the math and logic you want to use.
I'm left packing / sorting in order to obtain all possible overlaps from a quadtree like node array that I then pass into a narrowphase system.
It might be more efficient, depending on your math, to just integrate the mathematics into this system and skip the use of compress
you have the bool4 mask. You can just zero out portions that are not masked.
in the comments it says its useful for building intersections. atm i am using hashsets to build intersections between dynamic buffers in my AI. is there a much more efficient way with compress?
ah nvm. they would need to be in the same order right?
Hashsets obtains uniques. Compress obtains equals. So they're two complete different systems
i learned a lot again. thank you! ill head off to bed for now and ponder over how i will never get to use all those fancy tools ๐
is there any difference between doing:
RequireForUpdate(GetEntityQuery(ComponentType.ReadOnly<MyComponent>()));
and:
{
All = new ComponentType[] { typeof(MyComponent) }
}));
nope, no difference.
wait
All = new ComponentType[] { typeof(MyComponent) } translates to RequireForUpdate(GetEntityQuery(typeof(MyComponent)));
All does not imply readonly
you must also ComponentType.ReadOnly<MyComponent>() inside the all array
typeof is read write
Any and none querys.
I rarely use the inline ones since I have so many any queries.
right yeah
Although I hate to say it but I think my physics is hot garbage, damn. Well that was a great learning session. I'm gonna go back to old monobehaviors.
It works, kinda, it's more efficient than unity's by miles due to SIMD and burst everywhere but it just doesnt have the same stability as box2d and I really dont know how
I need continual collision detection for substep collisions.
or else it just penetrates into objects and bounces off violently
ugh, it works fine enough. and it's deterministic because it's all in burst (or at least as deterministic as DOTS physics is)
onto other things, i spent enough weeks on this already
i guess you could always go back to it with a fresh approach at a later point
Box2D is open source, just way beyond my current ability to replicate in SIMD though
why did unity stop 2d dots. I mean, I know why, money, but i am very sad
yeah i do wonder if they'll pick that up later, it seems a no brainer to leverage dots in that area
is the order of entities in a chunk deterministic? If it's not, is there any way I can define the order? I need the entity index to be consistent on both the server and client because I do not want to make the operation an O(n^2)
If you do not use any shared components, I think so. Dont quote me on this but nothing in the entity manager uses floats and integer operations are cross platform deterministic.
Even without burst. Integer math is deterministic. The second you add floats into it, not anymore.
Not too concerned with determinism of floats, just that the entities on the server and client have the same memory layout so I can do something like: clientPlayer[0].someValue = serverPlayer[0].someValue and not worry about modifying the wrong player/entity/etc
That might be an issue with network latency though. If a structural change occurs and the client doesnt replicate it in time, this will not be valid.
I think you're miss-understanding my question
Memory layout is not an issue though. It's 16kb of linearly allocated memory blocks per chunk.
entities itself is deterministic as far as i'm aware
if there is no structural changes, that section of code will be valid.
same with components or nah?
chunks is entities
but your client might not be the same as your server
you can have different entities on each
and the time things spawn might differ due to network conditions
but if you create things in the same order in different sessions on the server
the chunk layout will be identical
alright thanks
aw damn! but yeah, i know what you're talking about. as mentioned i wrote a physics engine in AS3 because we needed a very specific web demo and concave colliding. most was straight forward but then stability issues hit and i spent weeks full of tweaking on it. that's honestly where writing a physics engine stops being fun. so yeah, if you have a fallback model, go for that, for the sake of productivity. but revisit it some time later. i think it's worth it what you started.
Yea. And I think my BVH builder and broad/narrowphase is superior to unity's personally. But beyond that and the actual collision interactions, not so much.
I'm keeping my BVH though. Pinnacle of my coding right now.
that shit takes a lot of patience and time to get right
box2d is the default for unity 2d physics?
Yea
and dots physics is not an option?
3d locked Z axis has terrible top down stability
anyone knows how i can trigger source generatos before i google? ๐ i actually need the source gen to read a json file
Source gens run every time the code recompiles. Which is why having too many gets really chunky
in case the json doesn't work out i need to go in a roundabout way :/
It should work... should
hm, if not, i can just write the code file myself from a template. it's not that complicated, just a bunch of indices that are a pain to write
yep, no need for ISourceGenerator
are you able to read values from a referene type stored in ISharedComponentData in a parallel job?
not in a burst job
but technically yes
i wrote a SharedComponentDataFromIndex<T> that let's you do this
hmm, I found like 5 different ways to deal "use" animation curves in dots. All of them are way too memory heavy. So I thought about using ISharedComponentData since most of the entities will be sharing this data
why are they anymore heavy than a shared component?
if the animation curve is shared between multiple assets
just use a blob to store it
interesting ok, that will make sure the memory isn't duplicated ig? ima go read up on this
if I make a blob asset then pass it to components doesn't it just make a copy of the it since its a valuetype?
nvm this is what blobassetreference is ig
is it possible to create an authoring component for blobassetreference?
i tried but ig it doesnt' work cause the pointers shift when you enter play mode idk?
if you're feeling mildly adventurous @timber ivy you can just copypaste the Animation.Curve blobasset from the Unity.Animation package, it should have conversion in there as well
I thought about doing the same from unity.timeline.dots
they have animation curves in there too
that are dots compatible
Itโs most likely the same one. Wonder whatโs going on with that package
You can
Blob assets are saved in subscenes
And references are remapped correctly by Unity
During loading
Ok yeah it works if you do it in one of the conversion systems
but if you try to do it from an editor script it doesn't seem to work
I litterally copied my code from a custom editor window to a GameObjectConversionSystem and the blob reference worked
wasn't working in my custom editor window
I don't really understand what you're doing
oh i see what the problem was. Its is because blobassetreference isn't serializable
We'll, not really
It is serializable, just like entity
But
It requires remapping
Because otherwise during load it's invalid
They use some kind of memory offset approach for blobs that makes it possible
how do i convert Matrix4x4 to float4x4 ?
vertices[i] = vertexMatrix.MultiplyPoint3x4(v);
normals[i] = vertexMatrix.MultiplyVector(n);
where v and n are Vector3
float4x4 f = m;```
(float4x4)yourmatrix;
it has an implicit cast
tried math.mul but there is nothing for float4x4 and float3
will entities foreach work on gameobjects and monobehaviors?
no, but they work on entities with monobehaviours
Entities with monobehaviors?
yeah, you can add managed objects
oh so I can attach a camera to an entity for example?
yeah, that's pretty much how camera conversion works
so how do you do this?
if you want to go with this approach, I suggest you to make conversion system
dstManager.AddComponentObject(entity, object);
oh awesome thanks!
keep in mind, it'll keep actual game object around
and the downsides are ofc can only be ran without burst and on the main thread
any other?
what does error say?
it's slow, it's managed, it might not work very well if companion link system doesn't catch up
for built in types
like SpriteRenderer
it automatically creates gameobject clone
with same spriterenderer settings
for other monobehaviours
"wont catch up" Hmm does this mean I will have trouble making a camera smoothly follow an entity then?
I'm not sure if it will work the same every time
no it means, that potentially your camera attached to entity might be literally new Camera()
i can however do the following , so i could cast vec3 to flaot4 , any ideas which one is the correct way ( would the matrix be the 1st or the 2nd argument ) ?
ah yikes
looks like your matrix multiplication is simply incorrect
the first line is what im trying to replicate
or rather im trying to figure out how to write it using Unity.Mathematics
yep
hence the float4
any ideas which one is the correct way ( would the matrix be the 1st or the 2nd argument ) ?
so if u put float4 on the LHS the result would also have a single row
well, you can literally see the return type
of your math.mul
after you assigned parameters
both return float4 lol
so im guessing the vector is on the LHS
var result = math.mul( ( float4 ) vec3 , (float4x4) matrix ).xyz ;
gonna try something like that
i wonder would it be worth it
is Matrix4x4 is burst compatible ?
well this is the closest i got
from :
vertices[i] = vertexMatrix.MultiplyPoint3x4(v);
normals[i] = vertexMatrix.MultiplyVector(n).normalized;
to :
vertices[i] = math.mul( ( float4x4 ) vertexMatrix, new float4( v, 0 ) ).xyz;
normals[i] = math.normalize( math.mul( new float4( n, 0 ), ( float4x4 ) vertexMatrix ).xyz );
for the vert , the input is M4x4 x Vec , for the norm the input Vec x M4x4
however the math . mul doesn't not preserve position
Does the position of the game object automatically get synced to the position of the entity?
yes, it's built in
companion link
system
alright cool thank you!
hmmm, anyone remembers how to make command buffer for ISystem?
that can be played back multiple times
ah, nvm
/// <summary>
/// The <see cref="EntityCommandBuffer"/> can be played back more than once.
/// </summary>
/// <remarks>Even though the EntityCommandBuffer can be played back more than once, no commands can be added after the first playback.</remarks>
MultiPlayback
ooo i'm super interested what your use case is
i've never really found a good use for it
delayed component adding
but I was able to resolve it with other tools
like system groups and ordering
but tbh
I could use ECB in many other systems
which are for no reason managed rn
after all you can schedule jobs in ISystem
btw, I figured an interseting option
This isn't happening for me.
i attached a CameraComponentAuthoring script to the main camera in the scene. The authoring component is just autogenerated from this
[GenerateAuthoringComponent]
public struct CameraComponent : IComponentData
{
public float smoothTime;
public Entity observable;
public float3 offset;
public Vector3 velocity;
}
when the entity is created it looks like the pic below. However when I update the values of the translation component the cameras gameobject doesn't follow
I want to make helper method to get ref of actual ComponentData
so instead of doing double em call for GetComponentData and then SetComponentData
I could just do GetComponentDataReference
with ref value as return
doesn't look like you have companion link
I have been thinking about this as well but wasn't sure it would work
I think you need special compiler declaration
Im trying to get a subscene's entities in a SystemBase but having trouble finding info on how to do that. Thoughts?
HYBRID_ENTITIES_CAMERA_CONVERSION
Ah that explains why I can't manually add it
add this to Player options
awesome thank you!
that's not really meant to be done, what exactly are you trying to do?
can I just remove the main camera tag from the camera or do I need 2 cameras in the scene
Trying to get a chunk but it requires an entity
just try it with main
and see how it works first
maybe you won't need any special treatment at all
yeah if you remove main camera tag it wont have issues
but i think srp needs one
it still works btw on main camera
you might just get oddities in editor
like camera starting in wrong position when entering the game
as far as i'm aware these are editor only issues
and if you aren't lerping camera you probably won't notice anyway
EntityManager.GetChunk(Entity) doesn't specify any other parameters other-than Entity so idk what you mean by "what kind of chunk"
well yeah, because it gives you chunk where this exact entity is stored
why do you need it?
just query for the subscene?
trying to get info from a specific entity
specifically for UI purposes
but using GOs
well, that's not really supported so you'd need hacky ways to make it work
if it's UI related
why not just store data in GO
this way you can get reference to it with Object.FindObjectOfType<>()
you're telling me I can write to an entity, but I cannot read for it to be used elsewhere?
when you store entity in subscene
that means you store it in large chunk of serialized data which is not loaded during world creation
so in order to get data from subscene in System you either will have to do it on every frame
or in OnStartRunning
which will require you to implement some algorithm to ensure it only loads it once (assuming it's important)
so that's why it's all hacky
and rather be done differently
that didn't sound like their problem
what's stopping you querying this entity?
trying to get info from a specific entity
I assume he just stored settings for smth in here
query sounds like an overkill for that kind of purpose
allthough, completely ok
if it's some kind of true ECS UI interface
these are networked entites so storing the context of their UI on a GO isn't really ideal. Would rather just read the entity and copy the data to the UI
well then
RequireSingletonForUpdate<YourEntityComp>();
and then in OnStartRunning
GetSingleton<YourEntityComp>();
and do all your work in on start running
but that would be called every single time there's such entity added to world when it didn't exist previously
correct me if i'm wrong, but the problem sounded like extevious wants to get a specific entity and write it's data to the UI
not query a UI entity
var ptr = access->EntityComponentStore->GetComponentDataRawRW(entity, typeIndex);
Hmm
can I somehow cast ptr to ref T?
public static unsafe ref T GetComponentReference<T>(this EntityManager em, in Entity entity)
where T : struct, IComponentData
{
var access = em.GetCheckedEntityDataAccess();
var typeIndex = TypeManager.GetTypeIndex<T>();
access->EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);
access->EntityComponentStore->AssertNotZeroSizedComponent(typeIndex);
if (!access->IsInExclusiveTransaction)
access->DependencyManager->CompleteWriteDependency(typeIndex);
var ptr = access->EntityComponentStore->GetComponentDataRawRW(entity, typeIndex);
}
[BurstCompatible(GenericTypeArguments = new[] { typeof(BurstCompatibleComponentData) })]
public static unsafe ref T GetComponentReference<T>(this EntityManager em, in Entity entity)
where T : unmanaged, IComponentData
{
var access = em.GetCheckedEntityDataAccess();
var typeIndex = TypeManager.GetTypeIndex<T>();
access->EntityComponentStore->AssertEntityHasComponent(entity, typeIndex);
access->EntityComponentStore->AssertNotZeroSizedComponent(typeIndex);
if (!access->IsInExclusiveTransaction)
access->DependencyManager->CompleteWriteDependency(typeIndex);
var ptr = access->EntityComponentStore->GetComponentDataRawRW(entity, typeIndex);
var structure = (T*)ptr;
return ref *structure;
}
hmmm
let's see if it'll work
oh well
it's not even crashing
๐
you can shorten that last line to: return ref *(T*)ptr;
yeah, that's really interesting thing
just gotta remember
that structural changes invalidate it
oof how to debug without burst when burst is actually required to get any kind of performance? if i disable burst i need to wait minutes until i run into the error i wanna debug lol. with burst its seconds...
hmm any idea if its possible in rider?
I haven't been able to get it to work
I can hook riders native debugger up to native code run by unity but not burst
For some reason
how do you hook VS?
:/
im using vecctor3.smoothdamp so basically same thing
Quaternion.LookRotation
is there something similar to this in the math/collections library?
yeah works fine with main camera for now thanks
quaternion.LookRotation
Do I have to do something speicial to set the rotation of a rigidbody in unity.physics? in vanilla physics it just works
in unity physics with dots they are fighting each other
They call them different things like physics body and rigidtransform
But it's the same thing
Wait. Since I uninstalled entities, I can move to 2022.2... IM FREE
Yea. Went back to trusty pile of NA.
Do you guys separate Data, Authoring & System in separate files ?
I would have thought this was a good practice, but my code base is growing and I'm starting to find it annoying. I hesitate to put everything in one file.
I'm handing out raw pointers to everything and I want them to still be valid if I structural change
Three folders: Authoring conversion, components, and system files.
Files yes, folders no
usually I keep mechanics together
That's what I'm doing right now, "convention" oop, but I don't see much benefit in it.
My components are often a dozen lines or less but I have a lot of them. My authoring is quite large but one off and conglomerates (all the components for entities get added in one authoring system). My systems one per job
This is perhaps the only thing that motivates me to keep doing it, as some Data structures are very small.
I mean, you structure your project however you like. There is no set rules for this
"Just drop everything in /Scripts folder and it's fine"
That's what I do for in progress mechanics. Then I rename scripts to whatever it actually is, add an assembly def file, and create a new scripts folder
it's fine
Speaking of assembly def, Is there a faster way to add dependencies? It's a bit messy at the moment.
Manually adding them one by one until the scripts stop throwing errors about missing namespace is basically the way to do kt
It's a pain ๐
Keep your dependencies low and use the least amount of packages as possible and it's less amount of pain
Especially since sometimes the addiction is not very explicit, I've been known to look for a long time for what the addiction was. The experience could be more "automated".
That's just regular implicit assembly definition (using the scripts folder)
I would like to, but it's Unity that makes it difficult with its duplicates (Unity.Physics,Unity.Physics.Editor, Unity.Physics.Hybrid, Havok.Physics, Havok.Physics.Editor, Havok.Physics.Hybrid,...)
really don't understand why Rider doesn't do
That sounds interesting ๐
Or you can just buy that asset.
Ugh. Migrating to 2022 is gonna be pain
Or 2023... choices. FREEDOM in versions...
one thing Rider does tho
is lets you easily add references through code
but still
so annoying it doesn't add reference automatically
true
and now you have to reimplement everything yourself
must be heaven for you ๐
The official editor could be better at this
Pointers everywhere. Structural changes off main thread and parallel. It's so liberating
Although I am doing this because I moved back to built in physics 2d. So that's one thing I don't have to reimplement. And a functional sprite renderer
I chopped my entire project back down to my custom lighting engine. Archived my physics. Deleted my Sprite renderer
oh god
Freedom tastes amazing
I feel like I'm in cage when using GOs
What's stopping you from just rolling a mountain of native arrays?
Component data replaced with direct pointers to the NA element. Although resizing means invalidating all the pointers and reissuing them to all the GOs which is very painful
no chunks
no poggie woggie memory layout
You now have 1 chunk. One giant universal chunk.
yeah...
not much help here
for CPU cache
besides
Unity entities worked with pointers a lot too
just under a safe hood
and tons of checks for you
If you iterate in sequence, the cpu knows how to properly manage the cache
You dont need to divide up arrays in 128 sized chunks to get performance. In fact, that reduces performance
Fragmentation?
well yeah
if for example
there are 50 blue entities and 50 red entities
and they are all
go through 0-1-0-1
kind of thing in your array
and you only need one color
You can have multiple native arrays
so how that would handle multiple archetypes
1 per entity archetype and then string them together. Or use multiple sequential or parallel jobs
so array for each archetype
aaand how would that work
if you need multiple data from 2 different arrays
CPU cache will be lost with it
Yes. Or you can merge archetype similar components like one array for all colors and the two separate arrays for different components
The CPU cache doesnt need to be handheld. It's quite intelligent in knowing what information is required so long as you include it. What helps performance is following along its assumptions. That the next data to be iterated on is the best element when incrementing the pointer.
yeah, not really
the fastest cache is very small
if you load 1 large memory chunk and then the other
first one you load will be unloaded to less faster cache layer
Yes. Extremely small. 64 bytes. That's 1 struct.
so each time you grab your component data
for one iteration per entity
you basically reload cache
My entities? A pile of NAs is just that. Arrays of ints or structs of ints. It's the best cache friendly format
You can not get any better than NA<int>
but if you work multiple data at the same time
where you need data from several arrays
you end losing cache value with every call
to different array
What, is the cache reloading every time two arrays are called? What do you think is happening when two native arrays are added together and written into a third? The classic example of vectorization is pointed to as good cache utilization because its linear access. Despite multiple arrays
it is realoding when you need to access 2 parts of memory
and even your arrays will be multiple parts of memory, because cache can't load it all at once
so it all be chunked for it anyway
It can load from two sections of memory simultaneously. Divide up the cache into 2 parts for data from two sections of memory. It's not one continuous block
yeah and then you end up loading memory x N times per array used
It can load from parts of an array as well. Load 64 elements from one, 64 elements from a second, and 64 elements from a third and so on
What do you think a chunk is? It's a 16KB section of memory with multiple NAs
what I'm saying is that in case of chunks - it loads chunk and boom. YOu can access any data from entitiy - all already loaded in CPU cache
meanwhile in your case
for each component
it'll have to access dfiferent parts of memory
and what if some of it's memory will be in RAM and not L3 or smth?
yeah, it's good when you want to just iterate over 1 array only
So? It's just one initial access to declare that these memory locations will be required for the execution of this job
but when it comes to multiple, it seems slower
I highly doubt CPU is THAT smart with memory management
This isnt vacuum tube processors. The CPU and memory access has grown to be incredibly smart.
And plus, what is there to be intelligent about? It knows it has it's set cache size. It knows which arrays are required
it's still less fast though
It's a simple division operation to calculate the amount of elements it can load into the cache at once from every array
in case of chunks you load 1 chunk per lots of entities
let's say per 32
so per every 32 entities it'll load slow memory 1 time
and in case of multiple arrays, it'll have to access slow memory x N component type times
Not all 32 entities will be able to fit though. That cache is shared between all compute applications using whatever memory they want as eell
in best case scenario for not less than 32
they are all fit
In a completely isolated cpu running only your program, yes chunks can be read in sequence and fit in perfectly. But when other applications are also running, nothing will be in sequence
I'm just saying, this entire discussion can be concluded with a simple performance test. Generate a random number from one value and write that into an output.
One would assume reading and writing from one array is better than doing so from a set of linked arrays
That's what a chunk is. A linked array set
a bit different:
- have chunks with 10 different values. All must be multiplief/added/divided and etc between each other.
- have 10 arrays do the same thing
Okay. Have 10 arrays of size 10,000 vs 10 structs containing 10 arrays of size 100
In fact, I dont need to do that, ArowX has that benchmark on the forums
as long as chunk size is ~ size of chunk in entities
Have the arrays be of 4x4 TRS matrices and read and write to a corresponding float3 position value.
no no sir, I specifically mean what I mentioned above
this is what I think is worst case scenario for multiple array approach
I'm standing by ArowX's benchmark post as my proof that a size 10,000 NA performs better than an equivalent chunk implementation
1 array? or multiple arrays?
Just have 10 position values multiplied against a 4x4 TRS then
you have to ask yourself, is it practical?
isolated tests can be made faster. doesn't mean they are worth anything in practice. like how often do you use a float3 alone? if a single value is important why use float3. if you add/multiply/etc... a bunch of float3s they are as fast
to add something to the discussion. chunks will be slower as they are not linear in memory. but when i say slower. it'll be marginal. like extremely small. a quite good test is reading nativelist/array against nativestream. nativestream also uses small blocks of memory (4k)
The smaller the block, the higher the cost vs linearly arrayed elements. Which is why chunk size should be maximized
totally with you, the chunk size of 16k is not good. with their enabled comp feature they seem to be doubling down though
entities that are rarely added/destroyed and are big should have at least 32/64k
I'll do test
here's array approach
where ```cs
private static float4 DoWork(float a0, float2 a1, float3 a2, int a3, int2 a4, int3 a5, float4 a6, int4 a7,
float4 a8, int4 a9)
{
var kek = a0 * a1;
var lul = a2 * a3;
kek /= a4;
lul /= a5;
var adds = a6 + a7;
var subs = a8 - a9;
adds = new float4(adds.x * kek.x, adds.y * lul.x, adds.z * kek.y, adds.w * lul.y) / lul.z;
adds *= subs;
return adds;
}
now gotta do the same with Entities
"name": "Tests",
"rootNamespace": "",
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"Unity.Burst",
"Unity.Jobs",
"Unity.Jobs.Editor",
"Unity.Collections",
"Unity.Collections.BurstCompatibilityGen",
"Unity.Entities",
"Unity.Entities.Tests",
"Unity.Entities.Editor",
"Unity.Entities.Editor.Tests",
"Unity.PerformanceTesting",
"Unity.PerformanceTesting.Editor",
"Unity.Entities.Hybrid",
"Unity.Transforms",
"Unity.Mathematics"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": true,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll"
],
"autoReferenced": false,
"defineConstraints": [
"UNITY_INCLUDE_TESTS"
],
"versionDefines": [],
"noEngineReferences": false
}``` here's an asmdef for it
and some example to get you going
the annoying part of performancetests is setting them up. asmdef, boilerplate code. once done. excellent. saves so much time and timings are accurate.
i'll post a class to test ecs also. courtesy of some forum member with an anime avatar whose name i can't remember
More prep for 1.0
posted 2 mins ago. nice!
gotta continuously refresh the forum page
Hahahahahaha. I am 99% sure it's gonna be a no.
If it's a yes. I'm uninstalling 2023.1 and going back to entities.
what are these errors?
use ref?
public partial struct TestJob : IJobEntity
{
public void Execute(ref ResultComp result, in FloatComp a0, in Float2Comp a1, in Float3Comp a2,
in IntComp a3, in Int2Comp a4,
in Int3Comp a5, in Float4Comp a6, in Int4Comp a7, in OtherFloat4Comp a8, in OtherInt4Comp a9
)
{
result.value = Test.DoWork(a0.value,
a1.value,
a2.value,
a3.value,
a4.value,
a5.value,
a6.value,
a7.value,
a8.value,
a9.value);
}
}
I mean
why?
IJobEntity
I want RO access
ohhh
multiply the number of arrays by 10 as well
the length of them
not the actual number of arrays
10k not enough?
100k. You're measuring in the nanoseconds
all right
I also need separate project for this
so I can actually test it in build
ok, here's editor
here's build
welp
array wins by 2
@robust scaffold what would be fair IJobFor settings for that kind of array?
I want to test parallel too
job.Schedule(sampleSize, 16).Complete();
array batchSize
sampleSize = 10 mil
Editor
I'll play a bit with values
smaller sampleSize yields same result
huh
I mean
batchSize
for parallel in arrays
let's leave it at 16 then
interesting
pretty much same result
I'd say
chunks win, because in real life you won't have such nice synthetic 10 mil array xD
You say that
yeah, but if you'd need to have a query over multiple archetypes
you'll run into a same problem, why chunks lose here
they do way more job, than just iterating over 1 large array
combining multiple arrays
per archetype
and etc
I have a feeling, if pure array equals to perfomance with chunks, that means chunks compensate somehow
for such losses
Chunks compensate with flexability. If you know beforehand the archetype of the entities you're creating and the way you will be using them, hardcoding the array is faster
Not faster in coding time, but faster in performance
ofc hardcoding it is faster
but then you will have a very hard time creating mechanics along that hardcoded stuff
I'v been there, kek
this project... this is my 5th full redo
from scratch
kind of how I learn ECS, kek
everytime I recreate it better than it used to be
- dots ecs, 2. full OOP, 3 another dots attempt, 4 managed dots ecs attempt (works ok btw), 5 current fully unmanaged attempt
so far only 2, 4 and 5 worked out
I've done that I have tons of projects where I've started with dots and got better over time