您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

435 行
16 KiB

using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Jobs.LowLevel.Unsafe;
using UnityEngine.Profiling;
namespace Unity.Entities
{
internal unsafe class ComponentJobSafetyManager
{
private const int kMaxReadJobHandles = 17;
private const int kMaxTypes = TypeManager.MaximumTypesCount;
private readonly JobHandle* m_JobDependencyCombineBuffer;
private readonly int m_JobDependencyCombineBufferCount;
private ComponentSafetyHandle* m_ComponentSafetyHandles;
private JobHandle m_ExclusiveTransactionDependency;
private bool m_HasCleanHandles;
private JobHandle* m_ReadJobFences;
public ComponentJobSafetyManager()
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
m_TempSafety = AtomicSafetyHandle.Create();
#endif
m_ReadJobFences = (JobHandle*) UnsafeUtility.Malloc(sizeof(JobHandle) * kMaxReadJobHandles * kMaxTypes, 16,
Allocator.Persistent);
UnsafeUtility.MemClear(m_ReadJobFences, sizeof(JobHandle) * kMaxReadJobHandles * kMaxTypes);
m_ComponentSafetyHandles =
(ComponentSafetyHandle*) UnsafeUtility.Malloc(sizeof(ComponentSafetyHandle) * kMaxTypes, 16,
Allocator.Persistent);
UnsafeUtility.MemClear(m_ComponentSafetyHandles, sizeof(ComponentSafetyHandle) * kMaxTypes);
m_JobDependencyCombineBufferCount = 4 * 1024;
m_JobDependencyCombineBuffer = (JobHandle*) UnsafeUtility.Malloc(
sizeof(ComponentSafetyHandle) * m_JobDependencyCombineBufferCount, 16, Allocator.Persistent);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i != kMaxTypes; i++)
{
m_ComponentSafetyHandles[i].SafetyHandle = AtomicSafetyHandle.Create();
AtomicSafetyHandle.SetAllowSecondaryVersionWriting(m_ComponentSafetyHandles[i].SafetyHandle, false);
m_ComponentSafetyHandles[i].BufferHandle = AtomicSafetyHandle.Create();
}
#endif
m_HasCleanHandles = true;
}
public bool IsInTransaction { get; private set; }
public JobHandle ExclusiveTransactionDependency
{
get { return m_ExclusiveTransactionDependency; }
set
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (!IsInTransaction)
throw new InvalidOperationException(
"EntityManager.TransactionDependency can only after EntityManager.BeginExclusiveEntityTransaction has been called.");
if (!JobHandle.CheckFenceIsDependencyOrDidSyncFence(m_ExclusiveTransactionDependency, value))
throw new InvalidOperationException(
"EntityManager.TransactionDependency must depend on the Entity Transaction job.");
#endif
m_ExclusiveTransactionDependency = value;
}
}
#if ENABLE_UNITY_COLLECTIONS_CHECKS
public AtomicSafetyHandle ExclusiveTransactionSafety { get; private set; }
#endif
//@TODO: Optimize as one function call to in batch bump version on every single handle...
public void CompleteAllJobsAndInvalidateArrays()
{
if (m_HasCleanHandles)
return;
Profiler.BeginSample("CompleteAllJobsAndInvalidateArrays");
var count = TypeManager.GetTypeCount();
for (var t = 0; t != count; t++)
{
m_ComponentSafetyHandles[t].WriteFence.Complete();
var readFencesCount = m_ComponentSafetyHandles[t].NumReadFences;
var readFences = m_ReadJobFences + t * kMaxReadJobHandles;
for (var r = 0; r != readFencesCount; r++)
readFences[r].Complete();
m_ComponentSafetyHandles[t].NumReadFences = 0;
}
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i != count; i++)
{
AtomicSafetyHandle.CheckDeallocateAndThrow(m_ComponentSafetyHandles[i].SafetyHandle);
AtomicSafetyHandle.CheckDeallocateAndThrow(m_ComponentSafetyHandles[i].BufferHandle);
}
for (var i = 0; i != count; i++)
{
AtomicSafetyHandle.Release(m_ComponentSafetyHandles[i].SafetyHandle);
m_ComponentSafetyHandles[i].SafetyHandle = AtomicSafetyHandle.Create();
AtomicSafetyHandle.SetAllowSecondaryVersionWriting(m_ComponentSafetyHandles[i].SafetyHandle, false);
AtomicSafetyHandle.Release(m_ComponentSafetyHandles[i].BufferHandle);
m_ComponentSafetyHandles[i].BufferHandle = AtomicSafetyHandle.Create();
}
#endif
m_HasCleanHandles = true;
Profiler.EndSample();
}
public void Dispose()
{
for (var i = 0; i < kMaxTypes; i++)
m_ComponentSafetyHandles[i].WriteFence.Complete();
for (var i = 0; i < kMaxTypes * kMaxReadJobHandles; i++)
m_ReadJobFences[i].Complete();
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i < kMaxTypes; i++)
{
var res0 = AtomicSafetyHandle.EnforceAllBufferJobsHaveCompletedAndRelease(m_ComponentSafetyHandles[i].SafetyHandle);
var res1 = AtomicSafetyHandle.EnforceAllBufferJobsHaveCompletedAndRelease(m_ComponentSafetyHandles[i].BufferHandle);
if (res0 == EnforceJobResult.DidSyncRunningJobs || res1 == EnforceJobResult.DidSyncRunningJobs)
Debug.LogError(
"Disposing EntityManager but a job is still running against the ComponentData. It appears the job has not been registered with JobComponentSystem.AddDependency.");
}
AtomicSafetyHandle.Release(m_TempSafety);
#endif
UnsafeUtility.Free(m_JobDependencyCombineBuffer, Allocator.Persistent);
UnsafeUtility.Free(m_ComponentSafetyHandles, Allocator.Persistent);
m_ComponentSafetyHandles = null;
UnsafeUtility.Free(m_ReadJobFences, Allocator.Persistent);
m_ReadJobFences = null;
}
public void CompleteDependenciesNoChecks(int* readerTypes, int readerTypesCount, int* writerTypes, int writerTypesCount)
{
for (var i = 0; i != writerTypesCount; i++)
CompleteReadAndWriteDependencyNoChecks(writerTypes[i]);
for (var i = 0; i != readerTypesCount; i++)
CompleteWriteDependencyNoChecks(readerTypes[i]);
}
internal void PreDisposeCheck()
{
for (var i = 0; i < kMaxTypes; i++)
m_ComponentSafetyHandles[i].WriteFence.Complete();
for (var i = 0; i < kMaxTypes * kMaxReadJobHandles; i++)
m_ReadJobFences[i].Complete();
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i < kMaxTypes; i++)
{
var res0 = AtomicSafetyHandle.EnforceAllBufferJobsHaveCompleted(m_ComponentSafetyHandles[i].SafetyHandle);
var res1 = AtomicSafetyHandle.EnforceAllBufferJobsHaveCompleted(m_ComponentSafetyHandles[i].BufferHandle);
if (res0 == EnforceJobResult.DidSyncRunningJobs || res1 == EnforceJobResult.DidSyncRunningJobs)
Debug.LogError(
"Disposing EntityManager but a job is still running against the ComponentData. It appears the job has not been registered with JobComponentSystem.AddDependency.");
}
#endif
}
public bool HasReaderOrWriterDependency(int type, JobHandle dependency)
{
var writer = m_ComponentSafetyHandles[type].WriteFence;
if (JobHandle.CheckFenceIsDependencyOrDidSyncFence(dependency, writer))
return true;
var count = m_ComponentSafetyHandles[type].NumReadFences;
for (var r = 0; r < count; r++)
{
var reader = m_ReadJobFences[type * kMaxReadJobHandles + r];
if (JobHandle.CheckFenceIsDependencyOrDidSyncFence(dependency, reader))
return true;
}
return false;
}
public JobHandle GetDependency(int* readerTypes, int readerTypesCount, int* writerTypes, int writerTypesCount)
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (readerTypesCount * kMaxReadJobHandles + writerTypesCount > m_JobDependencyCombineBufferCount)
throw new ArgumentException("Too many readers & writers in GetDependency");
#endif
var count = 0;
for (var i = 0; i != readerTypesCount; i++)
m_JobDependencyCombineBuffer[count++] = m_ComponentSafetyHandles[readerTypes[i]].WriteFence;
for (var i = 0; i != writerTypesCount; i++)
{
var writerType = writerTypes[i];
m_JobDependencyCombineBuffer[count++] = m_ComponentSafetyHandles[writerType].WriteFence;
var numReadFences = m_ComponentSafetyHandles[writerType].NumReadFences;
for (var j = 0; j != numReadFences; j++)
m_JobDependencyCombineBuffer[count++] = m_ReadJobFences[writerType * kMaxReadJobHandles + j];
}
return JobHandleUnsafeUtility.CombineDependencies(m_JobDependencyCombineBuffer,
count);
}
public JobHandle AddDependency(int* readerTypes, int readerTypesCount, int* writerTypes, int writerTypesCount,
JobHandle dependency)
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
JobHandle* combinedDependencies = null;
var combinedDependenciesCount = 0;
#endif
for (var i = 0; i != writerTypesCount; i++)
{
var writer = writerTypes[i];
m_ComponentSafetyHandles[writer].WriteFence = dependency;
}
for (var i = 0; i != readerTypesCount; i++)
{
var reader = readerTypes[i];
m_ReadJobFences[reader * kMaxReadJobHandles + m_ComponentSafetyHandles[reader].NumReadFences] =
dependency;
m_ComponentSafetyHandles[reader].NumReadFences++;
if (m_ComponentSafetyHandles[reader].NumReadFences == kMaxReadJobHandles)
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
var combined = CombineReadDependencies(reader);
if (combinedDependencies == null)
{
JobHandle* temp = stackalloc JobHandle[readerTypesCount];
combinedDependencies = temp;
}
combinedDependencies[combinedDependenciesCount++] = combined;
#else
CombineReadDependencies(reader);
#endif
}
}
if (readerTypesCount != 0 || writerTypesCount != 0)
m_HasCleanHandles = false;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (combinedDependencies != null)
return JobHandleUnsafeUtility.CombineDependencies(combinedDependencies, combinedDependenciesCount);
return dependency;
#else
return dependency;
#endif
}
public void CompleteWriteDependencyNoChecks(int type)
{
m_ComponentSafetyHandles[type].WriteFence.Complete();
}
public void CompleteReadAndWriteDependencyNoChecks(int type)
{
for (var i = 0; i < m_ComponentSafetyHandles[type].NumReadFences; ++i)
m_ReadJobFences[type * kMaxReadJobHandles + i].Complete();
m_ComponentSafetyHandles[type].NumReadFences = 0;
m_ComponentSafetyHandles[type].WriteFence.Complete();
}
public void CompleteWriteDependency(int type)
{
CompleteWriteDependencyNoChecks(type);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
AtomicSafetyHandle.CheckReadAndThrow(m_ComponentSafetyHandles[type].SafetyHandle);
AtomicSafetyHandle.CheckReadAndThrow(m_ComponentSafetyHandles[type].BufferHandle);
#endif
}
public void CompleteReadAndWriteDependency(int type)
{
CompleteReadAndWriteDependencyNoChecks(type);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
AtomicSafetyHandle.CheckWriteAndThrow(m_ComponentSafetyHandles[type].SafetyHandle);
AtomicSafetyHandle.CheckWriteAndThrow(m_ComponentSafetyHandles[type].BufferHandle);
#endif
}
#if ENABLE_UNITY_COLLECTIONS_CHECKS
public AtomicSafetyHandle GetSafetyHandle(int type, bool isReadOnly)
{
m_HasCleanHandles = false;
var handle = m_ComponentSafetyHandles[type].SafetyHandle;
if (isReadOnly)
AtomicSafetyHandle.UseSecondaryVersion(ref handle);
return handle;
}
public AtomicSafetyHandle GetBufferSafetyHandle(int type)
{
m_HasCleanHandles = false;
return m_ComponentSafetyHandles[type].BufferHandle;
}
#endif
private JobHandle CombineReadDependencies(int type)
{
var combined = JobHandleUnsafeUtility.CombineDependencies(
m_ReadJobFences + type * kMaxReadJobHandles, m_ComponentSafetyHandles[type].NumReadFences);
m_ReadJobFences[type * kMaxReadJobHandles] = combined;
m_ComponentSafetyHandles[type].NumReadFences = 1;
return combined;
}
public void BeginExclusiveTransaction()
{
if (IsInTransaction)
return;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i != TypeManager.GetTypeCount(); i++)
{
AtomicSafetyHandle.CheckDeallocateAndThrow(m_ComponentSafetyHandles[i].SafetyHandle);
AtomicSafetyHandle.CheckDeallocateAndThrow(m_ComponentSafetyHandles[i].BufferHandle);
}
#endif
IsInTransaction = true;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
ExclusiveTransactionSafety = AtomicSafetyHandle.Create();
#endif
m_ExclusiveTransactionDependency = GetAllDependencies();
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i != TypeManager.GetTypeCount(); i++)
{
AtomicSafetyHandle.Release(m_ComponentSafetyHandles[i].SafetyHandle);
AtomicSafetyHandle.Release(m_ComponentSafetyHandles[i].BufferHandle);
}
#endif
}
public void EndExclusiveTransaction()
{
if (!IsInTransaction)
return;
m_ExclusiveTransactionDependency.Complete();
#if ENABLE_UNITY_COLLECTIONS_CHECKS
var res = AtomicSafetyHandle.EnforceAllBufferJobsHaveCompletedAndRelease(ExclusiveTransactionSafety);
if (res != EnforceJobResult.AllJobsAlreadySynced)
//@TODO: Better message
Debug.LogError("ExclusiveEntityTransaction job has not been registered");
#endif
IsInTransaction = false;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
for (var i = 0; i != TypeManager.GetTypeCount(); i++)
{
m_ComponentSafetyHandles[i].SafetyHandle = AtomicSafetyHandle.Create();
AtomicSafetyHandle.SetAllowSecondaryVersionWriting(m_ComponentSafetyHandles[i].SafetyHandle, false);
m_ComponentSafetyHandles[i].BufferHandle = AtomicSafetyHandle.Create();
}
#endif
}
private JobHandle GetAllDependencies()
{
var jobHandles =
new NativeArray<JobHandle>(TypeManager.GetTypeCount() * (kMaxReadJobHandles + 1), Allocator.Temp);
var count = 0;
for (var i = 0; i != TypeManager.GetTypeCount(); i++)
{
jobHandles[count++] = m_ComponentSafetyHandles[i].WriteFence;
var numReadFences = m_ComponentSafetyHandles[i].NumReadFences;
for (var j = 0; j != numReadFences; j++)
jobHandles[count++] = m_ReadJobFences[i * kMaxReadJobHandles + j];
}
var combined = JobHandle.CombineDependencies(jobHandles);
jobHandles.Dispose();
return combined;
}
private struct ComponentSafetyHandle
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
public AtomicSafetyHandle SafetyHandle;
public AtomicSafetyHandle BufferHandle;
#endif
public JobHandle WriteFence;
public int NumReadFences;
}
#if ENABLE_UNITY_COLLECTIONS_CHECKS
private readonly AtomicSafetyHandle m_TempSafety;
#endif
}
}