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))
|
if (!_unique.TryGetValue(context, out ContextResourcePool? pool))
|
||||||
{
|
{
|
||||||
pool = new ContextResourcePool(this, context);
|
pool = new ContextResourcePool(this, context);
|
||||||
|
_unique.Add(context, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
@ -21,6 +22,7 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
if (!_shared.TryGetValue(context.ContextGroup, out ContextResourcePool? pool))
|
if (!_shared.TryGetValue(context.ContextGroup, out ContextResourcePool? pool))
|
||||||
{
|
{
|
||||||
pool = new ContextResourcePool(this, context.ContextGroup);
|
pool = new ContextResourcePool(this, context.ContextGroup);
|
||||||
|
_shared.Add(context.ContextGroup, pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
@ -36,11 +38,14 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
public class ContextResourcePool : IGLDisposable, IArc
|
public class ContextResourcePool : IGLDisposable, IArc
|
||||||
{
|
{
|
||||||
private int _references = 0;
|
private int _references = 0;
|
||||||
|
private bool _isDisposed = false;
|
||||||
|
private readonly Dictionary<int, IResourceManager> _managers = new Dictionary<int, IResourceManager>();
|
||||||
|
|
||||||
public ContextResourcePoolManager Manager { get; }
|
public ContextResourcePoolManager Manager { get; }
|
||||||
public IGLContext? Context { get; private set; } = null;
|
public IGLContext? Context { get; private set; } = null;
|
||||||
public int ContextGroup { get; private set; } = -1;
|
public int ContextGroup { get; private set; } = -1;
|
||||||
public int References => _references;
|
public int References => _references;
|
||||||
|
public ContextCollector Collector { get; } = new ContextCollector();
|
||||||
|
|
||||||
internal ContextResourcePool(ContextResourcePoolManager manager, int contextGroup)
|
internal ContextResourcePool(ContextResourcePoolManager manager, int contextGroup)
|
||||||
{
|
{
|
||||||
@ -54,6 +59,23 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
Context = context;
|
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()
|
~ContextResourcePool()
|
||||||
{
|
{
|
||||||
Dispose(true, false);
|
Dispose(true, false);
|
||||||
@ -65,7 +87,23 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
|
|
||||||
private void Dispose(bool safeExit, bool disposing)
|
private void Dispose(bool safeExit, bool disposing)
|
||||||
{
|
{
|
||||||
|
if (_isDisposed)
|
||||||
|
return;
|
||||||
|
_isDisposed = true;
|
||||||
|
|
||||||
Manager.Disposed(this);
|
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()
|
public void IncrementReference()
|
||||||
@ -77,5 +115,17 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
{
|
{
|
||||||
return Interlocked.Decrement(ref _references) == 0;
|
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
|
namespace Dashboard.Drawing.OpenGL
|
||||||
{
|
{
|
||||||
public class GradientUniformBuffer
|
public class GradientUniformBuffer : IInitializer, IGLDisposable, IResourceManager
|
||||||
{
|
{
|
||||||
|
private bool _isDisposed;
|
||||||
private int _top = 0;
|
private int _top = 0;
|
||||||
private readonly MappableBuffer<GradientUniformStruct> _buffer = new MappableBuffer<GradientUniformStruct>();
|
private readonly MappableBuffer<GradientUniformStruct> _buffer = new MappableBuffer<GradientUniformStruct>();
|
||||||
private readonly Dictionary<Gradient, Entry> _entries = new Dictionary<Gradient, Entry>();
|
private readonly Dictionary<Gradient, Entry> _entries = new Dictionary<Gradient, Entry>();
|
||||||
|
|
||||||
|
public bool IsInitialized { get; private set; } = false;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
|
if (IsInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IsInitialized = true;
|
||||||
|
|
||||||
_buffer.Initialize();
|
_buffer.Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,6 +62,19 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
}
|
}
|
||||||
|
|
||||||
public record struct Entry(int Offset, int Count);
|
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))]
|
[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
|
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 Handle { get; private set; } = 0;
|
||||||
public int Capacity { get; set; } = BASE_CAPACITY;
|
public int Capacity { get; set; } = BASE_CAPACITY;
|
||||||
public IntPtr Pointer { get; private set; } = IntPtr.Zero;
|
public IntPtr Pointer { get; private set; } = IntPtr.Zero;
|
||||||
|
|
||||||
|
public bool IsInitialized => Handle != 0;
|
||||||
|
|
||||||
private bool _isDisposed = false;
|
private bool _isDisposed = false;
|
||||||
private const int BASE_CAPACITY = 4 << 10; // 4 KiB
|
private const int BASE_CAPACITY = 4 << 10; // 4 KiB
|
||||||
private const int MAX_INCREMENT = 4 << 20; // 4 MiB
|
private const int MAX_INCREMENT = 4 << 20; // 4 MiB
|
||||||
|
|
||||||
~MappableBuffer()
|
~MappableBuffer()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
|
if (IsInitialized)
|
||||||
|
return;
|
||||||
|
|
||||||
Handle = GL.GenBuffer();
|
Handle = GL.GenBuffer();
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
||||||
GL.BufferData(BufferTarget.ArrayBuffer, Capacity, IntPtr.Zero, BufferUsage.DynamicDraw);
|
GL.BufferData(BufferTarget.ArrayBuffer, Capacity, IntPtr.Zero, BufferUsage.DynamicDraw);
|
||||||
@ -31,9 +36,14 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
if (count < 0)
|
if (count < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
|
|
||||||
if (Capacity >= count)
|
if (Capacity > count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
SetSize(count, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSize(int count, bool clear = false)
|
||||||
|
{
|
||||||
AssertInitialized();
|
AssertInitialized();
|
||||||
Unmap();
|
Unmap();
|
||||||
|
|
||||||
@ -41,6 +51,10 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
int oldsize = Capacity * sz;
|
int oldsize = Capacity * sz;
|
||||||
int request = count * sz;
|
int request = count * sz;
|
||||||
int newsize;
|
int newsize;
|
||||||
|
|
||||||
|
if (request < BASE_CAPACITY)
|
||||||
|
request = BASE_CAPACITY;
|
||||||
|
|
||||||
if (request > MAX_INCREMENT)
|
if (request > MAX_INCREMENT)
|
||||||
{
|
{
|
||||||
newsize = ((request + MAX_INCREMENT - 1) / MAX_INCREMENT) * MAX_INCREMENT;
|
newsize = ((request + MAX_INCREMENT - 1) / MAX_INCREMENT) * MAX_INCREMENT;
|
||||||
@ -52,15 +66,23 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
|
|
||||||
int dest = GL.GenBuffer();
|
int dest = GL.GenBuffer();
|
||||||
|
|
||||||
GL.BindBuffer(BufferTarget.CopyWriteBuffer, dest);
|
if (clear)
|
||||||
GL.BindBuffer(BufferTarget.CopyReadBuffer, Handle);
|
{
|
||||||
|
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.BufferData(BufferTarget.CopyWriteBuffer, newsize, IntPtr.Zero, BufferUsage.DynamicDraw);
|
||||||
GL.CopyBufferSubData(CopyBufferSubDataTarget.CopyReadBuffer, CopyBufferSubDataTarget.CopyWriteBuffer, 0, 0, oldsize);
|
GL.CopyBufferSubData(CopyBufferSubDataTarget.CopyReadBuffer, CopyBufferSubDataTarget.CopyWriteBuffer, 0, 0, Math.Min(newsize, oldsize));
|
||||||
|
}
|
||||||
|
|
||||||
GL.DeleteBuffer(Handle);
|
GL.DeleteBuffer(Handle);
|
||||||
Handle = dest;
|
Handle = dest;
|
||||||
Capacity = newsize;
|
Capacity = newsize / Unsafe.SizeOf<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Map()
|
public unsafe void Map()
|
||||||
@ -83,6 +105,7 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
|
|
||||||
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
|
||||||
GL.UnmapBuffer(BufferTarget.ArrayBuffer);
|
GL.UnmapBuffer(BufferTarget.ArrayBuffer);
|
||||||
|
Pointer = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe Span<T> AsSpan()
|
public unsafe Span<T> AsSpan()
|
||||||
@ -92,7 +115,7 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
|
|
||||||
AssertInitialized();
|
AssertInitialized();
|
||||||
|
|
||||||
return new Span<T>(Pointer.ToPointer(), Capacity / Unsafe.SizeOf<T>());
|
return new Span<T>(Pointer.ToPointer(), Capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertInitialized()
|
private void AssertInitialized()
|
||||||
@ -101,7 +124,7 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
throw new InvalidOperationException("The buffer is not initialized.");
|
throw new InvalidOperationException("The buffer is not initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
private void Dispose(bool safeExit, bool disposing)
|
||||||
{
|
{
|
||||||
if (_isDisposed)
|
if (_isDisposed)
|
||||||
return;
|
return;
|
||||||
@ -110,9 +133,35 @@ namespace Dashboard.Drawing.OpenGL
|
|||||||
if (disposing)
|
if (disposing)
|
||||||
GC.SuppressFinalize(this);
|
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