修改水

This commit is contained in:
2026-01-01 22:00:33 +08:00
parent 040a222bd6
commit 9ceffccd39
1800 changed files with 103929 additions and 139495 deletions

View File

@@ -12,6 +12,11 @@ namespace Obi
for (int i = 0; i < capacity; ++i)
this[i] = Color.white;
}
public ObiNativeColorList(int capacity, int alignment, Color defaultValue) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = defaultValue;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: f377d76dadb3945b39cfac818a54d1be
guid: 391ffe5ba25364d2393afabc3083daa1
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,17 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[Serializable]
public class ObiNativeContactList : ObiNativeList<Oni.Contact>
{
public ObiNativeContactList() { }
public ObiNativeContactList(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = new Oni.Contact();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: aa58238d45b934704aede27415ce4242
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
using System;
using UnityEngine;
namespace Obi
{
[Serializable]
public class ObiNativeContactShapeList : ObiNativeList<Oni.Contact>
{
public ObiNativeContactShapeList() { }
public ObiNativeContactShapeList(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = new Oni.Contact();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3cbd83091221b46c9a724f3275281d2e
guid: 5ac88e1dd7e0249b5b361d60655d8d88
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,17 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[Serializable]
public class ObiNativeEffectiveMassesList : ObiNativeList<ContactEffectiveMasses>
{
public ObiNativeEffectiveMassesList() { }
public ObiNativeEffectiveMassesList(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = new ContactEffectiveMasses();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fc8b00cd716564eff82fc19de0c458a8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,17 +0,0 @@
using System;
namespace Obi
{
[Serializable]
public class ObiNativeEmitPointList : ObiNativeList<EmitPoint>
{
public ObiNativeEmitPointList() { }
public ObiNativeEmitPointList(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = new EmitPoint();
}
}
}

View File

@@ -1,18 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[Serializable]
public class ObiNativeForceZoneList : ObiNativeList<ForceZone>
{
public ObiNativeForceZoneList() { }
public ObiNativeForceZoneList(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = new ForceZone();
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 2815feee105f648149e0f5b1b22954bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,4 +1,5 @@
using System;
using UnityEngine;
namespace Obi
{

View File

@@ -1,4 +1,5 @@
using System;
using UnityEngine;
namespace Obi
{

View File

@@ -5,12 +5,10 @@ using UnityEngine;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using System.Collections;
using UnityEngine.Rendering;
using System.Linq;
namespace Obi
{
public unsafe class ObiNativeList<T> : IEnumerable<T>, IDisposable, ISerializationCallbackReceiver where T : struct
public unsafe abstract class ObiNativeList<T> : IEnumerable<T>, IDisposable, ISerializationCallbackReceiver where T : struct
{
public T[] serializedContents;
protected void* m_AlignedPtr = null;
@@ -23,13 +21,7 @@ namespace Obi
#if ENABLE_UNITY_COLLECTIONS_CHECKS
protected AtomicSafetyHandle m_SafetyHandle;
#endif
protected GraphicsBuffer.Target m_ComputeBufferType;
protected GraphicsBuffer m_ComputeBuffer;
protected GraphicsBuffer m_CountBuffer; // used to hold the counter value in case m_ComputeBufferType is Counter.
protected bool computeBufferDirty = false;
protected AsyncGPUReadbackRequest m_AsyncRequest;
protected AsyncGPUReadbackRequest m_CounterAsyncRequest;
protected ComputeBuffer m_ComputeBuffer;
public int count
{
@@ -41,9 +33,6 @@ namespace Obi
// we first ensure we can hold the previous count, and then set the new one.
EnsureCapacity(m_Count);
m_Count = Mathf.Min(m_Capacity, value);
if (m_ComputeBuffer != null && m_ComputeBuffer.IsValid() && m_ComputeBufferType == GraphicsBuffer.Target.Counter)
m_ComputeBuffer.SetCounterValue((uint)m_Count);
}
}
get { return m_Count; }
@@ -51,61 +40,37 @@ namespace Obi
public int capacity
{
set
{
if (value != m_Capacity)
ChangeCapacity(value);
}
get { return m_Capacity; }
}
public int stride
{
get { return m_Stride; }
}
public bool isCreated
{
get { return m_AlignedPtr != null; }
}
public bool noReadbackInFlight
{
get { return m_AsyncRequest.done && (m_ComputeBufferType != GraphicsBuffer.Target.Counter || m_CounterAsyncRequest.done); }
}
// Returns the current compute buffer representation of this list. Will return null if AsComputeBuffer() hasn't been called yet,
// or if the list has been disposed of.
public GraphicsBuffer computeBuffer
{
get { return m_ComputeBuffer; }
}
public T this[int index]
{
get
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (index < 0 || index >= m_Capacity)
{
throw new IndexOutOfRangeException($"Reading from index {index} is out of range of '{m_Capacity}' Capacity.");
}
#endif
return UnsafeUtility.ReadArrayElementWithStride<T>(m_AlignedPtr, index, m_Stride);
}
set
{
#if ENABLE_UNITY_COLLECTIONS_CHECKS
if (index < 0 || index >= m_Capacity)
{
throw new IndexOutOfRangeException($"Writing to index {index} is out of range of '{m_Capacity}' Capacity.");
}
#endif
UnsafeUtility.WriteArrayElementWithStride<T>(m_AlignedPtr, index, m_Stride, value);
computeBufferDirty = true;
if (m_ComputeBuffer != null)
m_ComputeBuffer.SetData(AsNativeArray<T>(), index, index, 1);
}
}
// Declare parameterless constructor, called by Unity upon deserialization.
protected ObiNativeList()
{
m_Stride = UnsafeUtility.SizeOf<T>();
#if ENABLE_UNITY_COLLECTIONS_CHECKS
m_SafetyHandle = AtomicSafetyHandle.Create();
#endif
@@ -113,8 +78,6 @@ namespace Obi
public ObiNativeList(int capacity = 8, int alignment = 16)
{
m_Stride = UnsafeUtility.SizeOf<T>();
#if ENABLE_UNITY_COLLECTIONS_CHECKS
m_SafetyHandle = AtomicSafetyHandle.Create();
#endif
@@ -129,21 +92,24 @@ namespace Obi
protected void Dispose(bool disposing)
{
DisposeOfComputeBuffer();
if (isCreated)
{
// dispose of compuse buffer representation:
if (m_ComputeBuffer != null)
{
m_ComputeBuffer.Dispose();
}
// free unmanaged memory buffer:
UnsafeUtility.Free(m_AlignedPtr, Allocator.Persistent);
m_AlignedPtr = null;
m_Count = m_Capacity = 0;
#if ENABLE_UNITY_COLLECTIONS_CHECKS
// dispose of atomic safety handle:
AtomicSafetyHandle.CheckDeallocateAndThrow(m_SafetyHandle);
AtomicSafetyHandle.Release(m_SafetyHandle);
#endif
}
#if ENABLE_UNITY_COLLECTIONS_CHECKS
// dispose of atomic safety handle:
AtomicSafetyHandle.CheckDeallocateAndThrow(m_SafetyHandle);
AtomicSafetyHandle.Release(m_SafetyHandle);
#endif
}
public void Dispose()
@@ -151,26 +117,6 @@ namespace Obi
Dispose(true);
}
public void DisposeOfComputeBuffer()
{
// dispose of compute buffer representation:
if (m_ComputeBuffer != null)
{
// if there's any pending async readback, finalize it.
// otherwise we pull the rug from under the readbacks' feet and that's no good.
WaitForReadback();
m_ComputeBuffer.Dispose();
m_ComputeBuffer = null;
}
if (m_CountBuffer != null)
{
m_CountBuffer.Dispose();
m_CountBuffer = null;
}
}
public void OnBeforeSerialize()
{
if (isCreated)
@@ -215,144 +161,38 @@ namespace Obi
return AsNativeArray<U>(m_Count);
}
public NativeArray<T> AsNativeArray()
{
return AsNativeArray<T>(m_Count);
}
// Reinterprets the data in the list as a native array of the given length, up to the list's capacity.
// Reinterprets the data in the list as a native array.
public NativeArray<U> AsNativeArray<U>(int arrayLength) where U : struct
{
unsafe
{
NativeArray<U> array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<U>(m_AlignedPtr, Mathf.Min(arrayLength, m_Capacity), Allocator.None);
NativeArray<U> array = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<U>(m_AlignedPtr, arrayLength, Allocator.None);
#if ENABLE_UNITY_COLLECTIONS_CHECKS
NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref array, m_SafetyHandle);
#endif
// assume the NativeArray will write new data, so we'll need to update the computeBuffer upon Upload().
computeBufferDirty = true;
return array;
}
}
// Reinterprets the data in the list as a compute buffer, in case of an empty list it returns a buffer of size 1 with uninitialized content.
public GraphicsBuffer SafeAsComputeBuffer<U>(GraphicsBuffer.Target bufferType = GraphicsBuffer.Target.Structured) where U : struct
// Reinterprets the data in the list as a compute buffer. Note: This also calls AsNativeArray() internally, to be able to pass the raw pointer to the compute buffer
public ComputeBuffer AsComputeBuffer<U>() where U : struct
{
return AsComputeBuffer<U>(Mathf.Max(1,m_Count), bufferType);
}
// Reinterprets the data in the list as a compute buffer.
public GraphicsBuffer AsComputeBuffer<U>(GraphicsBuffer.Target bufferType = GraphicsBuffer.Target.Structured) where U : struct
{
return AsComputeBuffer<U>(m_Count, bufferType);
}
// Reinterprets the data in the list as a compute buffer of the given length. Returns null if the list is empty.
public GraphicsBuffer AsComputeBuffer<U>(int arrayLength, GraphicsBuffer.Target bufferType = GraphicsBuffer.Target.Structured) where U : struct
{
DisposeOfComputeBuffer();
if (arrayLength > 0)
{
m_ComputeBufferType = bufferType;
m_ComputeBuffer = new GraphicsBuffer(bufferType, arrayLength, UnsafeUtility.SizeOf<U>());
m_ComputeBuffer.SetData(AsNativeArray<U>(arrayLength));
if (bufferType == GraphicsBuffer.Target.Counter)
{
// initialize count to zero, since counter buffers always start empty:
m_Count = 0;
m_ComputeBuffer.SetCounterValue((uint)m_Count);
m_CountBuffer = new GraphicsBuffer(GraphicsBuffer.Target.IndirectArguments, 1, 4);
GraphicsBuffer.CopyCount(m_ComputeBuffer, m_CountBuffer, 0);
}
return m_ComputeBuffer;
}
return null;
}
// Kicks a GPU readback request, to bring compute buffer data to this list.
public void Readback<U>(int readcount, bool async) where U : struct
{
if (m_ComputeBuffer != null && m_ComputeBuffer.IsValid() && noReadbackInFlight)
{
var nativeArray = AsNativeArray<U>(readcount);
// When using SafeAsComputeBuffer, we'll get a compute buffer of size 1 even if the list (and the NativeArray) is empty.
// Guard against trying to readback into a smaller NativeArray. Also guard against requesting zero items.
if (nativeArray.Length >= readcount && readcount > 0)
m_AsyncRequest = AsyncGPUReadback.RequestIntoNativeArray(ref nativeArray, m_ComputeBuffer, readcount * UnsafeUtility.SizeOf<U>(), 0);
// For counter buffers, request the counter value too:
if (m_ComputeBufferType == GraphicsBuffer.Target.Counter)
{
GraphicsBuffer.CopyCount(m_ComputeBuffer, m_CountBuffer, 0);
m_CounterAsyncRequest = AsyncGPUReadback.Request(m_CountBuffer, m_CountBuffer.stride, 0, (AsyncGPUReadbackRequest request)=>
{
if (!request.hasError)
m_Count = Mathf.Min(m_Capacity, request.GetData<int>()[0]);
});
}
if (!async)
WaitForReadback();
}
}
public void Readback(bool async = true)
{
// On counter buffers, we shouldn't read data up to m_Count and then update m_Count with the compute buffer's counter value *afterwards*.
// This would lead to reading back less data than we should, so we need to request the entire compute buffer.
if (m_ComputeBuffer != null)
Readback<T>(m_ComputeBuffer.count, async);
}
public void Readback(int readcount ,bool async = true)
{
Readback<T>(readcount, async);
}
// Makes sure any pending changes by the CPU are sent to the GPU.
// If the list data has been changed on the CPU since the last time Unmap() was called and there's a compute buffer associated to it,
// will write the current contents of the list to the compute buffer.
public void Upload<U>(int length, bool force = false) where U : struct
{
if ((computeBufferDirty || force) && m_ComputeBuffer != null && m_ComputeBuffer.IsValid())
m_ComputeBuffer.SetData(AsNativeArray<U>(length));
computeBufferDirty = false;
}
public void Upload(bool force = false)
{
Upload<T>(m_Count,force);
}
public void UploadFullCapacity()
{
Upload<T>(m_Capacity, true);
}
// Waits for the last readback request to be complete, this brings back data from the GPU to the CPU:
public void WaitForReadback()
{
if (isCreated)
{
m_AsyncRequest.WaitForCompletion();
m_CounterAsyncRequest.WaitForCompletion();
m_ComputeBuffer.Dispose();
}
m_ComputeBuffer = new ComputeBuffer(m_Count, m_Stride);
m_ComputeBuffer.SetData(AsNativeArray<U>());
return m_ComputeBuffer;
}
protected void ChangeCapacity(int newCapacity)
{
// invalidate compute buffer:
DisposeOfComputeBuffer();
// allocate a new buffer:
m_Stride = UnsafeUtility.SizeOf<T>();
var newAlignedPtr = UnsafeUtility.Malloc(newCapacity * m_Stride, m_AlignBytes, Allocator.Persistent);
var newAlignedPtr = UnsafeUtility.Malloc(newCapacity * m_Stride, 16, Allocator.Persistent);
// if there was a previous allocation:
if (isCreated)
@@ -409,45 +249,7 @@ namespace Obi
void* sourceAddress = source.AddressOfElement(sourceIndex);
void* destAddress = AddressOfElement(destIndex);
UnsafeUtility.MemCpy(destAddress, sourceAddress, length * m_Stride);
}
public void CopyFrom<U>(NativeArray<U> source, int sourceIndex, int destIndex, int length) where U : struct
{
if (!isCreated || !source.IsCreated || UnsafeUtility.SizeOf<U>() != m_Stride)
throw new ArgumentNullException();
if (length <= 0 || source.Length == 0)
return;
if (sourceIndex >= source.Length || sourceIndex < 0 || destIndex >= m_Count || destIndex < 0 ||
sourceIndex + length > source.Length || destIndex + length > m_Count)
throw new ArgumentOutOfRangeException();
void* sourceAddress = (byte*)source.GetUnsafePtr() + sourceIndex * m_Stride;
void* destAddress = AddressOfElement(destIndex);
UnsafeUtility.MemCpy(destAddress, sourceAddress, length * m_Stride);
}
public void CopyFrom(T[] source, int sourceIndex, int destIndex, int length)
{
if (source == null || !isCreated)
throw new ArgumentNullException();
if (length <= 0 || source.Length == 0)
return;
if (sourceIndex < 0 || destIndex < 0 ||
sourceIndex + length > source.Length || destIndex + length > m_Count)
throw new ArgumentOutOfRangeException();
// pin the managed array and get its address:
ulong sourceHandle;
void* sourceAddress = UnsafeUtility.PinGCArrayAndGetDataAddress(source, out sourceHandle);
void* destAddress = UnsafeUtility.AddressOf(ref UnsafeUtility.ArrayElementAsRef<T>(m_AlignedPtr, destIndex));
UnsafeUtility.MemCpy(destAddress, sourceAddress, length * m_Stride);
// unpin the managed array:
UnsafeUtility.ReleaseGCObject(sourceHandle);
}
public void CopyReplicate(T value, int destIndex, int length)
@@ -491,53 +293,9 @@ namespace Obi
public void Add(T item)
{
EnsureCapacity(m_Count + 1);
computeBufferDirty = true;
this[m_Count++] = item;
}
public void AddReplicate(T value, int times)
{
int appendAt = m_Count;
ResizeUninitialized(m_Count + times);
CopyReplicate(value, appendAt, times);
}
public void AddRange(T[] array)
{
AddRange(array, array.Length);
}
public void AddRange(T[] array, int length)
{
AddRange(array, 0, length);
}
public void AddRange(T[] array, int start, int length)
{
int appendAt = m_Count;
ResizeUninitialized(m_Count + length);
CopyFrom(array, start, appendAt, length);
}
public void AddRange(ObiNativeList<T> array, int length)
{
int appendAt = m_Count;
ResizeUninitialized(m_Count + length);
CopyFrom(array, 0, appendAt, length);
}
public void AddRange(ObiNativeList<T> array, int start, int length)
{
int appendAt = m_Count;
ResizeUninitialized(m_Count + length);
CopyFrom(array, start, appendAt, length);
}
public void AddRange(ObiNativeList<T> array)
{
AddRange(array, array.count);
}
public void AddRange(IEnumerable<T> enumerable)
{
ICollection<T> collection = enumerable as ICollection<T>;
@@ -585,9 +343,7 @@ namespace Obi
{
newCount = Mathf.Max(0, newCount);
bool realloc = EnsureCapacity(newCount);
m_Count = newCount;
return realloc;
}
@@ -625,25 +381,7 @@ namespace Obi
unsafe
{
if (isCreated)
{
UnsafeUtility.MemClear(m_AlignedPtr, count * m_Stride);
computeBufferDirty = true;
}
}
}
public void WipeToValue(T value)
{
unsafe
{
if (isCreated)
{
void* sourceAddress = UnsafeUtility.AddressOf(ref value);
UnsafeUtility.MemCpyReplicate(m_AlignedPtr, sourceAddress, m_Stride, count);
computeBufferDirty = true;
}
}
}
@@ -665,14 +403,10 @@ namespace Obi
public void* AddressOfElement(int index)
{
// UnsafeUtility.AddressOf(ref UnsafeUtilityEx.ArrayElementAsRef<T>(m_AlignedPtr, m_Count));
return (void*) ((byte*)m_AlignedPtr + m_Stride * index);
}
public NativeReference<int> GetCountReference(Allocator alloc)
{
return new NativeReference<int>(m_Count, alloc);
}
public IntPtr GetIntPtr()
{
if (isCreated)

View File

@@ -6,18 +6,11 @@ namespace Obi
[Serializable]
public class ObiNativeMatrix4x4List : ObiNativeList<Matrix4x4>
{
public ObiNativeMatrix4x4List() { } // TODO: WTF???? why does this prevent a crash?
public ObiNativeMatrix4x4List(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = Matrix4x4.identity;
}
public ObiNativeMatrix4x4List(int capacity, int alignment, Matrix4x4 defaultValue) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = defaultValue;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 57e079b439b8f4d71966919ca4fa4838
guid: f6b7295a6ebb4475fb050c4c5b3770cc
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,18 +0,0 @@
using System;
using UnityEngine;
namespace Obi
{
[Serializable]
public class ObiNativeUIntList : ObiNativeList<uint>
{
public ObiNativeUIntList(int capacity = 8, int alignment = 16) : base(capacity, alignment)
{
for (int i = 0; i < capacity; ++i)
this[i] = 0;
}
}
}

View File

@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: cee276900c5ce412aafe4e23112537eb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: