make some changes to opengl api gen, discussing on rewrite of all opengl binding, making it neat and structral

This commit is contained in:
Youmu Liu
2026-08-25 17:33:45 +08:00
parent 708a915549
commit 65041ff8bc
63 changed files with 14404 additions and 8851 deletions
@@ -6,6 +6,7 @@
// -----------------------------------------------------------------------------
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -92,6 +93,50 @@ namespace StgSharp.HighPerformance.Memory
return true;
}
/// <summary>
/// Fills the stack in place via a caller-supplied callback, mirroring
/// <c>CapacityFixedStack&lt;T&gt;.FillRange</c>.
/// </summary>
/// <remarks>
/// Preferred over building a temporary span and handing it to
/// <see cref="BufferStackBuilder.Create{T}(ReadOnlySpan{T})"/>:
/// <list type="bullet">
/// <item>The caller no longer needs a scratch buffer at all — the
/// callback writes straight into this stack's native storage, so there
/// is no <c>stackalloc</c> to size and no copy afterwards.</item>
/// <item><c>Span&lt;T&gt;</c> does not implicitly convert to
/// <c>ReadOnlySpan&lt;T&gt;</c> in a way that participates in generic
/// type inference before C# 14, so <c>Create(span)</c> fails with
/// CS0411 on older compilers. Passing the element type through the
/// enclosing instance sidesteps inference entirely.</item>
/// </list>
/// </remarks>
internal unsafe void FillRange(
SpanAction<T, nuint> filling,
nuint buffer
)
{
if (filling is null) {
return;
}
Header* header = (Header*)_buffer;
T* dataStart = (T*)(_buffer + sizeof(Header));
// Hand out only the unused tail, matching CapacityFixedStack:
// filling is an append, not a rewrite of live entries.
int start = (int)header->Top;
int room = (int)header->Capacity - start;
if (room <= 0) {
return;
}
filling(new Span<T>(dataStart + start, room), buffer);
header->Top = header->Capacity;
_count = header->Capacity;
}
// Internal method for efficient bulk initialization
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe void InitializeFromSpan(
@@ -8,6 +8,7 @@
using StgSharp.Threading;
using System;
using System.Buffers;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -253,6 +254,49 @@ namespace StgSharp.HighPerformance.Memory
}
}
/// <summary>
/// Fills the stack in place via a caller-supplied callback, mirroring
/// <c>CapacityFixedStack&lt;T&gt;.FillRange</c>.
/// </summary>
/// <remarks>
/// Intended for construction only, and therefore takes no lock — the
/// instance is not yet published to other threads at that point. Do not
/// call it on a stack that is already in concurrent use.
/// <para>
/// Preferred over building a temporary span and handing it to
/// <see cref="BufferStackBuilder.CreateConcurrent{T}(ReadOnlySpan{T})"/>
/// for the same two reasons as the non-concurrent variant: the callback
/// writes straight into native storage (no scratch buffer, no copy),
/// and passing the element type through the enclosing instance avoids
/// the <c>Span</c>-to-<c>ReadOnlySpan</c> inference gap that yields
/// CS0411 before C# 14.
/// </para>
/// </remarks>
internal unsafe void FillRange(
SpanAction<T, nuint> filling,
nuint buffer
)
{
if (filling is null) {
return;
}
Header* header = (Header*)_buffer;
T* dataStart = (T*)(_buffer + sizeof(Header));
// Append into the unused tail only, matching CapacityFixedStack.
int start = header->Top;
int room = header->Capacity - start;
if (room <= 0) {
return;
}
filling(new Span<T>(dataStart + start, room), buffer);
header->Top = header->Capacity;
Volatile.Write(ref _count, header->Capacity);
}
// Internal method for efficient bulk initialization
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal unsafe void InitializeFromSpan(
@@ -40,15 +40,28 @@ namespace StgSharp.HighPerformance.Memory
> 64 => 64,
_ => (int)count
};
Span<nuint> span = stackalloc nuint[initCount];
for (int i = 0; i < initCount; i++) {
span[i] = _currentBuffer + ((nuint)(i * _elementSize));
}
_buffers = new(4);
_buffers.Push(_currentBuffer);
_recycle = BufferStackBuilder.Create(span);
// Fill through a callback rather than building a scratch span and
// passing it to BufferStackBuilder.Create: no stackalloc, no copy,
// and no reliance on Span-to-ReadOnlySpan inference (CS0411 before
// C# 14). Same shape as FixedSlabAllocator.
int elementSize = _elementSize;
_recycle = new(initCount);
_recycle.FillRange(init, _currentBuffer);
_currentCapacity = count;
_currentIndex = (nuint)initCount;
void init(
Span<nuint> arr,
nuint buffer
)
{
for (int i = 0; i < arr.Length; i++) {
arr[i] = buffer + ((nuint)(i * elementSize));
}
}
}
public override nuint Allocate()
@@ -44,14 +44,26 @@ namespace StgSharp.HighPerformance.Memory
> 64 => 64,
_ => (int)count
};
Span<nuint> span = stackalloc nuint[initCount];
for (int i = 0; i < initCount; i++) {
span[i] = _currentBuffer + (nuint)(i * _elementSize);
}
_buffers = new(4);
_recycle = BufferStackBuilder.CreateConcurrent(span);
// Callback fill instead of scratch span + CreateConcurrent: avoids
// the stackalloc and the copy, and sidesteps the CS0411 inference
// gap. Safe without locking — not yet published to other threads.
int elementSize = _elementSize;
_recycle = new(initCount);
_recycle.FillRange(init, _currentBuffer);
_currentCapacity = count;
_currentIndex = (nuint)initCount;
void init(
Span<nuint> arr,
nuint buffer
)
{
for (int i = 0; i < arr.Length; i++) {
arr[i] = buffer + (nuint)(i * elementSize);
}
}
}
public override nuint Allocate()
@@ -43,12 +43,26 @@ namespace StgSharp.HighPerformance.Memory
> 64 => 64,
_ => ((int)_capacity) / 4
};
Span<nuint> span = stackalloc nuint[initCount];
for (int i = 0; i < initCount; i++) {
span[i] = (nuint)i;
}
_stack = BufferStackBuilder.CreateConcurrent(span);
// Callback fill instead of scratch span + CreateConcurrent: avoids
// the stackalloc and the copy, and sidesteps the CS0411 inference
// gap. Safe without locking — not yet published to other threads.
//
// Note this variant stores *indices*, not addresses, so the buffer
// argument is unused here; it is kept to match the shared
// SpanAction<T, nuint> shape.
_stack = new(initCount);
_stack.FillRange(init, 0);
_highestAllocated += (nuint)initCount;
static void init(
Span<nuint> arr,
nuint _
)
{
for (int i = 0; i < arr.Length; i++) {
arr[i] = (nuint)i;
}
}
}
internal T* BasePointer => _buffer;