Files
RobustToolbox/Robust.Client/Graphics/Clyde/GLObjects/Clyde.Buffer.cs
2022-02-05 19:31:58 +01:00

192 lines
5.9 KiB
C#

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using OpenToolkit.Graphics.OpenGL4;
using Robust.Shared.Utility;
namespace Robust.Client.Graphics.Clyde
{
internal partial class Clyde
{
/// <summary>
/// Represents an OpenGL buffer object.
/// </summary>
[Virtual]
private class GLBuffer
{
private readonly Clyde _clyde;
public BufferTarget Type { get; }
public uint ObjectHandle { get; private set; }
public BufferUsageHint UsageHint { get; }
public string? Name { get; }
public GLBuffer(Clyde clyde, BufferTarget type, BufferUsageHint usage, string? name = null)
{
_clyde = clyde;
Type = type;
Name = name;
UsageHint = usage;
GL.GenBuffers(1, out uint handle);
clyde.CheckGlError();
ObjectHandle = handle;
GL.BindBuffer(type, handle);
clyde.CheckGlError();
_clyde.ObjectLabelMaybe(ObjectLabelIdentifier.Buffer, ObjectHandle, name);
}
public GLBuffer(Clyde clyde, BufferTarget type, BufferUsageHint usage, int size, string? name = null)
: this(clyde, type, usage, name)
{
Reallocate(size);
}
public GLBuffer(Clyde clyde, BufferTarget type, BufferUsageHint usage, Span<byte> initialize,
string? name = null)
: this(clyde, type, usage, name)
{
Reallocate(initialize);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Use()
{
DebugTools.Assert(ObjectHandle != 0);
GL.BindBuffer(Type, ObjectHandle);
_clyde.CheckGlError();
}
public void Delete()
{
GL.DeleteBuffer(ObjectHandle);
_clyde.CheckGlError();
ObjectHandle = 0;
}
/// <summary>
/// <c>glBufferSubData</c>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteSubData<T>(int start, Span<T> data) where T : unmanaged
{
Use();
var byteSpan = MemoryMarshal.AsBytes(data);
unsafe
{
fixed (byte* ptr = byteSpan)
{
GL.BufferSubData(Type, (IntPtr) start, byteSpan.Length, (IntPtr) ptr);
}
}
_clyde.CheckGlError();
}
/// <summary>
/// <c>glBufferSubData</c>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteSubData<T>(Span<T> data) where T : unmanaged
{
Use();
var byteSpan = MemoryMarshal.AsBytes(data);
unsafe
{
fixed (byte* ptr = byteSpan)
{
GL.BufferSubData(Type, IntPtr.Zero, byteSpan.Length, (IntPtr) ptr);
}
}
_clyde.CheckGlError();
}
/// <summary>
/// <c>glBufferSubData</c>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void WriteSubData<T>(in T data) where T : unmanaged
{
Use();
unsafe
{
fixed (T* ptr = &data)
{
GL.BufferSubData(Type, IntPtr.Zero, sizeof(T), (IntPtr) ptr);
}
}
_clyde.CheckGlError();
}
/// <summary>
/// <c>glBufferData</c>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reallocate<T>(Span<T> data) where T : unmanaged
{
Use();
var byteSpan = MemoryMarshal.AsBytes(data);
unsafe
{
fixed (byte* ptr = byteSpan)
{
GL.BufferData(Type, byteSpan.Length, (IntPtr) ptr, UsageHint);
}
}
_clyde.CheckGlError();
}
/// <summary>
/// <c>glBufferData</c>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reallocate<T>(in T data) where T : unmanaged
{
Use();
unsafe
{
fixed (T* ptr = &data)
{
GL.BufferData(Type, sizeof(T), (IntPtr) ptr, UsageHint);
}
}
_clyde.CheckGlError();
}
/// <summary>
/// <c>glBufferData</c>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reallocate(int size)
{
Use();
GL.BufferData(Type, size, IntPtr.Zero, UsageHint);
_clyde.CheckGlError();
}
}
/// <inheritdoc />
/// <summary>
/// Subtype of buffers so that we can have a generic constructor.
/// Functionally equivalent to <see cref="GLBuffer"/> otherwise.
/// </summary>
private sealed class GLBuffer<T> : GLBuffer where T : unmanaged
{
public GLBuffer(Clyde clyde, BufferTarget type, BufferUsageHint usage, Span<T> initialize,
string? name = null)
: base(clyde, type, usage, MemoryMarshal.AsBytes(initialize), name)
{
}
}
}
}