feat(render): add meshlet rendering and ECS query ref API

Introduces meshlet-based rendering pipeline with new HLSL structures and push constant layouts. Refactors meshlet upload/cooking, updates RenderGraphContext for global/view/instance data, and enhances ECS QueryBuilder with ref returns and [UnscopedRef] for fluent chaining. Improves resource management and disposal patterns, updates D3D12 interop for compatibility, and refines test/app infrastructure. Includes dependency updates, bug fixes, and code cleanups.
This commit is contained in:
2026-03-25 20:27:46 +09:00
parent b729ca86f5
commit 447a4e6904
28 changed files with 407 additions and 165 deletions

View File

@@ -1,4 +1,4 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Ghost.Shader.Test")] [assembly: InternalsVisibleTo("Ghost.Shader.Test")]
[assembly: InternalsVisibleTo("Ghost.Graphics")] [assembly: InternalsVisibleTo("Ghost.Graphics.Test")]

View File

@@ -48,6 +48,6 @@ internal partial class ConsoleViewModel : ObservableObject
[RelayCommand] [RelayCommand]
private void ClearLogs() private void ClearLogs()
{ {
Logger.Clear(); //Logger.Clear();
} }
} }

View File

@@ -19,9 +19,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Misaki.HighPerformance" Version="1.0.4" /> <PackageReference Include="Misaki.HighPerformance" Version="1.0.5" />
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.5.3" /> <PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.5.3" />
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.5.2"> <PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.5.4">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -92,6 +92,7 @@ public class RenderExtractionSystem : ISystem
var rtSize = new uint2(rtResult.Value.TextureDescription.Width, rtResult.Value.TextureDescription.Height); var rtSize = new uint2(rtResult.Value.TextureDescription.Width, rtResult.Value.TextureDescription.Height);
var aspectScreen = (float)rtSize.x / rtSize.y; var aspectScreen = (float)rtSize.x / rtSize.y;
// TODO: Classify transparent objects into a separate render list and render via oit.
var renderList = new RenderList(1, 64, Allocator.FreeList); var renderList = new RenderList(1, 64, Allocator.FreeList);
var transparentRenderList = new RenderList(1, 64, Allocator.FreeList); var transparentRenderList = new RenderList(1, 64, Allocator.FreeList);
var shadowCasterRenderList = new RenderList(1, 64, Allocator.FreeList); var shadowCasterRenderList = new RenderList(1, 64, Allocator.FreeList);
@@ -215,7 +216,7 @@ public class RenderExtractionSystem : ISystem
depthTarget = camRef.depthTarget, depthTarget = camRef.depthTarget,
opaqueRenderList = renderList, opaqueRenderList = renderList,
shadowCasterRenderList = shadowCasterRenderList, shadowCasterRenderList = shadowCasterRenderList,
transparentRenderList = default, // TODO: Classify transparent objects into a separate render list and render via oit. transparentRenderList = transparentRenderList,
renderFunc = camRef.renderFunc, renderFunc = camRef.renderFunc,
view = new RenderView view = new RenderView
{ {

View File

@@ -636,6 +636,10 @@ public ref partial struct QueryBuilder : IDisposable
{ {
Dispose(); Dispose();
} }
else
{
Clear();
}
return query; return query;
} }

View File

@@ -340,7 +340,7 @@ public abstract class SystemGroup : ISystem
public sealed class DefaultSystemGroup : SystemGroup; public sealed class DefaultSystemGroup : SystemGroup;
public sealed class SystemManager public sealed class SystemManager : IDisposable
{ {
private readonly World _world; private readonly World _world;
@@ -415,4 +415,9 @@ public sealed class SystemManager
system.Cleanup(in systemAPI); system.Cleanup(in systemAPI);
} }
} }
public void Dispose()
{
CleanupAll(default);
}
} }

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Ghost.Entities; namespace Ghost.Entities;
@@ -10,12 +11,13 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAll<T0>() [UnscopedRef]
public ref QueryBuilder WithAll<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.Value); _all.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -23,13 +25,14 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<T0>() [UnscopedRef]
public ref QueryBuilder WithAllRW<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.Value); _all.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.Value); _rw.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -37,12 +40,13 @@ public ref partial struct QueryBuilder
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled. /// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAny<T0>() [UnscopedRef]
public ref QueryBuilder WithAny<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_any.Add(ComponentTypeID<T0>.Value); _any.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -50,12 +54,13 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types. /// Targets entities that do not have any of the specified component types.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAbsent<T0>() [UnscopedRef]
public ref QueryBuilder WithAbsent<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_absent.Add(ComponentTypeID<T0>.Value); _absent.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -63,12 +68,13 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types, or those component(s) are disabled. /// Targets entities that do not have any of the specified component types, or those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithNone<T0>() [UnscopedRef]
public ref QueryBuilder WithNone<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_none.Add(ComponentTypeID<T0>.Value); _none.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -76,12 +82,13 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) are disabled. /// Targets entities that have all of the specified component types and those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithDisabled<T0>() [UnscopedRef]
public ref QueryBuilder WithDisabled<T0>()
where T0 : unmanaged, IEnableableComponent where T0 : unmanaged, IEnableableComponent
{ {
_disabled.Add(ComponentTypeID<T0>.Value); _disabled.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -89,12 +96,13 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresent<T0>() [UnscopedRef]
public ref QueryBuilder WithPresent<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.Value); _present.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -102,13 +110,14 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<T0>() [UnscopedRef]
public ref QueryBuilder WithPresentRW<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.Value); _present.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.Value); _rw.Add(ComponentTypeID<T0>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -116,14 +125,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAll<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithAll<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.Value); _all.Add(ComponentTypeID<T0>.Value);
_all.Add(ComponentTypeID<T1>.Value); _all.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -131,7 +141,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithAllRW<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
@@ -140,7 +151,7 @@ public ref partial struct QueryBuilder
_all.Add(ComponentTypeID<T1>.Value); _all.Add(ComponentTypeID<T1>.Value);
_rw.Add(ComponentTypeID<T1>.Value); _rw.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -148,14 +159,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled. /// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAny<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithAny<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_any.Add(ComponentTypeID<T0>.Value); _any.Add(ComponentTypeID<T0>.Value);
_any.Add(ComponentTypeID<T1>.Value); _any.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -163,14 +175,15 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types. /// Targets entities that do not have any of the specified component types.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAbsent<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithAbsent<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_absent.Add(ComponentTypeID<T0>.Value); _absent.Add(ComponentTypeID<T0>.Value);
_absent.Add(ComponentTypeID<T1>.Value); _absent.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -178,14 +191,15 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types, or those component(s) are disabled. /// Targets entities that do not have any of the specified component types, or those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithNone<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithNone<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_none.Add(ComponentTypeID<T0>.Value); _none.Add(ComponentTypeID<T0>.Value);
_none.Add(ComponentTypeID<T1>.Value); _none.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -193,14 +207,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) are disabled. /// Targets entities that have all of the specified component types and those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithDisabled<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithDisabled<T0, T1>()
where T0 : unmanaged, IEnableableComponent where T0 : unmanaged, IEnableableComponent
where T1 : unmanaged, IEnableableComponent where T1 : unmanaged, IEnableableComponent
{ {
_disabled.Add(ComponentTypeID<T0>.Value); _disabled.Add(ComponentTypeID<T0>.Value);
_disabled.Add(ComponentTypeID<T1>.Value); _disabled.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -208,14 +223,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresent<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithPresent<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.Value); _present.Add(ComponentTypeID<T0>.Value);
_present.Add(ComponentTypeID<T1>.Value); _present.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -223,7 +239,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<T0, T1>() [UnscopedRef]
public ref QueryBuilder WithPresentRW<T0, T1>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
@@ -232,7 +249,7 @@ public ref partial struct QueryBuilder
_present.Add(ComponentTypeID<T1>.Value); _present.Add(ComponentTypeID<T1>.Value);
_rw.Add(ComponentTypeID<T1>.Value); _rw.Add(ComponentTypeID<T1>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -240,7 +257,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAll<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithAll<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -249,7 +267,7 @@ public ref partial struct QueryBuilder
_all.Add(ComponentTypeID<T1>.Value); _all.Add(ComponentTypeID<T1>.Value);
_all.Add(ComponentTypeID<T2>.Value); _all.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -257,7 +275,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithAllRW<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -269,7 +288,7 @@ public ref partial struct QueryBuilder
_all.Add(ComponentTypeID<T2>.Value); _all.Add(ComponentTypeID<T2>.Value);
_rw.Add(ComponentTypeID<T2>.Value); _rw.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -277,7 +296,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled. /// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAny<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithAny<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -286,7 +306,7 @@ public ref partial struct QueryBuilder
_any.Add(ComponentTypeID<T1>.Value); _any.Add(ComponentTypeID<T1>.Value);
_any.Add(ComponentTypeID<T2>.Value); _any.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -294,7 +314,8 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types. /// Targets entities that do not have any of the specified component types.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAbsent<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithAbsent<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -303,7 +324,7 @@ public ref partial struct QueryBuilder
_absent.Add(ComponentTypeID<T1>.Value); _absent.Add(ComponentTypeID<T1>.Value);
_absent.Add(ComponentTypeID<T2>.Value); _absent.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -311,7 +332,8 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types, or those component(s) are disabled. /// Targets entities that do not have any of the specified component types, or those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithNone<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithNone<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -320,7 +342,7 @@ public ref partial struct QueryBuilder
_none.Add(ComponentTypeID<T1>.Value); _none.Add(ComponentTypeID<T1>.Value);
_none.Add(ComponentTypeID<T2>.Value); _none.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -328,7 +350,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) are disabled. /// Targets entities that have all of the specified component types and those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithDisabled<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithDisabled<T0, T1, T2>()
where T0 : unmanaged, IEnableableComponent where T0 : unmanaged, IEnableableComponent
where T1 : unmanaged, IEnableableComponent where T1 : unmanaged, IEnableableComponent
where T2 : unmanaged, IEnableableComponent where T2 : unmanaged, IEnableableComponent
@@ -337,7 +360,7 @@ public ref partial struct QueryBuilder
_disabled.Add(ComponentTypeID<T1>.Value); _disabled.Add(ComponentTypeID<T1>.Value);
_disabled.Add(ComponentTypeID<T2>.Value); _disabled.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -345,7 +368,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresent<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithPresent<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -354,7 +378,7 @@ public ref partial struct QueryBuilder
_present.Add(ComponentTypeID<T1>.Value); _present.Add(ComponentTypeID<T1>.Value);
_present.Add(ComponentTypeID<T2>.Value); _present.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -362,7 +386,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<T0, T1, T2>() [UnscopedRef]
public ref QueryBuilder WithPresentRW<T0, T1, T2>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
@@ -374,7 +399,7 @@ public ref partial struct QueryBuilder
_present.Add(ComponentTypeID<T2>.Value); _present.Add(ComponentTypeID<T2>.Value);
_rw.Add(ComponentTypeID<T2>.Value); _rw.Add(ComponentTypeID<T2>.Value);
return this; return ref this;
} }
} }

View File

@@ -4,6 +4,7 @@
<#@ import namespace="System.Linq" #> <#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #> <#@ import namespace="System.Text" #>
<#@ include file="Helpers.ttinclude" #> <#@ include file="Helpers.ttinclude" #>
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Ghost.Entities; namespace Ghost.Entities;
@@ -21,14 +22,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAll<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithAll<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_all.Add(ComponentTypeID<T<#= j #>>.Value); _all.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -36,7 +38,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) must be enabled. /// Targets entities that have all of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAllRW<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithAllRW<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
@@ -44,7 +47,7 @@ public ref partial struct QueryBuilder
_rw.Add(ComponentTypeID<T<#= j #>>.Value); _rw.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -52,14 +55,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have at least one of the specified component types and those component(s) must be enabled. /// Targets entities that have at least one of the specified component types and those component(s) must be enabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAny<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithAny<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_any.Add(ComponentTypeID<T<#= j #>>.Value); _any.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -67,14 +71,15 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types. /// Targets entities that do not have any of the specified component types.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithAbsent<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithAbsent<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_absent.Add(ComponentTypeID<T<#= j #>>.Value); _absent.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -82,14 +87,15 @@ public ref partial struct QueryBuilder
/// Targets entities that do not have any of the specified component types, or those component(s) are disabled. /// Targets entities that do not have any of the specified component types, or those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithNone<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithNone<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_none.Add(ComponentTypeID<T<#= j #>>.Value); _none.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -97,14 +103,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types and those component(s) are disabled. /// Targets entities that have all of the specified component types and those component(s) are disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithDisabled<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithDisabled<<#= generics #>>()
<#= enableRestrictions #> <#= enableRestrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_disabled.Add(ComponentTypeID<T<#= j #>>.Value); _disabled.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -112,14 +119,15 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresent<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithPresent<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_present.Add(ComponentTypeID<T<#= j #>>.Value); _present.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
/// <summary> /// <summary>
@@ -127,7 +135,8 @@ public ref partial struct QueryBuilder
/// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled. /// Targets entities that have all of the specified component types, regardless of whether those component(s) are enabled or disabled.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public QueryBuilder WithPresentRW<<#= generics #>>() [UnscopedRef]
public ref QueryBuilder WithPresentRW<<#= generics #>>()
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
@@ -135,7 +144,7 @@ public ref partial struct QueryBuilder
_rw.Add(ComponentTypeID<T<#= j #>>.Value); _rw.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return ref this;
} }
<# } #> <# } #>

View File

@@ -268,6 +268,9 @@ public partial class World : IDisposable, IEquatable<World>
} }
} }
_componentManager.Dispose();
_systemManager.Dispose();
s_freeWorldSlots.Enqueue(_id); s_freeWorldSlots.Enqueue(_id);
s_worlds[_id] = null; s_worlds[_id] = null;

View File

@@ -10,9 +10,9 @@ namespace Ghost.Graphics.D3D12;
/// <summary> /// <summary>
/// D3D12 implementation of command queue interface /// D3D12 implementation of command queue interface
/// </summary> /// </summary>
internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue1>, ICommandQueue internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue>, ICommandQueue
{ {
private UniquePtr<ID3D12Fence1> _fence; private UniquePtr<ID3D12Fence> _fence;
private readonly AutoResetEvent _fenceEvent; private readonly AutoResetEvent _fenceEvent;
private ulong _fenceValue; private ulong _fenceValue;
@@ -22,7 +22,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue1>, ICom
get; get;
} }
private static ID3D12CommandQueue1* CreateCommandQueue(ID3D12Device14* device, CommandQueueType type) private static ID3D12CommandQueue* CreateCommandQueue(ID3D12Device14* device, CommandQueueType type)
{ {
var queueDesc = new D3D12_COMMAND_QUEUE_DESC var queueDesc = new D3D12_COMMAND_QUEUE_DESC
{ {
@@ -31,7 +31,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue1>, ICom
Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE, Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE,
}; };
ID3D12CommandQueue1* pQueue = default; ID3D12CommandQueue* pQueue = default;
ThrowIfFailed(device->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue)); ThrowIfFailed(device->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue));
return pQueue; return pQueue;
} }
@@ -43,7 +43,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object<ID3D12CommandQueue1>, ICom
_fenceEvent = new AutoResetEvent(false); _fenceEvent = new AutoResetEvent(false);
_fenceValue = 0; _fenceValue = 0;
ID3D12Fence1* pFence = default; ID3D12Fence* pFence = default;
ThrowIfFailed(device.NativeObject.Get()->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence)); ThrowIfFailed(device.NativeObject.Get()->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence));
_fence.Attach(pFence); _fence.Attach(pFence);

View File

@@ -160,6 +160,16 @@ internal class D3D12GraphicsEngine : IGraphicsEngine
return; return;
} }
while (_commandBufferReturnQueue.TryDequeue(out var entry))
{
entry.commandBuffer.Dispose();
}
while (_commandBufferPool.TryDequeue(out var cmd))
{
cmd.Dispose();
}
_resourceDatabase.ReleaseAllResourcesImmediately(); _resourceDatabase.ReleaseAllResourcesImmediately();
_resourceAllocator.Dispose(); _resourceAllocator.Dispose();

View File

@@ -29,9 +29,9 @@ internal unsafe class D3D12RenderDevice : D3D12Object<ID3D12Device14>, IRenderDe
public SharedPtr<IDXGIFactory7> DXGIFactory => _dxgiFactory.Share(); public SharedPtr<IDXGIFactory7> DXGIFactory => _dxgiFactory.Share();
public SharedPtr<IDXGIAdapter1> Adapter => _adapter.Share(); public SharedPtr<IDXGIAdapter1> Adapter => _adapter.Share();
public SharedPtr<ID3D12CommandQueue1> NativeGraphicsQueue => _graphicsQueue.NativeObject; public SharedPtr<ID3D12CommandQueue> NativeGraphicsQueue => _graphicsQueue.NativeObject;
public SharedPtr<ID3D12CommandQueue1> NativeComputeQueue => _computeQueue.NativeObject; public SharedPtr<ID3D12CommandQueue> NativeComputeQueue => _computeQueue.NativeObject;
public SharedPtr<ID3D12CommandQueue1> NativeCopyQueue => _copyQueue.NativeObject; public SharedPtr<ID3D12CommandQueue> NativeCopyQueue => _copyQueue.NativeObject;
public D3D12RenderDevice() public D3D12RenderDevice()
:base(CreateDevice(out var dxgiFactory, out var adapter)) :base(CreateDevice(out var dxgiFactory, out var adapter))

View File

@@ -53,8 +53,9 @@ internal static unsafe class D3D12Utility
var ptr = uPtr.Get(); var ptr = uPtr.Get();
if (ptr != null) if (ptr != null)
{ {
Debug.Assert(ptr != other);
var refCount = ptr->Release(); var refCount = ptr->Release();
Debug.Assert((refCount != 0) || (ptr != other)); Debug.Assert(refCount == 0);
} }
uPtr = new UniquePtr<T>(other); uPtr = new UniquePtr<T>(other);
@@ -68,7 +69,7 @@ internal static unsafe class D3D12Utility
if (ptr != null) if (ptr != null)
{ {
var refCount = ptr->Release(); var refCount = ptr->Release();
Debug.Assert(refCount != 0); //Debug.Assert(refCount == 0);
} }
} }
@@ -433,7 +434,7 @@ internal static unsafe class D3D12Utility
{ {
var flags = D3D12_RESOURCE_FLAG_NONE; var flags = D3D12_RESOURCE_FLAG_NONE;
if (usage.HasFlag(BufferUsage.Raw) || usage.HasFlag(BufferUsage.UnorderedAccess)) if (usage.HasFlag(BufferUsage.UnorderedAccess))
{ {
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
} }

View File

@@ -194,7 +194,7 @@ public struct Mesh : IResourceReleasable
this.ComputeBounds(); this.ComputeBounds();
} }
public readonly void ReleaseCpuResources() public void ReleaseCpuResources()
{ {
_vertices.Dispose(); _vertices.Dispose();
_indices.Dispose(); _indices.Dispose();
@@ -238,7 +238,7 @@ public struct Mesh : IResourceReleasable
MeshletUtility.Build(config, clodMesh, Unsafe.AsPointer(ref this), MeshletOutputCallback); MeshletUtility.Build(config, clodMesh, Unsafe.AsPointer(ref this), MeshletOutputCallback);
} }
private static unsafe int MeshletOutputCallback(void* context, ClodGroup group, ReadOnlyUnsafeCollection<ClodCluster>clusters) private static unsafe int MeshletOutputCallback(void* context, ClodGroup group, ReadOnlyUnsafeCollection<ClodCluster> clusters)
{ {
var mesh = (Mesh*)context; var mesh = (Mesh*)context;
ref var data = ref mesh->_meshletData; ref var data = ref mesh->_meshletData;
@@ -277,13 +277,13 @@ public struct Mesh : IResourceReleasable
data.meshletVertices.Add(cluster.uniqueVertices[j]); data.meshletVertices.Add(cluster.uniqueVertices[j]);
} }
// Add local triangles (packed into uints) // Add local triangles (packed into uints)
nuint triangleCount = cluster.localIndexCount / 3; var triangleCount = cluster.localIndexCount / 3;
for (nuint j = 0; j < triangleCount; j++) for (nuint j = 0; j < triangleCount; j++)
{ {
uint i0 = cluster.localIndices[j * 3 + 0]; uint i0 = cluster.localIndices[j * 3 + 0];
uint i1 = cluster.localIndices[j * 3 + 1]; uint i1 = cluster.localIndices[j * 3 + 1];
uint i2 = cluster.localIndices[j * 3 + 2]; uint i2 = cluster.localIndices[j * 3 + 2];
uint packedTriangle = i0 | (i1 << 8) | (i2 << 16); var packedTriangle = i0 | (i1 << 8) | (i2 << 16);
data.meshletTriangles.Add(packedTriangle); data.meshletTriangles.Add(packedTriangle);
} }
} }
@@ -291,7 +291,7 @@ public struct Mesh : IResourceReleasable
return 0; return 0;
} }
public readonly void ReleaseResource(IResourceDatabase database) public void ReleaseResource(IResourceDatabase database)
{ {
ReleaseCpuResources(); ReleaseCpuResources();

View File

@@ -38,7 +38,7 @@ public struct RenderList : IDisposable
{ {
while (_listIndex < _length) while (_listIndex < _length)
{ {
if (_itemIndex < _pList[_listIndex].Count) if (_itemIndex < _pList[_listIndex].Count - 1)
{ {
_itemIndex++; _itemIndex++;
return true; return true;

View File

@@ -93,7 +93,7 @@ public readonly unsafe ref struct RenderingContext
return mesh; return mesh;
} }
ref readonly var meshData = ref r.Value; ref var meshData = ref r.Value;
var vertexHandle = meshData.VertexBuffer.AsResource(); var vertexHandle = meshData.VertexBuffer.AsResource();
var indexHandle = meshData.IndexBuffer.AsResource(); var indexHandle = meshData.IndexBuffer.AsResource();
@@ -105,9 +105,12 @@ public readonly unsafe ref struct RenderingContext
if (staticMesh) if (staticMesh)
{ {
meshData.CookMeshlets();
meshData.ReleaseCpuResources(); meshData.ReleaseCpuResources();
TransitionBarrier(vertexHandle, false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.VertexShading); TransitionBarrier(vertexHandle, false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.VertexShading);
TransitionBarrier(indexHandle, false, BarrierLayout.Undefined, BarrierAccess.IndexBuffer, BarrierSync.IndexInput); TransitionBarrier(indexHandle, false, BarrierLayout.Undefined, BarrierAccess.IndexBuffer, BarrierSync.IndexInput);
UploadMeshlets(mesh);
} }
return mesh; return mesh;
@@ -205,17 +208,7 @@ public readonly unsafe ref struct RenderingContext
_directCmd.UploadBuffer(meshRef.MeshLetBuffer, meshletData.meshlets.AsSpan()); _directCmd.UploadBuffer(meshRef.MeshLetBuffer, meshletData.meshlets.AsSpan());
_directCmd.UploadBuffer(meshRef.MeshletVerticesBuffer, meshletData.meshletVertices.AsSpan()); _directCmd.UploadBuffer(meshRef.MeshletVerticesBuffer, meshletData.meshletVertices.AsSpan());
// Padding for triangle data if needed _directCmd.UploadBuffer(meshRef.MeshletTrianglesBuffer, meshletData.meshletTriangles.AsSpan());
if (trianglesSize > meshletData.meshletTriangles.Count)
{
var paddedData = new uint[trianglesSize];
meshletData.meshletTriangles.AsSpan().CopyTo(paddedData);
_directCmd.UploadBuffer(meshRef.MeshletTrianglesBuffer, paddedData.AsSpan());
}
else
{
_directCmd.UploadBuffer(meshRef.MeshletTrianglesBuffer, meshletData.meshletTriangles.AsSpan());
}
TransitionBarrier(meshRef.MeshLetBuffer.AsResource(), false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.NonPixelShading | BarrierSync.PixelShading); TransitionBarrier(meshRef.MeshLetBuffer.AsResource(), false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.NonPixelShading | BarrierSync.PixelShading);
TransitionBarrier(meshRef.MeshletVerticesBuffer.AsResource(), false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.NonPixelShading | BarrierSync.PixelShading); TransitionBarrier(meshRef.MeshletVerticesBuffer.AsResource(), false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.NonPixelShading | BarrierSync.PixelShading);

View File

@@ -18,7 +18,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.0.0"> <PackageReference Include="Misaki.HighPerformance.Analyzer" Version="1.1.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -1,4 +1,5 @@
using Ghost.Core; #if false
// Obsolete
using Ghost.Core.Graphics; using Ghost.Core.Graphics;
using Ghost.DSL.ShaderCompiler; using Ghost.DSL.ShaderCompiler;
using Ghost.Graphics.Core; using Ghost.Graphics.Core;
@@ -335,3 +336,4 @@ internal class MeshRenderPass : IRenderPass
} }
} }
} }
#endif

View File

@@ -22,6 +22,9 @@ public interface IRasterRenderContext : IRenderGraphContext
{ {
int ActiveMeshIndexCount { get; } int ActiveMeshIndexCount { get; }
void SetGlobalData(uint globalIndex, uint viewIndex);
void SetInstanceIndex(uint instanceIndex);
void SetActiveMaterial(Handle<Material> material); void SetActiveMaterial(Handle<Material> material);
void SetActiveMaterial(ref readonly Material material); void SetActiveMaterial(ref readonly Material material);
void SetActiveMesh(Handle<Mesh> mesh); void SetActiveMesh(Handle<Mesh> mesh);
@@ -58,6 +61,10 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
private Handle<GraphicsBuffer> _activePerMeshData; private Handle<GraphicsBuffer> _activePerMeshData;
private int _activeMeshIndexCount; private int _activeMeshIndexCount;
private uint _activeGlobalIndex;
private uint _activeViewIndex;
private uint _activeInstanceIndex;
public ResourceManager ResourceManager => _resourceManager; public ResourceManager ResourceManager => _resourceManager;
public IResourceDatabase ResourceDatabase => _resourceDatabase; public IResourceDatabase ResourceDatabase => _resourceDatabase;
@@ -221,12 +228,26 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC
_activeMeshIndexCount = mesh.IndexCount; _activeMeshIndexCount = mesh.IndexCount;
} }
public void SetGlobalData(uint globalIndex, uint viewIndex)
{
_activeGlobalIndex = globalIndex;
_activeViewIndex = viewIndex;
}
public void SetInstanceIndex(uint instanceIndex)
{
_activeInstanceIndex = instanceIndex;
}
public unsafe void DispatchMesh(uint3 threadGroupCount) public unsafe void DispatchMesh(uint3 threadGroupCount)
{ {
// TODO: Global and view constants // TODO: Global, view, and instance constants
var data = new PushConstantsData var data = new PushConstantsData
{ {
globalIndex = _activeGlobalIndex,
viewIndex = _activeViewIndex,
objectIndex = _resourceDatabase.GetBindlessIndex(_activePerMeshData.AsResource()), objectIndex = _resourceDatabase.GetBindlessIndex(_activePerMeshData.AsResource()),
instanceIndex = _activeInstanceIndex,
materialIndex = _resourceDatabase.GetBindlessIndex(_activePerMaterialData.AsResource()), materialIndex = _resourceDatabase.GetBindlessIndex(_activePerMaterialData.AsResource()),
}; };

View File

@@ -8,18 +8,6 @@ struct PixelInput
float4 uv : TEXCOORD0; float4 uv : TEXCOORD0;
}; };
struct Meshlet
{
float4 boundingSphere;
float3 boundingBoxMin;
float3 boundingBoxMax;
uint vertexOffset;
uint triangleOffset;
uint groupIndex;
float parentError;
uint packedCounts; // byte vertexCount, byte triangleCount, byte localMaterialIndex, byte lodLevel
};
[numthreads(128, 1, 1)] // 128 threads to cover max 64 vertices and 124 triangles [numthreads(128, 1, 1)] // 128 threads to cover max 64 vertices and 124 triangles
[outputtopology("triangle")] [outputtopology("triangle")]
void MSMain( void MSMain(
@@ -50,7 +38,9 @@ void MSMain(
// Basic MVP transform not needed if already in world space, but usually we need localToWorld and ViewProj // Basic MVP transform not needed if already in world space, but usually we need localToWorld and ViewProj
PerViewData perViewData = LoadData<PerViewData>(g_PushConstantData.perViewBuffer, 0); PerViewData perViewData = LoadData<PerViewData>(g_PushConstantData.perViewBuffer, 0);
float4 worldPos = mul(perObjectData.localToWorld, float4(v.position.xyz, 1.0f)); PerInstanceData perInstanceData = LoadData<PerInstanceData>(g_PushConstantData.perInstanceBuffer, 0);
float4 worldPos = mul(perInstanceData.localToWorld, float4(v.position.xyz, 1.0f));
outVerts[groupThreadID.x].position = mul(perViewData.viewMatrix, worldPos); outVerts[groupThreadID.x].position = mul(perViewData.viewMatrix, worldPos);
outVerts[groupThreadID.x].position = mul(perViewData.projectionMatrix, outVerts[groupThreadID.x].position); outVerts[groupThreadID.x].position = mul(perViewData.projectionMatrix, outVerts[groupThreadID.x].position);
@@ -76,13 +66,13 @@ void MSMain(
float4 PSMain(PixelInput input) : SV_TARGET float4 PSMain(PixelInput input) : SV_TARGET
{ {
PerMaterialData perMaterialData = LoadData<PerMaterialData>(g_PushConstantData.perMaterialBuffer, 0); // PerMaterialData perMaterialData = LoadData<PerMaterialData>(g_PushConstantData.perMaterialBuffer, 0);
//
float4 color1 = SAMPLE_TEXTURE2D(perMaterialData.texture1, perMaterialData.tex_sampler, input.uv.xy); // float4 color1 = SAMPLE_TEXTURE2D(perMaterialData.texture1, perMaterialData.tex_sampler, input.uv.xy);
float4 color2 = SAMPLE_TEXTURE2D(perMaterialData.texture2, perMaterialData.tex_sampler, input.uv.xy); // float4 color2 = SAMPLE_TEXTURE2D(perMaterialData.texture2, perMaterialData.tex_sampler, input.uv.xy);
float4 color3 = SAMPLE_TEXTURE2D(perMaterialData.texture3, perMaterialData.tex_sampler, input.uv.xy); // float4 color3 = SAMPLE_TEXTURE2D(perMaterialData.texture3, perMaterialData.tex_sampler, input.uv.xy);
float4 color4 = SAMPLE_TEXTURE2D(perMaterialData.texture4, perMaterialData.tex_sampler, input.uv.xy); // float4 color4 = SAMPLE_TEXTURE2D(perMaterialData.texture4, perMaterialData.tex_sampler, input.uv.xy);
//
float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f; // float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
return perMaterialData.color * blendedColor + input.color; // return perMaterialData.color * blendedColor + input.color;
} }

View File

@@ -422,6 +422,7 @@ public class RenderSystem : IDisposable
} }
_renderPipeline.Dispose(); _renderPipeline.Dispose();
_resourceManager.Dispose();
_graphicsEngine.Dispose(); _graphicsEngine.Dispose();
_shutdownEvent.Dispose(); _shutdownEvent.Dispose();

View File

@@ -10,6 +10,18 @@ struct Vertex
float4 color; float4 color;
}; };
struct Meshlet
{
float4 boundingSphere;
float3 boundingBoxMin;
float3 boundingBoxMax;
uint vertexOffset;
uint triangleOffset;
uint groupIndex;
float parentError;
uint packedCounts; // byte vertexCount, byte triangleCount, byte localMaterialIndex, byte lodLevel
};
// Resource descriptor heap definitions // Resource descriptor heap definitions
#define GLOBAL_TEXTURE2D_HEAP ResourceDescriptorHeap #define GLOBAL_TEXTURE2D_HEAP ResourceDescriptorHeap

View File

@@ -5,11 +5,20 @@
struct PushConstantData struct PushConstantData
{ {
BYTE_ADDRESS_BUFFER globalBuffer; uint globalIndex;
BYTE_ADDRESS_BUFFER perViewBuffer; uint viewIndex;
BYTE_ADDRESS_BUFFER perObjectBuffer; uint objectIndex;
BYTE_ADDRESS_BUFFER perInstanceBuffer; uint instanceIndex;
BYTE_ADDRESS_BUFFER perMaterialBuffer; uint materialIndex;
};
struct GlobalFrameData
{
uint viewBufferIndex;
uint instanceBufferIndex;
uint viewBufferCount;
uint instanceBufferCount;
uint userBufferIndex;
}; };
struct PerViewData struct PerViewData
@@ -23,6 +32,11 @@ struct PerViewData
float4 screenSize; // xy: size, zw: 1/size float4 screenSize; // xy: size, zw: 1/size
}; };
struct PerInstanceData
{
float4x4 localToWorld;
};
struct PerObjectData struct PerObjectData
{ {
float3 worldBoundsMin; float3 worldBoundsMin;

View File

@@ -2,12 +2,12 @@ shader "MyShader/Standard"
{ {
properties properties
{ {
float4 color = { 1, 1, 1, 1 }; //float4 color = { 1, 1, 1, 1 };
tex2d texture1 = { black }; //tex2d texture1 = { black };
tex2d texture2 = { white }; //tex2d texture2 = { white };
tex2d texture3 = { grey }; //tex2d texture3 = { grey };
tex2d texture4 = { normal }; //tex2d texture4 = { normal };
sampler tex_sampler; //sampler tex_sampler;
} }
pass "Forward" pass "Forward"
@@ -21,7 +21,96 @@ shader "MyShader/Standard"
color_mask = all; color_mask = all;
} }
mesh "F:/csharp/GhostEngine/src/Runtime//Ghost.Graphics/RenderPipeline/ShaderCode.hlsl" : "MSMain"; includes
pixel "F:/csharp/GhostEngine/src/Runtime//Ghost.Graphics/RenderPipeline/ShaderCode.hlsl" : "PSMain"; {
"F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/Shaders/Includes/Properties.hlsl";
}
hlsl
{
struct PixelInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
float4 uv : TEXCOORD0;
};
[numthreads(128, 1, 1)] // 128 threads to cover max 64 vertices and 124 triangles
[outputtopology("triangle")]
void MSMain(
uint3 groupThreadID : SV_GroupThreadID,
uint3 groupID : SV_GroupID,
out vertices PixelInput outVerts[64],
out indices uint3 outTris[124])
{
PerObjectData perObjectData = LoadData<PerObjectData>(g_PushConstantData.objectIndex, 0);
ByteAddressBuffer meshletBuffer = GET_BUFFER(perObjectData.meshletBuffer);
Meshlet m = meshletBuffer.Load<Meshlet>(groupID.x * sizeof(Meshlet));
uint vertexCount = m.packedCounts & 0xFF;
uint triangleCount = (m.packedCounts >> 8) & 0xFF;
SetMeshOutputCounts(vertexCount, triangleCount);
ByteAddressBuffer meshletVerticesBuffer = GET_BUFFER(perObjectData.meshletVerticesBuffer);
ByteAddressBuffer meshletTrianglesBuffer = GET_BUFFER(perObjectData.meshletTrianglesBuffer);
// Write vertex output
if (groupThreadID.x < vertexCount)
{
uint vertexIndex = meshletVerticesBuffer.Load((m.vertexOffset + groupThreadID.x) * 4);
ByteAddressBuffer vertices = GET_BUFFER(perObjectData.vertexBuffer);
Vertex v = vertices.Load<Vertex>(vertexIndex * sizeof(Vertex));
GlobalFrameData globalFrameData = LoadData<GlobalFrameData>(g_PushConstantData.globalIndex, 0);
PerViewData perViewData = LoadData<PerViewData>(g_PushConstantData.viewIndex, 0);
PerInstanceData perInstanceData = LoadData<PerInstanceData>(globalFrameData.instanceBufferIndex, g_PushConstantData.instanceIndex);
float4 worldPos = mul(perInstanceData.localToWorld, float4(v.position.xyz, 1.0f));
float4 viewPos = mul(perViewData.viewMatrix, worldPos);
outVerts[groupThreadID.x].position = mul(perViewData.projectionMatrix, viewPos);
outVerts[groupThreadID.x].color = v.color;
outVerts[groupThreadID.x].uv = v.uv;
}
// Write triangle output (1 thread processes 1 triangle)
if (groupThreadID.x < triangleCount)
{
uint triangleIndex = groupThreadID.x;
// Load the packed 32-bit integer containing the 3 local indices
uint packedIndices = meshletTrianglesBuffer.Load((m.triangleOffset + triangleIndex) * 4);
uint i0 = packedIndices & 0xFF;
uint i1 = (packedIndices >> 8) & 0xFF;
uint i2 = (packedIndices >> 16) & 0xFF;
outTris[triangleIndex] = uint3(i0, i1, i2);
}
}
float4 PSMain(PixelInput input) : SV_TARGET
{
// PerMaterialData perMaterialData = LoadData<PerMaterialData>(g_PushConstantData.materialIndex, 0);
//
// float4 color1 = SAMPLE_TEXTURE2D(perMaterialData.texture1, perMaterialData.tex_sampler, input.uv.xy);
// float4 color2 = SAMPLE_TEXTURE2D(perMaterialData.texture2, perMaterialData.tex_sampler, input.uv.xy);
// float4 color3 = SAMPLE_TEXTURE2D(perMaterialData.texture3, perMaterialData.tex_sampler, input.uv.xy);
// float4 color4 = SAMPLE_TEXTURE2D(perMaterialData.texture4, perMaterialData.tex_sampler, input.uv.xy);
//
// float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
// return perMaterialData.color * blendedColor + input.color;
// TODO: Randome color on meshlet.
return float4(1, 0, 0, 1);
}
}
mesh "hlsl_block" : "MSMain";
pixel "hlsl_block" : "PSMain";
} }
} }

View File

@@ -52,6 +52,7 @@
<ProjectReference Include="..\..\Runtime\Ghost.Engine\Ghost.Engine.csproj" /> <ProjectReference Include="..\..\Runtime\Ghost.Engine\Ghost.Engine.csproj" />
<ProjectReference Include="..\..\Test\Ghost.Test.Core\Ghost.Test.Core.csproj" /> <ProjectReference Include="..\..\Test\Ghost.Test.Core\Ghost.Test.Core.csproj" />
<ProjectReference Include="..\..\Runtime\Ghost.Graphics\Ghost.Graphics.csproj" /> <ProjectReference Include="..\..\Runtime\Ghost.Graphics\Ghost.Graphics.csproj" />
<ProjectReference Include="..\..\Editor\Ghost.DSL\Ghost.DSL.csproj" />
</ItemGroup> </ItemGroup>
<!-- <!--

View File

@@ -1,9 +1,12 @@
using Ghost.Core; using Ghost.Core;
using Ghost.Core.Graphics;
using Ghost.DSL.ShaderCompiler;
using Ghost.Graphics.Core; using Ghost.Graphics.Core;
using Ghost.Graphics.RenderGraphModule; using Ghost.Graphics.RenderGraphModule;
using Ghost.Graphics.RenderPipeline; using Ghost.Graphics.RenderPipeline;
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Mathematics;
using Misaki.HighPerformance.Utilities;
namespace Ghost.Graphics.Test.RenderPasses; namespace Ghost.Graphics.Test.RenderPasses;
@@ -21,10 +24,15 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
{ {
public Identifier<RGTexture> backbuffer; public Identifier<RGTexture> backbuffer;
public RenderList renderList; public RenderList renderList;
public Handle<Material> material;
public uint globalIndex;
public uint viewIndex;
} }
private readonly RenderGraph _renderGraph; private readonly RenderGraph _renderGraph;
private readonly RenderSystem _renderSystem; private readonly RenderSystem _renderSystem;
private Identifier<Shader> _meshletShader;
private Handle<Material> _meshletMaterial;
private bool _disposed; private bool _disposed;
@@ -41,6 +49,25 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
renderSystem.GraphicsEngine.ResourceDatabase, renderSystem.GraphicsEngine.ResourceDatabase,
renderSystem.GraphicsEngine.PipelineLibrary, renderSystem.GraphicsEngine.PipelineLibrary,
renderSystem.GraphicsEngine.ShaderCompiler); renderSystem.GraphicsEngine.ShaderCompiler);
var shaderDescriptor = DSLShaderCompiler.CompileShader("F:/csharp/GhostEngine/src/Runtime/Ghost.Graphics/test.gshdr", "C:/Users/Misaki/Downloads/Archive").GetValueOrThrow();
_meshletShader = renderSystem.ResourceManager.CreateGraphicsShader(shaderDescriptor);
_meshletMaterial = renderSystem.ResourceManager.CreateMaterial(_meshletShader);
var config = new ShaderCompilationConfig
{
optimizeLevel = CompilerOptimizeLevel.O3,
options = CompilerOption.KeepReflections,
tier = CompilerTier.Tier2
};
var pass = shaderDescriptor.passes[0];
var emptyKeywords = new LocalKeywordSet();
var variantKey = RHIUtility.CreateShaderVariantKey(
RHIUtility.CreateShaderPassKey(pass.identifier),
in emptyKeywords);
renderSystem.GraphicsEngine.ShaderCompiler.CompilePass(in pass, in config, variantKey).GetValueOrThrow();
} }
public void Render(RenderContext ctx, ReadOnlySpan<RenderRequest> requests) public void Render(RenderContext ctx, ReadOnlySpan<RenderRequest> requests)
@@ -137,7 +164,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
} }
else else
{ {
var backBuffer = _renderGraph.ImportTexture(request.colorTarget, "BackBuffer", clearAtFirstUse: false, discardAtLastUse: false); var backBuffer = _renderGraph.ImportTexture(request.colorTarget, "BackBuffer", clearAtFirstUse: true, discardAtLastUse: false);
MeshletDebugPass(backBuffer, request.opaqueRenderList, resourceDatabase.GetBindlessIndex(frameBufferResource.AsResource()), resourceDatabase.GetBindlessIndex(viewBufferResource.AsResource()));
} }
// We must enqueue a return for the pooled resources so they are freed next frame. // We must enqueue a return for the pooled resources so they are freed next frame.
@@ -147,16 +176,35 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
} }
} }
private void MeshletDebugPass(Identifier<RGTexture> backbuffer, RenderList renderList) private void MeshletDebugPass(Identifier<RGTexture> backbuffer, RenderList renderList, uint globalIndex, uint viewIndex)
{ {
using (var builder = _renderGraph.AddRasterRenderPass<MeshletDebugPassData>("Meshlet Debug Pass", out var passData)) using (var builder = _renderGraph.AddRasterRenderPass<MeshletDebugPassData>("Meshlet Debug Pass", out var passData))
{ {
passData.renderList = renderList; passData.renderList = renderList;
passData.globalIndex = globalIndex;
passData.viewIndex = viewIndex;
passData.material = _meshletMaterial;
builder.SetColorAttachment(backbuffer, 0); builder.SetColorAttachment(backbuffer, 0);
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx)=> builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx)=>
{ {
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
ctx.SetActiveMaterial(data.material);
var instanceIndex = 0u;
foreach (var record in data.renderList)
{
ctx.SetActiveMesh(record.mesh);
ctx.SetInstanceIndex(instanceIndex);
var meshRefResult = ctx.ResourceManager.GetMeshReference(record.mesh);
if (meshRefResult.IsSuccess)
{
var meshletCount = (uint)meshRefResult.Value.MeshletData.meshlets.Count;
ctx.DispatchMesh(new uint3(meshletCount, 1, 1));
}
instanceIndex++;
}
}); });
} }
} }
@@ -168,6 +216,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
return; return;
} }
_renderSystem.ResourceManager.ReleaseMaterial(_meshletMaterial);
_renderSystem.ResourceManager.ReleaseShader(_meshletShader);
_renderGraph.Dispose(); _renderGraph.Dispose();
_disposed = true; _disposed = true;

View File

@@ -2,6 +2,7 @@ using Ghost.Core;
using Ghost.Graphics.Test.Windows; using Ghost.Graphics.Test.Windows;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Misaki.HighPerformance.LowLevel.Buffer;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
@@ -32,22 +33,22 @@ public partial class UnitTestApp : Application
OperatingSystem.IsMacOS() ? "osx" : "unknown"; OperatingSystem.IsMacOS() ? "osx" : "unknown";
var arch = Environment.Is64BitProcess ? "x64" : "x86"; var arch = Environment.Is64BitProcess ? "x64" : "x86";
var nativeDllDir = Path.Combine(currentDir, "runtimes", platform + "-" + arch, "native"); var nativeDllDir = Path.Combine(currentDir, "runtimes", platform + "-" + arch, "native");
//if (Directory.Exists(nativeDllDir)) if (Directory.Exists(nativeDllDir))
//{
// foreach (var dll in Directory.EnumerateFiles(nativeDllDir, "*.dll"))
// {
// NativeLibrary.Load(dll);
// }
//}
NativeLibrary.SetDllImportResolver(typeof(UnitTestApp).Assembly, (libraryName, assembly, searchPath) =>
{ {
if (libraryName == "dxcompiler") foreach (var dll in Directory.EnumerateFiles(nativeDllDir, "*.dll"))
{ {
NativeLibrary.Load(Path.Combine(nativeDllDir, "dxil.dll")); NativeLibrary.Load(dll);
} }
}
//NativeLibrary.SetDllImportResolver(typeof(UnitTestApp).Assembly, (libraryName, assembly, searchPath) =>
//{
// if (libraryName == "dxcompiler")
// {
// NativeLibrary.Load(Path.Combine(nativeDllDir, "dxil.dll"));
// }
return IntPtr.Zero; // return IntPtr.Zero;
}); //});
} }
/// <summary> /// <summary>
@@ -58,6 +59,15 @@ public partial class UnitTestApp : Application
{ {
LoadDll(); LoadDll();
var opts = new AllocationManagerInitOpts
{
ArenaCapacity = 1024 * 1024 * 1024, // 1GB
StackCapacity = 1024 * 1024 * 32, // 32MB
FreeListConcurrencyLevel = Environment.ProcessorCount,
};
AllocationManager.Initialize(opts);
_window = new GraphicsTestWindow(); _window = new GraphicsTestWindow();
_window.Activate(); _window.Activate();

View File

@@ -20,6 +20,8 @@ public sealed partial class GraphicsTestWindow : Window
private ISwapChain? _swapChain; private ISwapChain? _swapChain;
private World? _world; private World? _world;
private Handle<Mesh> _meshHandle;
private bool _isFirstActivationHandled; private bool _isFirstActivationHandled;
public GraphicsTestWindow() public GraphicsTestWindow()
@@ -64,7 +66,9 @@ public sealed partial class GraphicsTestWindow : Window
_world.AddService(_renderSystem); _world.AddService(_renderSystem);
// Add Systems // Add Systems
_world.SystemManager.GetSystem<DefaultSystemGroup>().AddSystem<RenderExtractionSystem>(); var group = _world.SystemManager.GetSystem<DefaultSystemGroup>();
group.AddSystem<RenderExtractionSystem>();
group.SortSystems();
_world.SystemManager.InitializeAll(default); _world.SystemManager.InitializeAll(default);
@@ -101,16 +105,8 @@ public sealed partial class GraphicsTestWindow : Window
using var cmdAllocator = _renderSystem.GraphicsEngine.CreateCommandAllocator(CommandBufferType.Graphics); using var cmdAllocator = _renderSystem.GraphicsEngine.CreateCommandAllocator(CommandBufferType.Graphics);
directCmd.Begin(cmdAllocator); directCmd.Begin(cmdAllocator);
var meshHandle = ctx.CreateMesh(vertices, indices, true); _meshHandle = ctx.CreateMesh(vertices, indices, true);
ctx.UpdateObjectData(_meshHandle);
var meshRefResult = _renderSystem.ResourceManager.GetMeshReference(meshHandle);
if (meshRefResult.IsSuccess)
{
meshRefResult.Value.CookMeshlets();
}
ctx.UploadMeshlets(meshHandle);
ctx.UpdateObjectData(meshHandle);
directCmd.End().ThrowIfFailed(); directCmd.End().ThrowIfFailed();
_renderSystem.GraphicsEngine.Device.GraphicsQueue.Submit(directCmd); _renderSystem.GraphicsEngine.Device.GraphicsQueue.Submit(directCmd);
@@ -121,8 +117,8 @@ public sealed partial class GraphicsTestWindow : Window
var meshEntity = _world.EntityManager.CreateEntity(meshSet); var meshEntity = _world.EntityManager.CreateEntity(meshSet);
_world.EntityManager.SetComponent(meshEntity, new MeshInstance _world.EntityManager.SetComponent(meshEntity, new MeshInstance
{ {
mesh = meshHandle, mesh = _meshHandle,
renderingLayerMask = new RenderingLayerMask(uint.MaxValue), renderingLayerMask = RenderingLayerMask.All,
shadowCastingMode = Engine.ShadowCastingMode.On shadowCastingMode = Engine.ShadowCastingMode.On
}); });
@@ -147,6 +143,8 @@ public sealed partial class GraphicsTestWindow : Window
World.Destroy(_world.ID); World.Destroy(_world.ID);
} }
_renderSystem?.ResourceManager.ReleaseMesh(_meshHandle);
_swapChain?.Dispose(); _swapChain?.Dispose();
_renderSystem?.Dispose(); _renderSystem?.Dispose();
@@ -188,6 +186,8 @@ public sealed partial class GraphicsTestWindow : Window
var queryID = new QueryBuilder().WithAll<Camera>().Build(_world); var queryID = new QueryBuilder().WithAll<Camera>().Build(_world);
ref var query = ref _world.ComponentManager.GetEntityQueryReference(queryID); ref var query = ref _world.ComponentManager.GetEntityQueryReference(queryID);
// FIX: A critical bug that resize happens on the render thread, but OnRendering invoke on the UI thread, and there is a chance that our extraction system already send the request to the render thread with old back buffer handle, which is already become invalid after resize.
// A proper solution is to use swap chain manager, camera only reference the id of the swap chain, and we will extract the current back buffer handle on the render thread.
foreach (ref var cam in query.GetComponentIterator<Camera>()) foreach (ref var cam in query.GetComponentIterator<Camera>())
{ {
cam.colorTarget = _swapChain.GetCurrentBackBuffer(); cam.colorTarget = _swapChain.GetCurrentBackBuffer();