diff --git a/Ghost.Core/Ghost.Core.csproj b/Ghost.Core/Ghost.Core.csproj index a332e88..5bc2b61 100644 --- a/Ghost.Core/Ghost.Core.csproj +++ b/Ghost.Core/Ghost.Core.csproj @@ -18,9 +18,9 @@ - + - + diff --git a/Ghost.Core/Utilities/Win32Utility.cs b/Ghost.Core/Utilities/Win32Utility.cs index b426c4f..9bfa61a 100644 --- a/Ghost.Core/Utilities/Win32Utility.cs +++ b/Ghost.Core/Utilities/Win32Utility.cs @@ -64,17 +64,11 @@ internal static unsafe partial class Win32Utility if (ptr != null) { uPtr = default; - MemoryLeakException.ThrowIfRefCountNonZero(ptr->Release()); + ptr->Release(); + //MemoryLeakException.ThrowIfRefCountNonZero(ptr->Release()); } } - [Conditional("DEBUG")] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Assert(this HRESULT hr) - { - Debug.Assert(hr.SUCCEEDED, hr.ToString()); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Result ToResult(this HRESULT hr, [CallerArgumentExpression(nameof(hr))] string? op = null) { diff --git a/Ghost.Editor.Core/Ghost.Editor.Core.csproj b/Ghost.Editor.Core/Ghost.Editor.Core.csproj index d89cac8..6591feb 100644 --- a/Ghost.Editor.Core/Ghost.Editor.Core.csproj +++ b/Ghost.Editor.Core/Ghost.Editor.Core.csproj @@ -12,8 +12,8 @@ preview - - + + diff --git a/Ghost.Editor/Ghost.Editor.csproj b/Ghost.Editor/Ghost.Editor.csproj index c7e8e33..50966f4 100644 --- a/Ghost.Editor/Ghost.Editor.csproj +++ b/Ghost.Editor/Ghost.Editor.csproj @@ -75,12 +75,11 @@ - + - - - - + + + diff --git a/Ghost.Entities/Query/QueryFilter.cs b/Ghost.Entities/Query/QueryFilter.cs index baed40e..0acd9bc 100644 --- a/Ghost.Entities/Query/QueryFilter.cs +++ b/Ghost.Entities/Query/QueryFilter.cs @@ -30,7 +30,7 @@ public struct QueryFilter : IDisposable UnsafeBitSet absentMask = default; var result = new UnsafeBitSet(world.EntityManager.EntityCount, allocator); - result.SetAll(); + result.ClearAll(); using (AllocationManager.CreateStackScope()) { @@ -83,7 +83,7 @@ public struct QueryFilter : IDisposable if (absentMask.IsCreated) { - result.And(~absentMask); + result.ANDC(absentMask); } } diff --git a/Ghost.Entities/Template/QueryEnumerable.cs b/Ghost.Entities/Template/QueryEnumerable.cs index 6dda847..065db17 100644 --- a/Ghost.Entities/Template/QueryEnumerable.cs +++ b/Ghost.Entities/Template/QueryEnumerable.cs @@ -49,7 +49,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -84,7 +84,7 @@ public unsafe ref struct QueryEnumerable public bool MoveNext() { _index = _filterMask.NextSetBit(_index + 1); - if (_index < 0 || _count <= 0 || _index >= _entities.Length) + if (_index < 0 || _count <= 0) { return false; } @@ -102,101 +102,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -244,7 +244,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -299,101 +299,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -445,7 +445,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -502,101 +502,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -652,7 +652,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -711,101 +711,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -865,7 +865,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -926,101 +926,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -1084,7 +1084,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -1147,101 +1147,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -1309,7 +1309,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -1374,101 +1374,101 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } public unsafe ref struct QueryEnumerable @@ -1540,7 +1540,7 @@ public unsafe ref struct QueryEnumerable { private ref QueryFilter _filter; private UnsafeBitSet _filterMask; - + private readonly ReadOnlySpan _entities; private readonly Stack.Scope _stackScope; @@ -1607,100 +1607,100 @@ public unsafe ref struct QueryEnumerable } } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } - public QueryEnumerable WithAll() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + public QueryEnumerable WithAll() + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); _filter._all.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAny() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); _filter._any.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithAbsent() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); _filter._absent.Add(TypeHandle.Get()); return this; - } + } public QueryEnumerable WithDisabled() - where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData - { + where TComponent0 : unmanaged, IComponentData where TComponent1 : unmanaged, IComponentData where TComponent2 : unmanaged, IComponentData + { _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); _filter._disabled.Add(TypeHandle.Get()); return this; - } + } } diff --git a/Ghost.Entities/Template/QueryEnumerable.tt b/Ghost.Entities/Template/QueryEnumerable.tt index 3ae5136..a2a7960 100644 --- a/Ghost.Entities/Template/QueryEnumerable.tt +++ b/Ghost.Entities/Template/QueryEnumerable.tt @@ -1,4 +1,4 @@ -<#@ template language="C#" #> +<#@ template language="C#" #> <#@ output extension=".cs" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Text" #> diff --git a/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj b/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj index 828a7c7..f9024f3 100644 --- a/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj +++ b/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj @@ -46,11 +46,11 @@ - - - - - + + + + + diff --git a/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs b/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs index 9e2fc86..c85909a 100644 --- a/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs +++ b/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs @@ -3,6 +3,8 @@ using Ghost.Graphics.RHI; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; using Misaki.HighPerformance.LowLevel.Buffer; +using TerraFX.Interop.WinRT; +using WinRT; namespace Ghost.Graphics.Test.Windows; @@ -34,7 +36,7 @@ public sealed partial class GraphicsTestWindow : Window GraphicsAPI = GraphicsAPI.Direct3D12 }); _renderer = _renderSystem.GraphicsEngine.CreateRenderer(); - + _swapChain = _renderSystem.GraphicsEngine.CreateSwapChain(new SwapChainDesc((uint)AppWindow.Size.Width, (uint)AppWindow.Size.Height, SwapChainTarget.FromCompositionSurface(Panel))); _renderer.SetSwapChain(_swapChain); diff --git a/Ghost.Graphics/Contracts/IShaderCompiler.cs b/Ghost.Graphics/Contracts/IShaderCompiler.cs index 20c63b8..edac3ca 100644 --- a/Ghost.Graphics/Contracts/IShaderCompiler.cs +++ b/Ghost.Graphics/Contracts/IShaderCompiler.cs @@ -141,7 +141,7 @@ public readonly struct ShaderReflectionData } } -public unsafe interface IShaderCompiler +public interface IShaderCompiler : IDisposable { Result Compile(ref readonly CompilerConfig config, Allocator allocator); Result CompilePass(IPassDescriptor descriptor); diff --git a/Ghost.Graphics/Contracts/ISwapChainPanelNative.cs b/Ghost.Graphics/Contracts/ISwapChainPanelNative.cs index 1371fcb..ffba777 100644 --- a/Ghost.Graphics/Contracts/ISwapChainPanelNative.cs +++ b/Ghost.Graphics/Contracts/ISwapChainPanelNative.cs @@ -1,8 +1,8 @@ using System.Runtime.InteropServices; +using TerraFX.Interop.Windows; namespace Ghost.Graphics.Contracts; -[System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "")] public unsafe readonly struct ISwapChainPanelNative : ISwapChainPanelNative.Interface, IDisposable { [ComImport] diff --git a/Ghost.Graphics/Core/Material.cs b/Ghost.Graphics/Core/Material.cs index 6f1dae4..52b6647 100644 --- a/Ghost.Graphics/Core/Material.cs +++ b/Ghost.Graphics/Core/Material.cs @@ -18,7 +18,9 @@ internal struct CBufferCache : IResourceReleasable public readonly Handle GpuResource => _gpuResource; public readonly uint AlignedSize => _alignedSize; - public unsafe CBufferCache(Handle buffer, uint bufferSize) + public readonly bool IsCreated => _gpuResource.IsValid && _cpuData.IsCreated; + + public CBufferCache(Handle buffer, uint bufferSize) { _alignedSize = (bufferSize + 255u) & ~255u; @@ -65,6 +67,11 @@ public struct Material : IResourceReleasable, IHandleType var pass = database.GetShaderPass(shader.GetPassKey(i)); var cbufferInfo = pass.CBuffer; + if (cbufferInfo.SizeInBytes == 0) + { + continue; + } + var desc = new BufferDesc { Size = cbufferInfo.SizeInBytes, @@ -91,7 +98,7 @@ public struct Material : IResourceReleasable, IHandleType public ref struct MaterialAccessor { private ref Material _materialData; - private Shader _shader; + private readonly Shader _shader; private readonly IResourceDatabase _resourceDatabase; diff --git a/Ghost.Graphics/Core/Mesh.cs b/Ghost.Graphics/Core/Mesh.cs index 33a4274..68f27bc 100644 --- a/Ghost.Graphics/Core/Mesh.cs +++ b/Ghost.Graphics/Core/Mesh.cs @@ -1,5 +1,6 @@ using Ghost.Core; using Ghost.Graphics.RHI; +using Ghost.Graphics.Utilities; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Utilities; @@ -10,42 +11,118 @@ namespace Ghost.Graphics.Core; public struct Mesh : IResourceReleasable, IHandleType { - public UnsafeList vertices; - public UnsafeList indices; - public AABB boundingBox; - public Handle vertexBuffer; - public Handle indexBuffer; + internal bool IsMeshDataDirty + { + get; private set; + } + + /// + /// Gets or sets the collection of vertices that define the geometry. + /// + public UnsafeList Vertices + { + readonly get => field; + set + { + field = value; + VertexCount = value.Count; + IsMeshDataDirty = true; + } + } + + /// + /// Gets or sets the collection of indices that define the order of vertices. + /// + public UnsafeList Indices + { + readonly get => field; + set + { + field = value; + IndexCount = value.Count; + IsMeshDataDirty = true; + } + } + + /// + /// Get the number of vertices in the mesh. + /// + public int VertexCount + { + get; private set; + } + + /// + /// Get the number of indices in the mesh. + /// + public int IndexCount + { + get; private set; + } + + /// + /// Gets or sets the axis-aligned bounding box (AABB) of the mesh. + /// + public AABB BoundingBox + { + get; set; + } + + /// + /// Gets the handle to the vertex buffer on the GPU. + /// + public Handle VertexBuffer + { + get; internal set; + } + + /// + /// Gets the handle to the index buffer on the GPU. + /// + public Handle IndexBuffer + { + get; internal set; + } + + /// + /// Gets the handle to the mesh data buffer on the GPU. + /// + public Handle ObjectDataBuffer + { + get; internal set; + } public Mesh() { - vertexBuffer = Handle.Invalid; - indexBuffer = Handle.Invalid; + VertexBuffer = Handle.Invalid; + IndexBuffer = Handle.Invalid; } internal Mesh(ReadOnlySpan vertices, ReadOnlySpan indices, Handle vertexBuffer, Handle indexBuffer) { - this.vertices = new(vertices.Length, Allocator.Persistent); - this.indices = new(indices.Length, Allocator.Persistent); - this.vertices.CopyFrom(vertices); - this.indices.CopyFrom(indices); - this.vertexBuffer = vertexBuffer; - this.indexBuffer = indexBuffer; + Vertices = new(vertices.Length, Allocator.Persistent); + Indices = new(indices.Length, Allocator.Persistent); + Vertices.CopyFrom(vertices); + Indices.CopyFrom(indices); + VertexBuffer = vertexBuffer; + IndexBuffer = indexBuffer; this.ComputeBounds(); } - public void ReleaseCpuResources() + public readonly void ReleaseCpuResources() { - vertices.Dispose(); - indices.Dispose(); + Vertices.Dispose(); + Indices.Dispose(); } void IResourceReleasable.ReleaseResource(IResourceDatabase database) { ReleaseCpuResources(); - database.ReleaseResource(vertexBuffer.AsResource()); - database.ReleaseResource(indexBuffer.AsResource()); + database.ReleaseResource(VertexBuffer.AsResource()); + database.ReleaseResource(IndexBuffer.AsResource()); + database.ReleaseResource(ObjectDataBuffer.AsResource()); } } @@ -56,21 +133,21 @@ public static class MeshExtension /// public static void ComputeBounds(ref this Mesh mesh) { - if (mesh.vertices.Count == 0) + if (mesh.Vertices.Count == 0) { return; } var min = new float3(float.MaxValue); var max = new float3(float.MinValue); - foreach (var vertex in mesh.vertices) + foreach (var vertex in mesh.Vertices) { var pos = vertex.position.xyz; min = math.min(min, pos); max = math.max(max, pos); } - mesh.boundingBox = new AABB(min, max); + mesh.BoundingBox = new AABB(min, max); } /// @@ -81,35 +158,7 @@ public static class MeshExtension /// public static void ComputeNormal(ref this Mesh mesh) { - if (!mesh.vertices.IsCreated || mesh.vertices.Count < 3 - || !mesh.indices.IsCreated || mesh.indices.Count < 3) - { - return; - } - - for (var i = 0; i < mesh.indices.Count; i += 3) - { - var i0 = mesh.indices[i]; - var i1 = mesh.indices[i + 1]; - var i2 = mesh.indices[i + 2]; - - var v0 = mesh.vertices[i0]; - var v1 = mesh.vertices[i1]; - var v2 = mesh.vertices[i2]; - - var edge1 = v1.position - v0.position; - var edge2 = v2.position - v0.position; - var faceNormal = math.cross(edge1.xyz, edge2.xyz); - - mesh.vertices[i0].normal.xyz += faceNormal; - mesh.vertices[i1].normal.xyz += faceNormal; - mesh.vertices[i2].normal.xyz += faceNormal; - } - - for (var i = 0; i < mesh.vertices.Count; i++) - { - mesh.vertices[i].normal = math.normalize(mesh.vertices[i].normal); - } + MeshBuilder.ComputeNormal(mesh.Vertices, mesh.Indices); } /// @@ -120,53 +169,6 @@ public static class MeshExtension /// public static void ComputeTangents(ref this Mesh mesh) { - var bitangents = new float4[mesh.vertices.Count]; - - for (var i = 0; i < mesh.indices.Count; i += 3) - { - var i0 = mesh.indices[i]; - var i1 = mesh.indices[i + 1]; - var i2 = mesh.indices[i + 2]; - - var v0 = mesh.vertices[i0]; - var v1 = mesh.vertices[i1]; - var v2 = mesh.vertices[i2]; - - var uv0 = mesh.vertices[i0].uv; - var uv1 = mesh.vertices[i1].uv; - var uv2 = mesh.vertices[i2].uv; - - var deltaPos1 = v1.position - v0.position; - var deltaPos2 = v2.position - v0.position; - var deltaUV1 = uv1 - uv0; - var deltaUV2 = uv2 - uv0; - - var r = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV1.y * deltaUV2.x); - var tangent = (deltaPos1 * deltaUV2.y - deltaPos2 * deltaUV1.y) * r; - var bitangent = (deltaPos2 * deltaUV1.x - deltaPos1 * deltaUV2.x) * r; - - for (var j = 0; j < 3; j++) - { - var idx = mesh.indices[i + j]; - var t = mesh.vertices[idx].tangent; - mesh.vertices[idx].tangent.xyz = t.xyz + tangent.xyz; - - bitangents[idx] += bitangent; - } - } - - for (var i = 0; i < mesh.vertices.Count; i++) - { - var n = mesh.vertices[i].normal; - var t = mesh.vertices[i].tangent; - - var proj = n * math.dot(n, t); - t = math.normalize(t - proj); - - var b = bitangents[i]; - var w = math.dot(math.cross(n.xyz, t.xyz), b.xyz) < 0.0f ? -1.0f : 1.0f; - - mesh.vertices[i].tangent = new float4(t.x, t.y, t.z, w); - } + MeshBuilder.ComputeTangents(mesh.Vertices, mesh.Indices); } } diff --git a/Ghost.Graphics/Core/RenderingContext.cs b/Ghost.Graphics/Core/RenderingContext.cs index fefd5fd..14b6c9a 100644 --- a/Ghost.Graphics/Core/RenderingContext.cs +++ b/Ghost.Graphics/Core/RenderingContext.cs @@ -4,6 +4,7 @@ using Ghost.Graphics.RHI; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Utilities; +using Misaki.HighPerformance.Mathematics; namespace Ghost.Graphics.Core; @@ -72,6 +73,11 @@ public unsafe readonly ref struct RenderingContext return CreateMesh(vertexList, indexList); } + public MaterialAccessor GetMaterialAccessor(Handle material) + { + return new MaterialAccessor(material, ResourceDatabase); + } + // TODO: Make one memory pool for upload. /// @@ -82,32 +88,32 @@ public unsafe readonly ref struct RenderingContext public void UploadMesh(Handle mesh, bool markMeshStatic) { ref var meshData = ref ResourceDatabase.GetMeshReference(mesh); - var vertexState = ResourceDatabase.GetResourceState(meshData.vertexBuffer.AsResource()); - var indexState = ResourceDatabase.GetResourceState(meshData.indexBuffer.AsResource()); + var vertexState = ResourceDatabase.GetResourceState(meshData.VertexBuffer.AsResource()); + var indexState = ResourceDatabase.GetResourceState(meshData.IndexBuffer.AsResource()); var needVertexTransition = vertexState != ResourceState.CopyDest; var needIndexTransition = indexState != ResourceState.CopyDest; if (needVertexTransition) { - _directCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest); + _directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), vertexState, ResourceState.CopyDest); } if (needIndexTransition) { - _directCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest); + _directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), indexState, ResourceState.CopyDest); } - _directCmd.UploadBuffer(meshData.vertexBuffer, meshData.vertices.AsSpan()); - _directCmd.UploadBuffer(meshData.indexBuffer, meshData.indices.AsSpan()); + _directCmd.UploadBuffer(meshData.VertexBuffer, meshData.Vertices.AsSpan()); + _directCmd.UploadBuffer(meshData.IndexBuffer, meshData.Indices.AsSpan()); if (needVertexTransition) { - _directCmd.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState); + _directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer); } if (needIndexTransition) { - _directCmd.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState); + _directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.IndexBuffer); } if (markMeshStatic) @@ -116,6 +122,34 @@ public unsafe readonly ref struct RenderingContext } } + public void UpdateObjectData(Handle mesh, float4x4 localToWorld) + { + ref var meshData = ref ResourceDatabase.GetMeshReference(mesh); + var data = new PerObjectData + { + localToWorld = localToWorld, + worldBoundsMin = meshData.BoundingBox.Min, + worldBoundsMax = meshData.BoundingBox.Max, + vertexBuffer = (uint)_engine.ResourceDatabase.GetBindlessIndex(meshData.VertexBuffer.AsResource()), + indexBuffer = (uint)_engine.ResourceDatabase.GetBindlessIndex(meshData.IndexBuffer.AsResource()), + }; + + var bufferHandle = meshData.ObjectDataBuffer.AsResource(); + var state = ResourceDatabase.GetResourceState(bufferHandle); + var needTransition = state != ResourceState.CopyDest; + if (needTransition) + { + _directCmd.ResourceBarrier(bufferHandle, state, ResourceState.CopyDest); + } + + _directCmd.UploadBuffer(meshData.ObjectDataBuffer, [data]); + + if (needTransition) + { + _directCmd.ResourceBarrier(bufferHandle, ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer); + } + } + public Handle CreateTexture(ref readonly TextureDesc desc, bool tempResource = false) { return ResourceAllocator.CreateTexture(in desc, tempResource); @@ -126,13 +160,6 @@ public unsafe readonly ref struct RenderingContext var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()); desc.TextureDescription.Format.GetSurfaceInfo((int)desc.TextureDescription.Width, (int)desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _); - var subresourceData = new SubResourceData - { - pData = data.GetUnsafePtr(), - rowPitch = rowPitch, - slicePitch = slicePitch - }; - var sateBefore = ResourceDatabase.GetResourceState(texture.AsResource()); var needTransition = sateBefore != ResourceState.CopyDest; @@ -141,7 +168,17 @@ public unsafe readonly ref struct RenderingContext _directCmd.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest); } - _directCmd.UploadTexture(texture, subresourceData); + fixed (byte* pData = data) + { + var subresourceData = new SubResourceData + { + pData = pData, + rowPitch = rowPitch, + slicePitch = slicePitch + }; + + _directCmd.UploadTexture(texture, subresourceData); + } if (needTransition) { @@ -169,9 +206,14 @@ public unsafe readonly ref struct RenderingContext var pipelineKey = hash.GetKey(); _directCmd.SetPipelineState(pipelineKey); + _directCmd.SetConstantBufferView(RootSignatureLayout.PER_OBJECT_BUFFER_SLOT, meshRef.ObjectDataBuffer); + // NOTE: We use fixed root signature layout for bindless rendering. ref var cache = ref materialRef.GetPassCache(passIndex); - _directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource); + if (cache.IsCreated) + { + _directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource); + } // NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables. // TODO: Maybe handle the traditional bindless model? @@ -180,7 +222,7 @@ public unsafe readonly ref struct RenderingContext _commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle); #endif - var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX; - _directCmd.DispatchMesh(threadGroupCountX, 1, 1); + //var threadGroupCountX = ((uint)meshRef.IndexCount + numThreadsX - 1) / numThreadsX; + _directCmd.DispatchMesh(1, 1, 1); } -} +} \ No newline at end of file diff --git a/Ghost.Graphics/Core/RootSignatureLayout.cs b/Ghost.Graphics/Core/RootSignatureLayout.cs index d6785df..45c76f0 100644 --- a/Ghost.Graphics/Core/RootSignatureLayout.cs +++ b/Ghost.Graphics/Core/RootSignatureLayout.cs @@ -1,3 +1,6 @@ +using Misaki.HighPerformance.Mathematics; +using System.Runtime.InteropServices; + namespace Ghost.Graphics.Core; /// @@ -40,4 +43,14 @@ public static class RootSignatureLayout 4 #endif ; -} \ No newline at end of file +} + +[StructLayout(LayoutKind.Sequential, Pack = 1)] +public struct PerObjectData +{ + public float4x4 localToWorld; + public float3 worldBoundsMin; + public uint vertexBuffer; + public float3 worldBoundsMax; + public uint indexBuffer; +}; \ No newline at end of file diff --git a/Ghost.Graphics/Core/Shader.cs b/Ghost.Graphics/Core/Shader.cs index d5c6665..eb353ad 100644 --- a/Ghost.Graphics/Core/Shader.cs +++ b/Ghost.Graphics/Core/Shader.cs @@ -19,10 +19,11 @@ public class ShaderPass : IResourceReleasable { _cbufferInfo = info; - _propertyLookup = new Dictionary(info.Properties.Count); - for (var i = 0; i < info.Properties.Count; i++) + var capacity = info.Properties?.Count ?? 0; + _propertyLookup = new Dictionary(capacity); + for (var i = 0; i < capacity; i++) { - _propertyLookup[info.Properties[i].Name] = i; + _propertyLookup[info.Properties![i].Name] = i; } } diff --git a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs index dde52cf..6f47fef 100644 --- a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs +++ b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs @@ -8,14 +8,16 @@ using Misaki.HighPerformance.LowLevel.Utilities; using System.Runtime.CompilerServices; using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; + using static TerraFX.Aliases.D3D_Alias; using static TerraFX.Aliases.D3D12_Alias; using static TerraFX.Aliases.DXGI_Alias; namespace Ghost.Graphics.D3D12; -internal unsafe class D3D12CommandBuffer : D3D12Object, ICommandBuffer +internal unsafe class D3D12CommandBuffer : ICommandBuffer { + private UniquePtr _commandList; private UniquePtr _allocator; private readonly D3D12PipelineLibrary _pipelineLibrary; @@ -26,12 +28,28 @@ internal unsafe class D3D12CommandBuffer : D3D12Object nativeObject.Get(); + public SharedPtr NativeCommandList => _commandList.Get(); public CommandBufferType Type => _type; public bool IsEmpty => _commandCount == 0; + public string Name + { + get => field; + set + { + if (field == value) + { + return; + } + + field = value; + _commandList.Get()->SetName(value); + } + } = string.Empty; + public D3D12CommandBuffer( D3D12RenderDevice device, D3D12PipelineLibrary stateController, @@ -46,11 +64,11 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectCreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator); - device.NativeDevice->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList); + device.NativeDevice.Get()->CreateCommandAllocator(commandListType, __uuidof(pAllocator), (void**)&pAllocator); + device.NativeDevice.Get()->CreateCommandList1(0u, commandListType, D3D12_COMMAND_LIST_FLAG_NONE, __uuidof(pCommandList), (void**)&pCommandList); _allocator.Attach(pAllocator); - nativeObject.Attach(pCommandList); + _commandList.Attach(pCommandList); _pipelineLibrary = stateController; _resourceDatabase = resourceDatabase; @@ -60,6 +78,11 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectReset()); - ThrowIfFailed(nativeObject.Get()->Reset(_allocator.Get(), null)); + ThrowIfFailed(_commandList.Get()->Reset(_allocator.Get(), null)); } void SetBindlessHeap() @@ -108,14 +137,18 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectSetDescriptorHeaps(2, heaps); + _commandList.Get()->SetDescriptorHeaps(2, heaps); } ThrowIfDisposed(); ThrowIfRecording(); ResetCommandList(); - SetBindlessHeap(); + + if (Type == CommandBufferType.Graphics || Type == CommandBufferType.Compute) + { + SetBindlessHeap(); + } _commandCount = 0; _isRecording = true; @@ -126,7 +159,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectClose(); + _commandList.Get()->Close(); _isRecording = false; } @@ -137,7 +170,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectRSSetScissorRects(1, &d3d12Rect); + _commandList.Get()->RSSetScissorRects(1, &d3d12Rect); } public void ResourceBarrier(Handle resource, ResourceState before, ResourceState after) @@ -150,7 +183,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectResourceBarrier(1, &barrier); + _commandList.Get()->ResourceBarrier(1, &barrier); } public void SetRenderTargets(ReadOnlySpan> renderTargets, Handle depthTarget) @@ -168,17 +201,17 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectOMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle); + _commandList.Get()->OMSetRenderTargets((uint)renderTargets.Length, pRtvHandles, FALSE, pDsvHandle); } public void BeginRenderPass(ReadOnlySpan rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false) @@ -196,7 +229,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectBeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc, + _commandList.Get()->BeginRenderPass((uint)rtDescs.Length, pRtvDescs, pDsvDesc, allowUAVWrites ? D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES : D3D12_RENDER_PASS_FLAG_NONE); } @@ -263,7 +300,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectEndRenderPass(); + _commandList.Get()->EndRenderPass(); } public void SetViewport(ViewportDesc viewport) @@ -272,8 +309,8 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectRSSetViewports(1, &d3d12Viewport); + var d3d12Viewport = new D3D12_VIEWPORT(viewport.X, viewport.Y, viewport.Width, viewport.Height, viewport.MinDepth, viewport.MaxDepth); + _commandList.Get()->RSSetViewports(1, &d3d12Viewport); } public void SetPipelineState(GraphicsPipelineKey pipelineKey) @@ -288,9 +325,11 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectSetPipelineState(psor.Value); + + _commandList.Get()->SetGraphicsRootSignature(_pipelineLibrary.DefaultRootSignature); + _commandList.Get()->SetPipelineState(psor.Value); } public void SetConstantBufferView(uint slot, Handle buffer) @@ -300,7 +339,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectSetGraphicsRootConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, resource->GetGPUVirtualAddress()); + _commandList.Get()->SetGraphicsRootConstantBufferView(slot, resource.Get()->GetGPUVirtualAddress()); } public void SetVertexBuffer(uint slot, Handle buffer, ulong offset = 0) @@ -309,15 +348,15 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectGetGPUVirtualAddress() + offset, - SizeInBytes = (uint)(pResource->GetDesc().Width - offset), + BufferLocation = resource.Get()->GetGPUVirtualAddress() + offset, + SizeInBytes = (uint)(resource.Get()->GetDesc().Width - offset), StrideInBytes = _resourceDatabase.GetResourceDescription(buffer.AsResource()).BufferDescription.Stride }; - nativeObject.Get()->IASetVertexBuffers(slot, 1, &vbView); + _commandList.Get()->IASetVertexBuffers(slot, 1, &vbView); } public void SetIndexBuffer(Handle buffer, IndexType type, ulong offset = 0) @@ -326,15 +365,15 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectGetGPUVirtualAddress() + offset, - SizeInBytes = (uint)(pResource->GetDesc().Width - offset), + BufferLocation = resource.Get()->GetGPUVirtualAddress() + offset, + SizeInBytes = (uint)(resource.Get()->GetDesc().Width - offset), Format = type == IndexType.UInt16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT }; - nativeObject.Get()->IASetIndexBuffer(&ibView); + _commandList.Get()->IASetIndexBuffer(&ibView); } public void SetPrimitiveTopology(PrimitiveTopology topology) @@ -351,7 +390,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST }; - nativeObject.Get()->IASetPrimitiveTopology(d3d12Topology); + _commandList.Get()->IASetPrimitiveTopology(d3d12Topology); } public void Draw(uint vertexCount, uint instanceCount = 1, uint startVertex = 0, uint startInstance = 0) @@ -360,7 +399,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectDrawInstanced(vertexCount, instanceCount, startVertex, startInstance); + _commandList.Get()->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance); } public void DrawIndexed(uint indexCount, uint instanceCount = 1, uint startIndex = 0, int baseVertex = 0, uint startInstance = 0) @@ -369,7 +408,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectDrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance); + _commandList.Get()->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, startInstance); } public void DispatchCompute(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ) @@ -378,7 +417,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectDispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ); + _commandList.Get()->Dispatch(threadGroupCountX, threadGroupCountY, threadGroupCountZ); } public void DispatchMesh(uint threadGroupCountX, uint threadGroupCountY, uint threadGroupCountZ) @@ -387,7 +426,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectDispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ); + _commandList.Get()->DispatchMesh(threadGroupCountX, threadGroupCountY, threadGroupCountZ); } public void DispatchRay() @@ -398,7 +437,7 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectDispatchRays(); + // _device.Get()->DispatchRays(); } public void UploadBuffer(Handle buffer, ReadOnlySpan data) @@ -411,19 +450,19 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectMap(0, null, &pMappedData); + uploadResource.Get()->Map(0, null, &pMappedData); fixed (T* pData = data) { - MemoryUtility.MemCpy(pMappedData, pData, sizeInBytes); + MemoryUtility.MemCpy(pData, pMappedData, sizeInBytes); } - pUploadResource->Unmap(0, null); + uploadResource.Get()->Unmap(0, null); var pResource = _resourceDatabase.GetResource(buffer.AsResource()); - nativeObject.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes); + _commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes); } public void UploadTexture(Handle texture, params ReadOnlySpan subresources) @@ -432,10 +471,10 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectGetDesc(); - var requiredSize = GetRequiredIntermediateSize(pResource, 0, (uint)subresources.Length); + var resourceDesc = resource.Get()->GetDesc(); + var requiredSize = GetRequiredIntermediateSize(resource, 0, (uint)subresources.Length); var uploadHandle = _resourceAllocator.CreateUploadBuffer(requiredSize); var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource()); @@ -452,8 +491,8 @@ internal unsafe class D3D12CommandBuffer : D3D12ObjectCopyResource(pDestResource, pSrcResource); + _commandList.Get()->CopyResource(pDestResource, pSrcResource); } else { - nativeObject.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes); + _commandList.Get()->CopyBufferRegion(pDestResource, destOffset, pSrcResource, srcOffset, numBytes); } } - protected override void Dispose(bool disposing) + public void Dispose() { - if (Disposed) + if (_disposed) { return; } @@ -496,9 +535,11 @@ internal unsafe class D3D12CommandBuffer : D3D12Object /// D3D12 implementation of command queue interface /// -internal unsafe class D3D12CommandQueue : D3D12Object, ICommandQueue +internal unsafe class D3D12CommandQueue : ICommandQueue { + private UniquePtr _commandQueue; private UniquePtr _fence; + private readonly AutoResetEvent _fenceEvent; private ulong _fenceValue; + private bool _disposed; public CommandQueueType Type { get; } - public ID3D12CommandQueue* NativeQueue => nativeObject.Get(); + public SharedPtr NativeQueue => _commandQueue.Get(); public D3D12CommandQueue(ID3D12Device14* pDevice, CommandQueueType type) { @@ -41,10 +43,15 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm ThrowIfFailed(pDevice->CreateCommandQueue(&queueDesc, __uuidof(pQueue), (void**)&pQueue)); ThrowIfFailed(pDevice->CreateFence(0, D3D12_FENCE_FLAGS.D3D12_FENCE_FLAG_NONE, __uuidof(pFence), (void**)&pFence)); - nativeObject.Attach(pQueue); + _commandQueue.Attach(pQueue); _fence.Attach(pFence); } + ~D3D12CommandQueue() + { + Dispose(); + } + private static D3D12_COMMAND_LIST_TYPE ConvertCommandQueueType(CommandQueueType type) { return type switch @@ -58,7 +65,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm public void Submit(ICommandBuffer commandBuffer) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); if (commandBuffer.IsEmpty) { @@ -68,8 +75,8 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm if (commandBuffer is D3D12CommandBuffer d3d12CommandBuffer) { var commandList = d3d12CommandBuffer.NativeCommandList; - var commandListPtr = (ID3D12CommandList*)commandList; - nativeObject.Get()->ExecuteCommandLists(1, &commandListPtr); + var commandListPtr = (ID3D12CommandList*)commandList.Get(); + _commandQueue.Get()->ExecuteCommandLists(1, &commandListPtr); } else { @@ -79,7 +86,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm public void Submit(params ReadOnlySpan commandBuffers) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); Span executableIndices = stackalloc int[commandBuffers.Length]; executableIndices.Fill(-1); @@ -107,7 +114,7 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm if (commandBuffers[cmdIndex] is D3D12CommandBuffer d3d12CommandBuffer) { - ppCommandLists[currentIndex] = (ID3D12CommandList*)d3d12CommandBuffer.NativeCommandList; + ppCommandLists[currentIndex] = (ID3D12CommandList*)d3d12CommandBuffer.NativeCommandList.Get(); } else { @@ -117,21 +124,21 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm currentIndex++; } - nativeObject.Get()->ExecuteCommandLists((uint)currentIndex, ppCommandLists); + _commandQueue.Get()->ExecuteCommandLists((uint)currentIndex, ppCommandLists); } public ulong Signal(ulong value) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); _fenceValue = value; - nativeObject.Get()->Signal((ID3D12Fence*)_fence.Get(), _fenceValue); + _commandQueue.Get()->Signal((ID3D12Fence*)_fence.Get(), _fenceValue); return _fenceValue; } public void WaitForValue(ulong value) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); if (_fence.Get()->GetCompletedValue() < value) { @@ -145,28 +152,30 @@ internal unsafe class D3D12CommandQueue : D3D12Object, IComm public ulong GetCompletedValue() { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); return _fence.Get()->GetCompletedValue(); } public void WaitIdle() { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var fenceValue = Signal(Interlocked.Increment(ref _fenceValue)); WaitForValue(fenceValue); } - protected override void Dispose(bool disposing) + public void Dispose() { - if (Disposed) + if (_disposed) { return; } - _fenceEvent?.Dispose(); + _commandQueue.Dispose(); _fence.Dispose(); + _fenceEvent?.Dispose(); - base.Dispose(disposing); + _disposed = true; + GC.SuppressFinalize(this); } } diff --git a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs index 1eadabb..4fecc9c 100644 --- a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs +++ b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs @@ -105,7 +105,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine public ISwapChain CreateSwapChain(SwapChainDesc desc) { ThrowIfDisposed(); - return new D3D12SwapChain(_resourceDatabase, _device.DXGIFactory, ((D3D12CommandQueue)_device.GraphicsQueue).NativeQueue, desc); + return new D3D12SwapChain(_resourceDatabase, _descriptorAllocator, _device, desc); } public void BeginFrame() @@ -152,6 +152,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine _resourceDatabase.Dispose(); _descriptorAllocator.Dispose(); + _shaderCompiler.Dispose(); _device.Dispose(); #if DEBUG _debugLayer.Dispose(); diff --git a/Ghost.Graphics/D3D12/D3D12Object.cs b/Ghost.Graphics/D3D12/D3D12Object.cs deleted file mode 100644 index 91681ce..0000000 --- a/Ghost.Graphics/D3D12/D3D12Object.cs +++ /dev/null @@ -1,132 +0,0 @@ -using Ghost.Core.Utilities; -using Ghost.Graphics.D3D12.Utilities; -using Ghost.Graphics.RHI; -using Misaki.HighPerformance.LowLevel; -using System.Runtime.CompilerServices; -using TerraFX.Interop.DirectX; -using TerraFX.Interop.Windows; - -namespace Ghost.Graphics.D3D12; - -internal abstract class D3D12RHIObject : IRHIObject -{ - public string Name - { - get; set; - } = string.Empty; -} - -internal abstract unsafe class D3D12Object : IRHIObject, IDisposable - where T : unmanaged, ID3D12Object.Interface -{ - private bool _disposed; - private string _name = string.Empty; - - protected UniquePtr nativeObject; - - protected bool Disposed => _disposed; - - public string Name - { - get => _name; - set - { - if (_name == value) - { - return; - } - - _name = value; - if (nativeObject.Get() != null) - { - nativeObject.Get()->SetName(value); - } - } - } - - ~D3D12Object() - { - Dispose(false); - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ThrowIfDisposed() - { - ObjectDisposedException.ThrowIf(_disposed, this); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - nativeObject.Dispose(); - - _disposed = true; - } -} - - -internal abstract class IUnknownObject : IRHIObject, IDisposable - where T : unmanaged, IUnknown.Interface -{ - private bool _disposed; - private string _name = string.Empty; - - protected UniquePtr nativeObject; - - protected bool Disposed => _disposed; - - public string Name - { - get => _name; - set - { - if (_name == value) - { - return; - } - - _name = value; - } - } - - ~IUnknownObject() - { - Dispose(false); - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ThrowIfDisposed() - { - ObjectDisposedException.ThrowIf(_disposed, this); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed) - { - return; - } - - nativeObject.Dispose(); - - _disposed = true; - } -} \ No newline at end of file diff --git a/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs b/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs index 8b981dc..3116caa 100644 --- a/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs +++ b/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs @@ -31,7 +31,7 @@ internal struct D3D12PipelineState : IDisposable } } -internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable +internal unsafe class D3D12PipelineLibrary : IPipelineLibrary { private readonly D3D12RenderDevice _device; private readonly D3D12ResourceDatabase _resourceDatabase; @@ -153,7 +153,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable } ID3D12RootSignature* pRootSignature = default; - ThrowIfFailed(_device.NativeDevice->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(), + ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(), __uuidof(pRootSignature), (void**)&pRootSignature)); _defaultRootSignature.Attach(pRootSignature); @@ -183,12 +183,12 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable var fileBytes = File.ReadAllBytes(filePath!); fixed (byte* pFileBytes = fileBytes) { - ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary)); + ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineLibrary(pFileBytes, (nuint)fileBytes.Length, __uuidof(pLibrary), (void**)&pLibrary)); } } else { - ThrowIfFailed(_device.NativeDevice->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary)); + ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineLibrary(null, 0, __uuidof(pLibrary), (void**)&pLibrary)); } _library.Attach(pLibrary); @@ -213,18 +213,26 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable private static Result ValidateReflectionData(ShaderReflectionData reflectionData) { - CBufferInfo cbufferInfo; + var cbufferInfo = default(CBufferInfo); foreach (var info in reflectionData.ResourcesBindings) { - if (info.BindPoint > 3) + if (info.BindPoint >= RootSignatureLayout.ROOT_PARAMETER_COUNT) { return Result.Failure($"Resource binding point {info.BindPoint} is out of range. Only binding points 0-3 are supported in the current root signature."); } if (info.Type != ShaderInputType.ConstantBuffer) { - return Result.Failure($"Resource binding type {info.Type} is not supported. Only constant buffers are supported in the current root signature."); + return Result.Failure($"Resource binding type {info.Type} is not supported. Please consider using bindless resources for buffers, textures and samplers."); + } + + if (info.BindPoint == RootSignatureLayout.PER_OBJECT_BUFFER_SLOT) + { + if (info.Size != sizeof(PerObjectData)) + { + return Result.Failure($"Per-object constant buffer size mismatch. Expected size: {sizeof(PerObjectData)}, Actual size: {info.Size}"); + } } if (info.BindPoint == RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT) @@ -237,19 +245,15 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable SizeInBytes = info.Size, Properties = info.Properties ?? Array.Empty(), }; - - return Result.Success(cbufferInfo); } } - return Result.Failure("Per-material constant buffer not found in shader reflection data."); - - // TODO: Validate Cbuffer sizes and bindings. + return Result.Success(cbufferInfo); } private static D3D12_COMPARISON_FUNC ToD3DCompare(ZTestOptions z) => z switch { - ZTestOptions.Disabled => D3D12_COMPARISON_FUNC_ALWAYS, + ZTestOptions.Disabled => D3D12_COMPARISON_FUNC_NEVER, ZTestOptions.Less => D3D12_COMPARISON_FUNC_LESS, ZTestOptions.LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL, ZTestOptions.Equal => D3D12_COMPARISON_FUNC_EQUAL, @@ -284,7 +288,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable return Result.Failure("Validation of pixel shader reflection data failed: " + psr.Message); } - if (msr.Value != psr.Value) + if (msr.Value.Properties != null + && msr.Value.SizeInBytes != psr.Value.SizeInBytes) { return Result.Failure("Mesh shader and pixel shader constant buffer layouts do not match."); } @@ -297,12 +302,14 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable return Result.Failure("Validation of task shader reflection data failed: " + tsr.Message); } - if (tsr.Value != msr.Value) + if (tsr.Value.Properties != null + && tsr.Value.SizeInBytes != psr.Value.SizeInBytes) { - return Result.Failure("Task shader and mesh shader constant buffer layouts do not match."); + return Result.Failure("Task shader and pixel shader constant buffer layouts do not match."); } } + // ts and ms may not use per material cbuffer at all, so we return the psr value. return psr.Value; } @@ -396,7 +403,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary, IDisposable if (hr == E.E_INVALIDARG) { // Pipeline not found in the library, create a new one. - ThrowIfFailed(_device.NativeDevice->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState)); + ThrowIfFailed(_device.NativeDevice.Get()->CreatePipelineState(&streamDesc, __uuidof(pPipelineState), (void**)&pPipelineState)); ThrowIfFailed(_library.Get()->StorePipeline(pKeyStr, pPipelineState)); } else diff --git a/Ghost.Graphics/D3D12/D3D12RenderDevice.cs b/Ghost.Graphics/D3D12/D3D12RenderDevice.cs index 68873ea..7c5cdf2 100644 --- a/Ghost.Graphics/D3D12/D3D12RenderDevice.cs +++ b/Ghost.Graphics/D3D12/D3D12RenderDevice.cs @@ -12,8 +12,9 @@ namespace Ghost.Graphics.D3D12; /// /// D3D12 implementation of the render device interface /// -internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDevice +internal unsafe class D3D12RenderDevice : IRenderDevice { + private UniquePtr _device; private UniquePtr _dxgiFactory; private UniquePtr _adapter; @@ -21,21 +22,35 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe private readonly D3D12CommandQueue _computeQueue; private readonly D3D12CommandQueue _copyQueue; + private bool _disposed; + public ICommandQueue GraphicsQueue => _graphicsQueue; public ICommandQueue ComputeQueue => _computeQueue; public ICommandQueue CopyQueue => _copyQueue; - public IDXGIFactory7* DXGIFactory => _dxgiFactory.Get(); - public ID3D12Device14* NativeDevice => nativeObject.Get(); - public IDXGIAdapter1* Adapter => _adapter.Get(); + public SharedPtr DXGIFactory => _dxgiFactory.Get(); + public SharedPtr NativeDevice => _device.Get(); + public SharedPtr Adapter => _adapter.Get(); + public SharedPtr NativeGraphicsQueue => _graphicsQueue.NativeQueue; + public SharedPtr NativeComputeQueue => _computeQueue.NativeQueue; + public SharedPtr NativeCopyQueue => _copyQueue.NativeQueue; public D3D12RenderDevice() { + IDXGIFactory7* pFactory = default; +#if DEBUG + ThrowIfFailed(CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory)); +#else + ThrowIfFailed(CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory)); +#endif + + _dxgiFactory.Attach(pFactory); + InitializeDevice(); - _graphicsQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Graphics); - _computeQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Compute); - _copyQueue = new D3D12CommandQueue(nativeObject.Get(), CommandQueueType.Copy); + _graphicsQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Graphics); + _computeQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Compute); + _copyQueue = new D3D12CommandQueue(_device.Get(), CommandQueueType.Copy); } ~D3D12RenderDevice() @@ -45,15 +60,6 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe private void InitializeDevice() { - IDXGIFactory7* pFactory = default; -#if DEBUG - CreateDXGIFactory2(TRUE, __uuidof(pFactory), (void**)&pFactory); -#else - CreateDXGIFactory2(FALSE, __uuidof(pFactory), (void**)&pFactory); -#endif - - _dxgiFactory.Attach(pFactory); - ID3D12Device14* pDevice = default; IDXGIAdapter1* pAdapter = default; @@ -86,17 +92,17 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe throw new PlatformNotSupportedException("Cannot create ID3D12Device with feature level 12.0"); } - nativeObject.Attach(pDevice); + _device.Attach(pDevice); } public FeatureSupport GetFeatureSupport() { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); FeatureSupport support = FeatureSupport.None; D3D12_FEATURE_DATA_D3D12_OPTIONS options = default; - if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED) + if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)).SUCCEEDED) { if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3) { @@ -105,7 +111,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe } D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = default; - if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED) + if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS5)).SUCCEEDED) { if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { @@ -114,7 +120,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe } D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = default; - if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED) + if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS6)).SUCCEEDED) { if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED) { @@ -123,7 +129,7 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe } D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = default; - if (nativeObject.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED) + if (_device.Get()->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, (uint)sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS7)).SUCCEEDED) { if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) { @@ -139,9 +145,9 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe return support; } - protected override void Dispose(bool disposing) + public void Dispose() { - if (Disposed) + if (_disposed) { return; } @@ -150,9 +156,11 @@ internal unsafe class D3D12RenderDevice : D3D12Object, IRenderDe _computeQueue.Dispose(); _copyQueue.Dispose(); + _device.Dispose(); _dxgiFactory.Dispose(); _adapter.Dispose(); - base.Dispose(disposing); + _disposed = true; + GC.SuppressFinalize(this); } } diff --git a/Ghost.Graphics/D3D12/D3D12Renderer.cs b/Ghost.Graphics/D3D12/D3D12Renderer.cs index 851f46e..14784df 100644 --- a/Ghost.Graphics/D3D12/D3D12Renderer.cs +++ b/Ghost.Graphics/D3D12/D3D12Renderer.cs @@ -10,16 +10,17 @@ namespace Ghost.Graphics.D3D12; /// /// D3D12 implementation of the renderer interface using RHI abstractions /// -internal unsafe class D3D12Renderer : IRenderer +internal class D3D12Renderer : IRenderer { private struct FrameResource : IDisposable { public ICommandBuffer commandBuffer; public ulong fenceValue; - public FrameResource(D3D12GraphicsEngine graphicsEngine) + public FrameResource(D3D12GraphicsEngine graphicsEngine, int index) { commandBuffer = graphicsEngine.CreateCommandBuffer(); + commandBuffer.Name = $"Frame Command Buffer {index}"; fenceValue = 0; } @@ -67,7 +68,7 @@ internal unsafe class D3D12Renderer : IRenderer _frameResources = new FrameResource[D3D12PipelineResource.BACK_BUFFER_COUNT]; for (var i = 0; i < _frameResources.Length; i++) { - _frameResources[i] = new FrameResource(graphicsEngine); + _frameResources[i] = new FrameResource(graphicsEngine, i); } _renderTarget = Handle.Invalid; @@ -108,6 +109,12 @@ internal unsafe class D3D12Renderer : IRenderer CreateOffScreenRenderTarget(swapChain.Width, swapChain.Height); } + var newSize = swapChain != null ? new uint2(swapChain.Width, swapChain.Height) : _currentSize; + if (!math.all(newSize == _currentSize)) + { + RequestResize(newSize); + } + _swapChain = swapChain; } @@ -171,9 +178,22 @@ internal unsafe class D3D12Renderer : IRenderer frame.commandBuffer.Begin(); // NOTE: Temperary solution: render directly to the swap chain back buffer if available. + // HACK: This is hard coded for testing purposes only. + var rt = _swapChain?.GetCurrentBackBuffer() ?? _renderTarget; + + if(_swapChain != null) + { + frame.commandBuffer.ResourceBarrier(rt.AsResource(), ResourceState.Present, ResourceState.RenderTarget); + } + RenderScene(rt, frame.commandBuffer); + if (_swapChain != null) + { + frame.commandBuffer.ResourceBarrier(rt.AsResource(), ResourceState.RenderTarget, ResourceState.Present); + } + // if (_swapChain != null) // { // var backBufferRT = _swapChain.GetCurrentBackBuffer(); @@ -196,12 +216,14 @@ internal unsafe class D3D12Renderer : IRenderer { var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f }; - Span rtDesc = stackalloc PassRenderTargetDesc[1]; - rtDesc[0] = new PassRenderTargetDesc - { - Texture = target, - ClearColor = clearColor, - }; + Span rtDesc = + [ + new PassRenderTargetDesc + { + Texture = target, + ClearColor = clearColor, + }, + ]; var depthDesc = new PassDepthStencilDesc { @@ -217,11 +239,10 @@ internal unsafe class D3D12Renderer : IRenderer _pass.Initialize(ref ctx); } - cmd.BeginRenderPass(rtDesc, depthDesc, false); - var viewport = new ViewportDesc { Width = _currentSize.x, Height = _currentSize.y, MinDepth = 0, MaxDepth = 1 }; var scissor = new RectDesc { Right = _currentSize.x, Bottom = _currentSize.y }; + cmd.BeginRenderPass(rtDesc, depthDesc, false); cmd.SetViewport(viewport); cmd.SetScissorRect(scissor); diff --git a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs index a148c38..fc33db4 100644 --- a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs +++ b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs @@ -3,6 +3,7 @@ using Ghost.Core.Graphics; using Ghost.Core.Utilities; using Ghost.Graphics.Core; using Ghost.Graphics.RHI; +using Misaki.HighPerformance.LowLevel; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.Mathematics; using System.Runtime.CompilerServices; @@ -132,13 +133,13 @@ internal sealed unsafe partial class D3D12ResourceAllocator var resourceDesc = pResource->GetDesc(); var srvDesc = new D3D12_SHADER_RESOURCE_VIEW_DESC { - Format = resourceDesc.Format, ViewDimension = D3D12_SRV_DIMENSION_BUFFER, Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING }; if (isRaw) { + srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u); srvDesc.Buffer.StructureByteStride = 0; @@ -146,6 +147,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator } else // Assumes Structured { + srvDesc.Format = resourceDesc.Format; srvDesc.Buffer.FirstElement = 0; srvDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride); srvDesc.Buffer.StructureByteStride = stride; @@ -406,12 +408,12 @@ internal sealed unsafe partial class D3D12ResourceAllocator var resourceDesc = pResource->GetDesc(); var uavDesc = new D3D12_UNORDERED_ACCESS_VIEW_DESC { - Format = resourceDesc.Format, ViewDimension = D3D12_UAV_DIMENSION_BUFFER, }; if (isRaw) { + uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / 4u); uavDesc.Buffer.StructureByteStride = 0; @@ -419,6 +421,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator } else // Assumes Structured { + uavDesc.Format = resourceDesc.Format; uavDesc.Buffer.FirstElement = 0; uavDesc.Buffer.NumElements = (uint)(resourceDesc.Width / stride); uavDesc.Buffer.StructureByteStride = stride; @@ -521,6 +524,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator // Default to Common, but check for specific roles var state = D3D12_RESOURCE_STATE_COMMON; + return state; if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant)) { @@ -591,8 +595,10 @@ internal sealed unsafe partial class D3D12ResourceAllocator // TODO: Thread safety for resource allocator // A common solution is to use ticket. Each pAllocation request create a ticket and put it into a thread-safe queue. A dedicated thread process the queue and fulfill the requests. -internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject, IResourceAllocator +internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator { + private UniquePtr _d3d12MA; + private readonly IFenceSynchronizer _fenceSynchronizer; private readonly D3D12RenderDevice _device; private readonly D3D12DescriptorAllocator _descriptorAllocator; @@ -601,6 +607,8 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject> _temResources; + private bool _disposed; + public D3D12ResourceAllocator( IFenceSynchronizer fenceSynchronizer, D3D12RenderDevice device, @@ -610,14 +618,14 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject CreateTexture(ref readonly TextureDesc desc, bool isTemp = false) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); CheckTexture2DSize(desc.Width, desc.Height); @@ -706,7 +714,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectCreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null)); + ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null)); var resourceDescriptor = ResourceViewGroup.Invalid; if (desc.Usage.HasFlag(TextureUsage.ShaderResource)) @@ -717,7 +725,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectGetResource(), mipLevels, desc.Slice, isCubeMap); - _device.NativeDevice->CreateShaderResourceView(pAllocation->GetResource(), &srvDesc, cpuHandle); + _device.NativeDevice.Get()->CreateShaderResourceView(pAllocation->GetResource(), &srvDesc, cpuHandle); } if (desc.Usage.HasFlag(TextureUsage.RenderTarget)) @@ -726,7 +734,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectGetResource()); - _device.NativeDevice->CreateRenderTargetView(pAllocation->GetResource(), &rtvDesc, cpuHandle); + _device.NativeDevice.Get()->CreateRenderTargetView(pAllocation->GetResource(), &rtvDesc, cpuHandle); } if (desc.Usage.HasFlag(TextureUsage.DepthStencil)) @@ -735,7 +743,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectGetResource()); - _device.NativeDevice->CreateDepthStencilView(pAllocation->GetResource(), &dsvDesc, cpuHandle); + _device.NativeDevice.Get()->CreateDepthStencilView(pAllocation->GetResource(), &dsvDesc, cpuHandle); } if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess)) @@ -744,7 +752,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectGetResource()); - _device.NativeDevice->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle); + _device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle); } var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp); @@ -754,24 +762,27 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject CreateRenderTarget(ref readonly RenderTargetDesc desc, bool isTemp = false) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var textureDesc = desc.ToTextureDescripton(); - return CreateTexture(ref textureDesc, isTemp); + return CreateTexture(in textureDesc, isTemp); } public Handle CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); CheckBufferSize(desc.Size); - var resourceDescription = D3D12_RESOURCE_DESC.Buffer(desc.Size, ConvertBufferUsage(desc.Usage)); - var isRaw = desc.Usage.HasFlag(BufferUsage.Raw); - if (isRaw) + var alignedSize = desc.Size; + if (desc.Usage.HasFlag(BufferUsage.Constant)) { - resourceDescription.Format = DXGI_FORMAT_R32_TYPELESS; + // D3D12 CBV size must be 256-byte aligned + alignedSize = (uint)(desc.Size + 255) & ~255u; } + var resourceDescription = D3D12_RESOURCE_DESC.Buffer(alignedSize, ConvertBufferUsage(desc.Usage)); + var isRaw = desc.Usage.HasFlag(BufferUsage.Raw); + var allocationDesc = new D3D12MA_ALLOCATION_DESC { HeapType = ConvertMemoryType(desc.MemoryType), @@ -781,42 +792,41 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectCreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, Win32Utility.IID_NULL, null)); + var iid = IID.IID_NULL; + ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, &iid, null)); var resourceDescriptor = ResourceViewGroup.Invalid; var pResource = pAllocation->GetResource(); if (desc.Usage.HasFlag(BufferUsage.Constant)) { - // D3D12 CBV size must be 256-byte aligned - var alignedSize = (uint)(desc.Size + 255) & ~255u; - resourceDescriptor.cbv = _descriptorAllocator.AllocateCbvSrvUav(isTemp); + var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.cbv); var cbvDesc = new D3D12_CONSTANT_BUFFER_VIEW_DESC { BufferLocation = pResource->GetGPUVirtualAddress(), - SizeInBytes = alignedSize + SizeInBytes = (uint)alignedSize }; - _device.NativeDevice->CreateConstantBufferView(&cbvDesc, _descriptorAllocator.GetCpuHandle(resourceDescriptor.cbv)); + _device.NativeDevice.Get()->CreateConstantBufferView(&cbvDesc, cpuHandle); } if (desc.Usage.HasFlag(BufferUsage.ShaderResource)) { resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp); - var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv); + var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.srv); var srvDesc = CreateBufferSrvDesc(pAllocation->GetResource(), desc.Stride, isRaw); - _device.NativeDevice->CreateShaderResourceView(pResource, &srvDesc, cpuHandle); + _device.NativeDevice.Get()->CreateShaderResourceView(pResource, &srvDesc, cpuHandle); } if (desc.Usage.HasFlag(BufferUsage.UnorderedAccess)) { resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp); - var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav); + var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.uav); var uavDesc = CreateBufferUavDesc(pAllocation->GetResource(), desc.Stride, isRaw); - _device.NativeDevice->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle); + _device.NativeDevice.Get()->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle); } var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp); @@ -825,7 +835,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject CreateUploadBuffer(ulong size, bool isTemp = true) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var desc = new BufferDesc { @@ -834,18 +844,18 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject CreateMesh(UnsafeList vertices, UnsafeList indices) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var vertexBufferDesc = new BufferDesc { - Size = (uint)(vertices.Count * Unsafe.SizeOf()), - Stride = (uint)Unsafe.SizeOf(), - Usage = BufferUsage.Vertex | BufferUsage.ShaderResource, + Size = (uint)(vertices.Count * sizeof(Vertex)), + Stride = (uint)sizeof(Vertex), + Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw, MemoryType = ResourceMemoryType.Default, }; @@ -853,37 +863,47 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject CreateMaterial(Identifier shader) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var material = new Material(); material.SetShader(shader, this, _resourceDatabase); - return _resourceDatabase.AddMaterial(ref material); + return _resourceDatabase.AddMaterial(in material); } public Identifier CreateGraphicsShader(ShaderDescriptor descriptor) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var shader = new Shader(descriptor); foreach (var pass in descriptor.passes) @@ -893,6 +913,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObject 0) { @@ -933,9 +954,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IUnknownObjectGetDesc()); @@ -80,13 +79,13 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable { refCount = resourceUnion.allocation.Get()->Release(); } - - resourceUnion = default; - viewGroup = default; } descriptorAllocator.Release(viewGroup); + resourceUnion = default; + viewGroup = default; + return refCount; } } @@ -107,15 +106,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator) { - _resources = new(64, Allocator.Persistent, AllocationOption.Clear); + _resources = new UnsafeSlotMap(64, Allocator.Persistent, AllocationOption.Clear); #if DEBUG || GHOST_EDITOR - _resourceName = new(64); + _resourceName = new Dictionary, string>(64); #endif - _meshes = new(64, Allocator.Persistent, AllocationOption.Clear); - _materials = new(16, Allocator.Persistent, AllocationOption.Clear); - _shaders = new(16); - _shaderPasses = new(16); + _meshes = new UnsafeSlotMap(64, Allocator.Persistent, AllocationOption.Clear); + _materials = new UnsafeSlotMap(16, Allocator.Persistent, AllocationOption.Clear); + _shaders = new DynamicArray(16); + _shaderPasses = new Dictionary(16); _descriptorAllocator = descriptorAllocator; } @@ -132,11 +131,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable resource = default!; } - public unsafe Handle ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, string? name = null) + public unsafe Handle ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string? name = null) { ObjectDisposedException.ThrowIf(_disposed, this); - var id = _resources.Add(new ResourceRecord(pResource, initialState), out var generation); + var id = _resources.Add(new ResourceRecord(pResource, initialState, viewGroup), out var generation); var handle = new Handle(id, generation); #if DEBUG || GHOST_EDITOR @@ -172,7 +171,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable return _resources.Contains(handle.id, handle.generation); } - public ref ResourceRecord GetResourceInfo(Handle handle) + public ref ResourceRecord GetResourceRecord(Handle handle) { ObjectDisposedException.ThrowIf(_disposed, this); @@ -191,11 +190,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist); } - public unsafe ID3D12Resource* GetResource(Handle handle) + public unsafe SharedPtr GetResource(Handle handle) { ObjectDisposedException.ThrowIf(_disposed, this); - ref var info = ref GetResourceInfo(handle); + ref var info = ref GetResourceRecord(handle); if (!info.Allocated) { return null; @@ -207,7 +206,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable public ResourceState GetResourceState(Handle handle) { ObjectDisposedException.ThrowIf(_disposed, this); - return GetResourceInfo(handle).state; + return GetResourceRecord(handle).state; } public void SetResourceState(Handle handle, ResourceState state) @@ -226,7 +225,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable public ResourceDesc GetResourceDescription(Handle handle) { ObjectDisposedException.ThrowIf(_disposed, this); - return GetResourceInfo(handle).desc; + return GetResourceRecord(handle).desc; } public int GetBindlessIndex(Handle handle) @@ -273,10 +272,11 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable var refCount = info.Release(_descriptorAllocator); #if DEBUG || GHOST_EDITOR _resourceName.Remove(handle, out var name); - if (refCount > 0) - { - throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource"); - } + //if (refCount > 0) + //{ + // throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource"); + //} + //Debug.Assert(refCount == 0, "Resource released with non-zero reference count."); #endif _resources.Remove(handle.id, handle.generation); @@ -435,10 +435,9 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable public void Dispose() { - [Conditional("DEBUG"), Conditional("GHOST_EDITOR")] static void ThrowMemoryLeakException(string resourceType, int count) { - throw new InvalidOperationException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing."); + throw new MemoryLeakException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing."); } if (_disposed) diff --git a/Ghost.Graphics/D3D12/D3D12SwapChain.cs b/Ghost.Graphics/D3D12/D3D12SwapChain.cs index 03e9baa..c458afd 100644 --- a/Ghost.Graphics/D3D12/D3D12SwapChain.cs +++ b/Ghost.Graphics/D3D12/D3D12SwapChain.cs @@ -1,9 +1,10 @@ using Ghost.Core; using Ghost.Core.Utilities; -using Ghost.Graphics.Core; using Ghost.Graphics.Contracts; +using Ghost.Graphics.Core; using Ghost.Graphics.D3D12.Utilities; using Ghost.Graphics.RHI; +using Misaki.HighPerformance.LowLevel; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using System.Runtime.CompilerServices; @@ -17,12 +18,19 @@ namespace Ghost.Graphics.D3D12; /// /// D3D12 implementation of swap chain interface /// -internal unsafe class D3D12SwapChain : IUnknownObject, ISwapChain +internal unsafe class D3D12SwapChain : ISwapChain { private readonly D3D12ResourceDatabase _resourceDatabase; + private readonly D3D12DescriptorAllocator _descriptorAllocator; + private readonly D3D12RenderDevice _renderDevice; + private UniquePtr _swapChain; private UnsafeArray> _backBuffers; + private object? _compositionSurface; + + private bool _disposed; + public uint Width { get; private set; @@ -38,9 +46,11 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha get; } - public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, IDXGIFactory7* pFactory, ID3D12CommandQueue* pCommandQueue, SwapChainDesc desc) + public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc) { _resourceDatabase = resourceDatabase; + _descriptorAllocator = descriptorAllocator; + _renderDevice = device; _backBuffers = new UnsafeArray>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent); @@ -48,11 +58,18 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha Height = desc.height; BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT; - CreateSwapChain(pFactory, pCommandQueue, desc); + CreateSwapChain(desc); CreateBackBuffers(); + + _compositionSurface = desc.target.compositionSurface; } - private void CreateSwapChain(IDXGIFactory7* pFactory, ID3D12CommandQueue* commandQueue, SwapChainDesc desc) + ~D3D12SwapChain() + { + Dispose(); + } + + private void CreateSwapChain(SwapChainDesc desc) { var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1 { @@ -71,10 +88,13 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha IDXGISwapChain1* pTempSwapChain = default; + var pFactory = _renderDevice.DXGIFactory.Get(); + var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get(); + switch (desc.target.type) { case SwapChainTargetType.Composition: - ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)commandQueue, &swapChainDesc, null, &pTempSwapChain)); + ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain)); // Set the composition surface if (desc.target.compositionSurface != null) @@ -91,7 +111,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha }; pFactory->CreateSwapChainForHwnd( - (IUnknown*)commandQueue, + (IUnknown*)pCommandQueue, new HWND(desc.target.windowHandle.ToPointer()), &swapChainDesc, &swapChainFullscreenDesc, @@ -107,7 +127,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha pTempSwapChain->QueryInterface(__uuidof(pSwapChain), (void**)&pSwapChain); pTempSwapChain->Release(); - nativeObject.Attach(pSwapChain); + _swapChain.Attach(pSwapChain); } private void CreateBackBuffers() @@ -115,33 +135,37 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha for (uint i = 0; i < BufferCount; i++) { ID3D12Resource* pBackBuffer = default; - nativeObject.Get()->GetBuffer(i, __uuidof(pBackBuffer), (void**)&pBackBuffer); + ThrowIfFailed(_swapChain.Get()->GetBuffer(i, __uuidof(pBackBuffer), (void**)&pBackBuffer)); pBackBuffer->SetName($"SwapChain_BackBuffer_{i}"); - _backBuffers[i] = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present).AsTexture(); + var rtv = _descriptorAllocator.AllocateRTV(); + _renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv)); + + var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, new ResourceViewGroup() { rtv = rtv }); + _backBuffers[i] = handle.AsTexture(); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Handle GetCurrentBackBuffer() { - ThrowIfDisposed(); - return _backBuffers[nativeObject.Get()->GetCurrentBackBufferIndex()]; + ObjectDisposedException.ThrowIf(_disposed, this); + return _backBuffers[_swapChain.Get()->GetCurrentBackBufferIndex()]; } public void Present(bool vsync = true) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); var presentFlags = 0u; var syncInterval = vsync ? 1u : 0u; - ThrowIfFailed(nativeObject.Get()->Present(syncInterval, presentFlags)); + ThrowIfFailed(_swapChain.Get()->Present(syncInterval, presentFlags)); } public void Resize(uint width, uint height) { - ThrowIfDisposed(); + ObjectDisposedException.ThrowIf(_disposed, this); if (Width == width && Height == height) { @@ -155,7 +179,7 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha } // Resize the swap chain - if (nativeObject.Get()->ResizeBuffers(BufferCount, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING).FAILED) + if (_swapChain.Get()->ResizeBuffers(BufferCount, width, height, DXGI_FORMAT_B8G8R8A8_UNORM, (uint)DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING).FAILED) { throw new InvalidOperationException("Failed to resize swap chain buffers."); } @@ -167,20 +191,28 @@ internal unsafe class D3D12SwapChain : IUnknownObject, ISwapCha CreateBackBuffers(); } - protected override void Dispose(bool disposing) + public void Dispose() { - if (Disposed) + if (_disposed) { return; } + if (_compositionSurface != null) + { + using var panelNative = ISwapChainPanelNative.FromSwapChainPanel(_compositionSurface); + panelNative.SetSwapChain(IntPtr.Zero); + } + for (var i = 0; i < _backBuffers.Count; i++) { _resourceDatabase.ReleaseResource(_backBuffers[i].AsResource()); } _backBuffers.Dispose(); + _swapChain.Dispose(); - base.Dispose(disposing); + _disposed = true; + GC.SuppressFinalize(this); } } diff --git a/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs b/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs index 9879de9..31d8446 100644 --- a/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs +++ b/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs @@ -66,7 +66,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable HeapType = type; NumDescriptors = numDescriptors; ShaderVisible = type == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV || type == D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - Stride = device.NativeDevice->GetDescriptorHandleIncrementSize(type); + Stride = device.NativeDevice.Get()->GetDescriptorHandleIncrementSize(type); _dynamicHeapStart = Math.Clamp(dynamicHeapStart, 0, numDescriptors); _currentDynamicOffset = 0; @@ -254,14 +254,14 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable } var newLocation = AllocateDescriptors(count); - _device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandle(index), GetCpuHandle(newLocation), HeapType); + _device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandle(index), GetCpuHandle(newLocation), HeapType); return newLocation; } public readonly void CopyToShaderVisibleHeap(int index, int count = 1) { - _device.NativeDevice->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType); + _device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType); } private bool AllocateResources(int numDescriptors) @@ -279,7 +279,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable }; ID3D12DescriptorHeap* pHeap = default; - var hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap); + var hr = _device.NativeDevice.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(pHeap), (void**)&pHeap); if (hr.FAILED) { return false; @@ -291,11 +291,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable if (!_allocatedDescriptors.IsCreated) { - _allocatedDescriptors = new UnsafeArray(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent); + _allocatedDescriptors = new UnsafeArray(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption.Clear); } else { - _allocatedDescriptors.Resize(numDescriptors); + _allocatedDescriptors.Resize(numDescriptors, Misaki.HighPerformance.LowLevel.Buffer.AllocationOption.Clear); } if (ShaderVisible) @@ -303,7 +303,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable ID3D12DescriptorHeap* pShaderVisibleHeap = default; heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - hr = _device.NativeDevice->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap); + hr = _device.NativeDevice.Get()->CreateDescriptorHeap(&heapDesc, __uuidof(pShaderVisibleHeap), (void**)&pShaderVisibleHeap); if (hr.FAILED) { return false; @@ -332,11 +332,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable return false; } - _device.NativeDevice->CopyDescriptorsSimple((uint)oldSize, _startCpuHandle, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType); + _device.NativeDevice.Get()->CopyDescriptorsSimple((uint)oldSize, _startCpuHandle, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType); if (_shaderVisibleHeap.Get() != null) { - _device.NativeDevice->CopyDescriptorsSimple((uint)oldSize, _startCpuHandleShaderVisible, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType); + _device.NativeDevice.Get()->CopyDescriptorsSimple((uint)oldSize, _startCpuHandleShaderVisible, oldHeap->GetCPUDescriptorHandleForHeapStart(), HeapType); } } finally @@ -350,12 +350,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable /// public void Dispose() { -#if DEBUG - if (NumAllocatedDescriptors > 0) - { - Debug.WriteLine($"Warning: Descriptor heap of type {HeapType} is being disposed with {NumAllocatedDescriptors} allocated descriptors."); - } -#endif + Debug.Assert(NumAllocatedDescriptors == 0); _heap.Dispose(); _shaderVisibleHeap.Dispose(); diff --git a/Ghost.Graphics/GPUResourceLeakException.cs b/Ghost.Graphics/GPUResourceLeakException.cs index d2082b8..9a78f0f 100644 --- a/Ghost.Graphics/GPUResourceLeakException.cs +++ b/Ghost.Graphics/GPUResourceLeakException.cs @@ -1,3 +1,5 @@ +using Misaki.HighPerformance.LowLevel; + namespace Ghost.Graphics; internal unsafe class GPUResourceLeakException : Exception @@ -6,4 +8,12 @@ internal unsafe class GPUResourceLeakException : Exception : base($"GPU resource leak detected! Resource '{name}' at address {(UIntPtr)address} has a reference count of {refCount} when it should be 0. This indicates that the resource was not properly released before being destroyed, which can lead to memory leaks and other issues. Please ensure that all references to this resource are released appropriately.") { } + + public static void ThrowIfRefCountNonZero(uint refCount, void* address, string name) + { + if (refCount != 0) + { + throw new GPUResourceLeakException(refCount, address, name); + } + } } \ No newline at end of file diff --git a/Ghost.Graphics/RHI/Common.cs b/Ghost.Graphics/RHI/Common.cs index 6140574..bb601bb 100644 --- a/Ghost.Graphics/RHI/Common.cs +++ b/Ghost.Graphics/RHI/Common.cs @@ -166,7 +166,7 @@ public ref struct GraphicsPSODescriptor } } -public readonly record struct CBufferPropertyInfo +public readonly struct CBufferPropertyInfo { public string Name { @@ -184,7 +184,7 @@ public readonly record struct CBufferPropertyInfo } } -public readonly record struct CBufferInfo +public readonly struct CBufferInfo { public string Name { diff --git a/Ghost.Graphics/RHI/ICommandBuffer.cs b/Ghost.Graphics/RHI/ICommandBuffer.cs index 821a9c1..359d225 100644 --- a/Ghost.Graphics/RHI/ICommandBuffer.cs +++ b/Ghost.Graphics/RHI/ICommandBuffer.cs @@ -24,9 +24,6 @@ public interface ICommandBuffer : IDisposable get; } - /// - /// Gets the name of the command buffer. - /// string Name { get; diff --git a/Ghost.Graphics/RHI/IPipelineLibrary.cs b/Ghost.Graphics/RHI/IPipelineLibrary.cs index 0950764..a9f5f89 100644 --- a/Ghost.Graphics/RHI/IPipelineLibrary.cs +++ b/Ghost.Graphics/RHI/IPipelineLibrary.cs @@ -14,7 +14,7 @@ public interface IShaderPipeline } } -public interface IPipelineLibrary +public interface IPipelineLibrary : IDisposable { /// /// Load pipeline library from disk. diff --git a/Ghost.Graphics/RHI/IResourceAllocator.cs b/Ghost.Graphics/RHI/IResourceAllocator.cs index c146285..ba4e645 100644 --- a/Ghost.Graphics/RHI/IResourceAllocator.cs +++ b/Ghost.Graphics/RHI/IResourceAllocator.cs @@ -5,7 +5,7 @@ using Ghost.Graphics.Core; namespace Ghost.Graphics.RHI; -public interface IResourceAllocator +public interface IResourceAllocator : IDisposable { /// /// Creates a texture resource diff --git a/Ghost.Graphics/RHI/IResourceDatabase.cs b/Ghost.Graphics/RHI/IResourceDatabase.cs index dbb676d..639c346 100644 --- a/Ghost.Graphics/RHI/IResourceDatabase.cs +++ b/Ghost.Graphics/RHI/IResourceDatabase.cs @@ -11,7 +11,7 @@ public interface IResourceReleasable void ReleaseResource(IResourceDatabase database); } -public interface IResourceDatabase +public interface IResourceDatabase : IDisposable { /* /// diff --git a/Ghost.Graphics/RenderPasses/MeshRenderPass.cs b/Ghost.Graphics/RenderPasses/MeshRenderPass.cs index 1262801..c6fb500 100644 --- a/Ghost.Graphics/RenderPasses/MeshRenderPass.cs +++ b/Ghost.Graphics/RenderPasses/MeshRenderPass.cs @@ -6,6 +6,7 @@ using Ghost.Graphics.RHI; using Ghost.Graphics.Utilities; using Ghost.SDL.Compiler; using Misaki.HighPerformance.Image; +using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Utilities; using TerraFX.Interop.Windows; @@ -57,42 +58,40 @@ internal unsafe class MeshRenderPass : IRenderPass ctx.PipelineLibrary.CompilePSO(in psoDes, in compileResult.GetValueRef()).GetValueOrThrow(); } - MeshBuilder.CreateCube(0.75f, default, out var vertices, out var indices); + MeshBuilder.CreateCube(0.75f, default, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent, out var vertices, out var indices); _mesh = ctx.CreateMesh(vertices, indices); + ctx.UpdateObjectData(_mesh, float4x4.identity); ctx.UploadMesh(_mesh, true); _shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor); _material = ctx.ResourceAllocator.CreateMaterial(_shader); - var imageResults = new ImageResult[_textureFiles.Length]; + //_textures = new Handle[_textureFiles.Length]; + //for (var i = 0; i < _textureFiles.Length; i++) + //{ + // using var stream = File.OpenRead(_textureFiles[i]); + // using var imageData = ImageResult.FromStream(stream); - _textures = new Handle[_textureFiles.Length]; - for (var i = 0; i < _textureFiles.Length; i++) - { - using var stream = File.OpenRead(_textureFiles[i]); - using var imageData = ImageResult.FromStream(stream); - imageResults[i] = imageData; + // var desc = new TextureDesc + // { + // Width = imageData.Width, + // Height = imageData.Height, + // Dimension = TextureDimension.Texture2D, + // Format = TextureFormat.R8G8B8A8_UNorm, + // MipLevels = 1, + // Slice = 1, + // Usage = TextureUsage.ShaderResource, + // }; - var desc = new TextureDesc - { - Width = imageData.Width, - Height = imageData.Height, - Dimension = TextureDimension.Texture2D, - Format = TextureFormat.R8G8B8A8_UNorm, - MipLevels = 1, - Slice = 1, - Usage = TextureUsage.ShaderResource, - }; - - _textures[i] = ctx.CreateTexture(ref desc); - ctx.UploadTexture(_textures[i], new Span(imageData.Data, (int)imageData.Size)); - } + // _textures[i] = ctx.CreateTexture(ref desc); + // ctx.UploadTexture(_textures[i], new Span(imageData.Data, (int)imageData.Size)); + //} } public void Execute(ref readonly RenderingContext ctx) { - ctx.DispatchMesh(_mesh, _material, "Forward", 8); + ctx.DispatchMesh(_mesh, _material, "Forward", 3); } public void Cleanup(IResourceDatabase resourceDatabase) diff --git a/Ghost.Graphics/RenderPasses/ShaderCode.hlsl b/Ghost.Graphics/RenderPasses/ShaderCode.hlsl index 12d5e39..359caf9 100644 --- a/Ghost.Graphics/RenderPasses/ShaderCode.hlsl +++ b/Ghost.Graphics/RenderPasses/ShaderCode.hlsl @@ -26,6 +26,7 @@ void MSMain( out vertices PixelInput outVerts[3], out indices uint3 outTris[1]) { +#if 0 // Fetch bindless buffers ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerObjectData.vertexBuffer]; ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerObjectData.indexBuffer]; @@ -45,8 +46,7 @@ void MSMain( v.uv = asfloat(vertexBuffer.Load4(vertexOffset + 64)); SetMeshOutputCounts(3, 1); - - v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position)); + //v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position)); // Write vertex output outVerts[vertexId].position = v.position; @@ -58,15 +58,50 @@ void MSMain( { outTris[0] = uint3(0, 1, 2); } +#else + // 1. Tell the hardware how much data to expect + SetMeshOutputCounts(3, 1); + + // 2. Hardcoded Clip Space Positions (X, Y, Z, W) + // Visible range: X[-1, 1], Y[-1, 1], Z[0, 1] + // W must be 1.0 + float4 positions[3] = + { + float4(0.0f, 0.5f, 0.5f, 1.0f), // Top + float4(0.5f, -0.5f, 0.5f, 1.0f), // Bottom Right + float4(-0.5f, -0.5f, 0.5f, 1.0f) // Bottom Left + }; + + float4 colors[3] = + { + float4(g_PerObjectData.vertexBuffer, 0.0f, 0.0f, 1.0f), // Red + float4(0.0f, g_PerObjectData.indexBuffer, 0.0f, 1.0f), // Green + float4(0.0f, 0.0f, 0.0f, 1.0f) // Blue + }; + + uint gtid = groupThreadID.x; + + // 3. Write Vertex Data (Parallel) + outVerts[gtid].position = positions[gtid]; + outVerts[gtid].color = colors[gtid]; + + // 4. Write Index Data (Only 1st thread needs to do this) + if (gtid == 0) + { + // Clockwise winding (Standard for DX12) + outTris[0] = uint3(0, 1, 2); + } +#endif } float4 PSMain(PixelInput input) : SV_TARGET { - float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy); - float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy); - float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy); - float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy); + //float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy); + //float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy); + //float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy); + //float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy); - float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f; - return blendedColor * g_PerMaterialData.color; + //float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f; + return g_PerMaterialData.color + input.color;; + //return input.color; } diff --git a/Ghost.Graphics/RenderSystem.cs b/Ghost.Graphics/RenderSystem.cs index a6fa1b8..94357ab 100644 --- a/Ghost.Graphics/RenderSystem.cs +++ b/Ghost.Graphics/RenderSystem.cs @@ -172,11 +172,7 @@ internal class RenderSystem : IRenderSystem _isRunning = false; _shutdownEvent.Set(); - - if (_renderThread.IsAlive) - { - _renderThread.Join(); - } + _renderThread.Join(); } public bool WaitForGPUReady(int timeOut = -1) @@ -242,7 +238,10 @@ internal class RenderSystem : IRenderSystem frameResource.Dispose(); } + _graphicsEngine.Dispose(); _shutdownEvent.Dispose(); + _disposed = true; + GC.SuppressFinalize(this); } } diff --git a/Ghost.Graphics/Utilities/DxcShaderCompiler.cs b/Ghost.Graphics/Utilities/DxcShaderCompiler.cs index f02e1db..6638569 100644 --- a/Ghost.Graphics/Utilities/DxcShaderCompiler.cs +++ b/Ghost.Graphics/Utilities/DxcShaderCompiler.cs @@ -115,7 +115,7 @@ internal sealed partial class DxcShaderCompiler } } -internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler, IDisposable +internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler { private UniquePtr _compiler; private UniquePtr _utils; diff --git a/Ghost.Graphics/Utilities/MeshBuilder.cs b/Ghost.Graphics/Utilities/MeshBuilder.cs index 99b2dbd..9ba4541 100644 --- a/Ghost.Graphics/Utilities/MeshBuilder.cs +++ b/Ghost.Graphics/Utilities/MeshBuilder.cs @@ -10,12 +10,12 @@ public unsafe static class MeshBuilder /// /// Creates a unit cube centered at the origin with size 1. /// - public static void CreateCube(float size, Color128 color, out UnsafeList vertices, out UnsafeList indices) + public static void CreateCube(float size, Color128 color, Allocator allocator, out UnsafeList vertices, out UnsafeList indices) { var half = size * 0.5f; - vertices = new UnsafeList(24, Allocator.Persistent); - indices = new UnsafeList(36, Allocator.Persistent); + vertices = new UnsafeList(24, allocator); + indices = new UnsafeList(36, allocator); var corners = new float4[] { @@ -71,13 +71,13 @@ public unsafe static class MeshBuilder /// /// Creates a plane on the XZ axis centered at the origin. /// - public static void CreatePlane(float width, float depth, Color128 color, out UnsafeList vertices, out UnsafeList indices) + public static void CreatePlane(float width, float depth, Color128 color, Allocator allocator, out UnsafeList vertices, out UnsafeList indices) { var hw = width * 0.5f; var hd = depth * 0.5f; - vertices = new UnsafeList(4, Allocator.Persistent); - indices = new UnsafeList(6, Allocator.Persistent); + vertices = new UnsafeList(4, allocator); + indices = new UnsafeList(6, allocator); vertices.Add(new Vertex() { @@ -129,10 +129,10 @@ public unsafe static class MeshBuilder /// /// Creates a UV sphere centered at the origin. /// - public static void CreateSphere(int latitudeSegments, int longitudeSegments, float radius, Color128 color, out UnsafeList vertices, out UnsafeList indices) + public static void CreateSphere(int latitudeSegments, int longitudeSegments, float radius, Color128 color, Allocator allocator, out UnsafeList vertices, out UnsafeList indices) { - vertices = new UnsafeList((latitudeSegments + 1) * (longitudeSegments + 1), Allocator.Persistent); - indices = new UnsafeList(latitudeSegments * longitudeSegments * 6, Allocator.Persistent); + vertices = new UnsafeList((latitudeSegments + 1) * (longitudeSegments + 1), allocator); + indices = new UnsafeList(latitudeSegments * longitudeSegments * 6, allocator); // Vertices for (var lat = 0; lat <= latitudeSegments; lat++) diff --git a/Ghost.Graphics/test.gshader b/Ghost.Graphics/test.gshader index 52bb857..3070a85 100644 --- a/Ghost.Graphics/test.gshader +++ b/Ghost.Graphics/test.gshader @@ -9,17 +9,17 @@ shader "MyShader/Standard" tex2d_b texture4 = tex2d_b(normal); } - pipeline - { - ztest = less_equal; - zwrite = on; - cull = back; - blend = opaque; - color_mask = 0; - } - pass "Forward" { + pipeline + { + ztest = disable; + zwrite = off; + cull = off; + blend = opaque; + color_mask = 15; + } + ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain"); ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain"); } diff --git a/Ghost.Shader/Compiler/SDLCompiler.cs b/Ghost.Shader/Compiler/SDLCompiler.cs index 9e94b24..981a2b5 100644 --- a/Ghost.Shader/Compiler/SDLCompiler.cs +++ b/Ghost.Shader/Compiler/SDLCompiler.cs @@ -211,6 +211,7 @@ internal static class SDLCompiler var fullPass = new FullPassDescriptor { uniqueIdentifier = GetPassUniqueId(semantics, pass), + name = pass.name, taskShader = pass.taskShader, meshShader = pass.meshShader, pixelShader = pass.pixelShader,