From 364fbf92085f1a404bb746a6e8d1651053c8edcb Mon Sep 17 00:00:00 2001 From: Misaki Date: Sun, 25 Jan 2026 16:34:28 +0900 Subject: [PATCH] Refactor error handling: use Error enum, update APIs Replaces ErrorStatus with Error across all systems for consistency. Renames ResourceBarrierData fields to camelCase. Adds BindlessAccess enum and updates GetBindlessIndex API. Updates method signatures, result types, and error checks. Modernizes HLSL mesh shader syntax and fixes naming. Improves code style and updates comments for clarity. --- Ghost.Core/Result.cs | 10 +-- .../AssetHandle/AssetDatabase.Meta.cs | 6 +- Ghost.Entities/Archetype.cs | 40 +++++----- Ghost.Entities/Component.cs | 2 +- Ghost.Entities/EntityManager.cs | 78 +++++++++---------- Ghost.Entities/Query.cs | 6 +- Ghost.Entities/SharedComponent.cs | 2 +- Ghost.Graphics/Contracts/IShaderCompiler.cs | 2 +- Ghost.Graphics/Core/DxcShaderCompiler.cs | 10 +-- Ghost.Graphics/Core/Material.cs | 67 +++++++++------- Ghost.Graphics/Core/RenderingContext.cs | 42 +++++----- Ghost.Graphics/Core/Shader.cs | 4 +- Ghost.Graphics/D3D12/D3D12CommandBuffer.cs | 72 ++++++++--------- Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs | 4 +- Ghost.Graphics/D3D12/D3D12Renderer.cs | 6 +- .../D3D12/D3D12ResourceAllocator.cs | 22 +++--- Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs | 57 +++++++------- Ghost.Graphics/D3D12/D3D12SwapChain.cs | 6 +- Ghost.Graphics/RHI/Common.cs | 4 +- Ghost.Graphics/RHI/IResourceDatabase.cs | 36 +++++---- .../RenderGraphModule/RenderGraph.cs | 3 +- .../RenderGraphModule/RenderGraphBarriers.cs | 12 +-- .../RenderGraphModule/RenderGraphContext.cs | 4 +- .../RenderGraphModule/RenderGraphExecutor.cs | 24 +++--- .../RenderGraphModule/RenderGraphPass.cs | 3 +- Ghost.Graphics/RenderPasses/ShaderCode.hlsl | 3 +- Ghost.Graphics/Shaders/Blit.gsdef | 2 +- Ghost.Graphics/Shaders/Includes/Common.hlsl | 7 +- 28 files changed, 282 insertions(+), 252 deletions(-) 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)