diff --git a/Ghost.Core/Result.cs b/Ghost.Core/Result.cs index ab2d865..b611c16 100644 --- a/Ghost.Core/Result.cs +++ b/Ghost.Core/Result.cs @@ -28,7 +28,7 @@ public readonly struct Result return new Result(false, message); } - public static Result Failure(ErrorStatus status) + public static Result Failure(Error status) { return new Result(false, status.ToString()); } @@ -43,7 +43,7 @@ public readonly struct Result return Result.Failure(message); } - public static Result Failure(ErrorStatus status) + public static Result Failure(Error status) { return Result.Failure(status.ToString()); } @@ -117,7 +117,7 @@ public readonly struct Result public static implicit operator bool(Result result) => result.IsSuccess; } -public enum ErrorStatus : byte +public enum Error : byte { None, NotFound, @@ -249,9 +249,9 @@ public readonly ref struct RefResult public static class ResultExtensions { - public static void ThrowIfFailed(this ErrorStatus result, [CallerArgumentExpression(nameof(result))] string? op = null) + public static void ThrowIfFailed(this Error result, [CallerArgumentExpression(nameof(result))] string? op = null) { - if (result != ErrorStatus.None) + if (result != Error.None) { throw new InvalidOperationException($"{op} failed: {result}"); } diff --git a/Ghost.Editor.Core/AssetHandle/AssetDatabase.Meta.cs b/Ghost.Editor.Core/AssetHandle/AssetDatabase.Meta.cs index b6f400a..11d80a2 100644 --- a/Ghost.Editor.Core/AssetHandle/AssetDatabase.Meta.cs +++ b/Ghost.Editor.Core/AssetHandle/AssetDatabase.Meta.cs @@ -31,16 +31,16 @@ public static partial class AssetDatabase s_watcher.Renamed += OnAssetRenamed; } - private static Result GetMetaFilePath(string assetPath) + private static Result GetMetaFilePath(string assetPath) { if (Directory.Exists(assetPath)) { - return ErrorStatus.NotFound; + return Error.NotFound; } if (Path.GetExtension(assetPath).Equals(".meta", StringComparison.OrdinalIgnoreCase)) { - return ErrorStatus.InvalidState; + return Error.InvalidState; } return assetPath + ".meta"; diff --git a/Ghost.Entities/Archetype.cs b/Ghost.Entities/Archetype.cs index 91b0640..5b4b1c8 100644 --- a/Ghost.Entities/Archetype.cs +++ b/Ghost.Entities/Archetype.cs @@ -392,10 +392,10 @@ internal unsafe struct Archetype : IDisposable } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ErrorStatus SetComponentData(int chunkIndex, int rowIndex, Identifier componentID, void* pComponent) + public readonly Error SetComponentData(int chunkIndex, int rowIndex, Identifier componentID, void* pComponent) { var r = GetLayout(componentID); - if (r.Error != ErrorStatus.None) + if (r.Error != Error.None) { return r.Error; } @@ -412,14 +412,14 @@ internal unsafe struct Archetype : IDisposable var world = World.GetWorldUncheck(_worldID); MarkChanged(chunkIndex, componentID, world.Version); - return ErrorStatus.None; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void* GetComponentData(int chunkIndex, int rowIndex, Identifier componentID) { var r = GetLayout(componentID); - if (r.Error != ErrorStatus.None) + if (r.Error != Error.None) { return null; } @@ -439,24 +439,24 @@ internal unsafe struct Archetype : IDisposable } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Result GetLayout(int componentID) + public readonly Result GetLayout(int componentID) { if (componentID >= _componentIDToLayoutIndex.Count) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } var layoutIndex = _componentIDToLayoutIndex[componentID]; if (layoutIndex == -1) { - return ErrorStatus.NotFound; + return Error.NotFound; } return _layouts[layoutIndex]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ErrorStatus MarkChanged(int chunkIndex, int componentTypeId, int globalVersion) + public readonly Error MarkChanged(int chunkIndex, int componentTypeId, int globalVersion) { var layoutResult = GetLayout(componentTypeId); if (layoutResult.IsFailure) @@ -467,14 +467,14 @@ internal unsafe struct Archetype : IDisposable ref var chunk = ref _chunks[chunkIndex]; chunk.GetVersionUnsafePtr()[layoutResult.Value.versionIndex] = globalVersion; - return ErrorStatus.None; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Result GetVersion(int chunkIndex, int componentTypeId) + public readonly Result GetVersion(int chunkIndex, int componentTypeId) { var layoutResult = GetLayout(componentTypeId); - if (layoutResult.Error != ErrorStatus.None) + if (layoutResult.Error != Error.None) { return layoutResult.Error; } @@ -483,11 +483,11 @@ internal unsafe struct Archetype : IDisposable return chunk.GetVersionUnsafePtr()[layoutResult.Value.versionIndex]; } - public ErrorStatus RemoveEntity(int chunkIndex, int rowIndex) + public Error RemoveEntity(int chunkIndex, int rowIndex) { if (chunkIndex < 0 || chunkIndex >= _chunks.Count) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } var world = World.GetWorldUncheck(_worldID); @@ -502,7 +502,7 @@ internal unsafe struct Archetype : IDisposable var pRowEntity = chunkBase + _entityIdsOffset + (sizeof(Entity) * rowIndex); var result = world.EntityManager.UpdateEntityLocation(*(Entity*)pLastEntity, _id, chunkIndex, rowIndex); - if (result != ErrorStatus.None) + if (result != Error.None) { return result; } @@ -524,19 +524,19 @@ internal unsafe struct Archetype : IDisposable chunk._count--; chunk._structuralVersion = world.Version; - return ErrorStatus.None; + return Error.None; } - public ErrorStatus RemoveEntities(int chunkIndex, ReadOnlySpan sortedIndicesToRemove) + public Error RemoveEntities(int chunkIndex, ReadOnlySpan sortedIndicesToRemove) { if (chunkIndex < 0 || chunkIndex >= _chunks.Count) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } if (sortedIndicesToRemove.Length == 0) { - return ErrorStatus.None; + return Error.None; } ref var chunk = ref _chunks[chunkIndex]; @@ -603,7 +603,7 @@ internal unsafe struct Archetype : IDisposable // 1. Update the Map (Critical Step) // We tell the world: "The entity that WAS at 'candidateIndex' is now at 'holeIndex'" var result = world.EntityManager.UpdateEntityLocation(*(Entity*)pFillerEntity, _id, chunkIndex, holeIndex); - if (result != ErrorStatus.None) + if (result != Error.None) { return result; } @@ -628,7 +628,7 @@ internal unsafe struct Archetype : IDisposable chunk._count = newCount; chunk._structuralVersion = world.Version; - return ErrorStatus.None; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Ghost.Entities/Component.cs b/Ghost.Entities/Component.cs index a839a82..43758de 100644 --- a/Ghost.Entities/Component.cs +++ b/Ghost.Entities/Component.cs @@ -64,7 +64,7 @@ internal static class ComponentRegistry size = sizeof(T), alignment = (int)MemoryUtility.AlignOf(), isEnableable = typeof(IEnableableComponent).IsAssignableFrom(type), - // isShared = typeof(ISharedComponent).IsAssignableFrom(type), + //isShared = typeof(ISharedComponent).IsAssignableFrom(type), }; s_registeredComponents.Add(info); diff --git a/Ghost.Entities/EntityManager.cs b/Ghost.Entities/EntityManager.cs index 872787a..5ac1f2e 100644 --- a/Ghost.Entities/EntityManager.cs +++ b/Ghost.Entities/EntityManager.cs @@ -60,29 +60,29 @@ public unsafe partial class EntityManager : IDisposable Dispose(); } - internal ErrorStatus UpdateEntityLocation(Entity entity, Identifier newArchetypeID, int newChunkIndex, int newRowIndex) + internal Error UpdateEntityLocation(Entity entity, Identifier newArchetypeID, int newChunkIndex, int newRowIndex) { ref var location = ref _entityLocations.GetElementReferenceAt(entity.ID, entity.Generation, out var exist); if (!exist) { - return ErrorStatus.NotFound; + return Error.NotFound; } location.archetypeID = newArchetypeID; location.chunkIndex = newChunkIndex; location.rowIndex = newRowIndex; - return ErrorStatus.None; + return Error.None; } - internal Result GetEntityLocation(Entity entity) + internal Result GetEntityLocation(Entity entity) { if (_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location)) { return location; } - return ErrorStatus.NotFound; + return Error.NotFound; } /// @@ -240,28 +240,28 @@ public unsafe partial class EntityManager : IDisposable /// Destroy the specified entity. /// /// The result status of the operation. - public ErrorStatus DestroyEntity(Entity entity) + public Error DestroyEntity(Entity entity) { if (!_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location)) { - return ErrorStatus.NotFound; + return Error.NotFound; } ref var archetype = ref _world.ComponentManager.GetArchetypeReference(location.archetypeID); DestoryManagedEntityIfExists(in archetype, location); var r = archetype.RemoveEntity(location.chunkIndex, location.rowIndex); - if (r != ErrorStatus.None) + if (r != Error.None) { return r; } if (!_entityLocations.Remove(entity.ID, entity.Generation)) { - return ErrorStatus.NotFound; + return Error.NotFound; } - return ErrorStatus.None; + return Error.None; } /// @@ -383,11 +383,11 @@ public unsafe partial class EntityManager : IDisposable /// The component space ID of the singleton. /// Pointer to the component data. /// The result status of the operation. - public ErrorStatus CreateSingleton(Identifier componentID, void* pComponent) + public Error CreateSingleton(Identifier componentID, void* pComponent) { if (pComponent == null) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } // Check if singleton already exists @@ -396,7 +396,7 @@ public unsafe partial class EntityManager : IDisposable if (arcID.IsValid) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } arcID = _world.ComponentManager.CreateArchetype([componentID], signatureHash); @@ -415,7 +415,7 @@ public unsafe partial class EntityManager : IDisposable archetype.SetEntity(chunkIndex, rowIndex, entity); archetype.SetComponentData(chunkIndex, rowIndex, componentID, pComponent); - return ErrorStatus.None; + return Error.None; } /// @@ -424,7 +424,7 @@ public unsafe partial class EntityManager : IDisposable /// The component space. /// The component data. /// The result status of the operation. - public ErrorStatus CreateSingleton(T component = default) + public Error CreateSingleton(T component = default) where T : unmanaged, IComponent { return CreateSingleton(ComponentTypeID.Value, &component); @@ -447,7 +447,7 @@ public unsafe partial class EntityManager : IDisposable ref var archetype = ref _world.ComponentManager.GetArchetypeReference(arcID); var layoutResult = archetype.GetLayout(componentID); - if (layoutResult.Error != ErrorStatus.None) + if (layoutResult.Error != Error.None) { return null; } @@ -480,7 +480,7 @@ public unsafe partial class EntityManager : IDisposable var src = oldArch._chunks[oldChunk].GetUnsafePtr() + layout.offset + (layout.size * oldRow); var r = newArch.GetLayout(layout.componentID); - if (r.Error != ErrorStatus.None) + if (r.Error != Error.None) { // New archetype does not have this component, skip it. // This can happen when removing components. @@ -500,13 +500,13 @@ public unsafe partial class EntityManager : IDisposable /// The component space ID to add. /// Pointer to the component data. /// The result status of the operation. - public ErrorStatus AddComponent(Entity entity, Identifier componentID, void* pComponent) + public Error AddComponent(Entity entity, Identifier componentID, void* pComponent) { // Find current location ref var location = ref _entityLocations.GetElementReferenceAt(entity.ID, entity.Generation, out var exist); if (!exist) { - return ErrorStatus.NotFound; + return Error.NotFound; } // Build new archetype signature @@ -516,7 +516,7 @@ public unsafe partial class EntityManager : IDisposable if (oldSignature.IsSet(componentID)) { // Component already exists - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } var newArcID = oldArchetype.GetEdgeAdd(componentID); @@ -572,8 +572,8 @@ public unsafe partial class EntityManager : IDisposable newArchetype.SetComponentData(newChunkIndex, newRowIndex, componentID, pComponent); var r = oldArchetype.RemoveEntity(location.chunkIndex, location.rowIndex); - Debug.Assert(r == ErrorStatus.None); // We assert it because the entity should exist if the whole system is consistent. - if (r != ErrorStatus.None) + Debug.Assert(r == Error.None); // We assert it because the entity should exist if the whole system is consistent. + if (r != Error.None) { return r; } @@ -583,7 +583,7 @@ public unsafe partial class EntityManager : IDisposable location.chunkIndex = newChunkIndex; location.rowIndex = newRowIndex; - return ErrorStatus.None; + return Error.None; } /// @@ -593,7 +593,7 @@ public unsafe partial class EntityManager : IDisposable /// The entity to add the component to. /// The component data. /// The result status of the operation. - public ErrorStatus AddComponent(Entity entity, T component = default) + public Error AddComponent(Entity entity, T component = default) where T : unmanaged, IComponent { return AddComponent(entity, ComponentTypeID.Value, &component); @@ -605,13 +605,13 @@ public unsafe partial class EntityManager : IDisposable /// The entity to remove the component from. /// The component space ID to remove. /// The result status of the operation. - public ErrorStatus RemoveComponent(Entity entity, Identifier componentID) + public Error RemoveComponent(Entity entity, Identifier componentID) { // Find current location ref var location = ref _entityLocations.GetElementReferenceAt(entity.ID, entity.Generation, out var exist); if (!exist) { - return ErrorStatus.NotFound; + return Error.NotFound; } // Build new archetype signature @@ -670,8 +670,8 @@ public unsafe partial class EntityManager : IDisposable newArchetype.SetEntity(newChunkIndex, newRowIndex, entity); var r = oldArchetype.RemoveEntity(location.chunkIndex, location.rowIndex); - Debug.Assert(r == ErrorStatus.None); // We assert it because the entity should exist if the whole system is consistent. - if (r != ErrorStatus.None) + Debug.Assert(r == Error.None); // We assert it because the entity should exist if the whole system is consistent. + if (r != Error.None) { return r; } @@ -687,7 +687,7 @@ public unsafe partial class EntityManager : IDisposable location.chunkIndex = newChunkIndex; location.rowIndex = newRowIndex; - return ErrorStatus.None; + return Error.None; } /// @@ -696,7 +696,7 @@ public unsafe partial class EntityManager : IDisposable /// The component space. /// The entity to remove the component from. /// The result status of the operation. - public ErrorStatus RemoveComponent(Entity entity) + public Error RemoveComponent(Entity entity) where T : unmanaged, IComponent { return RemoveComponent(entity, ComponentTypeID.Value); @@ -709,17 +709,17 @@ public unsafe partial class EntityManager : IDisposable /// The component space ID to set. /// Pointer to the component data. /// The result status of the operation. - public ErrorStatus SetComponent(Entity entity, Identifier componentID, void* pComponent) + public Error SetComponent(Entity entity, Identifier componentID, void* pComponent) { if (!_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location)) { - return ErrorStatus.NotFound; + return Error.NotFound; } ref var archetype = ref _world.ComponentManager.GetArchetypeReference(location.archetypeID); archetype.SetComponentData(location.chunkIndex, location.rowIndex, componentID, pComponent); - return ErrorStatus.None; + return Error.None; } /// @@ -728,7 +728,7 @@ public unsafe partial class EntityManager : IDisposable /// The component space. /// The entity to set the component data for. /// The component data. - public ErrorStatus SetComponent(Entity entity, T component) + public Error SetComponent(Entity entity, T component) where T : unmanaged, IComponent { return SetComponent(entity, ComponentTypeID.Value, &component); @@ -800,11 +800,11 @@ public unsafe partial class EntityManager : IDisposable /// The component space ID of the enableable component.True to enable the component, false to disable it. /// The result status of the operation. - public ErrorStatus SetEnabled(Entity entity, Identifier componentID, bool enabled) + public Error SetEnabled(Entity entity, Identifier componentID, bool enabled) { if (!_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location)) { - return ErrorStatus.NotFound; + return Error.NotFound; } ref var archetype = ref _world.ComponentManager.GetArchetypeReference(location.archetypeID); @@ -812,7 +812,7 @@ public unsafe partial class EntityManager : IDisposable var rowIndex = location.rowIndex; var layoutResult = archetype.GetLayout(componentID); - if (layoutResult.Error != ErrorStatus.None) + if (layoutResult.Error != Error.None) { return layoutResult.Error; } @@ -833,7 +833,7 @@ public unsafe partial class EntityManager : IDisposable maskBase[byteIndex] &= (byte)~(1 << bitIndex); } - return ErrorStatus.None; + return Error.None; } /// @@ -843,7 +843,7 @@ public unsafe partial class EntityManager : IDisposable /// The entity to set the enabled state for. /// True to enable the component, false to disable it.The result status of the operation. - public ErrorStatus SetEnabled(Entity entity, bool enabled) + public Error SetEnabled(Entity entity, bool enabled) where T : unmanaged, IEnableableComponent { return SetEnabled(entity, ComponentTypeID.Value, enabled); diff --git a/Ghost.Entities/Query.cs b/Ghost.Entities/Query.cs index 299ad10..41fbab2 100644 --- a/Ghost.Entities/Query.cs +++ b/Ghost.Entities/Query.cs @@ -355,7 +355,7 @@ public unsafe partial struct EntityQuery : IDisposable { // Get the EnableBitmask for this component in this chunk var layoutResult = archetype.GetLayout(id); - if (layoutResult.Error != ErrorStatus.None + if (layoutResult.Error != Error.None // Not enableable, always true || layoutResult.Value.enableBitsOffset == -1) { @@ -374,7 +374,7 @@ public unsafe partial struct EntityQuery : IDisposable while (it.Next(out var id)) { var layoutResult = archetype.GetLayout(id); - if (layoutResult.Error != ErrorStatus.None) + if (layoutResult.Error != Error.None) { continue; } @@ -395,7 +395,7 @@ public unsafe partial struct EntityQuery : IDisposable while (it.Next(out var id)) { var layoutResult = archetype.GetLayout(id); - if (layoutResult.Error != ErrorStatus.None) + if (layoutResult.Error != Error.None) { continue; } diff --git a/Ghost.Entities/SharedComponent.cs b/Ghost.Entities/SharedComponent.cs index 1e2e259..48c2026 100644 --- a/Ghost.Entities/SharedComponent.cs +++ b/Ghost.Entities/SharedComponent.cs @@ -1,4 +1,4 @@ -#if false // FIX: API update in Misaki.HighPerformance.LowLevel.Collections require me to disable this for now. +#if false using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Utilities; diff --git a/Ghost.Graphics/Contracts/IShaderCompiler.cs b/Ghost.Graphics/Contracts/IShaderCompiler.cs index cffac20..c968ba9 100644 --- a/Ghost.Graphics/Contracts/IShaderCompiler.cs +++ b/Ghost.Graphics/Contracts/IShaderCompiler.cs @@ -146,5 +146,5 @@ public interface IShaderCompiler : IDisposable { Result Compile(ref readonly ShaderCompilationConfig config, Allocator allocator); Result CompilePass(ref readonly PassDescriptor descriptor, ref readonly ShaderCompilationConfig additionalConfig, Key64 key); - Result LoadCompiledCache(Key64 key); + Result LoadCompiledCache(Key64 key); } diff --git a/Ghost.Graphics/Core/DxcShaderCompiler.cs b/Ghost.Graphics/Core/DxcShaderCompiler.cs index cc46e5c..01d942c 100644 --- a/Ghost.Graphics/Core/DxcShaderCompiler.cs +++ b/Ghost.Graphics/Core/DxcShaderCompiler.cs @@ -89,14 +89,14 @@ internal sealed partial class DxcShaderCompiler return argsArray; } - private static Result GetFinalShaderCode(string shaderPath, ReadOnlySpan includes, string? injectedCode) + private static Result GetFinalShaderCode(string shaderPath, ReadOnlySpan includes, string? injectedCode) { string shaderCode; if (shaderPath == "hlsl_block") { if (string.IsNullOrEmpty(injectedCode)) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } shaderCode = string.Empty; @@ -105,7 +105,7 @@ internal sealed partial class DxcShaderCompiler { if (!File.Exists(shaderPath)) { - return ErrorStatus.NotFound; + return Error.NotFound; } shaderCode = File.ReadAllText(shaderPath); @@ -487,7 +487,7 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler return compiled; } - public Result LoadCompiledCache(Key64 key) + public Result LoadCompiledCache(Key64 key) { ObjectDisposedException.ThrowIf(_disposed, this); @@ -496,7 +496,7 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler return compiledResult; } - return ErrorStatus.NotFound; + return Error.NotFound; } public void Dispose() diff --git a/Ghost.Graphics/Core/Material.cs b/Ghost.Graphics/Core/Material.cs index daa23bc..27b134a 100644 --- a/Ghost.Graphics/Core/Material.cs +++ b/Ghost.Graphics/Core/Material.cs @@ -3,7 +3,9 @@ using Ghost.Core.Graphics; using Ghost.Graphics.RHI; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; +using Misaki.HighPerformance.LowLevel.Utilities; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace Ghost.Graphics.Core; @@ -66,17 +68,11 @@ public struct Material : IResourceReleasable get; set; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetDirty() - { - _isDirty = true; - } - - public ErrorStatus SetShader(Identifier shaderId, IResourceAllocator allocator, IResourceDatabase database) + public Error SetShader(Identifier shaderId, IResourceAllocator allocator, IResourceDatabase database) { if (!shaderId.IsValid) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } _cBufferCache.ReleaseResource(database); @@ -125,16 +121,16 @@ public struct Material : IResourceReleasable _cBufferCache = new CBufferCache(buffer, shader.CBufferSize); } - return ErrorStatus.None; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly unsafe Result GetPropertyCache() + public readonly unsafe Result GetPropertyCache() where T : unmanaged { if (sizeof(T) != _cBufferCache.Size) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } return *(T*)_cBufferCache.CpuData.GetUnsafePtr(); @@ -152,32 +148,45 @@ public struct Material : IResourceReleasable } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe ErrorStatus SetPropertyCache(ref readonly T data) + public unsafe Error SetPropertyCache(ref readonly T data) where T : unmanaged { if (sizeof(T) != _cBufferCache.Size) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } - Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data); - SetDirty(); + var dataSpan = MemoryMarshal.AsBytes(new ReadOnlySpan(in data)); + var cacheSpan = _cBufferCache.CpuData.AsSpan(); + if (cacheSpan.SequenceEqual(dataSpan)) + { + return Error.None; + } - return ErrorStatus.None; + dataSpan.CopyTo(cacheSpan); + + _isDirty = true; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe ErrorStatus SetRawPropertyCache(ReadOnlySpan data) + public Error SetRawPropertyCache(ReadOnlySpan data) { if (data.Length != _cBufferCache.Size) { - return ErrorStatus.InvalidArgument; + return Error.InvalidArgument; } - Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data); - SetDirty(); + var cacheSpan = _cBufferCache.CpuData.AsSpan(); + if (cacheSpan.SequenceEqual(data)) + { + return Error.None; + } - return ErrorStatus.None; + data.CopyTo(cacheSpan); + + _isDirty = true; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -191,11 +200,11 @@ public struct Material : IResourceReleasable { ref var pipelineOverride = ref _passPipelineOverride[passIndex]; pipelineOverride.options = options; - SetDirty(); + _isDirty = true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ErrorStatus SetKeyword(IResourceDatabase resourceDatabase, int keywordId, bool enabled) + public Error SetKeyword(IResourceDatabase resourceDatabase, int keywordId, bool enabled) { var r = resourceDatabase.GetShaderReference(_shader); if (r.IsFailure) @@ -207,13 +216,13 @@ public struct Material : IResourceReleasable var localIndex = shader.GetLocalKeywordIndex(keywordId); if (localIndex == -1) { - return ErrorStatus.NotFound; + return Error.NotFound; } _keywordMask.SetKeyword(localIndex, enabled); - SetDirty(); + _isDirty = true; - return ErrorStatus.None; + return Error.None; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -252,14 +261,14 @@ public struct Material : IResourceReleasable var barrierData = r.Value; var desc = BarrierDesc.Buffer( cbufferResource, - barrierData.Sync, + barrierData.sync, BarrierSync.Copy, - barrierData.Access, + barrierData.access, BarrierAccess.CopyDest); cmd.ResourceBarrier(desc); cmd.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan()); - + desc = BarrierDesc.Buffer( cbufferResource, BarrierSync.Copy, diff --git a/Ghost.Graphics/Core/RenderingContext.cs b/Ghost.Graphics/Core/RenderingContext.cs index f2c7e3e..67b4b2e 100644 --- a/Ghost.Graphics/Core/RenderingContext.cs +++ b/Ghost.Graphics/Core/RenderingContext.cs @@ -55,23 +55,27 @@ public readonly unsafe ref struct RenderingContext } var data = r.Value; - if (data.Layout == newLayout && data.Access == newAccess && data.Sync == newSync) + if (data.layout == newLayout && data.access == newAccess && data.sync == newSync) { return; } - // For buffers, layout is usually Undefined/Common and doesn't change, but Access/Sync do. - // For textures, layout changes matter. - var desc = isTexture ? - BarrierDesc.Texture( + BarrierDesc desc; + if (isTexture) + { + desc = BarrierDesc.Texture( resource, - data.Sync, newSync, - data.Access, newAccess, - data.Layout, newLayout) - : BarrierDesc.Buffer( + data.sync, newSync, + data.access, newAccess, + data.layout, newLayout); + } + else + { + desc = BarrierDesc.Buffer( resource, - data.Sync, newSync, - data.Access, newAccess); + data.sync, newSync, + data.access, newAccess); + } _directCmd.ResourceBarrier(new ReadOnlySpan(in desc)); ResourceDatabase.SetResourceBarrierData(resource, new ResourceBarrierData(newLayout, newAccess, newSync)); @@ -188,13 +192,13 @@ public readonly unsafe ref struct RenderingContext public void UploadTexture(Handle texture, ReadOnlySpan data) where T : unmanaged { - var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()) - .GetValueOrThrow(); - - if (data.Length * sizeof(T) != desc.TextureDescription.GetTotalBytes()) - { - throw new ArgumentException("Data size does not match texture size."); - } + var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()).GetValueOrThrow(); + + //var size = ResourceAllocator.GetSizeInfo(desc).Size; + //if ((ulong)(data.Length * sizeof(T)) != ResourceAllocator.GetSizeInfo(desc).Size) + //{ + // throw new ArgumentException("Data size does not match texture size."); + //} desc.TextureDescription.Format.GetSurfaceInfo(desc.TextureDescription.Width, desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _); @@ -209,7 +213,7 @@ public readonly unsafe ref struct RenderingContext slicePitch = slicePitch }; - _directCmd.UploadTexture(texture, [subresourceData]); + _directCmd.UploadTexture(texture, subresourceData); } } } diff --git a/Ghost.Graphics/Core/Shader.cs b/Ghost.Graphics/Core/Shader.cs index 20550e0..c2aec2d 100644 --- a/Ghost.Graphics/Core/Shader.cs +++ b/Ghost.Graphics/Core/Shader.cs @@ -186,12 +186,12 @@ public partial struct Shader : IResourceReleasable return ref _shaderPasses[index]; } - public readonly Result TryGetPass(Identifier passID, out int passIndex) + public readonly Result TryGetPass(Identifier passID, out int passIndex) { if (_passIDToLocal.TryGetValue(passID.Value, out var index)) { passIndex = -1; - return ErrorStatus.NotFound; + return Error.NotFound; } passIndex = index; diff --git a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs index cf11def..ce39c07 100644 --- a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs +++ b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs @@ -115,9 +115,9 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer [MethodImpl(MethodImplOptions.AggressiveInlining)] #if DEBUG [System.Diagnostics.CodeAnalysis.DoesNotReturn] - private static void RecordError(string cmdName, ErrorStatus status) + private static void RecordError(string cmdName, Error status) #else - private void RecordError(string cmdName, ErrorStatus status) + private void RecordError(string cmdName, Error status) #endif { #if DEBUG @@ -168,7 +168,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer _isRecording = false; #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return Result.Failure($"Command buffer ended with errors at {_lastError.CommandIndex}, command '{_lastError.CommandName}': {_lastError.Status}"); } @@ -182,7 +182,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -198,7 +198,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -351,7 +351,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -365,12 +365,12 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer var handle = renderTargets[i]; if (!handle.IsValid) { - RecordError(nameof(SetRenderTargets), ErrorStatus.InvalidArgument); + RecordError(nameof(SetRenderTargets), Error.InvalidArgument); continue; } var recordResult = _resourceDatabase.GetResourceRecord(handle.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(SetRenderTargets), recordResult.Error); continue; @@ -386,7 +386,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer if (pDsvHandle != null) { var recordResult = _resourceDatabase.GetResourceRecord(depthTarget.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(SetRenderTargets), recordResult.Error); return; @@ -404,7 +404,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -412,7 +412,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer IncrementCommandCount(); var recordResult = _resourceDatabase.GetResourceRecord(renderTarget.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(ClearRenderTargetView), recordResult.Error); return; @@ -436,7 +436,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -444,7 +444,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer IncrementCommandCount(); var recordResult = _resourceDatabase.GetResourceRecord(depthStencil.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(ClearDepthStencilView), recordResult.Error); return; @@ -467,7 +467,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -480,12 +480,12 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer var rtDesc = rtDescs[i]; if (rtDesc.Texture.IsInvalid) { - RecordError(nameof(BeginRenderPass), ErrorStatus.InvalidArgument); + RecordError(nameof(BeginRenderPass), Error.InvalidArgument); continue; } var recordResult = _resourceDatabase.GetResourceRecord(rtDesc.Texture.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(BeginRenderPass), recordResult.Error); continue; @@ -539,7 +539,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer if (pDsvDesc != null) { var recordResult = _resourceDatabase.GetResourceRecord(depthDesc.Texture.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(BeginRenderPass), recordResult.Error); return; @@ -628,7 +628,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -643,7 +643,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -659,7 +659,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -667,7 +667,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer IncrementCommandCount(); var psor = _pipelineLibrary.GetGraphicsPSO(pipelineKey); - if (psor.Error != ErrorStatus.None) + if (psor.Error != Error.None) { RecordError(nameof(SetPipelineState), psor.Error); return; @@ -682,7 +682,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -698,7 +698,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -706,7 +706,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer IncrementCommandCount(); var recordResult = _resourceDatabase.GetResourceRecord(buffer.AsResource()); - if (recordResult.Error != ErrorStatus.None) + if (recordResult.Error != Error.None) { RecordError(nameof(BeginRenderPass), recordResult.Error); return; @@ -728,7 +728,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -751,7 +751,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -774,7 +774,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -792,7 +792,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -807,7 +807,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -822,7 +822,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -837,7 +837,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -870,7 +870,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -890,7 +890,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -919,7 +919,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -960,7 +960,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer ThrowIfDisposed(); ThrowIfNotRecording(); #if !DEBUG - if (_lastError.Status != ErrorStatus.None) + if (_lastError.Status != Error.None) { return; } @@ -971,7 +971,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer var pSrcResource = _resourceDatabase.GetResource(src.AsResource()); if (pSrcResource == null || pDestResource == null) { - RecordError(nameof(CopyBuffer), ErrorStatus.InvalidArgument); + RecordError(nameof(CopyBuffer), Error.InvalidArgument); return; } diff --git a/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs b/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs index 91a15af..48dff78 100644 --- a/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs +++ b/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs @@ -331,14 +331,14 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary return _pipelineCache.ContainsKey(key); } - public Result, ErrorStatus> GetGraphicsPSO(Key128 key) + public Result, Error> GetGraphicsPSO(Key128 key) { if (_pipelineCache.TryGetValue(key, out var cacheEntry)) { return cacheEntry.pso.Share(); } - return ErrorStatus.NotFound; + return Error.NotFound; } public void Dispose() diff --git a/Ghost.Graphics/D3D12/D3D12Renderer.cs b/Ghost.Graphics/D3D12/D3D12Renderer.cs index 1a9bbb3..9ac4619 100644 --- a/Ghost.Graphics/D3D12/D3D12Renderer.cs +++ b/Ghost.Graphics/D3D12/D3D12Renderer.cs @@ -68,7 +68,7 @@ internal class D3D12Renderer : IRenderer // HACK: This is hard coded for testing purposes only. var error = RenderScene(target, RenderOutput.Viewport, RenderOutput.Scissor); - if (error != ErrorStatus.None) + if (error != Error.None) { _commandBuffer.End(); return Result.Failure(error); @@ -88,7 +88,7 @@ internal class D3D12Renderer : IRenderer } // TODO: A proper render graph integration. - private ErrorStatus RenderScene(Handle target, ViewportDesc viewport, RectDesc rect) + private Error RenderScene(Handle target, ViewportDesc viewport, RectDesc rect) { // NOTE: Testing only. var ctx = new RenderingContext(_graphicsEngine, _commandBuffer); @@ -116,7 +116,7 @@ internal class D3D12Renderer : IRenderer //_commandBuffer.EndRenderPass(); _frameIndex++; - return ErrorStatus.None; + return Error.None; } public void Dispose() diff --git a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs index a9656c0..45715c6 100644 --- a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs +++ b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs @@ -605,9 +605,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator var barrierData = new ResourceBarrierData { - Access = BarrierAccess.NoAccess, - Layout = BarrierLayout.Common, - Sync = BarrierSync.None + access = BarrierAccess.NoAccess, + layout = BarrierLayout.Common, + sync = BarrierSync.None }; return TrackAllocation(alloc, barrierData, ResourceViewGroup.Invalid, default, name, false); @@ -693,9 +693,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator var barrierData = new ResourceBarrierData { - Access = BarrierAccess.NoAccess, - Layout = BarrierLayout.Common, - Sync = BarrierSync.None + access = BarrierAccess.NoAccess, + layout = BarrierLayout.Common, + sync = BarrierSync.None }; Handle resource; @@ -715,7 +715,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator { ObjectDisposedException.ThrowIf(_disposed, this); - var textureDesc = desc.ToTextureDescripton(); + var textureDesc = desc.ToTextureDescription(); return CreateTexture(in textureDesc, name, options); } @@ -803,9 +803,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator var barrierData = new ResourceBarrierData { - Access = BarrierAccess.NoAccess, - Layout = BarrierLayout.Undefined, - Sync = BarrierSync.None + access = BarrierAccess.NoAccess, + layout = BarrierLayout.Undefined, + sync = BarrierSync.None }; Handle resource; @@ -927,7 +927,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator ObjectDisposedException.ThrowIf(_disposed, this); var material = new Material(); - if (material.SetShader(shader, this, _resourceDatabase) != ErrorStatus.None) + if (material.SetShader(shader, this, _resourceDatabase) != Error.None) { return Handle.Invalid; } diff --git a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs index 447ca0a..0177c22 100644 --- a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs +++ b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs @@ -6,11 +6,14 @@ using Misaki.HighPerformance.Collections; using Misaki.HighPerformance.LowLevel; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using TerraFX.Interop.DirectX; namespace Ghost.Graphics.D3D12; +// TODO: Thread safety internal class D3D12ResourceDatabase : IResourceDatabase { internal unsafe record struct ResourceRecord @@ -38,9 +41,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase public ResourceViewGroup viewGroup; public ResourceUnion resource; - //public BarrierLayout layout; - //public BarrierAccess access; - //public BarrierSync sync; public ResourceBarrierData barrierData; public uint cpuFenceValue; @@ -71,7 +71,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase this.desc = resource->GetDesc().ToResourceDesc(); } - public uint Release(D3D12DescriptorAllocator descriptorAllocator) + public readonly uint Release(D3D12DescriptorAllocator descriptorAllocator) { var refCount = 0u; if (Allocated) @@ -87,10 +87,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase } descriptorAllocator.Release(viewGroup); - - resource = default; - viewGroup = default; - return refCount; } } @@ -138,6 +134,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase public unsafe Handle ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, string? name = null) { ObjectDisposedException.ThrowIf(_disposed, this); + if (pResource == null) { #if DEBUG @@ -196,17 +193,17 @@ internal class D3D12ResourceDatabase : IResourceDatabase return _resources.Contains(handle.ID, handle.Generation); } - public RefResult GetResourceRecord(Handle handle) + public RefResult GetResourceRecord(Handle handle) { ObjectDisposedException.ThrowIf(_disposed, this); ref var info = ref _resources.GetElementReferenceAt(handle.ID, handle.Generation, out var exist); if (!exist) { - return ErrorStatus.NotFound; + return Error.NotFound; } - return RefResult.Success(ref info); + return RefResult.Success(ref info); } public SharedPtr GetResource(Handle handle) @@ -220,7 +217,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase return r.Value.ResourcePtr; } - public Result GetResourceBarrierData(Handle handle) + public Result GetResourceBarrierData(Handle handle) { var r = GetResourceRecord(handle); if (r.IsFailure) @@ -231,7 +228,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase return r.Value.barrierData; } - public ErrorStatus SetResourceBarrierData(Handle handle, ResourceBarrierData data) + public Error SetResourceBarrierData(Handle handle, ResourceBarrierData data) { var r = GetResourceRecord(handle); if (r.IsFailure) @@ -240,10 +237,10 @@ internal class D3D12ResourceDatabase : IResourceDatabase } r.Value.barrierData = data; - return ErrorStatus.None; + return Error.None; } - public Result GetResourceDescription(Handle handle) + public Result GetResourceDescription(Handle handle) { var r = GetResourceRecord(handle); if (r.IsFailure) @@ -254,7 +251,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase return r.Value.desc; } - public uint GetBindlessIndex(Handle handle) + public uint GetBindlessIndex(Handle handle, BindlessAccess access = BindlessAccess.ShaderResource) { var r = GetResourceRecord(handle); if (r.IsFailure || !r.Value.Allocated) @@ -262,7 +259,13 @@ internal class D3D12ResourceDatabase : IResourceDatabase return ~0u; } - return (uint)r.Value.viewGroup.srv.Value; + return access switch + { + BindlessAccess.ShaderResource => (uint)r.Value.viewGroup.srv.Value, + BindlessAccess.ConstantBuffer => (uint)r.Value.viewGroup.cbv.Value, + BindlessAccess.UnorderedAccess => (uint)r.Value.viewGroup.uav.Value, + _ => ~0u, + }; } public string? GetResourceName(Handle handle) @@ -345,15 +348,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase return _meshes.Contains(handle.ID, handle.Generation); } - public RefResult GetMeshReference(Handle handle) + public RefResult GetMeshReference(Handle handle) { ref var mesh = ref _meshes.GetElementReferenceAt(handle.ID, handle.Generation, out var exist); if (!exist) { - return ErrorStatus.NotFound; + return Error.NotFound; } - return RefResult.Success(ref mesh); + return RefResult.Success(ref mesh); } public void ReleaseMesh(Handle handle) @@ -384,15 +387,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase return _materials.Contains(handle.ID, handle.Generation); } - public RefResult GetMaterialReference(Handle handle) + public RefResult GetMaterialReference(Handle handle) { ref var material = ref _materials.GetElementReferenceAt(handle.ID, handle.Generation, out var exist); if (!exist) { - return ErrorStatus.NotFound; + return Error.NotFound; } - return RefResult.Success(ref material); + return RefResult.Success(ref material); } public void ReleaseMaterial(Handle handle) @@ -424,14 +427,14 @@ internal class D3D12ResourceDatabase : IResourceDatabase return id.Value >= 0 && id.Value < _shaders.Count; } - public RefResult GetShaderReference(Identifier id) + public RefResult GetShaderReference(Identifier id) { if (!HasShader(id)) { - return ErrorStatus.NotFound; + return Error.NotFound; } - return RefResult.Success(ref _shaders[id.Value]); + return RefResult.Success(ref _shaders[id.Value]); } public void ReleaseShader(Identifier id) @@ -449,6 +452,8 @@ internal class D3D12ResourceDatabase : IResourceDatabase public void Dispose() { + [DoesNotReturn] + [Conditional("DEBUG")] static void ThrowMemoryLeakException(string resourceType, int count) { throw new MemoryLeakException($"ResourceAllocator is being disposed with {count} {resourceType} still registered. Ensure all resources are released before disposing."); diff --git a/Ghost.Graphics/D3D12/D3D12SwapChain.cs b/Ghost.Graphics/D3D12/D3D12SwapChain.cs index c6c956a..2ba96db 100644 --- a/Ghost.Graphics/D3D12/D3D12SwapChain.cs +++ b/Ghost.Graphics/D3D12/D3D12SwapChain.cs @@ -159,9 +159,9 @@ internal unsafe class D3D12SwapChain : ISwapChain var barrierData = new ResourceBarrierData { - Access = BarrierAccess.NoAccess, - Layout = BarrierLayout.Present, - Sync = BarrierSync.None, + access = BarrierAccess.NoAccess, + layout = BarrierLayout.Present, + sync = BarrierSync.None, }; var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, barrierData, view); diff --git a/Ghost.Graphics/RHI/Common.cs b/Ghost.Graphics/RHI/Common.cs index 5dd3297..95e87cd 100644 --- a/Ghost.Graphics/RHI/Common.cs +++ b/Ghost.Graphics/RHI/Common.cs @@ -601,7 +601,7 @@ public struct RenderTargetDesc } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TextureDesc ToTextureDescripton() + public TextureDesc ToTextureDescription() { var usage = Type == RenderTargetType.Color ? TextureUsage.RenderTarget : TextureUsage.DepthStencil; if (CreationFlags.HasFlag(RenderTargetCreationFlags.AllowUAV)) @@ -768,7 +768,7 @@ public struct CommandError get; set; } - public ErrorStatus Status + public Error Status { get; set; } diff --git a/Ghost.Graphics/RHI/IResourceDatabase.cs b/Ghost.Graphics/RHI/IResourceDatabase.cs index 30500c9..caa03b6 100644 --- a/Ghost.Graphics/RHI/IResourceDatabase.cs +++ b/Ghost.Graphics/RHI/IResourceDatabase.cs @@ -13,18 +13,25 @@ public interface IResourceReleasable public struct ResourceBarrierData { - public BarrierLayout Layout; - public BarrierAccess Access; - public BarrierSync Sync; + public BarrierLayout layout; + public BarrierAccess access; + public BarrierSync sync; public ResourceBarrierData(BarrierLayout layout, BarrierAccess access, BarrierSync sync) { - Layout = layout; - Access = access; - Sync = sync; + this.layout = layout; + this.access = access; + this.sync = sync; } } +public enum BindlessAccess +{ + ShaderResource, + ConstantBuffer, + UnorderedAccess, +} + // TODO: Consider adding methods for resource enumeration, statistics, and bulk operations. // TODO: Consider adding async resource loading and streaming support. // TODO: Mesh, Material, Shader management could be separated into their own interfaces for better modularity because they are not bound to specific graphics API. @@ -53,29 +60,30 @@ public interface IResourceDatabase : IDisposable /// /// The handle that uniquely identifies the resource. /// A ResourceBarrierData value representing the current barrier state. - Result GetResourceBarrierData(Handle handle); + Result GetResourceBarrierData(Handle handle); /// /// Sets the barrier data of the specified resource handle. /// /// The handle that identifies the resource. /// The new barrier data. - /// An ErrorStatus indicating the success or failure of the operation. - ErrorStatus SetResourceBarrierData(Handle handle, ResourceBarrierData data); + /// An Error indicating the success or failure of the operation. + Error SetResourceBarrierData(Handle handle, ResourceBarrierData data); /// /// Retrieves the description of a GPU resource associated with the specified handle. /// /// A handle that identifies the GPU resource for which to obtain the description. Must reference a valid resource. /// A ResourceDesc structure containing details about the specified GPU resource. - Result GetResourceDescription(Handle handle); + Result GetResourceDescription(Handle handle); /// /// Retrieves the bindless index associated with the specified GPU resource handle. /// /// A handle to the GPU resource for which to obtain the bindless index. Must reference a valid, currently registered resource. + /// The type of bindless access for which to obtain the index. /// The bindless index corresponding to the specified GPU resource handle. ~0 if the resource does not support bindless access or is not found. - uint GetBindlessIndex(Handle handle); + uint GetBindlessIndex(Handle handle, BindlessAccess access = BindlessAccess.ShaderResource); /// /// Retrieves the name of the GPU resource associated with the specified handle. @@ -135,7 +143,7 @@ public interface IResourceDatabase : IDisposable /// /// The handle of the mesh to retrieve. Must refer to a valid mesh; otherwise, the behavior is undefined. /// A result containing a reference to the mesh corresponding to the specified handle, or an error status if the handle is invalid. - RefResult GetMeshReference(Handle handle); + RefResult GetMeshReference(Handle handle); /// /// Releases the mesh resource associated with the specified handle, freeing any resources held by it. Includes both CPU and GPU resources. @@ -162,7 +170,7 @@ public interface IResourceDatabase : IDisposable /// /// The handle of the material to retrieve. Must refer to a valid material. /// A result containing a reference to the material corresponding to the specified handle, or an error status if the handle is invalid. - RefResult GetMaterialReference(Handle handle); + RefResult GetMaterialReference(Handle handle); /// /// Releases the material associated with the specified handle, making it available for reuse or disposal. @@ -189,7 +197,7 @@ public interface IResourceDatabase : IDisposable /// /// The identifier of the shader to retrieve. Must refer to a valid shader. /// A result containing a reference to the shader corresponding to the specified identifier, or an error status if the identifier is invalid. - RefResult GetShaderReference(Identifier id); + RefResult GetShaderReference(Identifier id); /// /// Releases the shader associated with the specified identifier, freeing any resources allocated to it. diff --git a/Ghost.Graphics/RenderGraphModule/RenderGraph.cs b/Ghost.Graphics/RenderGraphModule/RenderGraph.cs index 54b810d..66e744d 100644 --- a/Ghost.Graphics/RenderGraphModule/RenderGraph.cs +++ b/Ghost.Graphics/RenderGraphModule/RenderGraph.cs @@ -68,7 +68,6 @@ public sealed class RenderGraph : IDisposable Blackboard = new RenderGraphBlackboard(); } - /// /// Resets the render graph for a new frame. /// Reuses existing allocations to minimize GC. @@ -224,7 +223,7 @@ public sealed class RenderGraph : IDisposable { _compiler.Dispose(); - // We need to reset the whole graph to return resources to the pool + // HACK: Ideally, we should have a Dispose method. But for now, we just reset to release resources. Reset(); } } diff --git a/Ghost.Graphics/RenderGraphModule/RenderGraphBarriers.cs b/Ghost.Graphics/RenderGraphModule/RenderGraphBarriers.cs index 76b13e7..b355232 100644 --- a/Ghost.Graphics/RenderGraphModule/RenderGraphBarriers.cs +++ b/Ghost.Graphics/RenderGraphModule/RenderGraphBarriers.cs @@ -50,8 +50,8 @@ internal struct ResourceBarrier public override readonly string ToString() { return AliasingPredecessor.IsValid - ? $"[Pass {PassIndex}] Aliasing Barrier: {AliasingPredecessor.Value}->{Resource.Value} Target: {TargetState.Layout}" - : $"[Pass {PassIndex}] Barrier: {Resource.Value} Target: {TargetState.Layout}"; + ? $"[Pass {PassIndex}] Aliasing Barrier: {AliasingPredecessor.Value}->{Resource.Value} Target: {TargetState.layout}" + : $"[Pass {PassIndex}] Barrier: {Resource.Value} Target: {TargetState.layout}"; } } @@ -88,8 +88,8 @@ internal struct CompiledBarrier public override readonly string ToString() { return AliasingPredecessor.IsValid - ? $"[Pass {PassIndex}] Aliasing: {AliasingPredecessor.Value}->{Resource.Value} -> {TargetState.Layout}" - : $"[Pass {PassIndex}] Transition: {Resource.Value} -> {TargetState.Layout}"; + ? $"[Pass {PassIndex}] Aliasing: {AliasingPredecessor.Value}->{Resource.Value} -> {TargetState.layout}" + : $"[Pass {PassIndex}] Transition: {Resource.Value} -> {TargetState.layout}"; } } @@ -254,7 +254,7 @@ internal static class RenderGraphBarriers if (pass.colorAccess[i].id.IsValid) { var usage = pass.colorAccess[i].usage; - var targetState = new ResourceBarrierData(usage.Layout, usage.Access, usage.Sync); + var targetState = new ResourceBarrierData(usage.layout, usage.access, usage.sync); AddTransition(pass.colorAccess[i].id.AsResource(), targetState); } } @@ -263,7 +263,7 @@ internal static class RenderGraphBarriers if (pass.depthAccess.id.IsValid) { var usage = pass.depthAccess.usage; - var targetState = new ResourceBarrierData(usage.Layout, usage.Access, usage.Sync); + var targetState = new ResourceBarrierData(usage.layout, usage.access, usage.sync); AddTransition(pass.depthAccess.id.AsResource(), targetState); } diff --git a/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs b/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs index 83375ae..4b80123 100644 --- a/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs +++ b/Ghost.Graphics/RenderGraphModule/RenderGraphContext.cs @@ -47,6 +47,7 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC private readonly TextureFormat[] _rtvFormats; private TextureFormat _dsvFormat; + private int _rtvCount; private Handle _activePerMaterialData; private Handle _activePerMeshData; @@ -82,6 +83,7 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC } _dsvFormat = dsvFormat; + _rtvCount = rtvFormats.Length; } public Handle GetActualResource(Identifier resource) @@ -145,7 +147,7 @@ internal sealed class RenderGraphContext : IRasterRenderContext, IComputeRenderC VariantKey = shaderVariantKey, PipelineOption = materialPipeline, - RtvFormats = _rtvFormats, + RtvFormats = _rtvFormats.AsSpan(0, _rtvCount), DsvFormat = _dsvFormat, }; diff --git a/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs b/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs index 1cb2be0..257a9cc 100644 --- a/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs +++ b/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs @@ -173,22 +173,22 @@ internal sealed class RenderGraphExecutor layoutBefore = BarrierLayout.Undefined; accessBefore = BarrierAccess.NoAccess; - syncBefore = predState.Sync; + syncBefore = predState.sync; } else { - layoutBefore = currentState.Layout; - accessBefore = currentState.Access; - syncBefore = currentState.Sync; + layoutBefore = currentState.layout; + accessBefore = currentState.access; + syncBefore = currentState.sync; } var target = compiledBarrier.TargetState; // Skip if already in target state (optimization) if (!compiledBarrier.AliasingPredecessor.IsValid && - layoutBefore == target.Layout && - accessBefore == target.Access && - syncBefore == target.Sync) + layoutBefore == target.layout && + accessBefore == target.access && + syncBefore == target.sync) { continue; } @@ -198,16 +198,16 @@ internal sealed class RenderGraphExecutor if (compiledBarrier.ResourceType == RenderGraphResourceType.Texture) { desc = BarrierDesc.Texture(resourceHandle, - syncBefore, target.Sync, - accessBefore, target.Access, - layoutBefore, target.Layout, + syncBefore, target.sync, + accessBefore, target.access, + layoutBefore, target.layout, discard: compiledBarrier.Flags.HasFlag(BarrierFlags.Discard)); } else { desc = BarrierDesc.Buffer(resourceHandle, - syncBefore, target.Sync, - accessBefore, target.Access); + syncBefore, target.sync, + accessBefore, target.access); } if (barrierCount >= MaxBatch) diff --git a/Ghost.Graphics/RenderGraphModule/RenderGraphPass.cs b/Ghost.Graphics/RenderGraphModule/RenderGraphPass.cs index 45809e6..4534e2f 100644 --- a/Ghost.Graphics/RenderGraphModule/RenderGraphPass.cs +++ b/Ghost.Graphics/RenderGraphModule/RenderGraphPass.cs @@ -1,4 +1,5 @@ using Ghost.Core; +using Ghost.Graphics.RHI; using System.Runtime.CompilerServices; namespace Ghost.Graphics.RenderGraphModule; @@ -27,7 +28,7 @@ internal abstract class RenderGraphPassBase public bool asyncCompute; public TextureAccess depthAccess; - public TextureAccess[] colorAccess = new TextureAccess[8]; + public TextureAccess[] colorAccess = new TextureAccess[RHIUtility.MAX_RENDER_TARGETS]; public int maxColorIndex = -1; public List> randomAccess = new(8); diff --git a/Ghost.Graphics/RenderPasses/ShaderCode.hlsl b/Ghost.Graphics/RenderPasses/ShaderCode.hlsl index 598a5a9..afc5d6b 100644 --- a/Ghost.Graphics/RenderPasses/ShaderCode.hlsl +++ b/Ghost.Graphics/RenderPasses/ShaderCode.hlsl @@ -8,7 +8,7 @@ struct PixelInput float4 uv : TEXCOORD0; }; -[NumThreads(3, 1, 1)] // 3 threads per triangle +[numthreads(3, 1, 1)] // 3 threads per triangle [OUTPUT_TRIANGLE_TOPOLOGY] void MSMain( uint3 groupThreadID : SV_GroupThreadID, @@ -22,7 +22,6 @@ void MSMain( Vertex v = LoadVertexData(vertexId, groupID.x, perObjectData.vertexBuffer, perObjectData.indexBuffer); SetMeshOutputCounts(3, 1); - //v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position)); // Write vertex output outVerts[vertexId].position = v.position; diff --git a/Ghost.Graphics/Shaders/Blit.gsdef b/Ghost.Graphics/Shaders/Blit.gsdef index ab7ea18..03a7fe9 100644 --- a/Ghost.Graphics/Shaders/Blit.gsdef +++ b/Ghost.Graphics/Shaders/Blit.gsdef @@ -32,7 +32,7 @@ shader "Hidden/Blit" float4 uv : TEXCOORD0; }; - [NumThreads(4, 1, 1)] + [numthreads(4, 1, 1)] [OUTPUT_TRIANGLE_TOPOLOGY] void MSMain( uint gtid : SV_GroupThreadID, diff --git a/Ghost.Graphics/Shaders/Includes/Common.hlsl b/Ghost.Graphics/Shaders/Includes/Common.hlsl index c05f764..90e56d7 100644 --- a/Ghost.Graphics/Shaders/Includes/Common.hlsl +++ b/Ghost.Graphics/Shaders/Includes/Common.hlsl @@ -49,8 +49,11 @@ struct Vertex #define SAMPLE_TEXTURE2D_ARRAY(texId, sampId, uvw) SampleTextureArray(texId, sampId, uvw) -#define OUTPUT_TRIANGLE_TOPOLOGY OutputTopology("triangle") -#define OUTPUT_LINE_TOPOLOGY OutputTopology("line") +#define OUTPUT_TRIANGLE_TOPOLOGY outputtopology("triangle") +#define OUTPUT_LINE_TOPOLOGY outputtopology("line") + + +#define ZERO_INIT(T) (T)0 static inline float4 SampleTexture2D(uint texId, uint sampId, float2 uv)