Enhance noise generation and memory management
Added new noise generation methods in `ParallelNoiseBenchmark`, including `Frac`, `Lerp`, and `GradientNoiseDirect`, and updated the `GradientNoise` method to utilize them. Changed constants to use `_LENGTH` for consistency. Changed `Arena` and `DynamicArena` classes to use `uint` instead of `ulong` for size fields, improving memory usage. Updated memory allocation to use `NativeMemory` for better performance and safety. Updated `UnsafeArray<T>` and `UnsafeList<T>` classes to replace `Marshal` methods with `NativeMemory`, enhancing performance and safety. Modified `Dispose` methods to use `NativeMemory.AlignedFree`. Added `MemoryUtilities` class with new methods for memory management, including `MemClear`, `MemSet`, `MemCpy`, `SizeOf`, and `AlignOf`, utilizing `NativeMemory`. Fixed minor cleanup in the `ObjectPool` class's `Dispose` method.
This commit is contained in:
@@ -14,6 +14,43 @@ public class ParallelNoiseBenchmark
|
|||||||
public UnsafeArray<float> buffers;
|
public UnsafeArray<float> buffers;
|
||||||
public int width;
|
public int width;
|
||||||
public int height;
|
public int height;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static float Frac(float x)
|
||||||
|
{
|
||||||
|
return x - MathF.Truncate(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static float Lerp(float a, float b, float t)
|
||||||
|
{
|
||||||
|
return a + t * (b - a);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vector2 GradientNoiseDirect(Vector2 uv)
|
||||||
|
{
|
||||||
|
uv.X %= 289;
|
||||||
|
uv.Y %= 289;
|
||||||
|
var x = (34 * uv.X + 1) * uv.X % 289 + uv.Y;
|
||||||
|
x = (34 * x + 1) * x % 289;
|
||||||
|
x = Frac(x / 41) * 2 - 1;
|
||||||
|
return Vector2.Normalize(new Vector2(x - MathF.Floor(x + 0.5f), MathF.Abs(x) - 0.5f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float GradientNoise(Vector2 uv)
|
||||||
|
{
|
||||||
|
var ip = new Vector2(MathF.Floor(uv.X), MathF.Floor(uv.Y));
|
||||||
|
var fp = new Vector2(Frac(uv.X), Frac(uv.Y));
|
||||||
|
|
||||||
|
var d00 = Vector2.Dot(GradientNoiseDirect(ip), fp);
|
||||||
|
var d01 = Vector2.Dot(GradientNoiseDirect(ip + new Vector2(0, 1)), fp - new Vector2(0, 1));
|
||||||
|
var d10 = Vector2.Dot(GradientNoiseDirect(ip + new Vector2(1, 0)), fp - new Vector2(1, 0));
|
||||||
|
var d11 = Vector2.Dot(GradientNoiseDirect(ip + new Vector2(1, 1)), fp - new Vector2(1, 1));
|
||||||
|
|
||||||
|
fp = fp * fp * fp * (fp * (fp * new Vector2(6.0f) - new Vector2(15.0f)) + new Vector2(10.0f));
|
||||||
|
return Lerp(Lerp(d00, d10, fp.Y), Lerp(d01, d11, fp.Y), fp.X);
|
||||||
|
}
|
||||||
|
|
||||||
public void Execute(int index)
|
public void Execute(int index)
|
||||||
{
|
{
|
||||||
var x = index % width;
|
var x = index % width;
|
||||||
@@ -27,46 +64,10 @@ public class ParallelNoiseBenchmark
|
|||||||
private const int _HEIGHT = 512;
|
private const int _HEIGHT = 512;
|
||||||
private const int _LENGTH = _WIDTH * _HEIGHT;
|
private const int _LENGTH = _WIDTH * _HEIGHT;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static float Frac(float x)
|
|
||||||
{
|
|
||||||
return x - MathF.Truncate(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static float Lerp(float a, float b, float t)
|
|
||||||
{
|
|
||||||
return a + t * (b - a);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Vector2 GradientNoiseDirect(Vector2 uv)
|
|
||||||
{
|
|
||||||
uv.X %= 289;
|
|
||||||
uv.Y %= 289;
|
|
||||||
var x = (34 * uv.X + 1) * uv.X % 289 + uv.Y;
|
|
||||||
x = (34 * x + 1) * x % 289;
|
|
||||||
x = Frac(x / 41) * 2 - 1;
|
|
||||||
return Vector2.Normalize(new Vector2(x - MathF.Floor(x + 0.5f), MathF.Abs(x) - 0.5f));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static float GradientNoise(Vector2 uv)
|
|
||||||
{
|
|
||||||
var ip = new Vector2(MathF.Floor(uv.X), MathF.Floor(uv.Y));
|
|
||||||
var fp = new Vector2(Frac(uv.X), Frac(uv.Y));
|
|
||||||
|
|
||||||
var d00 = Vector2.Dot(GradientNoiseDirect(ip), fp);
|
|
||||||
var d01 = Vector2.Dot(GradientNoiseDirect(ip + new Vector2(0, 1)), fp - new Vector2(0, 1));
|
|
||||||
var d10 = Vector2.Dot(GradientNoiseDirect(ip + new Vector2(1, 0)), fp - new Vector2(1, 0));
|
|
||||||
var d11 = Vector2.Dot(GradientNoiseDirect(ip + new Vector2(1, 1)), fp - new Vector2(1, 1));
|
|
||||||
|
|
||||||
fp = fp * fp * fp * (fp * (fp * new Vector2(6.0f) - new Vector2(15.0f)) + new Vector2(10.0f));
|
|
||||||
return Lerp(Lerp(d00, d10, fp.Y), Lerp(d01, d11, fp.Y), fp.X);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void JobSystem()
|
public void JobSystem()
|
||||||
{
|
{
|
||||||
using var buffers = new UnsafeArray<float>(_WIDTH * _HEIGHT, AllocationType.UnInitialized);
|
using var buffers = new UnsafeArray<float>(_LENGTH, AllocationType.UnInitialized);
|
||||||
var job = new NoiseJob()
|
var job = new NoiseJob()
|
||||||
{
|
{
|
||||||
buffers = buffers,
|
buffers = buffers,
|
||||||
@@ -81,14 +82,14 @@ public class ParallelNoiseBenchmark
|
|||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void ParallelFor()
|
public void ParallelFor()
|
||||||
{
|
{
|
||||||
using var buffers = new UnsafeArray<float>(_WIDTH * _HEIGHT, AllocationType.UnInitialized);
|
using var buffers = new UnsafeArray<float>(_LENGTH, AllocationType.UnInitialized);
|
||||||
|
|
||||||
Parallel.For(0, _LENGTH, i =>
|
Parallel.For(0, _LENGTH, i =>
|
||||||
{
|
{
|
||||||
var x = i % _WIDTH;
|
var x = i % _WIDTH;
|
||||||
var y = i / _HEIGHT;
|
var y = i / _HEIGHT;
|
||||||
var uv = new Vector2(x, y);
|
var uv = new Vector2(x, y);
|
||||||
buffers[i] = GradientNoise(uv);
|
buffers[i] = NoiseJob.GradientNoise(uv);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Misaki.HighPerformance.Unsafe.Collections;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Unsafe.Buffer;
|
namespace Misaki.HighPerformance.Unsafe.Buffer;
|
||||||
|
|
||||||
@@ -8,14 +9,14 @@ namespace Misaki.HighPerformance.Unsafe.Buffer;
|
|||||||
public unsafe struct Arena : IDisposable
|
public unsafe struct Arena : IDisposable
|
||||||
{
|
{
|
||||||
private void* _buffer;
|
private void* _buffer;
|
||||||
private ulong _size;
|
private uint _size;
|
||||||
private ulong _offset;
|
private uint _offset;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public Arena(ulong size)
|
public Arena(uint size)
|
||||||
{
|
{
|
||||||
_buffer = Marshal.AllocHGlobal((IntPtr)size).ToPointer();
|
_buffer = NativeMemory.Alloc(size);
|
||||||
_size = size;
|
_size = size;
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
}
|
}
|
||||||
@@ -23,12 +24,13 @@ public unsafe struct Arena : IDisposable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Allocates a block of memory of a specified size with a given alignment. Returns a pointer to the allocated
|
/// Allocates a block of memory of a specified size with a given alignment. Returns a pointer to the allocated
|
||||||
/// memory or null if allocation fails.
|
/// memory or null if allocation fails.
|
||||||
|
/// Must use <see cref="NativeMemory.AlignedFree"/> to free the memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="size">Specifies the amount of memory to allocate in bytes.</param>
|
/// <param name="size">Specifies the amount of memory to allocate in bytes.</param>
|
||||||
/// <param name="alignSize">Defines the alignment requirement for the allocated memory.</param>
|
/// <param name="alignSize">Defines the alignment requirement for the allocated memory.</param>
|
||||||
/// <returns>A pointer to the allocated memory block or null if the allocation cannot be fulfilled.</returns>
|
/// <returns>A pointer to the allocated memory block or null if the allocation cannot be fulfilled.</returns>
|
||||||
/// <exception cref="ObjectDisposedException">Thrown if the arena has been disposed.</exception>
|
/// <exception cref="ObjectDisposedException">Thrown if the arena has been disposed.</exception>
|
||||||
public void* Allocate(ulong size, uint alignSize)
|
public void* Allocate(uint size, uint alignSize, AllocationType allocationType)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -40,7 +42,11 @@ public unsafe struct Arena : IDisposable
|
|||||||
|
|
||||||
_offset = offset + size;
|
_offset = offset + size;
|
||||||
var ptr = (byte*)_buffer + offset;
|
var ptr = (byte*)_buffer + offset;
|
||||||
MemClear(ptr, (uint)size);
|
|
||||||
|
if (allocationType == AllocationType.Clear)
|
||||||
|
{
|
||||||
|
MemClear(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@@ -56,7 +62,7 @@ public unsafe struct Arena : IDisposable
|
|||||||
|
|
||||||
if (clear)
|
if (clear)
|
||||||
{
|
{
|
||||||
MemClear(_buffer, (uint)_size);
|
MemClear(_buffer, _size);
|
||||||
}
|
}
|
||||||
|
|
||||||
_offset = 0;
|
_offset = 0;
|
||||||
@@ -64,7 +70,7 @@ public unsafe struct Arena : IDisposable
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal((IntPtr)_buffer);
|
NativeMemory.Free(_buffer);
|
||||||
|
|
||||||
_buffer = null;
|
_buffer = null;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Runtime.InteropServices;
|
using Misaki.HighPerformance.Unsafe.Collections;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Unsafe.Buffer;
|
namespace Misaki.HighPerformance.Unsafe.Buffer;
|
||||||
|
|
||||||
@@ -16,28 +17,28 @@ public unsafe struct DynamicArena : IDisposable
|
|||||||
|
|
||||||
private ArenaNode* _root;
|
private ArenaNode* _root;
|
||||||
private ArenaNode* _current;
|
private ArenaNode* _current;
|
||||||
private readonly ulong _initialSize;
|
private readonly uint _initialSize;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of DynamicArena with the specified initial size.
|
/// Initializes a new instance of DynamicArena with the specified initial size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="initialSize">The initial size in bytes for the first arena block.</param>
|
/// <param name="initialSize">The initial size in bytes for the first arena block.</param>
|
||||||
public DynamicArena(ulong initialSize)
|
public DynamicArena(uint initialSize)
|
||||||
{
|
{
|
||||||
_initialSize = initialSize;
|
_initialSize = initialSize;
|
||||||
_root = (ArenaNode*)Marshal.AllocHGlobal(sizeof(ArenaNode));
|
_root = (ArenaNode*)NativeMemory.Alloc(SizeOf<ArenaNode>());
|
||||||
_root->arena = new Arena(initialSize);
|
_root->arena = new Arena(initialSize);
|
||||||
_root->next = null;
|
_root->next = null;
|
||||||
_current = _root;
|
_current = _root;
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CreateNewNode(ulong size)
|
private bool CreateNewNode(uint size)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var newNode = (ArenaNode*)Marshal.AllocHGlobal(sizeof(ArenaNode));
|
var newNode = (ArenaNode*)NativeMemory.Alloc(SizeOf<ArenaNode>());
|
||||||
newNode->arena = new Arena(size);
|
newNode->arena = new Arena(size);
|
||||||
newNode->next = null;
|
newNode->next = null;
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ public unsafe struct DynamicArena : IDisposable
|
|||||||
/// <param name="alignSize">Alignment requirement for the memory block.</param>
|
/// <param name="alignSize">Alignment requirement for the memory block.</param>
|
||||||
/// <returns>Pointer to the allocated memory block.</returns>
|
/// <returns>Pointer to the allocated memory block.</returns>
|
||||||
/// <exception cref="ObjectDisposedException">Thrown if the arena has been disposed.</exception>
|
/// <exception cref="ObjectDisposedException">Thrown if the arena has been disposed.</exception>
|
||||||
public void* Allocate(ulong size, uint alignSize)
|
public void* Allocate(uint size, uint alignSize, AllocationType allocationType)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -67,7 +68,7 @@ public unsafe struct DynamicArena : IDisposable
|
|||||||
|
|
||||||
while (current != null)
|
while (current != null)
|
||||||
{
|
{
|
||||||
result = current->arena.Allocate(size, alignSize);
|
result = current->arena.Allocate(size, alignSize, allocationType);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@@ -113,7 +114,7 @@ public unsafe struct DynamicArena : IDisposable
|
|||||||
{
|
{
|
||||||
var next = current->next;
|
var next = current->next;
|
||||||
current->arena.Dispose();
|
current->arena.Dispose();
|
||||||
Marshal.FreeHGlobal((IntPtr)current);
|
NativeMemory.Free(current);
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
public UnsafeArray(int size, AllocationType allocationType)
|
public UnsafeArray(int size, AllocationType allocationType)
|
||||||
{
|
{
|
||||||
_size = size;
|
_size = size;
|
||||||
_buffer = (T*)Marshal.AllocHGlobal(size * sizeof(T)).ToPointer();
|
_buffer = (T*)NativeMemory.AlignedAlloc((nuint)(size * sizeof(T)), (nuint)AlignOf<T>());
|
||||||
|
|
||||||
if (allocationType == AllocationType.Clear)
|
if (allocationType == AllocationType.Clear)
|
||||||
{
|
{
|
||||||
@@ -93,7 +93,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer = (T*)Marshal.ReAllocHGlobal((IntPtr)_buffer, newSize * sizeof(T)).ToPointer();
|
_buffer = (T*)NativeMemory.AlignedRealloc(_buffer, (nuint)(newSize * sizeof(T)), (nuint)AlignOf<T>());
|
||||||
_size = newSize;
|
_size = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ public unsafe struct UnsafeArray<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal((IntPtr)_buffer);
|
NativeMemory.AlignedFree(_buffer);
|
||||||
|
|
||||||
_buffer = null;
|
_buffer = null;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
public UnsafeList(int capacity, AllocationType allocationType)
|
public UnsafeList(int capacity, AllocationType allocationType)
|
||||||
{
|
{
|
||||||
_buffer = (T*)Marshal.AllocHGlobal(capacity * sizeof(T));
|
_buffer = (T*)NativeMemory.AlignedAlloc((nuint)(capacity * sizeof(T)), (nuint)AlignOf<T>());
|
||||||
_size = 0;
|
_size = 0;
|
||||||
_capacity = capacity;
|
_capacity = capacity;
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffer = (T*)Marshal.ReAllocHGlobal((IntPtr)_buffer, newSize * sizeof(T)).ToPointer();
|
_buffer = (T*)NativeMemory.AlignedRealloc(_buffer, (nuint)(newSize * sizeof(T)), (nuint)AlignOf<T>());
|
||||||
_size = newSize;
|
_size = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ public unsafe struct UnsafeList<T> : IUnsafeCollection<T>, IEnumerable<T> where
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal((IntPtr)_buffer);
|
NativeMemory.AlignedFree(_buffer);
|
||||||
|
|
||||||
_buffer = null;
|
_buffer = null;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Misaki.HighPerformance.Unsafe.Helpers;
|
namespace Misaki.HighPerformance.Unsafe.Helpers;
|
||||||
public unsafe static class MemoryUtilities
|
public unsafe static class MemoryUtilities
|
||||||
{
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
private struct AlignOfHelper<T> where T : struct
|
||||||
|
{
|
||||||
|
public byte dummy;
|
||||||
|
public T data;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears a block of memory by setting it to zero. It initializes a specified number of bytes at a given memory
|
/// Clears a block of memory by setting it to zero. It initializes a specified number of bytes at a given memory
|
||||||
/// address.
|
/// address.
|
||||||
@@ -10,32 +18,63 @@ public unsafe static class MemoryUtilities
|
|||||||
/// <param name="ptr">Specifies the memory address where the clearing operation will begin.</param>
|
/// <param name="ptr">Specifies the memory address where the clearing operation will begin.</param>
|
||||||
/// <param name="size">Indicates the number of bytes to be cleared in the memory block.</param>
|
/// <param name="size">Indicates the number of bytes to be cleared in the memory block.</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void MemClear(void* ptr, uint size)
|
public static void MemClear(void* ptr, nuint size)
|
||||||
{
|
{
|
||||||
SystemUnsfae.InitBlock(ptr, 0, size);
|
NativeMemory.Clear(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets a block of memory to a specified byte value for a given size.
|
/// Sets a block of memory to a specified byte value for a given size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ptr">The memory address where the byte value will be set.</param>
|
/// <param name="ptr">The memory address where the byte value will be set.</param>
|
||||||
/// <param name="value">The byte value to which the memory block will be initialized.</param>
|
|
||||||
/// <param name="size">The number of bytes to set to the specified value.</param>
|
/// <param name="size">The number of bytes to set to the specified value.</param>
|
||||||
|
/// <param name="value">The byte value to which the memory block will be initialized.</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void MemSet(void* ptr, byte value, uint size)
|
public static void MemSet(void* ptr, nuint size, byte value)
|
||||||
{
|
{
|
||||||
SystemUnsfae.InitBlock(ptr, value, size);
|
NativeMemory.Fill(ptr, size, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies a block of memory from a source location to a destination location.
|
/// Copies a block of memory from a source location to a destination location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="destination">Specifies the memory address where the copied data will be stored.</param>
|
|
||||||
/// <param name="source">Indicates the memory address from which data will be copied.</param>
|
/// <param name="source">Indicates the memory address from which data will be copied.</param>
|
||||||
|
/// <param name="destination">Specifies the memory address where the copied data will be stored.</param>
|
||||||
/// <param name="size">Defines the number of bytes to be copied from the source to the destination.</param>
|
/// <param name="size">Defines the number of bytes to be copied from the source to the destination.</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void MemCpy(void* destination, void* source, uint size)
|
public static void MemCpy(void* source, void* destination, nuint size)
|
||||||
{
|
{
|
||||||
SystemUnsfae.CopyBlock(destination, source, size);
|
NativeMemory.Copy(source, destination, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the size in bytes of a specified unmanaged type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Represents an unmanaged type for which the size is being calculated.</typeparam>
|
||||||
|
/// <returns>Returns the size of the specified type as an unsigned integer.</returns>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static nuint SizeOf<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
return (nuint)sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the alignment size of a specified unmanaged type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Represents an unmanaged type for which the alignment size is being calculated.</typeparam>
|
||||||
|
/// <returns>Returns the difference in size between a helper structure and the specified type.</returns>
|
||||||
|
public static int AlignOf<T>() where T : unmanaged
|
||||||
|
{
|
||||||
|
return sizeof(AlignOfHelper<T>) - sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the alignment size difference between a specified struct and a helper struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Represents a value type that is used to determine the alignment size.</typeparam>
|
||||||
|
/// <returns>Returns the size difference in bytes as an integer.</returns>
|
||||||
|
public static int MarshalAlignOf<T>() where T : struct
|
||||||
|
{
|
||||||
|
return Marshal.SizeOf<AlignOfHelper<T>>() - Marshal.SizeOf<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ namespace Misaki.HighPerformance.Buffer
|
|||||||
{
|
{
|
||||||
PoolCleanup();
|
PoolCleanup();
|
||||||
|
|
||||||
_disposed = true:
|
_disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user