99 lines
3.4 KiB
C#
99 lines
3.4 KiB
C#
using System.Runtime.CompilerServices;
|
|
using Dashboard.Drawing;
|
|
using OpenTK.Graphics.OpenGL;
|
|
|
|
namespace Dashboard.OpenGL
|
|
{
|
|
public class GLBuffer(GLDeviceContext dc, BufferAccessPattern pattern, int handle, long size, long offset) : IBuffer
|
|
{
|
|
// TODO: At the moment, this class does no pooling. Convert it to a pool for better API usage.
|
|
|
|
public BufferAccessPattern AccessPattern { get; } = pattern;
|
|
public long Size { get; private set; } = size;
|
|
public long Offset { get; private set; } = offset;
|
|
public int Handle { get; private set; }
|
|
|
|
public void Reallocate(long newSize)
|
|
{
|
|
GL.CreateBuffer(out int handle);
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, handle);
|
|
GL.BufferData(BufferTarget.ArrayBuffer, (nint)newSize, (nint)0, AccessPattern switch
|
|
{
|
|
BufferAccessPattern.Stream => BufferUsage.StreamDraw,
|
|
BufferAccessPattern.Static => BufferUsage.StaticDraw,
|
|
BufferAccessPattern.Download => BufferUsage.DynamicCopy,
|
|
BufferAccessPattern.Upload => BufferUsage.DynamicCopy,
|
|
_ => BufferUsage.DynamicDraw,
|
|
});
|
|
|
|
if (Handle != -1)
|
|
GL.DeleteBuffer(Handle);
|
|
|
|
Handle = handle;
|
|
Size = newSize;
|
|
Offset = 0;
|
|
}
|
|
|
|
public unsafe Span<T> Map<T>(long offset, int count = -1)
|
|
where T : unmanaged
|
|
{
|
|
ArgumentOutOfRangeException.ThrowIfNegative(offset);
|
|
|
|
if (count < 0)
|
|
count = (int)(Size / Unsafe.SizeOf<T>());
|
|
|
|
long absOffset = Offset + offset;
|
|
long absCount = count * Unsafe.SizeOf<T>();
|
|
ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + absCount, Size);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
|
nint ptr = (nint)GL.MapBuffer(BufferTarget.ArrayBuffer, BufferAccess.ReadWrite);
|
|
|
|
return new Span<T>((T*)(ptr + absOffset), count);
|
|
}
|
|
|
|
public void Unmap()
|
|
{
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
|
GL.UnmapBuffer(BufferTarget.ArrayBuffer);
|
|
}
|
|
|
|
public void Read<T>(long offset, Span<T> span) where T : unmanaged
|
|
{
|
|
long absCount = span.Length * Unsafe.SizeOf<T>();
|
|
ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + absCount, Size);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
|
GL.GetBufferSubData(BufferTarget.ArrayBuffer, (nint)(Offset + offset), (nint)absCount, span);
|
|
}
|
|
|
|
public void Write<T>(long offset, ReadOnlySpan<T> span) where T : unmanaged
|
|
{
|
|
long absCount = span.Length * Unsafe.SizeOf<T>();
|
|
ArgumentOutOfRangeException.ThrowIfGreaterThan(offset + absCount, Size);
|
|
|
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
|
GL.BufferSubData(BufferTarget.ArrayBuffer, (nint)(Offset + offset), (nint)absCount, span);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (Handle == -1)
|
|
return;
|
|
|
|
dc.Collector.DeleteBufffer(Handle);
|
|
Handle = -1;
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
public static GLBuffer Create(GLDeviceContext dc, BufferAccessPattern pattern, long size)
|
|
{
|
|
GLBuffer buffer = new GLBuffer(dc, pattern, -1, 0, 0);
|
|
buffer.Reallocate(size);
|
|
|
|
return buffer;
|
|
}
|
|
}
|
|
}
|