Added RenderPipelineBase

This commit is contained in:
2026-03-02 19:06:19 +09:00
parent 5e42d699c3
commit b8af6e8c3a
13 changed files with 338 additions and 32 deletions

View File

@@ -12,7 +12,7 @@ public record struct RenderRecord
public struct RenderList : IDisposable
{
public unsafe ref struct Reader
public unsafe ref struct Enumerator
{
private readonly UnsafeList<RenderRecord>* pList;
private readonly int length;
@@ -20,7 +20,7 @@ public struct RenderList : IDisposable
private int _listIndex;
private int _itemIndex;
internal Reader(RenderList List)
internal Enumerator(RenderList List)
{
pList = (UnsafeList<RenderRecord>*)List._threadLocalRecords.GetUnsafePtr();
length = List._threadLocalRecords.Length;
@@ -59,8 +59,16 @@ public struct RenderList : IDisposable
private UnsafeArray<UnsafeList<RenderRecord>> _threadLocalRecords;
public readonly int ThreadLocalCount => _threadLocalRecords.Length;
public readonly bool IsCreated => _threadLocalRecords.IsCreated;
public RenderList(int maxLevelOfConcurrency, int capacity, AllocationHandle allocationHandle)
{
if (maxLevelOfConcurrency <= 0)
{
throw new ArgumentOutOfRangeException(nameof(maxLevelOfConcurrency), "Max level of concurrency must be greater than zero.");
}
_threadLocalRecords = new UnsafeArray<UnsafeList<RenderRecord>>(maxLevelOfConcurrency, allocationHandle);
for (int i = 0; i < maxLevelOfConcurrency; i++)
@@ -74,16 +82,70 @@ public struct RenderList : IDisposable
{
}
public readonly Reader GetEnumerator()
private readonly void ThrowIfNotCreated()
{
return new Reader(this);
if (!IsCreated)
{
throw new InvalidOperationException("RenderList is not created.");
}
}
public readonly Enumerator GetEnumerator()
{
ThrowIfNotCreated();
return new Enumerator(this);
}
public readonly void Add(RenderRecord record, int threadIndex)
{
ThrowIfNotCreated();
_threadLocalRecords[threadIndex].Add(record);
}
public readonly ReadOnlyUnsafeCollection<RenderRecord> GetThreadLocalRecords(int threadIndex)
{
ThrowIfNotCreated();
return _threadLocalRecords[threadIndex].AsReadOnly();
}
public readonly void Clear()
{
ThrowIfNotCreated();
for (int i = 0; i < _threadLocalRecords.Length; i++)
{
_threadLocalRecords[i].Clear();
}
}
public readonly void ClearThreadLocal(int threadIndex)
{
ThrowIfNotCreated();
_threadLocalRecords[threadIndex].Clear();
}
public readonly void Append(RenderList other)
{
if (!IsCreated || !other.IsCreated)
{
throw new InvalidOperationException("Both RenderLists must be created before appending.");
}
var maxConcurrency = Math.Min(_threadLocalRecords.Length, other._threadLocalRecords.Length);
for (int i = 0; i < maxConcurrency; i++)
{
_threadLocalRecords[i].AddRange(other._threadLocalRecords[i].AsSpan());
}
if (other._threadLocalRecords.Length > _threadLocalRecords.Length)
{
// Add remaining records from other lists to the first list if other has more thread local lists than this
for (int i = _threadLocalRecords.Length; i < other._threadLocalRecords.Length; i++)
{
_threadLocalRecords[0].AddRange(other._threadLocalRecords[i].AsSpan());
}
}
}
public void Dispose()
{
for (int i = 0; i < _threadLocalRecords.Length; i++)

View File

@@ -5,6 +5,15 @@ using System.Runtime.InteropServices;
namespace Ghost.Graphics.Core;
public enum GateFit : uint
{
Vertical,
Horizontal,
Fill,
Overscan,
None
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct Frustum
{
@@ -33,6 +42,7 @@ public struct Frustum
public float3 corner7;
}
// Since we are using ByteAddressBuffer in hlsl, we don't need to care about the 16 bytes alignment of the data like in CBuffer.
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct RenderView
{
@@ -46,13 +56,14 @@ public struct RenderView
public float farClipPlane;
public float2 sensorSize;
public GateFit gateFit;
public float iso;
public float shutterSpeed;
public float aperture;
public float focalLength;
public float focusDistance;
public uint renderingLayerMask;
public RenderingLayerMask renderingLayerMask;
}
public unsafe struct RenderRequest

View File

@@ -0,0 +1,33 @@
using System.Diagnostics;
namespace Ghost.Graphics.Core;
public struct RenderingLayerMask
{
private static readonly Dictionary<string, uint> _layerNameToBit = new (32);
private static readonly Dictionary<uint, string> _bitToLayerName = new (32);
internal static void SetLayerName(int layerIndex, string name)
{
Debug.Assert(layerIndex >= 0 && layerIndex < 32, "Layer index must be between 0 and 31.");
var bit = 1u << layerIndex;
_layerNameToBit[name] = bit;
_bitToLayerName[bit] = name;
}
public static uint GetLayerBit(string name)
{
if (_layerNameToBit.TryGetValue(name, out var bit))
{
return bit;
}
return ~0u;
}
public uint value;
public static implicit operator uint(RenderingLayerMask mask) => mask.value;
public static implicit operator RenderingLayerMask(uint value) => new RenderingLayerMask { value = value };
}