Skip to content

Instantly share code, notes, and snippets.

@OswaldHurlem
Last active October 26, 2023 09:04
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save OswaldHurlem/10d43704b23d493e190fca15d8197725 to your computer and use it in GitHub Desktop.
Save OswaldHurlem/10d43704b23d493e190fca15d8197725 to your computer and use it in GitHub Desktop.
// This doesn't seem to work properly
//#define USE_UNITY_PIN_FUNCTION
using System;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.Assertions;
// Trick for creating a temporary NativeArray which points to the contents of a managed array.
// Good for mischief and bleeding-edge perf. BEWARE! Very likely to cause bugs now and break later.
public class Test : MonoBehaviour
{
unsafe void Start()
{
const bool tryToF__kUpTheHeap = true;
const bool useTempHandle = true;
int[] managedArray = new int[20];
NativeSlice<int> sliceCopy;
using (var adapter = new SliceAdapter<int>(managedArray, useTempHandle))
{
adapter.NativeSlice[5] = 5;
if (tryToF__kUpTheHeap) { sliceCopy = adapter.NativeSlice; }
}
if (tryToF__kUpTheHeap) { sliceCopy[2] = 500; }
Debug.Log(managedArray[5]);
Debug.Log(managedArray[2]);
}
}
public unsafe class SliceAdapter<T> : IDisposable
where T : struct
{
private readonly bool _handleIsTemp;
private readonly AtomicSafetyHandle _safetyHandle;
public NativeSlice<T> NativeSlice;
#if USE_UNITY_PIN_FUNCTION
private readonly ulong _pinHandle;
#else
private readonly GCHandle _gcHandle;
#endif
public SliceAdapter(T[] managedArray, bool useTempHandle)
{
Assert.IsTrue(UnsafeUtility.IsBlittable<T>());
_safetyHandle = useTempHandle ? AtomicSafetyHandle.GetTempUnsafePtrSliceHandle() : AtomicSafetyHandle.Create();
_handleIsTemp = useTempHandle;
#if USE_UNITY_PIN_FUNCTION
NativeSlice = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<T>(
UnsafeUtility.PinGCObjectAndGetAddress(managedArray, out _pinHandle),
UnsafeUtility.SizeOf<T>(),
managedArray.Length);
#else
_gcHandle = GCHandle.Alloc(managedArray, GCHandleType.Pinned);
NativeSlice = NativeSliceUnsafeUtility.ConvertExistingDataToNativeSlice<T>(
(void*)_gcHandle.AddrOfPinnedObject(),
UnsafeUtility.SizeOf<T>(),
managedArray.Length);
#endif
NativeSliceUnsafeUtility.SetAtomicSafetyHandle(ref NativeSlice, _safetyHandle);
}
public void Dispose()
{
// DO NOT Release handle if it is shared
if (!_handleIsTemp) { AtomicSafetyHandle.Release(_safetyHandle); }
#if USE_UNITY_PIN_FUNCTION
UnsafeUtility.ReleaseGCObject(_pinHandle);
#else
_gcHandle.Free();
#endif
// DO NOT CALL _nativeArray.Dispose();
NativeSlice = default(NativeArray<T>);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment