Work on resource classes and generic interfaces.
This commit is contained in:
parent
8ce1329dfc
commit
5014d218e2
@ -12,6 +12,7 @@ namespace Dashboard.Drawing.OpenGL
|
||||
if (!_unique.TryGetValue(context, out ContextResourcePool? pool))
|
||||
{
|
||||
pool = new ContextResourcePool(this, context);
|
||||
_unique.Add(context, pool);
|
||||
}
|
||||
|
||||
return pool;
|
||||
@ -21,6 +22,7 @@ namespace Dashboard.Drawing.OpenGL
|
||||
if (!_shared.TryGetValue(context.ContextGroup, out ContextResourcePool? pool))
|
||||
{
|
||||
pool = new ContextResourcePool(this, context.ContextGroup);
|
||||
_shared.Add(context.ContextGroup, pool);
|
||||
}
|
||||
|
||||
return pool;
|
||||
@ -36,11 +38,14 @@ namespace Dashboard.Drawing.OpenGL
|
||||
public class ContextResourcePool : IGLDisposable, IArc
|
||||
{
|
||||
private int _references = 0;
|
||||
private bool _isDisposed = false;
|
||||
private readonly Dictionary<int, IResourceManager> _managers = new Dictionary<int, IResourceManager>();
|
||||
|
||||
public ContextResourcePoolManager Manager { get; }
|
||||
public IGLContext? Context { get; private set; } = null;
|
||||
public int ContextGroup { get; private set; } = -1;
|
||||
public int References => _references;
|
||||
public ContextCollector Collector { get; } = new ContextCollector();
|
||||
|
||||
internal ContextResourcePool(ContextResourcePoolManager manager, int contextGroup)
|
||||
{
|
||||
@ -54,6 +59,23 @@ namespace Dashboard.Drawing.OpenGL
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public T GetResourceManager<T>(bool init = true) where T : IResourceManager, new()
|
||||
{
|
||||
int index = ManagerAtom<T>.Atom;
|
||||
|
||||
if (!_managers.TryGetValue(index, out IResourceManager? resourceClass))
|
||||
{
|
||||
_managers[index] = resourceClass = new T();
|
||||
}
|
||||
|
||||
if (init && resourceClass is IInitializer initializer)
|
||||
{
|
||||
initializer.Initialize();
|
||||
}
|
||||
|
||||
return (T)resourceClass;
|
||||
}
|
||||
|
||||
~ContextResourcePool()
|
||||
{
|
||||
Dispose(true, false);
|
||||
@ -65,7 +87,23 @@ namespace Dashboard.Drawing.OpenGL
|
||||
|
||||
private void Dispose(bool safeExit, bool disposing)
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
_isDisposed = true;
|
||||
|
||||
Manager.Disposed(this);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
foreach ((int _, IResourceManager manager) in _managers)
|
||||
{
|
||||
if (manager is IGLDisposable glDisposable)
|
||||
glDisposable.Dispose(safeExit);
|
||||
else if (manager is IDisposable disposable)
|
||||
disposable.Dispose();
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void IncrementReference()
|
||||
@ -77,5 +115,17 @@ namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
return Interlocked.Decrement(ref _references) == 0;
|
||||
}
|
||||
|
||||
|
||||
private class ManagerAtom
|
||||
{
|
||||
private static int _counter = -1;
|
||||
|
||||
protected static int Acquire() => Interlocked.Increment(ref _counter);
|
||||
}
|
||||
private class ManagerAtom<T> : ManagerAtom where T : IResourceManager
|
||||
{
|
||||
public static int Atom { get; } = Acquire();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,22 @@ using OpenTK.Mathematics;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public class GradientUniformBuffer
|
||||
public class GradientUniformBuffer : IInitializer, IGLDisposable, IResourceManager
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private int _top = 0;
|
||||
private readonly MappableBuffer<GradientUniformStruct> _buffer = new MappableBuffer<GradientUniformStruct>();
|
||||
private readonly Dictionary<Gradient, Entry> _entries = new Dictionary<Gradient, Entry>();
|
||||
|
||||
public bool IsInitialized { get; private set; } = false;
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized)
|
||||
return;
|
||||
|
||||
IsInitialized = true;
|
||||
|
||||
_buffer.Initialize();
|
||||
}
|
||||
|
||||
@ -54,6 +62,19 @@ namespace Dashboard.Drawing.OpenGL
|
||||
}
|
||||
|
||||
public record struct Entry(int Offset, int Count);
|
||||
|
||||
public void Dispose() => Dispose(true);
|
||||
|
||||
public void Dispose(bool safeExit)
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
_isDisposed = true;
|
||||
|
||||
_buffer.Dispose(safeExit);
|
||||
}
|
||||
|
||||
string IResourceManager.Name { get; } = nameof(GradientUniformBuffer);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(float))]
|
||||
|
9
Dashboard.Drawing.OpenGL/IInitializer.cs
Normal file
9
Dashboard.Drawing.OpenGL/IInitializer.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public interface IInitializer
|
||||
{
|
||||
bool IsInitialized { get; }
|
||||
|
||||
void Initialize();
|
||||
}
|
||||
}
|
7
Dashboard.Drawing.OpenGL/IResourceManager.cs
Normal file
7
Dashboard.Drawing.OpenGL/IResourceManager.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public interface IResourceManager
|
||||
{
|
||||
public string Name { get; }
|
||||
}
|
||||
}
|
@ -4,23 +4,28 @@ using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Dashboard.Drawing.OpenGL
|
||||
{
|
||||
public class MappableBuffer<T> : IDisposable
|
||||
public class MappableBuffer<T> : IInitializer, IGLDisposable where T : struct
|
||||
{
|
||||
public int Handle { get; private set; } = 0;
|
||||
public int Capacity { get; set; } = BASE_CAPACITY;
|
||||
public IntPtr Pointer { get; private set; } = IntPtr.Zero;
|
||||
|
||||
public bool IsInitialized => Handle != 0;
|
||||
|
||||
private bool _isDisposed = false;
|
||||
private const int BASE_CAPACITY = 4 << 10; // 4 KiB
|
||||
private const int MAX_INCREMENT = 4 << 20; // 4 MiB
|
||||
|
||||
~MappableBuffer()
|
||||
{
|
||||
Dispose(false);
|
||||
Dispose(true, false);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
if (IsInitialized)
|
||||
return;
|
||||
|
||||
Handle = GL.GenBuffer();
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, Capacity, IntPtr.Zero, BufferUsage.DynamicDraw);
|
||||
@ -31,9 +36,14 @@ namespace Dashboard.Drawing.OpenGL
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(count));
|
||||
|
||||
if (Capacity >= count)
|
||||
if (Capacity > count)
|
||||
return;
|
||||
|
||||
SetSize(count, false);
|
||||
}
|
||||
|
||||
public void SetSize(int count, bool clear = false)
|
||||
{
|
||||
AssertInitialized();
|
||||
Unmap();
|
||||
|
||||
@ -41,6 +51,10 @@ namespace Dashboard.Drawing.OpenGL
|
||||
int oldsize = Capacity * sz;
|
||||
int request = count * sz;
|
||||
int newsize;
|
||||
|
||||
if (request < BASE_CAPACITY)
|
||||
request = BASE_CAPACITY;
|
||||
|
||||
if (request > MAX_INCREMENT)
|
||||
{
|
||||
newsize = ((request + MAX_INCREMENT - 1) / MAX_INCREMENT) * MAX_INCREMENT;
|
||||
@ -52,15 +66,23 @@ namespace Dashboard.Drawing.OpenGL
|
||||
|
||||
int dest = GL.GenBuffer();
|
||||
|
||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, dest);
|
||||
GL.BindBuffer(BufferTarget.CopyReadBuffer, Handle);
|
||||
if (clear)
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, dest);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, newsize, IntPtr.Zero, BufferUsage.DynamicDraw);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, dest);
|
||||
GL.BindBuffer(BufferTarget.CopyReadBuffer, Handle);
|
||||
|
||||
GL.BufferData(BufferTarget.CopyWriteBuffer, newsize, IntPtr.Zero, BufferUsage.DynamicDraw);
|
||||
GL.CopyBufferSubData(CopyBufferSubDataTarget.CopyReadBuffer, CopyBufferSubDataTarget.CopyWriteBuffer, 0, 0, oldsize);
|
||||
GL.BufferData(BufferTarget.CopyWriteBuffer, newsize, IntPtr.Zero, BufferUsage.DynamicDraw);
|
||||
GL.CopyBufferSubData(CopyBufferSubDataTarget.CopyReadBuffer, CopyBufferSubDataTarget.CopyWriteBuffer, 0, 0, Math.Min(newsize, oldsize));
|
||||
}
|
||||
|
||||
GL.DeleteBuffer(Handle);
|
||||
Handle = dest;
|
||||
Capacity = newsize;
|
||||
Capacity = newsize / Unsafe.SizeOf<T>();
|
||||
}
|
||||
|
||||
public unsafe void Map()
|
||||
@ -83,6 +105,7 @@ namespace Dashboard.Drawing.OpenGL
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
||||
GL.UnmapBuffer(BufferTarget.ArrayBuffer);
|
||||
Pointer = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public unsafe Span<T> AsSpan()
|
||||
@ -92,7 +115,7 @@ namespace Dashboard.Drawing.OpenGL
|
||||
|
||||
AssertInitialized();
|
||||
|
||||
return new Span<T>(Pointer.ToPointer(), Capacity / Unsafe.SizeOf<T>());
|
||||
return new Span<T>(Pointer.ToPointer(), Capacity);
|
||||
}
|
||||
|
||||
private void AssertInitialized()
|
||||
@ -101,7 +124,7 @@ namespace Dashboard.Drawing.OpenGL
|
||||
throw new InvalidOperationException("The buffer is not initialized.");
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
private void Dispose(bool safeExit, bool disposing)
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
@ -110,9 +133,35 @@ namespace Dashboard.Drawing.OpenGL
|
||||
if (disposing)
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
ContextCollector.Global.DeleteBufffer(Handle);
|
||||
if (safeExit)
|
||||
ContextCollector.Global.DeleteBufffer(Handle);
|
||||
}
|
||||
|
||||
public void Dispose() => Dispose(true);
|
||||
public void Dispose() => Dispose(true, true);
|
||||
public void Dispose(bool safeExit) => Dispose(safeExit, true);
|
||||
}
|
||||
|
||||
public class MappableBumpAllocator<T> : MappableBuffer<T> where T : struct
|
||||
{
|
||||
private int _top = 0;
|
||||
private int _previousTop = 0;
|
||||
|
||||
public ref T Take(out int index)
|
||||
{
|
||||
index = _top;
|
||||
EnsureCapacity(++_top);
|
||||
Map();
|
||||
|
||||
return ref AsSpan()[index];
|
||||
}
|
||||
|
||||
public ref T Take() => ref Take(out _);
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
SetSize(0, true);
|
||||
_previousTop = _top;
|
||||
_top = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user