Skip to content

Instantly share code, notes, and snippets.

@OswaldHurlem
Created February 20, 2018 07:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OswaldHurlem/959a12005f049375f1eab98c06572ae8 to your computer and use it in GitHub Desktop.
Save OswaldHurlem/959a12005f049375f1eab98c06572ae8 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 System.Threading;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Assertions;
// Trick for creating a temporary NativeSlice 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
{
JobHandle jobHandle;
SliceAdapter<int> adapter;
int[] managedArray;
void Start()
{
managedArray = new int[20];
adapter = new SliceAdapter<int>(managedArray);
jobHandle = (new ModifySliceJob() { Slice = adapter.NativeSlice }).Schedule();
}
void Update()
{
if (jobHandle.IsCompleted && !adapter.Disposed)
{
adapter.Dispose();
Debug.Log(managedArray[1]);
Debug.Log(managedArray[2]);
Debug.Log(managedArray[3]);
Debug.Log(managedArray[4]);
Debug.Log(managedArray[5]);
}
}
}
public struct ModifySliceJob : IJob
{
public NativeSlice<int> Slice;
public void Execute()
{
Slice[1] = 1;
Thread.Sleep(1000);
Slice[2] = 2;
Thread.Sleep(1000);
Slice[3] = 3;
Thread.Sleep(1000);
Slice[4] = 4;
Thread.Sleep(1000);
Slice[5] = 5;
}
}
public unsafe class SliceAdapter<T> : IDisposable
where T : struct
{
private readonly AtomicSafetyHandle _safetyHandle;
private NativeSlice<T> _nativeSlice;
public NativeSlice<T> NativeSlice { get { return _nativeSlice; } }
public bool Disposed { get; private set; }
#if USE_UNITY_PIN_FUNCTION
private readonly ulong _pinHandle;
#else
private readonly GCHandle _gcHandle;
#endif
public SliceAdapter(T[] managedArray)
{
Assert.IsTrue(UnsafeUtility.IsBlittable<T>());
_safetyHandle = AtomicSafetyHandle.Create();
#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()
{
if (Disposed) return;
Disposed = true;
// DO NOT Release handle if it is shared
AtomicSafetyHandle.Release(_safetyHandle);
#if USE_UNITY_PIN_FUNCTION
UnsafeUtility.ReleaseGCObject(_pinHandle);
#else
_gcHandle.Free();
#endif
// DO NOT CALL _nativeArray.Dispose();
_nativeSlice = default(NativeSlice<T>);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment