make some changes to opengl api gen, discussing on rewrite of all opengl binding, making it neat and structral
This commit is contained in:
@@ -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<T>.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<T></c> does not implicitly convert to
|
||||
/// <c>ReadOnlySpan<T></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<T>.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;
|
||||
|
||||
Reference in New Issue
Block a user