Dynamic buffer - usage in jobs best practices

Hi all, one thing I still find a bit confusing from all the learning resources is how we are supposed to work with dynamic buffers in jobs. I have the following questions to better understand the topic:

1) ReadOnly dynamic buffers
Documentation basically says we should always use BufferLookup for accessing dynamic buffers from jobs, but it is also possible to pass buffer directly to the job like this:

// in system:
new BufferExampleJob
{
    PrefabCollection = SystemAPI.GetSingletonBuffer<PrefabCollection>()
}
.Schedule(state.Dependency);

// job:
public partial struct BufferExampleJob : IJobEntity
{
    [ReadOnly] public DynamicBuffer<PrefabCollection> PrefabCollection;

    public void Execute(....)
    {
        // loop through buffer, instantiate the prefabs or whatever
    }
}

Is this considered as a bad practice for some reason? For example I have a lot of read only singleton buffers in my project and accessing buffer directly instead of using lookups contributes to code clarity.

2) Converting to NativeArray
I’ve also seen practice of converting DynamicBuffer to NativeArray before it is passed to the job. Is this in general recommended? What are advantages of doing this?

3) Writing to dynamic buffers in jobs
Very similar to question nr. 1 - why should I always use BufferLookup when (in some cases) I can pass buffer directly to the job and work directly with it?
Also, when I want to add element to the buffer I can also use EntityCommandBuffer AppendToBuffer method - I guess ECB usage is preferred instead of direct usage of DynamicBuffer.Add()?

Thanks in advance for your answers! I’m looking to gain a better understanding of the whole dynamic buffer topic!

  1. I don’t use singletons, so I can never keep straight when they cause sync points on the main thread and when they don’t. But that’s what you need to watch out for. That and having two buffers of the same type in the job with one of them having write access will trigger the safety check since they share the same safety handle as the BufferLookup.

  2. If you mean using .AsArray(), then yes, it is a good idea to do this, as it saves a bunch of runtime checks that Burst periodically fails to optimize out.

  3. The fastest option is actually to make your DynamicBuffer a ref arg in the Execute() of IJobEntity and just append directly. ECB.AppendtoBuffer() doesn’t actually append to a buffer. It instead registers a command for the main thread to append to the buffer later. And it being on the main thread generally makes it a bad idea. Not a big deal if these appends are infrequent events in your game, but can quickly become problematic if you abuse this API.

1 Like

Thanks for the valuable info! Points 2 and 3 are pretty clear to me, I am not sure if I understood point 1 in regards to my original question though - can it be interpreted like “no matter how you pass dynamic buffer into a job, as long as it’s not triggering safety check it’s fine”?

Also may I ask how you are typically dealing with with things like “global weapon prefab storage” (in general data which are existing only once in the project and are accessed from various places) without usage of the singletons?

As long as you don’t disable safety checks, it will at least be valid. But there are some situations where the safety system will give you a false positive that BufferLookup would avoid. And there are also some situations where BufferLookup will avoid a stall on the main thread.

I don’t know if I would necessarily use a singleton-like pattern for the use case you just described, but in general, I use this: Latios-Framework-Documentation/Core/README.md at main · Dreaming381/Latios-Framework-Documentation · GitHub

I got really annoyed with the EntityQuery interactions of singletons, as it can cause stupid errors when subscenes load and often breaks the practicality of [RequireMatchingQueriesForUpdate], so I use this instead.

1 Like

Aah ok, now I get it, thanks for explanation!

That definitely looks like a possible solution, also other parts of your framework seems promising, maybe I will give it a go in a close future.

I think that pretty much closes my question, so thanks again for your help and keep up the great work! :heart: