Render graph integration and resource management refactor

Introduces a full-featured render graph system with pass culling, resource aliasing, and automatic barrier generation. Refactors resource and barrier APIs, improves error handling, and unifies result types. Renderer and render passes now use the new graph-based workflow. Updates shader includes, adds a blit shader, and improves HLSL parsing. Removes dynamic descriptor heaps in favor of persistent ones. Project file now includes the render graph module. Lays the foundation for advanced rendering features and improved memory efficiency.
This commit is contained in:
2026-01-21 18:32:03 +09:00
parent 1c155f962c
commit 92b966fe0d
62 changed files with 4843 additions and 621 deletions

View File

@@ -64,13 +64,13 @@ internal unsafe sealed class ChunkDebugView
}
var views = new List<object>();
var r = World.GetWorld(worldID);
if (!r)
var world = World.GetWorld(worldID);
if (world is null)
{
return [];
}
ref var archetype = ref r.Value.ComponentManager.GetArchetypeReference(archetypeID);
ref var archetype = ref world.ComponentManager.GetArchetypeReference(archetypeID);
var it = archetype._signature.GetIterator();
while (it.Next(out var index))
{

View File

@@ -47,7 +47,12 @@ public unsafe partial struct EntityQuery
public JobHandle ScheduleChunkParallel<TJob>(TJob job, int batchSize, JobHandle dependency)
where TJob : unmanaged, IJobChunk
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");

View File

@@ -434,7 +434,12 @@ public unsafe partial struct EntityQuery : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ChunkIterator GetChunkIterator()
{
var world = World.GetWorld(_worldID).Value;
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ChunkIterator(_matchingArchetypes.AsReadOnly(), world);
}
@@ -442,13 +447,12 @@ public unsafe partial struct EntityQuery : IDisposable
public readonly int GetEntityCount()
{
var total = 0;
var r = World.GetWorld(_worldID);
if (r.IsFailure)
var world = World.GetWorld(_worldID);
if (world is null)
{
return 0;
}
var world = r.Value;
for(var i = 0; i < _matchingArchetypes.Count; i++)
{
var archetypeID = _matchingArchetypes[i];

View File

@@ -176,7 +176,13 @@ public unsafe partial struct EntityQuery
public readonly ComponentIterator<T0> GetComponentIterator<T0>()
where T0 : unmanaged, IComponent
{
return new ComponentIterator<T0>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1>
@@ -373,7 +379,13 @@ public unsafe partial struct EntityQuery
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1, T2>
@@ -580,7 +592,13 @@ public unsafe partial struct EntityQuery
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1, T2>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1, T2>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1, T2, T3>
@@ -797,7 +815,13 @@ public unsafe partial struct EntityQuery
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1, T2, T3>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1, T2, T3>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1, T2, T3, T4>
@@ -1024,7 +1048,13 @@ public unsafe partial struct EntityQuery
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1, T2, T3, T4>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1, T2, T3, T4>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1, T2, T3, T4, T5>
@@ -1261,7 +1291,13 @@ public unsafe partial struct EntityQuery
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1, T2, T3, T4, T5>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1, T2, T3, T4, T5>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1, T2, T3, T4, T5, T6>
@@ -1508,7 +1544,13 @@ public unsafe partial struct EntityQuery
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1, T2, T3, T4, T5, T6>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1, T2, T3, T4, T5, T6>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct ComponentIterator<T0, T1, T2, T3, T4, T5, T6, T7>
@@ -1765,7 +1807,13 @@ public unsafe partial struct EntityQuery
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
return new ComponentIterator<T0, T1, T2, T3, T4, T5, T6, T7>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<T0, T1, T2, T3, T4, T5, T6, T7>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
}

View File

@@ -221,7 +221,13 @@ public unsafe partial struct EntityQuery
public readonly ComponentIterator<<#= generics#>> GetComponentIterator<<#= generics#>>()
<#= restrictions #>
{
return new ComponentIterator<<#= generics#>>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new ComponentIterator<<#= generics#>>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
<# } #>

View File

@@ -199,7 +199,13 @@ public unsafe partial struct EntityQuery
public readonly EntityComponentIterator<T0> GetEntityComponentIterator<T0>()
where T0 : unmanaged, IComponent
{
return new EntityComponentIterator<T0>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1>
@@ -403,7 +409,13 @@ public unsafe partial struct EntityQuery
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1, T2>
@@ -617,7 +629,13 @@ public unsafe partial struct EntityQuery
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1, T2>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1, T2>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1, T2, T3>
@@ -841,7 +859,13 @@ public unsafe partial struct EntityQuery
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1, T2, T3>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1, T2, T3>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1, T2, T3, T4>
@@ -1075,7 +1099,13 @@ public unsafe partial struct EntityQuery
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1, T2, T3, T4>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1, T2, T3, T4>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1, T2, T3, T4, T5>
@@ -1319,7 +1349,13 @@ public unsafe partial struct EntityQuery
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1, T2, T3, T4, T5>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1, T2, T3, T4, T5>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1, T2, T3, T4, T5, T6>
@@ -1573,7 +1609,13 @@ public unsafe partial struct EntityQuery
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1, T2, T3, T4, T5, T6>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1, T2, T3, T4, T5, T6>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
public readonly ref struct EntityComponentIterator<T0, T1, T2, T3, T4, T5, T6, T7>
@@ -1837,7 +1879,13 @@ public unsafe partial struct EntityQuery
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
return new EntityComponentIterator<T0, T1, T2, T3, T4, T5, T6, T7>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<T0, T1, T2, T3, T4, T5, T6, T7>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
}

View File

@@ -222,7 +222,13 @@ public unsafe partial struct EntityQuery
public readonly EntityComponentIterator<<#= generics#>> GetEntityComponentIterator<<#= generics#>>()
<#= restrictions #>
{
return new EntityComponentIterator<<#= generics#>>(_matchingArchetypes.AsReadOnly(), _mask, World.GetWorld(_worldID).GetValueOrThrow());
var world = World.GetWorld(_worldID);
if (world is null)
{
return default;
}
return new EntityComponentIterator<<#= generics#>>(_matchingArchetypes.AsReadOnly(), _mask, world);
}
<# } #>

View File

@@ -1095,7 +1095,12 @@ public unsafe partial struct EntityQuery
where TJob : unmanaged, IJobEntity<T0>
where T0 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -1232,7 +1237,12 @@ public unsafe partial struct EntityQuery
where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -1396,7 +1406,12 @@ public unsafe partial struct EntityQuery
where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -1587,7 +1602,12 @@ public unsafe partial struct EntityQuery
where T2 : unmanaged, IComponent
where T3 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -1805,7 +1825,12 @@ public unsafe partial struct EntityQuery
where T3 : unmanaged, IComponent
where T4 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -2050,7 +2075,12 @@ public unsafe partial struct EntityQuery
where T4 : unmanaged, IComponent
where T5 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -2322,7 +2352,12 @@ public unsafe partial struct EntityQuery
where T5 : unmanaged, IComponent
where T6 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");
@@ -2621,7 +2656,12 @@ public unsafe partial struct EntityQuery
where T6 : unmanaged, IComponent
where T7 : unmanaged, IComponent
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");

View File

@@ -125,7 +125,12 @@ public unsafe partial struct EntityQuery
where TJob : unmanaged, IJobEntity<<#= generics #>>
<#= restrictions #>
{
var world = World.GetWorld(_worldID).GetValueOrThrow();
var world = World.GetWorld(_worldID);
if (world is null)
{
return JobHandle.Invalid;
}
if (world.JobScheduler == null)
{
throw new InvalidOperationException("The World has no JobScheduler assigned.");

View File

@@ -46,7 +46,7 @@ public partial class World
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static World GetWorldUncheck(Identifier<World> id)
public static World GetWorldUncheck(Identifier<World> id)
{
#if DEBUG || GHOST_EDITOR
if (id.Value < 0 || id.Value >= s_worlds.Count)
@@ -62,15 +62,14 @@ public partial class World
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Result<World, ErrorStatus> GetWorld(Identifier<World> id)
public static World? GetWorld(Identifier<World> id)
{
if (id.Value < 0 || id.Value >= s_worlds.Count)
{
return ErrorStatus.InvalidArgument;
return null;
}
var world = s_worlds[id.Value];
return world is null ? ErrorStatus.NotFound : world;
return s_worlds[id.Value];
}
}