When do Syncpoints Happen

Are jobs that perform a structural change by default run at the end of the frame?
in other words, is there any point of using an entity command buffer for a system whose sole purpose is to spawn / destroy entities?
this happens often when i need to send / receive rpcs
my thinking is, if it optimised, it should just run at the end of the frame just as the commandbuffersystem is about to update and so it would make no difference if you use .WithStructuralChanges() vs using a CommandBuffer to queue up commands for the EndSimulationEntityCommandBufferSystem because either way those two systems should update at the same time

no?

2 Likes

also does using the entity manager outside the lambda job cause a sync point?
what about a structural change from monobehaviour?

2 Likes

Any modification add/set/remove etc of entity manager cause sync point.

WIth one note - SetComponentData does not cause synch point (SetSharedComponentData of course does) which completes all jobs in app but only completes the current type dependency chain.

1 Like

Just to clarify, you are saying SetComponentData does not complete all jobs, but instead just the dependency chain of that component type.

2 Likes

Yes.
When you SetComponentData it only gets dependencies by type index and completes them (and this is expected for me as it’s not structural change and not rearrange chunks, thus other irrelevant types wouldn’t be affected and their dependencies shouldn’t be completed but only current type dependency chain (which of course can contain other types if you share\combine handles but it’s another story) ):

DependencyManager->CompleteReadAndWriteDependency(typeIndex);

Which in the end calls:

        void CompleteReadAndWriteDependencyNoChecks(int type)
        {
            var withoutFlags = type & TypeManager.ClearFlagsMask;
            var arrayIndex = m_TypeArrayIndices[withoutFlags];
            if (arrayIndex != NullTypeIndex)
            {
                for (var i = 0; i < m_DependencyHandles[arrayIndex].NumReadFences; ++i)
                    m_ReadJobFences[arrayIndex * kMaxReadJobHandles + i].Complete();
                m_DependencyHandles[arrayIndex].NumReadFences = 0;

                m_DependencyHandles[arrayIndex].WriteFence.Complete();
            }
        }

As you can see it only complete WriteFence and m_ReadJobFences for specific arrayIndex (type index from m_TypeArrayIndices)

Synch Point trigger call similar code, but instead of using a specific index from m_DependencyHandles it iterate through whole m_DependencyHandles
Which starts from BeforeStructuralChange (as they always trigger synch point) which in turn call DependencyManager->CompleteAllJobsAndInvalidateArrays();, which in the end completes all dependency chains:

                for (int t = 0; t < m_DependencyHandlesCount; ++t)
                {
                    m_DependencyHandles[t].WriteFence.Complete();

                    var readFencesCount = m_DependencyHandles[t].NumReadFences;
                    var readFences = m_ReadJobFences + t * kMaxReadJobHandles;
                    for (var r = 0; r != readFencesCount; r++)
                        readFences[r].Complete();
                    m_DependencyHandles[t].NumReadFences = 0;
                }
                ClearDependencies();
6 Likes