Skip to content

Commit

Permalink
[Graphics] LightList and LightingStep now use ValueFreeRefList
Browse files Browse the repository at this point in the history
[Graphics] Added missing summaries in SceneRenderData
  • Loading branch information
Syncaidius committed May 11, 2024
1 parent 7384292 commit fc14339
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 117 deletions.
2 changes: 1 addition & 1 deletion Molten.Engine/Components/Lights/CapsuleLightComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ private void AddToScene(SceneObject obj)

// Add mesh to render data if possible.
if (_visible && obj.Scene != null)
_instance = obj.Scene.RenderData.CapsuleLights.New(_data);
_instance = obj.Scene.RenderData.CapsuleLights.New(ref _data);
}

private void RemoveFromScene(SceneObject obj)
Expand Down
2 changes: 1 addition & 1 deletion Molten.Engine/Components/Lights/PointLightComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private void AddToScene(SceneObject obj)
// Add mesh to render data if possible.
if (_visible && obj.Scene != null)
{
_instance = obj.Scene.RenderData.PointLights.New(_data);
_instance = obj.Scene.RenderData.PointLights.New(ref _data);
_instance.Range = _range;
}
}
Expand Down
30 changes: 6 additions & 24 deletions Molten.Engine/Graphics/GpuTaskBank.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Molten.Graphics;
using Molten.Collections;

namespace Molten.Graphics;
internal abstract class GpuTaskBank
{
internal abstract void Process(GpuCommandList cmd, uint taskIndex);
Expand All @@ -9,10 +11,7 @@ internal abstract class GpuTaskBank
internal class GpuTaskBank<T> : GpuTaskBank
where T : struct, IGpuTask<T>
{
T[] _tasks = new T[8];

uint _nextIndex = 0;
Stack<uint> _free = new();
ValueFreeRefList<T> _tasks = new();

internal GpuTaskBank(int bankIndex)
{
Expand All @@ -24,28 +23,11 @@ internal override void Process(GpuCommandList cmd, uint taskIndex)
ref T task = ref _tasks[taskIndex];
bool success = T.Process(cmd, ref task);
task.Complete(success);

_tasks[taskIndex] = default;
_free.Push(taskIndex);
_tasks.RemoveAt(taskIndex);
}

internal uint Enqueue(ref T task)
{
uint index;

if (_free.Count > 0)
{
index = _free.Pop();
}
else
{
if (_nextIndex >= _tasks.Length)
Array.Resize(ref _tasks, _tasks.Length * 2);

index = _nextIndex++;
}

_tasks[index] = task;
return index;
return _tasks.Add(ref task);
}
}
14 changes: 6 additions & 8 deletions Molten.Engine/Graphics/Renderer/Steps/LightingStep.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,21 @@ private void RenderPointLights(RenderService renderer, GpuCommandList cmd, Rende

// Calculate camera-specific information for each point light
LightInstance instance;
LightData ld;
for(int i = 0; i < scene.PointLights.ElementCount; i++)

for(int i = 0; i < scene.PointLights.Data.Count; i++)
{
instance = scene.PointLights.Instances[i];
ld = scene.PointLights.Data[instance.ID];
ref LightData ld = ref scene.PointLights.Data[instance.ID];

float distFromCam = Vector3F.Distance(camera.Position, scene.PointLights.Data[i].Position);
float distPercent = Math.Min(1.0f, distFromCam / camera.MaxDrawDistance);
ld.Transform = Matrix4F.Scaling(instance.Range) * Matrix4F.CreateTranslation(ld.Position) * camera.ViewProjection;
ld.Transform.Transpose();

ld.TessFactor = GraphicsSettings.MAX_LIGHT_TESS_FACTOR - (GraphicsSettings.LIGHT_TESS_FACTOR_RANGE * distPercent);
scene.PointLights.Data[i] = ld;
}

GpuBuffer lightData = cmd.Device.UploadBuffer.Get<LightData>(scene.PointLights.Data.Length);
lightData.SetData(GpuPriority.Immediate, cmd, scene.PointLights.Data);
GpuBuffer lightData = cmd.Device.UploadBuffer.Get<LightData>(scene.PointLights.Data.Count);
lightData.SetData(GpuPriority.Immediate, cmd, scene.PointLights.Data.Items);

// Set data buffer on domain and pixel shaders
_matPoint.Light.Data.Value = lightData; // TODO Need to implement a dynamic structured buffer we can reuse here.
Expand All @@ -83,7 +81,7 @@ private void RenderPointLights(RenderService renderer, GpuCommandList cmd, Rende
//set correct buffers and shaders
cmd.State.VertexBuffers[0] = null;
cmd.State.IndexBuffer.Value = null;
uint pointCount = scene.PointLights.ElementCount * 2;
uint pointCount = scene.PointLights.Data.Count * 2;

cmd.Draw(_matPoint, pointCount, 0);
//cmd.Sync();
Expand Down
64 changes: 12 additions & 52 deletions Molten.Engine/Graphics/Scene/Lights/LightList.cs
Original file line number Diff line number Diff line change
@@ -1,76 +1,36 @@
namespace Molten.Graphics;
using Molten.Collections;

namespace Molten.Graphics;

/// <summary>
/// A list
/// </summary>
public class LightList
{
public LightInstance[] Instances;
public LightData[] Data;
uint[] _free;
uint _freeCount;
uint _elementCount; // Number of elements initialized at least once.
uint _itemCount; // Number of active items.
uint _resizeIncrement;
public ValueFreeRefList<LightData> Data;

internal LightList(uint initialCapacity, uint resizeIncrement)
internal LightList(uint initialCapacity)
{
Data = new LightData[initialCapacity];
Data = new ValueFreeRefList<LightData>(initialCapacity);
Instances = new LightInstance[initialCapacity];
_free = new uint[10];
_resizeIncrement = resizeIncrement;
_itemCount = 0;
}

public void EnsureCapacity(int capacity)
public LightInstance New(ref LightData data)
{
if (capacity >= Data.Length)
Array.Resize(ref Data, capacity);
}
uint id = Data.Add(ref data);
if(id >= Instances.Length)
Array.Resize(ref Instances, (int)Data.Capacity);

public LightInstance New(LightData data)
{
uint id = 0;
if (_freeCount > 0)
{
id = _free[--_freeCount];
}
else
{
id = _elementCount++;
if (_elementCount == Data.Length)
{
Array.Resize(ref Data, (int)(Data.Length + _resizeIncrement));
Array.Resize(ref Instances, Data.Length);
}
}
Instances[id] = new LightInstance() { ID = id };

Data[id] = new LightData();
Instances[id] ??= new LightInstance() { ID = id };
_itemCount++;
return Instances[id];
}

public void Remove(LightInstance instance)
{
Data[instance.ID].TessFactor = 0; // Lights with a tess factor of 0 will be skipped.

if (_freeCount == _free.Length)
Array.Resize(ref _free, _free.Length * 2);

if (instance.ID == _elementCount - 1)
_elementCount--;
else
_free[_freeCount++] = instance.ID;

_itemCount--;
Data.RemoveAt(instance.ID);
}

public uint ItemCount => _itemCount;

public uint ElementCount => _elementCount;

public uint ResizeIncrement => _resizeIncrement;
}

/// <summary>
Expand Down
15 changes: 12 additions & 3 deletions Molten.Engine/Graphics/Scene/SceneRenderData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,20 @@ public void RemoveObject(Renderable obj, ObjectRenderData renderData, LayerRende
* - Renderer will upload the latest data to the GPU
*/

public LightList PointLights { get; } = new LightList(100, 100);
/// <summary>
/// Gets the management list for point lights
/// </summary>
public LightList PointLights { get; } = new(100);

public LightList CapsuleLights { get; } = new LightList(50, 100);
/// <summary>
/// Gets the management list for capsule lights.
/// </summary>
public LightList CapsuleLights { get; } = new(50);

public List<RenderCamera> Cameras { get; } = new List<RenderCamera>();
/// <summary>
/// Gets a list of cameras that are part of the scene.
/// </summary>
public List<RenderCamera> Cameras { get; } = new();

/// <summary>
/// Gets or sets the skybox cube-map texture.
Expand Down
119 changes: 91 additions & 28 deletions Molten.Utility/Collections/ValueFreeRefList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
/// </summary>
/// <typeparam name="T">The type of element to store in the list.</typeparam>
public class ValueFreeRefList<T>
where T : unmanaged
where T : struct
{
T[] _items;
uint[] _free;
int _freeIndex;
uint _freeIndex;
uint _capacity;
uint _count;

Expand All @@ -37,13 +37,18 @@ public void EnsureCapacity(uint capacity)
}
}

public void Add(ref T item)
/// <summary>
/// Adds the provided value to the list and returns the index it was added at.
/// </summary>
/// <param name="item">The item to be added.</param>
/// <returns>The index of the item within the list.</returns>
public uint Add(ref T item)
{
uint index = 0;

if (_freeIndex > 0)
{
uint index = _free[--_freeIndex];
_items[index] = item;
return;
index = _free[--_freeIndex];
}
else
{
Expand All @@ -53,41 +58,65 @@ public void Add(ref T item)
Array.Resize(ref _items, (int)_capacity);
}

_items[_count++] = item;
index = _count++;
}

_items[index] = item;
return index;
}

public void Add(T item)
/// <summary>
/// Adds the provided value to the list and returns the index it was added at.
/// </summary>
/// <param name="item">The item to be added.</param>
/// <returns>The index of the item within the list.</returns>
public uint Add(T item)
{
Add(ref item);
return Add(ref item);
}

public void AddRange(IEnumerable<T> values)
/// <summary>
/// Adds the provided items to the list and returns the start index they were added at.
/// </summary>
/// <param name="items">The items to be added.</param>
/// <returns>The start index of the range within the list.</returns>
public uint AddRange(List<T> items)
{
switch (values)
{
case List<T> list:
if(_capacity - _count < list.Count)
EnsureCapacity(_capacity + (uint)list.Count);
uint count = (uint)items.Count;
if (_capacity - _count < items.Count)
EnsureCapacity(_capacity + count);

list.CopyTo(_items, (int)_count);
break;
uint startIndex = _count;
items.CopyTo(_items, (int)startIndex);
_count += count;

case T[] array:
if (_capacity - _count < array.LongLength)
EnsureCapacity(_capacity + (uint)array.LongLength);
return startIndex;
}

array.CopyTo(_items, _count);
break;
/// <summary>
/// Adds the provided items to the list and returns the start index they were added at.
/// </summary>
/// <param name="items">The items to be added.</param>
/// <returns>The start index of the range within the list.</returns>
public uint AddRange(T[] items)
{
uint count = (uint)items.LongLength;
if (_capacity - _count < items.LongLength)
EnsureCapacity(_capacity + (uint)items.LongLength);

default:
foreach (T value in values)
Add(value);
break;
}
uint startIndex = _count;
Array.Copy(items, 0, _items, startIndex, items.Length);
_count += count;

return startIndex;
}

public unsafe void RemoveAt(uint index)
/// <summary>
/// Removes an item at the specified index and adds it to an internal free stack.
/// </summary>
/// <param name="index"></param>
/// <exception cref="IndexOutOfRangeException"></exception>
public void RemoveAt(uint index)
{
if (index >= _count)
throw new IndexOutOfRangeException();
Expand All @@ -106,6 +135,30 @@ public unsafe void RemoveAt(uint index)
}
}

public void RemoveRange(uint startIndex, uint count)
{
uint end = startIndex + count;

if (startIndex >= _count || end > _count)
throw new IndexOutOfRangeException();

if(end == _count)
{
for(uint i = startIndex; i < count; i++)
_items[i] = default;

_count -= count;
}
else
{
if(_freeIndex == _free.Length)
Array.Resize(ref _free, (int)Math.Max(_free.Length * 2, _free.Length + count));

for(uint i = startIndex; i < end; i++)
_free[_freeIndex++] = i;
}
}

/// <summary>
/// Clears the current <see cref="ValueFreeRefList{T}"/>.
/// </summary>
Expand All @@ -131,11 +184,21 @@ public void Clear(uint newCapacity = 0)
/// </summary>
public uint Count => _count;

/// <summary>
/// Gets the number of free indices in the list.
/// </summary>
public uint FreeCount => _freeIndex;

/// <summary>
/// Gets the capacity of the current <see cref="ValueFreeRefList{T}"/>.
/// </summary>
public uint Capacity => _capacity;

/// <summary>
/// Gets the underlying array of items. Note: directly manipulating this array may cause unexpected behaviour.
/// </summary>
public T[] Items => _items;

/// <summary>
/// Gets or sets an item at the specified index by reference.
/// </summary>
Expand Down

0 comments on commit fc14339

Please sign in to comment.