From 447a4e690499cfdd495ccc3766a580fc08e84bc5 Mon Sep 17 00:00:00 2001 From: Misaki Date: Wed, 25 Mar 2026 20:27:46 +0900 Subject: [PATCH] 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. --- src/Editor/Ghost.DSL/AssemblyInfo.cs | 2 +- .../Pages/EngineEditor/ConsoleViewModel.cs | 2 +- src/Runtime/Ghost.Core/Ghost.Core.csproj | 4 +- .../Systems/RenderExtractionSystem.cs | 3 +- src/Runtime/Ghost.Entities/Query.cs | 4 + src/Runtime/Ghost.Entities/System.cs | 7 +- .../Templates/QueryBuilder.With.gen.cs | 121 +++++++++++------- .../Templates/QueryBuilder.With.tt | 41 +++--- src/Runtime/Ghost.Entities/World.cs | 3 + .../Ghost.Graphics.D3D12/D3D12CommandQueue.cs | 10 +- .../D3D12GraphicsEngine.cs | 10 ++ .../Ghost.Graphics.D3D12/D3D12RenderDevice.cs | 6 +- .../Utilities/D3D12Utility.cs | 7 +- src/Runtime/Ghost.Graphics/Core/Mesh.cs | 10 +- src/Runtime/Ghost.Graphics/Core/RenderList.cs | 2 +- .../Ghost.Graphics/Core/RenderingContext.cs | 17 +-- .../Ghost.Graphics/Ghost.Graphics.csproj | 2 +- .../Ghost.Graphics/Obsolete/MeshRenderPass.cs | 4 +- .../RenderGraphModule/RenderGraphContext.cs | 23 +++- .../RenderPipeline/ShaderCode.hlsl | 36 ++---- src/Runtime/Ghost.Graphics/RenderSystem.cs | 1 + .../Shaders/Includes/Common.hlsl | 12 ++ .../Shaders/Includes/Properties.hlsl | 24 +++- src/Runtime/Ghost.Graphics/test.gshdr | 105 +++++++++++++-- .../Ghost.Graphics.Test.csproj | 1 + .../RenderPasses/TestRenderPipeline.cs | 55 +++++++- .../Ghost.Graphics.Test/UnitTestApp.xaml.cs | 34 +++-- .../Windows/GraphicsTestWindow.xaml.cs | 26 ++-- 28 files changed, 407 insertions(+), 165 deletions(-) diff --git a/src/Editor/Ghost.DSL/AssemblyInfo.cs b/src/Editor/Ghost.DSL/AssemblyInfo.cs index 539e855..cda28dd 100644 --- a/src/Editor/Ghost.DSL/AssemblyInfo.cs +++ b/src/Editor/Ghost.DSL/AssemblyInfo.cs @@ -1,4 +1,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Ghost.Shader.Test")] -[assembly: InternalsVisibleTo("Ghost.Graphics")] \ No newline at end of file +[assembly: InternalsVisibleTo("Ghost.Graphics.Test")] \ No newline at end of file diff --git a/src/Editor/Ghost.Editor/ViewModels/Pages/EngineEditor/ConsoleViewModel.cs b/src/Editor/Ghost.Editor/ViewModels/Pages/EngineEditor/ConsoleViewModel.cs index ca36c14..5ddd4d6 100644 --- a/src/Editor/Ghost.Editor/ViewModels/Pages/EngineEditor/ConsoleViewModel.cs +++ b/src/Editor/Ghost.Editor/ViewModels/Pages/EngineEditor/ConsoleViewModel.cs @@ -48,6 +48,6 @@ internal partial class ConsoleViewModel : ObservableObject [RelayCommand] private void ClearLogs() { - Logger.Clear(); + //Logger.Clear(); } } \ No newline at end of file diff --git a/src/Runtime/Ghost.Core/Ghost.Core.csproj b/src/Runtime/Ghost.Core/Ghost.Core.csproj index df24c47..06b3588 100644 --- a/src/Runtime/Ghost.Core/Ghost.Core.csproj +++ b/src/Runtime/Ghost.Core/Ghost.Core.csproj @@ -19,9 +19,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Runtime/Ghost.Engine/Systems/RenderExtractionSystem.cs b/src/Runtime/Ghost.Engine/Systems/RenderExtractionSystem.cs index 01e2e02..c8e31c2 100644 --- a/src/Runtime/Ghost.Engine/Systems/RenderExtractionSystem.cs +++ b/src/Runtime/Ghost.Engine/Systems/RenderExtractionSystem.cs @@ -92,6 +92,7 @@ public class RenderExtractionSystem : ISystem var rtSize = new uint2(rtResult.Value.TextureDescription.Width, rtResult.Value.TextureDescription.Height); 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 transparentRenderList = 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, opaqueRenderList = renderList, shadowCasterRenderList = shadowCasterRenderList, - transparentRenderList = default, // TODO: Classify transparent objects into a separate render list and render via oit. + transparentRenderList = transparentRenderList, renderFunc = camRef.renderFunc, view = new RenderView { diff --git a/src/Runtime/Ghost.Entities/Query.cs b/src/Runtime/Ghost.Entities/Query.cs index 5d97c0e..3ddbc35 100644 --- a/src/Runtime/Ghost.Entities/Query.cs +++ b/src/Runtime/Ghost.Entities/Query.cs @@ -636,6 +636,10 @@ public ref partial struct QueryBuilder : IDisposable { Dispose(); } + else + { + Clear(); + } return query; } diff --git a/src/Runtime/Ghost.Entities/System.cs b/src/Runtime/Ghost.Entities/System.cs index e3524f8..fad8cef 100644 --- a/src/Runtime/Ghost.Entities/System.cs +++ b/src/Runtime/Ghost.Entities/System.cs @@ -340,7 +340,7 @@ public abstract class SystemGroup : ISystem public sealed class DefaultSystemGroup : SystemGroup; -public sealed class SystemManager +public sealed class SystemManager : IDisposable { private readonly World _world; @@ -415,4 +415,9 @@ public sealed class SystemManager system.Cleanup(in systemAPI); } } + + public void Dispose() + { + CleanupAll(default); + } } diff --git a/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.gen.cs b/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.gen.cs index eb3787f..d6ecbc9 100644 --- a/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.gen.cs +++ b/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.gen.cs @@ -1,4 +1,5 @@ +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; 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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAll() + [UnscopedRef] + public ref QueryBuilder WithAll() where T0 : unmanaged, IComponent { _all.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAllRW() + [UnscopedRef] + public ref QueryBuilder WithAllRW() where T0 : unmanaged, IComponent { _all.Add(ComponentTypeID.Value); _rw.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAny() + [UnscopedRef] + public ref QueryBuilder WithAny() where T0 : unmanaged, IComponent { _any.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -50,12 +54,13 @@ public ref partial struct QueryBuilder /// Targets entities that do not have any of the specified component types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAbsent() + [UnscopedRef] + public ref QueryBuilder WithAbsent() where T0 : unmanaged, IComponent { _absent.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithNone() + [UnscopedRef] + public ref QueryBuilder WithNone() where T0 : unmanaged, IComponent { _none.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithDisabled() + [UnscopedRef] + public ref QueryBuilder WithDisabled() where T0 : unmanaged, IEnableableComponent { _disabled.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresent() + [UnscopedRef] + public ref QueryBuilder WithPresent() where T0 : unmanaged, IComponent { _present.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresentRW() + [UnscopedRef] + public ref QueryBuilder WithPresentRW() where T0 : unmanaged, IComponent { _present.Add(ComponentTypeID.Value); _rw.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAll() + [UnscopedRef] + public ref QueryBuilder WithAll() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { _all.Add(ComponentTypeID.Value); _all.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAllRW() + [UnscopedRef] + public ref QueryBuilder WithAllRW() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { @@ -140,7 +151,7 @@ public ref partial struct QueryBuilder _all.Add(ComponentTypeID.Value); _rw.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAny() + [UnscopedRef] + public ref QueryBuilder WithAny() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { _any.Add(ComponentTypeID.Value); _any.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -163,14 +175,15 @@ public ref partial struct QueryBuilder /// Targets entities that do not have any of the specified component types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAbsent() + [UnscopedRef] + public ref QueryBuilder WithAbsent() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { _absent.Add(ComponentTypeID.Value); _absent.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithNone() + [UnscopedRef] + public ref QueryBuilder WithNone() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { _none.Add(ComponentTypeID.Value); _none.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithDisabled() + [UnscopedRef] + public ref QueryBuilder WithDisabled() where T0 : unmanaged, IEnableableComponent where T1 : unmanaged, IEnableableComponent { _disabled.Add(ComponentTypeID.Value); _disabled.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresent() + [UnscopedRef] + public ref QueryBuilder WithPresent() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { _present.Add(ComponentTypeID.Value); _present.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresentRW() + [UnscopedRef] + public ref QueryBuilder WithPresentRW() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent { @@ -232,7 +249,7 @@ public ref partial struct QueryBuilder _present.Add(ComponentTypeID.Value); _rw.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAll() + [UnscopedRef] + public ref QueryBuilder WithAll() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -249,7 +267,7 @@ public ref partial struct QueryBuilder _all.Add(ComponentTypeID.Value); _all.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAllRW() + [UnscopedRef] + public ref QueryBuilder WithAllRW() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -269,7 +288,7 @@ public ref partial struct QueryBuilder _all.Add(ComponentTypeID.Value); _rw.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAny() + [UnscopedRef] + public ref QueryBuilder WithAny() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -286,7 +306,7 @@ public ref partial struct QueryBuilder _any.Add(ComponentTypeID.Value); _any.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -294,7 +314,8 @@ public ref partial struct QueryBuilder /// Targets entities that do not have any of the specified component types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAbsent() + [UnscopedRef] + public ref QueryBuilder WithAbsent() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -303,7 +324,7 @@ public ref partial struct QueryBuilder _absent.Add(ComponentTypeID.Value); _absent.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithNone() + [UnscopedRef] + public ref QueryBuilder WithNone() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -320,7 +342,7 @@ public ref partial struct QueryBuilder _none.Add(ComponentTypeID.Value); _none.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithDisabled() + [UnscopedRef] + public ref QueryBuilder WithDisabled() where T0 : unmanaged, IEnableableComponent where T1 : unmanaged, IEnableableComponent where T2 : unmanaged, IEnableableComponent @@ -337,7 +360,7 @@ public ref partial struct QueryBuilder _disabled.Add(ComponentTypeID.Value); _disabled.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresent() + [UnscopedRef] + public ref QueryBuilder WithPresent() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -354,7 +378,7 @@ public ref partial struct QueryBuilder _present.Add(ComponentTypeID.Value); _present.Add(ComponentTypeID.Value); - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresentRW() + [UnscopedRef] + public ref QueryBuilder WithPresentRW() where T0 : unmanaged, IComponent where T1 : unmanaged, IComponent where T2 : unmanaged, IComponent @@ -374,7 +399,7 @@ public ref partial struct QueryBuilder _present.Add(ComponentTypeID.Value); _rw.Add(ComponentTypeID.Value); - return this; + return ref this; } } \ No newline at end of file diff --git a/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.tt b/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.tt index 974af82..b96a841 100644 --- a/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.tt +++ b/src/Runtime/Ghost.Entities/Templates/QueryBuilder.With.tt @@ -4,6 +4,7 @@ <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ include file="Helpers.ttinclude" #> +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; 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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAll<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithAll<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> _all.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAllRW<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithAllRW<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> @@ -44,7 +47,7 @@ public ref partial struct QueryBuilder _rw.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAny<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithAny<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> _any.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -67,14 +71,15 @@ public ref partial struct QueryBuilder /// Targets entities that do not have any of the specified component types. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithAbsent<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithAbsent<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> _absent.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithNone<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithNone<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> _none.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithDisabled<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithDisabled<<#= generics #>>() <#= enableRestrictions #> { <# for (var j = 0; j < i; j++) { #> _disabled.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresent<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithPresent<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> _present.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } /// @@ -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. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public QueryBuilder WithPresentRW<<#= generics #>>() + [UnscopedRef] + public ref QueryBuilder WithPresentRW<<#= generics #>>() <#= restrictions #> { <# for (var j = 0; j < i; j++) { #> @@ -135,7 +144,7 @@ public ref partial struct QueryBuilder _rw.Add(ComponentTypeID>.Value); <# } #> - return this; + return ref this; } <# } #> diff --git a/src/Runtime/Ghost.Entities/World.cs b/src/Runtime/Ghost.Entities/World.cs index d4073b0..36129bf 100644 --- a/src/Runtime/Ghost.Entities/World.cs +++ b/src/Runtime/Ghost.Entities/World.cs @@ -268,6 +268,9 @@ public partial class World : IDisposable, IEquatable } } + _componentManager.Dispose(); + _systemManager.Dispose(); + s_freeWorldSlots.Enqueue(_id); s_worlds[_id] = null; diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandQueue.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandQueue.cs index e4ba11d..cb7d54c 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandQueue.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandQueue.cs @@ -10,9 +10,9 @@ namespace Ghost.Graphics.D3D12; /// /// D3D12 implementation of command queue interface /// -internal unsafe class D3D12CommandQueue : D3D12Object, ICommandQueue +internal unsafe class D3D12CommandQueue : D3D12Object, ICommandQueue { - private UniquePtr _fence; + private UniquePtr _fence; private readonly AutoResetEvent _fenceEvent; private ulong _fenceValue; @@ -22,7 +22,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object, ICom get; } - private static ID3D12CommandQueue1* CreateCommandQueue(ID3D12Device14* device, CommandQueueType type) + private static ID3D12CommandQueue* CreateCommandQueue(ID3D12Device14* device, CommandQueueType type) { var queueDesc = new D3D12_COMMAND_QUEUE_DESC { @@ -31,7 +31,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object, ICom Flags = D3D12_COMMAND_QUEUE_FLAGS.D3D12_COMMAND_QUEUE_FLAG_NONE, }; - ID3D12CommandQueue1* pQueue = default; + ID3D12CommandQueue* pQueue = default; ThrowIfFailed(device->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue)); return pQueue; } @@ -43,7 +43,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object, ICom _fenceEvent = new AutoResetEvent(false); _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)); _fence.Attach(pFence); diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12GraphicsEngine.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12GraphicsEngine.cs index 8995bcb..b929a23 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12GraphicsEngine.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12GraphicsEngine.cs @@ -160,6 +160,16 @@ internal class D3D12GraphicsEngine : IGraphicsEngine return; } + while (_commandBufferReturnQueue.TryDequeue(out var entry)) + { + entry.commandBuffer.Dispose(); + } + + while (_commandBufferPool.TryDequeue(out var cmd)) + { + cmd.Dispose(); + } + _resourceDatabase.ReleaseAllResourcesImmediately(); _resourceAllocator.Dispose(); diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12RenderDevice.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12RenderDevice.cs index f58780e..805d966 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12RenderDevice.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12RenderDevice.cs @@ -29,9 +29,9 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe public SharedPtr DXGIFactory => _dxgiFactory.Share(); public SharedPtr Adapter => _adapter.Share(); - public SharedPtr NativeGraphicsQueue => _graphicsQueue.NativeObject; - public SharedPtr NativeComputeQueue => _computeQueue.NativeObject; - public SharedPtr NativeCopyQueue => _copyQueue.NativeObject; + public SharedPtr NativeGraphicsQueue => _graphicsQueue.NativeObject; + public SharedPtr NativeComputeQueue => _computeQueue.NativeObject; + public SharedPtr NativeCopyQueue => _copyQueue.NativeObject; public D3D12RenderDevice() :base(CreateDevice(out var dxgiFactory, out var adapter)) diff --git a/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs b/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs index 5672ecb..08a3147 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs @@ -53,8 +53,9 @@ internal static unsafe class D3D12Utility var ptr = uPtr.Get(); if (ptr != null) { + Debug.Assert(ptr != other); var refCount = ptr->Release(); - Debug.Assert((refCount != 0) || (ptr != other)); + Debug.Assert(refCount == 0); } uPtr = new UniquePtr(other); @@ -68,7 +69,7 @@ internal static unsafe class D3D12Utility if (ptr != null) { 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; - if (usage.HasFlag(BufferUsage.Raw) || usage.HasFlag(BufferUsage.UnorderedAccess)) + if (usage.HasFlag(BufferUsage.UnorderedAccess)) { flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } diff --git a/src/Runtime/Ghost.Graphics/Core/Mesh.cs b/src/Runtime/Ghost.Graphics/Core/Mesh.cs index ddca026..9768f43 100644 --- a/src/Runtime/Ghost.Graphics/Core/Mesh.cs +++ b/src/Runtime/Ghost.Graphics/Core/Mesh.cs @@ -194,7 +194,7 @@ public struct Mesh : IResourceReleasable this.ComputeBounds(); } - public readonly void ReleaseCpuResources() + public void ReleaseCpuResources() { _vertices.Dispose(); _indices.Dispose(); @@ -238,7 +238,7 @@ public struct Mesh : IResourceReleasable MeshletUtility.Build(config, clodMesh, Unsafe.AsPointer(ref this), MeshletOutputCallback); } - private static unsafe int MeshletOutputCallback(void* context, ClodGroup group, ReadOnlyUnsafeCollectionclusters) + private static unsafe int MeshletOutputCallback(void* context, ClodGroup group, ReadOnlyUnsafeCollection clusters) { var mesh = (Mesh*)context; ref var data = ref mesh->_meshletData; @@ -277,13 +277,13 @@ public struct Mesh : IResourceReleasable data.meshletVertices.Add(cluster.uniqueVertices[j]); } // Add local triangles (packed into uints) - nuint triangleCount = cluster.localIndexCount / 3; + var triangleCount = cluster.localIndexCount / 3; for (nuint j = 0; j < triangleCount; j++) { uint i0 = cluster.localIndices[j * 3 + 0]; uint i1 = cluster.localIndices[j * 3 + 1]; 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); } } @@ -291,7 +291,7 @@ public struct Mesh : IResourceReleasable return 0; } - public readonly void ReleaseResource(IResourceDatabase database) + public void ReleaseResource(IResourceDatabase database) { ReleaseCpuResources(); diff --git a/src/Runtime/Ghost.Graphics/Core/RenderList.cs b/src/Runtime/Ghost.Graphics/Core/RenderList.cs index e87bbe4..c34ea32 100644 --- a/src/Runtime/Ghost.Graphics/Core/RenderList.cs +++ b/src/Runtime/Ghost.Graphics/Core/RenderList.cs @@ -38,7 +38,7 @@ public struct RenderList : IDisposable { while (_listIndex < _length) { - if (_itemIndex < _pList[_listIndex].Count) + if (_itemIndex < _pList[_listIndex].Count - 1) { _itemIndex++; return true; diff --git a/src/Runtime/Ghost.Graphics/Core/RenderingContext.cs b/src/Runtime/Ghost.Graphics/Core/RenderingContext.cs index 3b0e2fe..021bede 100644 --- a/src/Runtime/Ghost.Graphics/Core/RenderingContext.cs +++ b/src/Runtime/Ghost.Graphics/Core/RenderingContext.cs @@ -93,7 +93,7 @@ public readonly unsafe ref struct RenderingContext return mesh; } - ref readonly var meshData = ref r.Value; + ref var meshData = ref r.Value; var vertexHandle = meshData.VertexBuffer.AsResource(); var indexHandle = meshData.IndexBuffer.AsResource(); @@ -105,9 +105,12 @@ public readonly unsafe ref struct RenderingContext if (staticMesh) { + meshData.CookMeshlets(); meshData.ReleaseCpuResources(); TransitionBarrier(vertexHandle, false, BarrierLayout.Undefined, BarrierAccess.ShaderResource, BarrierSync.VertexShading); TransitionBarrier(indexHandle, false, BarrierLayout.Undefined, BarrierAccess.IndexBuffer, BarrierSync.IndexInput); + + UploadMeshlets(mesh); } return mesh; @@ -205,17 +208,7 @@ public readonly unsafe ref struct RenderingContext _directCmd.UploadBuffer(meshRef.MeshLetBuffer, meshletData.meshlets.AsSpan()); _directCmd.UploadBuffer(meshRef.MeshletVerticesBuffer, meshletData.meshletVertices.AsSpan()); - // Padding for triangle data if needed - 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()); - } + _directCmd.UploadBuffer(meshRef.MeshletTrianglesBuffer, meshletData.meshletTriangles.AsSpan()); 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); diff --git a/src/Runtime/Ghost.Graphics/Ghost.Graphics.csproj b/src/Runtime/Ghost.Graphics/Ghost.Graphics.csproj index e9b6b34..4002b0b 100644 --- a/src/Runtime/Ghost.Graphics/Ghost.Graphics.csproj +++ b/src/Runtime/Ghost.Graphics/Ghost.Graphics.csproj @@ -18,7 +18,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Runtime/Ghost.Graphics/Obsolete/MeshRenderPass.cs b/src/Runtime/Ghost.Graphics/Obsolete/MeshRenderPass.cs index 6a5ed83..024e700 100644 --- a/src/Runtime/Ghost.Graphics/Obsolete/MeshRenderPass.cs +++ b/src/Runtime/Ghost.Graphics/Obsolete/MeshRenderPass.cs @@ -1,4 +1,5 @@ -using Ghost.Core; +#if false +// Obsolete using Ghost.Core.Graphics; using Ghost.DSL.ShaderCompiler; using Ghost.Graphics.Core; @@ -335,3 +336,4 @@ internal class MeshRenderPass : IRenderPass } } } +#endif diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs index 0d1993e..b86a16c 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs @@ -22,6 +22,9 @@ public interface IRasterRenderContext : IRenderGraphContext { int ActiveMeshIndexCount { get; } + void SetGlobalData(uint globalIndex, uint viewIndex); + void SetInstanceIndex(uint instanceIndex); + void SetActiveMaterial(Handle material); void SetActiveMaterial(ref readonly Material material); void SetActiveMesh(Handle mesh); @@ -58,6 +61,10 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC private Handle _activePerMeshData; private int _activeMeshIndexCount; + private uint _activeGlobalIndex; + private uint _activeViewIndex; + private uint _activeInstanceIndex; + public ResourceManager ResourceManager => _resourceManager; public IResourceDatabase ResourceDatabase => _resourceDatabase; @@ -221,12 +228,26 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC _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) { - // TODO: Global and view constants + // TODO: Global, view, and instance constants var data = new PushConstantsData { + globalIndex = _activeGlobalIndex, + viewIndex = _activeViewIndex, objectIndex = _resourceDatabase.GetBindlessIndex(_activePerMeshData.AsResource()), + instanceIndex = _activeInstanceIndex, materialIndex = _resourceDatabase.GetBindlessIndex(_activePerMaterialData.AsResource()), }; diff --git a/src/Runtime/Ghost.Graphics/RenderPipeline/ShaderCode.hlsl b/src/Runtime/Ghost.Graphics/RenderPipeline/ShaderCode.hlsl index 348add4..77e335d 100644 --- a/src/Runtime/Ghost.Graphics/RenderPipeline/ShaderCode.hlsl +++ b/src/Runtime/Ghost.Graphics/RenderPipeline/ShaderCode.hlsl @@ -8,18 +8,6 @@ struct PixelInput 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 [outputtopology("triangle")] 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 PerViewData perViewData = LoadData(g_PushConstantData.perViewBuffer, 0); - float4 worldPos = mul(perObjectData.localToWorld, float4(v.position.xyz, 1.0f)); + PerInstanceData perInstanceData = LoadData(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.projectionMatrix, outVerts[groupThreadID.x].position); @@ -62,7 +52,7 @@ void MSMain( 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); @@ -76,13 +66,13 @@ void MSMain( float4 PSMain(PixelInput input) : SV_TARGET { - PerMaterialData perMaterialData = LoadData(g_PushConstantData.perMaterialBuffer, 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; + // PerMaterialData perMaterialData = LoadData(g_PushConstantData.perMaterialBuffer, 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; } diff --git a/src/Runtime/Ghost.Graphics/RenderSystem.cs b/src/Runtime/Ghost.Graphics/RenderSystem.cs index 17f845e..57f05e9 100644 --- a/src/Runtime/Ghost.Graphics/RenderSystem.cs +++ b/src/Runtime/Ghost.Graphics/RenderSystem.cs @@ -422,6 +422,7 @@ public class RenderSystem : IDisposable } _renderPipeline.Dispose(); + _resourceManager.Dispose(); _graphicsEngine.Dispose(); _shutdownEvent.Dispose(); diff --git a/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl b/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl index 16e11ac..ad9124d 100644 --- a/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl +++ b/src/Runtime/Ghost.Graphics/Shaders/Includes/Common.hlsl @@ -10,6 +10,18 @@ struct Vertex 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 #define GLOBAL_TEXTURE2D_HEAP ResourceDescriptorHeap diff --git a/src/Runtime/Ghost.Graphics/Shaders/Includes/Properties.hlsl b/src/Runtime/Ghost.Graphics/Shaders/Includes/Properties.hlsl index 2b4aa65..b9a3d16 100644 --- a/src/Runtime/Ghost.Graphics/Shaders/Includes/Properties.hlsl +++ b/src/Runtime/Ghost.Graphics/Shaders/Includes/Properties.hlsl @@ -5,11 +5,20 @@ struct PushConstantData { - BYTE_ADDRESS_BUFFER globalBuffer; - BYTE_ADDRESS_BUFFER perViewBuffer; - BYTE_ADDRESS_BUFFER perObjectBuffer; - BYTE_ADDRESS_BUFFER perInstanceBuffer; - BYTE_ADDRESS_BUFFER perMaterialBuffer; + uint globalIndex; + uint viewIndex; + uint objectIndex; + uint instanceIndex; + uint materialIndex; +}; + +struct GlobalFrameData +{ + uint viewBufferIndex; + uint instanceBufferIndex; + uint viewBufferCount; + uint instanceBufferCount; + uint userBufferIndex; }; struct PerViewData @@ -23,6 +32,11 @@ struct PerViewData float4 screenSize; // xy: size, zw: 1/size }; +struct PerInstanceData +{ + float4x4 localToWorld; +}; + struct PerObjectData { float3 worldBoundsMin; diff --git a/src/Runtime/Ghost.Graphics/test.gshdr b/src/Runtime/Ghost.Graphics/test.gshdr index 98f4c4d..d1b3583 100644 --- a/src/Runtime/Ghost.Graphics/test.gshdr +++ b/src/Runtime/Ghost.Graphics/test.gshdr @@ -2,12 +2,12 @@ shader "MyShader/Standard" { properties { - float4 color = { 1, 1, 1, 1 }; - tex2d texture1 = { black }; - tex2d texture2 = { white }; - tex2d texture3 = { grey }; - tex2d texture4 = { normal }; - sampler tex_sampler; + //float4 color = { 1, 1, 1, 1 }; + //tex2d texture1 = { black }; + //tex2d texture2 = { white }; + //tex2d texture3 = { grey }; + //tex2d texture4 = { normal }; + //sampler tex_sampler; } pass "Forward" @@ -21,7 +21,96 @@ shader "MyShader/Standard" color_mask = all; } - mesh "F:/csharp/GhostEngine/src/Runtime//Ghost.Graphics/RenderPipeline/ShaderCode.hlsl" : "MSMain"; - pixel "F:/csharp/GhostEngine/src/Runtime//Ghost.Graphics/RenderPipeline/ShaderCode.hlsl" : "PSMain"; + includes + { + "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(g_PushConstantData.objectIndex, 0); + + ByteAddressBuffer meshletBuffer = GET_BUFFER(perObjectData.meshletBuffer); + Meshlet m = meshletBuffer.Load(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(vertexIndex * sizeof(Vertex)); + + GlobalFrameData globalFrameData = LoadData(g_PushConstantData.globalIndex, 0); + PerViewData perViewData = LoadData(g_PushConstantData.viewIndex, 0); + PerInstanceData perInstanceData = LoadData(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(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"; } } diff --git a/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj b/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj index 3d299fb..2eb85fa 100644 --- a/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj +++ b/src/Test/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj @@ -52,6 +52,7 @@ +