Hello !
I currently have a static class with methods that are used everywhere in my game so I need them to be as fast as possible. That's why I was using the [BurstCompile] attribute whenever possible. But there is a problem I still haven't been able to solve : how to access the static arrays that contain all the data needed for the methods. No matter what I try, it always leads to burst errors 😦
So far I've avoided the problem by passing the arrays as arguments to the methods but it is becoming more and more ugly and hard to maintain as more features (that require new data) are added to the game.
Is there something I don't understand ? Would anyone have an idea of how I should structure my data and methods to solve this problem in a cleaner way ?
#Accessing static data from burst compiled function
1 messages · Page 1 of 1 (latest)
It's becoming REALLY bad 🥲
public static bool _Raycast(in float3 origin, in float3 direction, float distance, in int4 dynamicMask, out float3 position, out CubeNormal normal, out int objectHit, out bool dynamicObject,
in int sizeX, in int3 bigSize, in NativeArray<int> solidMicroBlocks, in NativeArray<int> solidMicroBlockIndexes, in NativeArray<int> bigBlockIDs,
in NativeList<int> SPOIndexes, in NativeList<int> SPOMicroBlockIndexes, in NativeList<int> SPOMicroBlocks, in NativeList<int3> SPOPositions, in NativeList<int> SPOSizes,
in NativeList<int4> DPOBigBlocks, in NativeList<VoxelBoxCollider> DPOColliders)
And it's even worse when a job calls a method that calls another method and so on for example 😦
did you consider grouping the arrays in another structure? for example
struct RaycastParams
{
int sizeX;
int3 bigSize;
NativeArray<int> solidMicroBlocks;
NativeArray<int> solidMicroBlockIndexes;
NativeArray<int> bigBlockIDs;
//... etc.
}
That's a good idea !
But I still find it weird to have to pass static data of that same class when calling its methods 🥲
But you're right that grouping everything in a struct will make it less ugly 😅
Oh I've just found out about SharedStatic 😮
I can put the struct in a SharedStatic variable 😁
if that works for you, great! 🙂
sharedstatic is very easy to screw up, fwiw, since it has no safety checks to help with race conditions. i would ideally only use it on the main thread. when writing my own main-thread bursted code in user projects, i usually stick with a void* to a struct and then UnsafeUtility.AsRef inside the bursted function
then if you ever call the function in more than one situation you're less likely to have one invocation stomp on the results of another
I tried this method but I'm getting this error : External and internal calls are not allowed inside static constructors
I couldn't find any way to get rid of it 😦
Also I'm not sure I understand how it prevents race conditions better ?
Is there something I do wrong ?
Field declaration :
private static readonly void* data2 = UnsafeUtility.Malloc(sizeof(CubePhysicsData*), UnsafeUtility.AlignOf<CubePhysicsData>(), Allocator.Persistent);
Assignment of data :
UnsafeUtility.AsRef<CubePhysicsData>(data2) = new CubePhysicsData(microBlocks, microBlockIndexes, bigBlocks);
Getting the data :
UnsafeUtility.AsRef<CubePhysicsData>(data2).bigBlockIDs[bigX + (bigZ << WorldManager.horizontalBits) + (bigY << (2 * WorldManager.horizontalBits))];
it says you're calling functions that aren't allowed to be called from static constructors; I'm gonna guess on the line of allocating data2? Move it to some system's OnCreate or something like that perhaps
Ooh OK, I didn't understand it like this but now that you say it it makes sense !
I'll try that tomorrow, thank you ! 🙂
I rember the problem with this : if I initialize it somewhere else it can't be readonly anymore 😦
So Burst will complain when accessing it 😢
that doesn't ring a bell for me, but I never tried something like that so I can't really help you ^^"
If I'm not mistaking, Burst can only access static readonly variables, it's really annoying 🥲
There's always something that doesn't work 🥲
But shared statics seem to work so it's good for now 🙂
I'll just have to be careful not to schedule a job while I modify the data
This is pretty much a terrible idea btw.
How can you sure your job is complete before you write your data
You really shouldn't use this for anything but constant data
I make sure to complete all running jobs before modifying the data 🙂
For now I'm just completing it before running the Updates (I only have one update with an event that calls all others to handle this kind of things) so I'm 100% sure 🙂
I might need a more complicated system later but it's not impossible 🙂
And I really don't see how I could do it in a safer way. I can't really copy the data every time, it's a few hundred mo 🥲
I made my own voxel collision system so it contains all the data about the terrain and all objects, it's a lot 😅
There's just no real reason to use a static for this
But then how do I access it ?
Just pass it in as a field
Put it on a singleton - have automatic dependency management between your systems
But then when I call these functions I need to access that data to give it to the function. So it would be static anyways 🥲
I really don't understand how to not make it static. These functions are used everywhere in my game.
The functions exist on the same struct that has the data that you pass in
It seems like we have the same problem, I have a static SingletonUtilities which create a singleton entity and will attach any singleton component/buffer to it.
Should I use "sharedStatic" in this case? I haven't read a thing about it
So if I understand what you're saying, you have a struct in a static field and pass it to the functions as an argument ?
Personally since I discovered shared statics, I find them even easier to use.
I don't see how there could be more risk, in both cases the function accesses a static struct anyways. And it's more convenient because it doesn't have to be passed as an argument 🙂
But I might not understand everything you said, I hardly know anything about entity, components and systems, all I know is how to burst compile a static function and a job 😅
nah no, SingletonUtilities is a singleton struct (original idea from this video: https://www.youtube.com/watch?v=PRfFjvULgY0).
The reason why it is struct: "struct is unmanaged", that was what came into my head when I made it.
Clip taken from The Hot Path Show ep. 5 - https://www.youtube.com/watch?v=Ol3IQHh2p4E
Subscribe to Turbo Makes Games for new episodes of The Hot Path Show - @TurboMakesGames
Support The Hot Path Show - https://www.patreon.com/TurboMakesGames
Join us and other data-oriented developers on Discord: https://tmg.dev/Discord
The purpose of SingletonUtilities is quite simple, its job is to create a Singleton Entity in the World and attach every Singleton component/dynamic buffer.
The reason why we should do that got mentioned in the video i sent you. And Yeah, i'm not totally understand it.
will read about shared statics later, does it support using static managed object in burst?
I guess not but we can modify the struct it stores even though it is a static readonly field 🙂
Alright, I'll try to understand better with the video, thank you 😄