diff --git a/Ghost.Core/Ghost.Core.csproj b/Ghost.Core/Ghost.Core.csproj
index 5bc2b61..4b98d7f 100644
--- a/Ghost.Core/Ghost.Core.csproj
+++ b/Ghost.Core/Ghost.Core.csproj
@@ -10,17 +10,18 @@
True
$(DefineConstants);PLATEFORME_WIN64
+ True
True
$(DefineConstants);PLATEFORME_WIN64
+ True
-
-
+
diff --git a/Ghost.Core/Graphics/ShaderDescriptor.cs b/Ghost.Core/Graphics/ShaderDescriptor.cs
index 74e79ef..5baa4ff 100644
--- a/Ghost.Core/Graphics/ShaderDescriptor.cs
+++ b/Ghost.Core/Graphics/ShaderDescriptor.cs
@@ -10,11 +10,12 @@ public enum ShaderPropertyType
{
None,
Float, Float2, Float3, Float4,
+ Float4x4,
Int, Int2, Int3, Int4,
UInt, UInt2, UInt3, UInt4,
Bool, Bool2, Bool3, Bool4,
- Texture2DBindless, Texture3DBindless, TextureCubeBindless,
- Texture2DArrayBindless, TextureCubeArrayBindless,
+ Texture2D, Texture3D, TextureCube,
+ Texture2DArray, TextureCubeArray,
}
public struct ShaderEntryPoint
@@ -77,11 +78,8 @@ public class FullPassDescriptor : IPassDescriptor
public ShaderEntryPoint taskShader;
public ShaderEntryPoint meshShader;
public ShaderEntryPoint pixelShader;
- public string? generatedCodePath;
public List? defines;
- public List? includes;
public List? keywords;
- public List? properties;
public PipelineDescriptor localPipeline;
public string Identifier => uniqueIdentifier;
@@ -100,6 +98,42 @@ public class FallbackPassDescriptor : IPassDescriptor
public class ShaderDescriptor
{
public string name = string.Empty;
+ public string? generatedCodePath;
+ public uint cbufferSize;
public List globalProperties = new();
+ public List properties = new();
public List passes = new();
-}
\ No newline at end of file
+}
+
+public static class ShaderDescriptorExtensions
+{
+ public static uint GetSize(this ShaderPropertyType type)
+ {
+ return type switch
+ {
+ ShaderPropertyType.Float => 4,
+ ShaderPropertyType.Float2 => 8,
+ ShaderPropertyType.Float3 => 12,
+ ShaderPropertyType.Float4 => 16,
+ ShaderPropertyType.Float4x4 => 64,
+ ShaderPropertyType.Int => 4,
+ ShaderPropertyType.Int2 => 8,
+ ShaderPropertyType.Int3 => 12,
+ ShaderPropertyType.Int4 => 16,
+ ShaderPropertyType.UInt => 4,
+ ShaderPropertyType.UInt2 => 8,
+ ShaderPropertyType.UInt3 => 12,
+ ShaderPropertyType.UInt4 => 16,
+ ShaderPropertyType.Bool => 4,
+ ShaderPropertyType.Bool2 => 8,
+ ShaderPropertyType.Bool3 => 12,
+ ShaderPropertyType.Bool4 => 16,
+ ShaderPropertyType.Texture2D => 4, // Bindless resource use uint32
+ ShaderPropertyType.Texture3D => 4,
+ ShaderPropertyType.TextureCube => 4,
+ ShaderPropertyType.Texture2DArray => 4,
+ ShaderPropertyType.TextureCubeArray => 4,
+ _ => 0,
+ };
+ }
+}
diff --git a/Ghost.Core/Logging.cs b/Ghost.Core/Logging.cs
index 4358005..702749d 100644
--- a/Ghost.Core/Logging.cs
+++ b/Ghost.Core/Logging.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Diagnostics;
namespace Ghost.Core;
diff --git a/Ghost.Core/Result.cs b/Ghost.Core/Result.cs
index 745c850..06184bf 100644
--- a/Ghost.Core/Result.cs
+++ b/Ghost.Core/Result.cs
@@ -1,5 +1,4 @@
using System.Runtime.CompilerServices;
-using TerraFX.Interop.Windows;
namespace Ghost.Core;
@@ -44,6 +43,11 @@ public readonly struct Result
return new Result(value, status);
}
+ public static RefResult CreateRef(ref T value, S status)
+ {
+ return new RefResult(ref value, status);
+ }
+
public override string ToString() => IsSuccess ? "OK" : $"Error: {Message}";
public static implicit operator bool(Result result) => result.IsSuccess;
@@ -68,16 +72,6 @@ public readonly struct Result
_message = message;
}
- public ref readonly T GetValueRef()
- {
- if (!IsSuccess)
- {
- throw new InvalidOperationException("Cannot get value from a failed Result.");
- }
-
- return ref Unsafe.AsRef(in _value);
- }
-
public static Result Success(T value)
{
return new Result(true, value);
@@ -92,9 +86,7 @@ public readonly struct Result
public static implicit operator Result(T? data) => data is not null ? Success(data) : Failure(null);
public static implicit operator Result(Result result) => result.IsSuccess ? Success(default!) : Failure(result.Message);
-
public static implicit operator bool(Result result) => result.IsSuccess;
- public static implicit operator Result(Result result) => result.IsSuccess ? Result.Success() : Result.Failure(result.Message);
}
public enum ResultStatus : byte
@@ -126,11 +118,6 @@ public readonly struct Result
_status = status;
}
- public ref readonly T GetValueRef()
- {
- return ref Unsafe.AsRef(in _value);
- }
-
public static Result Create(T value, S status)
{
return new Result(value, status);
@@ -139,6 +126,28 @@ public readonly struct Result
public override string ToString() => $"Value: {_value}, Status: {_status}";
}
+public readonly ref struct RefResult
+{
+ private readonly ref T _value;
+ private readonly S _status;
+
+ public ref T Value => ref _value;
+ public S Status => _status;
+
+ public RefResult(ref T value, S status)
+ {
+ _value = ref value;
+ _status = status;
+ }
+
+ public static RefResult Create(ref T value, S status)
+ {
+ return new RefResult(ref value, status);
+ }
+
+ public override string ToString() => $"Value: {_value}, Status: {_status}";
+}
+
public static class ResultExtensions
{
public static void ThrowIfFailed(this Result result)
diff --git a/Ghost.Core/Utilities/Win32Utility.cs b/Ghost.Core/Utilities/Win32Utility.cs
index 9bfa61a..4a3675d 100644
--- a/Ghost.Core/Utilities/Win32Utility.cs
+++ b/Ghost.Core/Utilities/Win32Utility.cs
@@ -32,14 +32,14 @@ internal static unsafe partial class Win32Utility
public static Guid* IID_NULL
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in TerraFX.Interop.Windows.IID.IID_NULL));
+ get => (Guid*)Unsafe.AsPointer(ref Unsafe.AsRef(in IID.IID_NULL));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static IID_PPV IID_PPV_ARGS(ComPtr comPtr)
+ public static IID_PPV IID_PPV_ARGS(ComPtr* comPtr)
where T : unmanaged, IUnknown.Interface
{
- return new IID_PPV(Windows.__uuidof(), comPtr.PPV());
+ return new IID_PPV(Windows.__uuidof(), (void**)comPtr);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -80,27 +80,6 @@ internal static unsafe partial class Win32Utility
return Result.Failure($"{op} failed with code {hr}");
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Guid* IID(this ComPtr comPtr)
- where T : unmanaged, IUnknown.Interface
- {
- return Windows.__uuidof();
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Guid* IID(this T ptr)
- where T : unmanaged, IUnknown.Interface
- {
- return Windows.__uuidof();
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void** PPV(ref this ComPtr comPtr)
- where T : unmanaged, IUnknown.Interface
- {
- return (void**)comPtr.GetAddressOf();
- }
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void** ReleaseAndGetVoidAddressOf(ref this ComPtr comPtr)
where T : unmanaged, IUnknown.Interface
diff --git a/Ghost.Editor/App.xaml b/Ghost.Editor/App.xaml
index 32a4449..961b1c6 100644
--- a/Ghost.Editor/App.xaml
+++ b/Ghost.Editor/App.xaml
@@ -9,6 +9,7 @@
+
diff --git a/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj b/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj
index f9024f3..f0dbf77 100644
--- a/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj
+++ b/Ghost.Graphics.Test/Ghost.Graphics.Test.csproj
@@ -55,7 +55,6 @@
-
@@ -84,9 +83,14 @@
False
True
- False
10.0.20348.0
enable
True
+
+
+
+
+
+
diff --git a/Ghost.Graphics.Test/Properties/launchSettings.json b/Ghost.Graphics.Test/Properties/launchSettings.json
index a2a54f9..ce2e5c5 100644
--- a/Ghost.Graphics.Test/Properties/launchSettings.json
+++ b/Ghost.Graphics.Test/Properties/launchSettings.json
@@ -2,7 +2,7 @@
"profiles": {
"Ghost.Graphics.Test (Package)": {
"commandName": "MsixPackage",
- "nativeDebugging": true
+ "nativeDebugging": false
},
"Ghost.Graphics.Test (Unpackaged)": {
"commandName": "Project"
diff --git a/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs b/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs
index c85909a..74e6ef0 100644
--- a/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs
+++ b/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs
@@ -1,15 +1,14 @@
-using Ghost.Graphics;
using Ghost.Graphics.RHI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Misaki.HighPerformance.LowLevel.Buffer;
-using TerraFX.Interop.WinRT;
-using WinRT;
namespace Ghost.Graphics.Test.Windows;
public sealed partial class GraphicsTestWindow : Window
{
+ private bool _isFirstActivationHandled = false;
+
private IRenderSystem? _renderSystem;
private IRenderer? _renderer;
private ISwapChain? _swapChain;
@@ -18,33 +17,46 @@ public sealed partial class GraphicsTestWindow : Window
{
InitializeComponent();
- Panel.Loaded += SwapChainPanel_Loaded;
- Panel.Unloaded += SwapChainPanel_Unloaded;
+ Activated += GraphicsTestWindow_Activated;
+ Closed += GraphicsTestWindow_Closed;
Panel.SizeChanged += SwapChainPanel_SizeChanged;
}
- private void SwapChainPanel_Loaded(object sender, RoutedEventArgs e)
+ private void GraphicsTestWindow_Activated(object sender, WindowActivatedEventArgs e)
{
+ if (_isFirstActivationHandled)
+ {
+ return;
+ }
+
#if DEBUG
AllocationManager.EnableDebugLayer();
#endif
- _renderSystem = new RenderSystem(new()
+ _renderSystem = new RenderSystem(new RenderingConfig()
{
FrameBufferCount = 2,
GraphicsAPI = GraphicsAPI.Direct3D12
});
_renderer = _renderSystem.GraphicsEngine.CreateRenderer();
-
- _swapChain = _renderSystem.GraphicsEngine.CreateSwapChain(new SwapChainDesc((uint)AppWindow.Size.Width, (uint)AppWindow.Size.Height, SwapChainTarget.FromCompositionSurface(Panel)));
+
+ _swapChain = _renderSystem.GraphicsEngine.CreateSwapChain(new SwapChainDesc
+ {
+ Width = (uint)AppWindow.Size.Width,
+ Height = (uint)AppWindow.Size.Height,
+ Target = SwapChainTarget.FromCompositionSurface(Panel)
+ });
_renderer.SetSwapChain(_swapChain);
_renderSystem.Start();
CompositionTarget.Rendering += OnRendering;
+
+ e.Handled = true;
+ _isFirstActivationHandled = true;
}
- private void SwapChainPanel_Unloaded(object sender, RoutedEventArgs e)
+ private void GraphicsTestWindow_Closed(object sender, WindowEventArgs e)
{
CompositionTarget.Rendering -= OnRendering;
_renderSystem?.Stop();
@@ -52,6 +64,10 @@ public sealed partial class GraphicsTestWindow : Window
_renderer?.Dispose();
_swapChain?.Dispose();
_renderSystem?.Dispose();
+
+#if DEBUG
+ AllocationManager.Dispose();
+#endif
}
private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
@@ -69,7 +85,7 @@ public sealed partial class GraphicsTestWindow : Window
return;
}
- if (_renderSystem.CPUFenceValue < _renderSystem.GPUFenceValue + _renderSystem.Config.FrameBufferCount)
+ if (_renderSystem.CPUFenceValue < _renderSystem.GPUFenceValue + _renderSystem.MaxFrameLatency)
{
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, () =>
{
diff --git a/Ghost.Graphics/Contracts/IShaderCompiler.cs b/Ghost.Graphics/Contracts/IShaderCompiler.cs
index edac3ca..6fedfa3 100644
--- a/Ghost.Graphics/Contracts/IShaderCompiler.cs
+++ b/Ghost.Graphics/Contracts/IShaderCompiler.cs
@@ -6,7 +6,7 @@ using Misaki.HighPerformance.LowLevel.Collections;
namespace Ghost.Graphics.Contracts;
-public struct CompileResult : IDisposable
+public struct ShaderCompileResult : IDisposable
{
public UnsafeArray bytecode;
public ShaderReflectionData reflectionData;
@@ -21,9 +21,9 @@ public struct CompileResult : IDisposable
public struct GraphicsCompiledResult : IDisposable
{
- public CompileResult tsResult;
- public CompileResult msResult;
- public CompileResult psResult;
+ public ShaderCompileResult tsResult;
+ public ShaderCompileResult msResult;
+ public ShaderCompileResult psResult;
public void Dispose()
{
@@ -143,7 +143,7 @@ public readonly struct ShaderReflectionData
public interface IShaderCompiler : IDisposable
{
- Result Compile(ref readonly CompilerConfig config, Allocator allocator);
- Result CompilePass(IPassDescriptor descriptor);
+ Result Compile(ref readonly CompilerConfig config, Allocator allocator);
+ Result CompilePass(IPassDescriptor descriptor, string? generatedCodePath);
Result LoadCompiledCache(ShaderPassKey key);
}
diff --git a/Ghost.Graphics/Core/Material.cs b/Ghost.Graphics/Core/Material.cs
index 52b6647..d1faa70 100644
--- a/Ghost.Graphics/Core/Material.cs
+++ b/Ghost.Graphics/Core/Material.cs
@@ -2,8 +2,6 @@ using Ghost.Core;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
-using Misaki.HighPerformance.LowLevel.Utilities;
-using Misaki.HighPerformance.Mathematics;
using System.Runtime.CompilerServices;
namespace Ghost.Graphics.Core;
@@ -12,29 +10,38 @@ internal struct CBufferCache : IResourceReleasable
{
private UnsafeArray _cpuData;
private Handle _gpuResource;
+ private uint _size;
private uint _alignedSize;
public readonly UnsafeArray CpuData => _cpuData;
public readonly Handle GpuResource => _gpuResource;
+ public readonly uint Size => _size;
public readonly uint AlignedSize => _alignedSize;
- public readonly bool IsCreated => _gpuResource.IsValid && _cpuData.IsCreated;
+ public readonly bool IsCreated => _size != 0 && _gpuResource.IsValid && _cpuData.IsCreated;
public CBufferCache(Handle buffer, uint bufferSize)
{
+ _size = bufferSize;
_alignedSize = (bufferSize + 255u) & ~255u;
- _cpuData = new((int)AlignedSize, Allocator.Persistent);
+ _cpuData = new UnsafeArray((int)AlignedSize, Allocator.Persistent);
_gpuResource = buffer;
}
public void ReleaseResource(IResourceDatabase database)
{
+ if (!IsCreated)
+ {
+ return;
+ }
+
_cpuData.Dispose();
database.ReleaseResource(GpuResource.AsResource());
_gpuResource = Handle.Invalid;
+ _size = 0;
_alignedSize = 0;
}
}
@@ -42,183 +49,96 @@ internal struct CBufferCache : IResourceReleasable
public struct Material : IResourceReleasable, IHandleType
{
private Identifier _shader;
- private UnsafeArray _materialPropertiesCache; // One per shader pass
+ private CBufferCache _cBufferCache;
+
+ internal readonly CBufferCache CBufferCache => _cBufferCache;
public readonly Identifier Shader => _shader;
- internal ref CBufferCache GetPassCache(int passIndex)
- {
- return ref _materialPropertiesCache[passIndex];
- }
-
- public void SetShader(Identifier shaderId, IResourceAllocator allocator, IResourceDatabase database)
+ public Result SetShader(Identifier shaderId, IResourceAllocator allocator, IResourceDatabase database)
{
if (!shaderId.IsValid)
{
- throw new ArgumentException("Shader ID is invalid.");
+ return Result.Failure("Shader ID is invalid.");
}
+ _cBufferCache.ReleaseResource(database);
_shader = shaderId;
var shader = database.GetShaderReference(shaderId);
- _materialPropertiesCache = new UnsafeArray(shader.PassCount, Allocator.Persistent);
- for (var i = 0; i < shader.PassCount; i++)
+ if (shader.CBufferSize != 0)
{
- var pass = database.GetShaderPass(shader.GetPassKey(i));
- var cbufferInfo = pass.CBuffer;
-
- if (cbufferInfo.SizeInBytes == 0)
- {
- continue;
- }
-
var desc = new BufferDesc
{
- Size = cbufferInfo.SizeInBytes,
+ Size = shader.CBufferSize,
Usage = BufferUsage.Constant,
MemoryType = ResourceMemoryType.Default,
};
var buffer = allocator.CreateBuffer(ref desc);
- _materialPropertiesCache[i] = new CBufferCache(buffer, cbufferInfo.SizeInBytes);
- }
- }
-
- void IResourceReleasable.ReleaseResource(IResourceDatabase database)
- {
- foreach (var cache in _materialPropertiesCache)
- {
- cache.ReleaseResource(database);
+ _cBufferCache = new CBufferCache(buffer, shader.CBufferSize);
}
- _materialPropertiesCache.Dispose();
- }
-}
-
-public ref struct MaterialAccessor
-{
- private ref Material _materialData;
- private readonly Shader _shader;
-
- private readonly IResourceDatabase _resourceDatabase;
-
- public MaterialAccessor(Handle material, IResourceDatabase resourceDatabase)
- {
- _resourceDatabase = resourceDatabase;
-
- _materialData = ref resourceDatabase.GetMaterialReference(material);
- _shader = resourceDatabase.GetShaderReference(_materialData.Shader);
+ return Result.Success();
}
- private readonly unsafe void WriteToCache(string propertyName, in T value)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly unsafe Result GetPropertyCache()
where T : unmanaged
{
- foreach (var index in _shader.GetPropertyPassIndices(propertyName))
+ if (sizeof(T) != _cBufferCache.Size)
{
- var passKey = _shader.GetPassKey(index);
- var pass = _resourceDatabase.GetShaderPass(passKey);
- var propertyInfo = pass.GetPropertyInfo(propertyName);
-
- if (propertyInfo.Size != sizeof(T))
- {
- throw new ArgumentException($"Property '{propertyName}' has a size mismatch. Expected {propertyInfo.Size} bytes, but got {sizeof(T)} bytes.");
- }
-
- ref var cache = ref _materialData.GetPassCache(index);
- Unsafe.WriteUnaligned(ref cache.CpuData[propertyInfo.StartOffset], value);
- }
- }
-
- ///
- /// Sets a float property in the material's constant buffer.
- ///
- /// The name of the property to set.
- /// The Value to set for the property.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void SetFloat(string propertyName, in float value)
- {
- WriteToCache(propertyName, in value);
- }
-
- ///
- /// Sets a uint property in the material's constant buffer (useful for texture indices).
- ///
- /// The name of the property to set.
- /// The Value to set for the property.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void SetUInt(string propertyName, in uint value)
- {
- WriteToCache(propertyName, in value);
- }
-
- ///
- /// Sets a Vector property in the material's constant buffer.
- ///
- /// The name of the property to set.
- /// The Value to set for the property.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void SetVector(string propertyName, in float4 value)
- {
- WriteToCache(propertyName, in value);
- }
-
- ///
- /// Sets a Matrix property in the material's constant buffer.
- ///
- /// The name of the property to set.
- /// The Value to set for the property.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void SetMatrix(string propertyName, in float4x4 value)
- {
- WriteToCache(propertyName, in value);
- }
-
- ///
- /// Sets a texture index for a shader property (for bindless texture access)
- ///
- /// The name of the shader property (e.g., "_TextureIndex1")
- /// The bindless texture to reference
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void SetTextureBindless(string propertyName, Handle texture)
- {
- var bindlessIndex = _resourceDatabase.GetBindlessIndex(texture.AsResource());
- if (bindlessIndex == -1)
- {
- throw new ArgumentException("The provided texture does not have a valid bindless index. Ensure the texture is created with bindless support.");
+ return Result.Create(default(T), ResultStatus.InvalidArgument);
}
- SetUInt(propertyName, (uint)bindlessIndex);
+ return Result.Create(*(T*)_cBufferCache.CpuData.GetUnsafePtr(), ResultStatus.Success);
}
- ///
- /// Sets the mesh buffer indices for bindless vertex and index buffer access
- ///
- /// The mesh whose buffer indices to set
- /// The name of the vertex buffer index property
- /// The name of the index buffer index property
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void SetBufferBindless(string propertyName, Handle buffer)
+ public readonly Span GetRawPropertyCache()
{
- var bindlessIndex = _resourceDatabase.GetBindlessIndex(buffer.AsResource());
- if (bindlessIndex == -1)
+ if (_cBufferCache.Size == 0)
{
- throw new ArgumentException("The provided buffer does not have a valid bindless index. Ensure the buffer is created with bindless support.");
+ return Span.Empty;
}
- SetUInt(propertyName, (uint)bindlessIndex);
+ return _cBufferCache.CpuData.AsSpan(0, (int)_cBufferCache.Size);
}
- ///
- /// Uploads all cached material data to the GPU using the specified command buffer.
- ///
- /// The command buffer used to perform the upload operations to the GPU. Cannot be null.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public readonly void UploadMaterialData(ICommandBuffer cmb)
+ public readonly unsafe Result SetPropertyCache(ref readonly T data)
+ where T : unmanaged
{
- for (var i = 0; i < _shader.PassCount; i++)
+ if (sizeof(T) != _cBufferCache.Size)
{
- ref var cache = ref _materialData.GetPassCache(i);
- cmb.UploadBuffer(cache.GpuResource, cache.CpuData.AsSpan());
+ return new Result(false, ResultStatus.InvalidArgument);
}
+
+ Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data);
+ return Result.Success(ResultStatus.Success);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly unsafe Result SetRawPropertyCache(ReadOnlySpan data)
+ {
+ if (data.Length != _cBufferCache.Size)
+ {
+ return new Result(false, ResultStatus.InvalidArgument);
+ }
+
+ Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data);
+ return Result.Success(ResultStatus.Success);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly void UploadData(ICommandBuffer cmb)
+ {
+ cmb.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ void IResourceReleasable.ReleaseResource(IResourceDatabase database)
+ {
+ _cBufferCache.ReleaseResource(database);
}
}
diff --git a/Ghost.Graphics/Core/Mesh.cs b/Ghost.Graphics/Core/Mesh.cs
index 68f27bc..9c6bf54 100644
--- a/Ghost.Graphics/Core/Mesh.cs
+++ b/Ghost.Graphics/Core/Mesh.cs
@@ -11,6 +11,9 @@ namespace Ghost.Graphics.Core;
public struct Mesh : IResourceReleasable, IHandleType
{
+ private UnsafeList _vertices;
+ private UnsafeList _indices;
+
internal bool IsMeshDataDirty
{
get; private set;
@@ -21,10 +24,10 @@ public struct Mesh : IResourceReleasable, IHandleType
///
public UnsafeList Vertices
{
- readonly get => field;
+ readonly get => _vertices;
set
{
- field = value;
+ _vertices = value;
VertexCount = value.Count;
IsMeshDataDirty = true;
}
@@ -35,10 +38,10 @@ public struct Mesh : IResourceReleasable, IHandleType
///
public UnsafeList Indices
{
- readonly get => field;
+ readonly get => _indices;
set
{
- field = value;
+ _indices = value;
IndexCount = value.Count;
IsMeshDataDirty = true;
}
@@ -100,8 +103,8 @@ public struct Mesh : IResourceReleasable, IHandleType
internal Mesh(ReadOnlySpan vertices, ReadOnlySpan indices, Handle vertexBuffer, Handle indexBuffer)
{
- Vertices = new(vertices.Length, Allocator.Persistent);
- Indices = new(indices.Length, Allocator.Persistent);
+ Vertices = new UnsafeList(vertices.Length, Allocator.Persistent);
+ Indices = new UnsafeList(indices.Length, Allocator.Persistent);
Vertices.CopyFrom(vertices);
Indices.CopyFrom(indices);
VertexBuffer = vertexBuffer;
@@ -112,8 +115,8 @@ public struct Mesh : IResourceReleasable, IHandleType
public readonly void ReleaseCpuResources()
{
- Vertices.Dispose();
- Indices.Dispose();
+ _vertices.Dispose();
+ _indices.Dispose();
}
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
diff --git a/Ghost.Graphics/Core/RenderingContext.cs b/Ghost.Graphics/Core/RenderingContext.cs
index 14b6c9a..d11db14 100644
--- a/Ghost.Graphics/Core/RenderingContext.cs
+++ b/Ghost.Graphics/Core/RenderingContext.cs
@@ -56,13 +56,32 @@ public unsafe readonly ref struct RenderingContext
queue.WaitIdle();
}
- public Handle CreateMesh(UnsafeList vertices, UnsafeList indices)
+ public Handle CreateMesh(UnsafeList vertices, UnsafeList indices, bool staticMesh)
{
var mesh = ResourceAllocator.CreateMesh(vertices, indices);
+ ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
+
+ var vertexHandle = meshData.VertexBuffer.AsResource();
+ var indexHandle = meshData.IndexBuffer.AsResource();
+
+ _directCmd.ResourceBarrier(vertexHandle, ResourceState.Common, ResourceState.CopyDest);
+ _directCmd.ResourceBarrier(indexHandle, ResourceState.Common, ResourceState.CopyDest);
+
+ _directCmd.UploadBuffer(meshData.VertexBuffer, meshData.Vertices.AsSpan());
+ _directCmd.UploadBuffer(meshData.IndexBuffer, meshData.Indices.AsSpan());
+
+ _directCmd.ResourceBarrier(vertexHandle, ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
+ _directCmd.ResourceBarrier(indexHandle, ResourceState.CopyDest, ResourceState.IndexBuffer);
+
+ if (staticMesh)
+ {
+ meshData.ReleaseCpuResources();
+ }
+
return mesh;
}
- public Handle CreateMesh(ReadOnlySpan vertices, ReadOnlySpan indices)
+ public Handle CreateMesh(ReadOnlySpan vertices, ReadOnlySpan indices, bool staticMesh)
{
var vertexList = new UnsafeList(vertices.Length, Allocator.Persistent);
var indexList = new UnsafeList(indices.Length, Allocator.Persistent);
@@ -70,12 +89,7 @@ public unsafe readonly ref struct RenderingContext
vertexList.CopyFrom(vertices);
indexList.CopyFrom(indices);
- return CreateMesh(vertexList, indexList);
- }
-
- public MaterialAccessor GetMaterialAccessor(Handle material)
- {
- return new MaterialAccessor(material, ResourceDatabase);
+ return CreateMesh(vertexList, indexList, staticMesh);
}
// TODO: Make one memory pool for upload.
@@ -108,12 +122,12 @@ public unsafe readonly ref struct RenderingContext
if (needVertexTransition)
{
- _directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
+ _directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
}
if (needIndexTransition)
{
- _directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.IndexBuffer);
+ _directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, indexState);
}
if (markMeshStatic)
@@ -177,7 +191,7 @@ public unsafe readonly ref struct RenderingContext
slicePitch = slicePitch
};
- _directCmd.UploadTexture(texture, subresourceData);
+ _directCmd.UploadTexture(texture, [subresourceData]);
}
if (needTransition)
@@ -194,10 +208,15 @@ public unsafe readonly ref struct RenderingContext
ref var materialRef = ref ResourceDatabase.GetMaterialReference(material);
var shader = ResourceDatabase.GetShaderReference(materialRef.Shader);
- shader.TryGetPassKey(passName, out var passIndex, out var passKey);
+ var keyResult = shader.TryGetPassKey(passName, out var passIndex);
+ if (keyResult.Status != ResultStatus.Success)
+ {
+ throw new Exception(keyResult.ToString());
+ }
+
var hash = new GraphicsPipelineHash
{
- Id = passKey,
+ Id = keyResult.Value.Identifier,
RtvCount = 1,
DsvFormat = TextureFormat.Unknown,
};
@@ -209,20 +228,13 @@ public unsafe readonly ref struct RenderingContext
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_OBJECT_BUFFER_SLOT, meshRef.ObjectDataBuffer);
// NOTE: We use fixed root signature layout for bindless rendering.
- ref var cache = ref materialRef.GetPassCache(passIndex);
+ var cache = materialRef.CBufferCache;
if (cache.IsCreated)
{
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
}
- // NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
- // TODO: Maybe handle the traditional bindless model?
-#if false
- var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
- _commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
-#endif
-
- //var threadGroupCountX = ((uint)meshRef.IndexCount + numThreadsX - 1) / numThreadsX;
- _directCmd.DispatchMesh(1, 1, 1);
+ var threadGroupCountX = ((uint)meshRef.IndexCount + numThreadsX - 1) / numThreadsX;
+ _directCmd.DispatchMesh(threadGroupCountX, 1, 1);
}
}
\ No newline at end of file
diff --git a/Ghost.Graphics/Core/Shader.cs b/Ghost.Graphics/Core/Shader.cs
index eb353ad..9d56a77 100644
--- a/Ghost.Graphics/Core/Shader.cs
+++ b/Ghost.Graphics/Core/Shader.cs
@@ -3,45 +3,44 @@ using Ghost.Core.Graphics;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
-using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
namespace Ghost.Graphics.Core;
-public class ShaderPass : IResourceReleasable
+public struct ShaderPass : IResourceReleasable
{
- private CBufferInfo _cbufferInfo;
- // NOTE: This is for per pass cbuffer only. Global, per view, and per mesh cbuffers are fixed.
- private readonly Dictionary _propertyLookup;
-
- public CBufferInfo CBuffer => _cbufferInfo;
-
- public ShaderPass(CBufferInfo info)
+ public ShaderPassKey Identifier
{
- _cbufferInfo = info;
-
- var capacity = info.Properties?.Count ?? 0;
- _propertyLookup = new Dictionary(capacity);
- for (var i = 0; i < capacity; i++)
- {
- _propertyLookup[info.Properties![i].Name] = i;
- }
+ get; init;
}
- public int GetPropertyId(string propertyName)
+ public ZTestOptions ZTest
{
- return _propertyLookup.TryGetValue(propertyName, out var id) ? id : -1;
+ get; set;
}
- public CBufferPropertyInfo GetPropertyInfo(int id)
+ public ZWriteOptions ZWrite
{
- return _cbufferInfo.Properties[id];
+ get; set;
}
- public CBufferPropertyInfo GetPropertyInfo(string propertyName)
+ public CullOptions Cull
{
- return _cbufferInfo.Properties[GetPropertyId(propertyName)];
+ get; set;
}
+ public BlendOptions Blend
+ {
+ get; set;
+ }
+
+ public uint ColorMask
+ {
+ get; set;
+ }
+
+ // TODO: Shader variant.
+
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
{
}
@@ -52,46 +51,43 @@ public class ShaderPass : IResourceReleasable
///
public class Shader : IResourceReleasable, IIdentifierType
{
- private UnsafeArray _passIDs;
+ private readonly uint _cbufferSize;
+ private UnsafeArray _passes;
// TODO: Optmize lookups with a better data structure if needed
private readonly Dictionary _passLookup; // pass name to index
- private readonly Dictionary> _propertyLookup; // property name to pass index (property name to list of pass indices that contain the property)
- public int PassCount => _passIDs.Count;
+ public int PassCount => _passes.Count;
+ public uint CBufferSize => _cbufferSize;
internal Shader(ShaderDescriptor descriptor)
{
- _passIDs = new UnsafeArray(descriptor.passes.Count, Allocator.Persistent);
- _passLookup = new(descriptor.passes.Count);
- _propertyLookup = new(descriptor.passes.Count);
+ _cbufferSize = descriptor.cbufferSize;
+ _passes = new UnsafeArray(descriptor.passes.Count, Allocator.Persistent);
+ _passLookup = new Dictionary(descriptor.passes.Count);
for (var i = 0; i < descriptor.passes.Count; i++)
{
var pass = descriptor.passes[i];
+
+ // TODO: Handle inherited passes
+ if (pass is not FullPassDescriptor fullPass)
+ {
+ continue;
+ }
+
var passKey = new ShaderPassKey(pass.Identifier);
- _passIDs[i] = passKey;
- _passLookup[pass.Name] = i;
-
- if (pass is FullPassDescriptor fullPass)
+ _passes[i] = new ShaderPass
{
- if (fullPass.properties == null)
- {
- continue;
- }
+ Identifier = passKey,
+ ZTest = fullPass.localPipeline.zTest,
+ ZWrite = fullPass.localPipeline.zWrite,
+ Cull = fullPass.localPipeline.cull,
+ Blend = fullPass.localPipeline.blend,
+ ColorMask = fullPass.localPipeline.colorMask
+ };
- foreach (var property in fullPass.properties)
- {
- ref var passIndices = ref CollectionsMarshal.GetValueRefOrAddDefault(_propertyLookup, property.name, out var exists);
- if (!exists || passIndices == null)
- {
- passIndices = new List();
- }
-
- passIndices.Add(i);
- }
- }
- // TODO: handle inherited passes
+ _passLookup[pass.Name] = i;
}
}
@@ -100,38 +96,26 @@ public class Shader : IResourceReleasable, IIdentifierType
return _passLookup.GetValueOrDefault(passName, -1);
}
- public ShaderPassKey GetPassKey(int index)
+ public ref ShaderPass GetPassReference(int index)
{
- return _passIDs[index];
+ return ref _passes[index];
}
- public bool TryGetPassKey(string passName, out int passIndex, out ShaderPassKey passID)
+ public RefResult TryGetPassKey(string passName, out int passIndex)
{
var index = _passLookup.GetValueOrDefault(passName, -1);
if (index == -1)
{
passIndex = -1;
- passID = new(0);
- return false;
+ return Result.CreateRef(ref Unsafe.NullRef(), ResultStatus.NotFound);
}
passIndex = index;
- passID = _passIDs[index];
- return true;
- }
-
- public IReadOnlyCollection GetPropertyPassIndices(string propertyName)
- {
- if (_propertyLookup.TryGetValue(propertyName, out var passIndices))
- {
- return passIndices;
- }
-
- return Array.Empty();
+ return Result.CreateRef(ref _passes[index], ResultStatus.Success);
}
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
{
- _passIDs.Dispose();
+ _passes.Dispose();
}
}
diff --git a/Ghost.Graphics/Core/Vertex.cs b/Ghost.Graphics/Core/Vertex.cs
index aaacf45..b47b066 100644
--- a/Ghost.Graphics/Core/Vertex.cs
+++ b/Ghost.Graphics/Core/Vertex.cs
@@ -9,7 +9,7 @@ namespace Ghost.Graphics.Core;
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
- public unsafe static class Semantic
+ public static class Semantic
{
public const DXGI_FORMAT ALIGNED_FORMAT = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT;
public const int COUNT = 5;
diff --git a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs
index 6f47fef..08e5dfd 100644
--- a/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs
+++ b/Ghost.Graphics/D3D12/D3D12CommandBuffer.cs
@@ -173,17 +173,65 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
}
- public void ResourceBarrier(Handle resource, ResourceState before, ResourceState after)
+ public void ResourceBarrier(ReadOnlySpan barrierDescs)
{
ThrowIfDisposed();
ThrowIfNotRecording();
IncrementCommandCount();
- var d3d12Resource = _resourceDatabase.GetResource(resource);
- var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
- before.ToD3D12States(), after.ToD3D12States());
+ var count = 0u;
+ var pBarriers = stackalloc D3D12_RESOURCE_BARRIER[barrierDescs.Length];
+
+ for (int i = 0; i < barrierDescs.Length; i++)
+ {
+ var desc = barrierDescs[i];
+ if (desc.StateBefore == desc.StateAfter)
+ {
+ continue;
+ }
+
+ if (!desc.Resource.IsValid)
+ {
+ throw new ArgumentException($"Barrier resource at index {i} is not a valid resource handle");
+ }
+
+ ref var resourceRecord = ref _resourceDatabase.GetResourceRecord(desc.Resource.AsResource());
+ if (resourceRecord.state != desc.StateBefore)
+ {
+ throw new InvalidOperationException($"Resource state mismatch: expected {desc.StateBefore}, actual {resourceRecord.state}");
+ }
+
+ var barrier = D3D12_RESOURCE_BARRIER.InitTransition(resourceRecord.ResourcePtr,
+ desc.StateBefore.ToD3D12States(), desc.StateAfter.ToD3D12States());
+
+ pBarriers[count] = barrier;
+ count++;
+
+ // Update the resource state in the database
+ resourceRecord.state = desc.StateAfter;
+ }
+
+ _commandList.Get()->ResourceBarrier(count, pBarriers);
+ }
+
+ public void ResourceBarrier(Handle resource, ResourceState stateBefore, ResourceState stateAfter)
+ {
+ if (stateBefore == stateAfter)
+ {
+ return;
+ }
+
+ ref var resourceRecord = ref _resourceDatabase.GetResourceRecord(resource);
+ if (resourceRecord.state != stateBefore)
+ {
+ throw new InvalidOperationException($"Resource state mismatch: expected {stateBefore}, actual {resourceRecord.state}");
+ }
+
+ var barrier = D3D12_RESOURCE_BARRIER.InitTransition(resourceRecord.ResourcePtr,
+ stateBefore.ToD3D12States(), stateAfter.ToD3D12States());
_commandList.Get()->ResourceBarrier(1, &barrier);
+ resourceRecord.state = stateAfter;
}
public void SetRenderTargets(ReadOnlySpan> renderTargets, Handle depthTarget)
@@ -465,7 +513,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
}
- public void UploadTexture(Handle texture, params ReadOnlySpan subresources)
+ public void UploadTexture(Handle texture, ReadOnlySpan subresources)
{
ThrowIfDisposed();
ThrowIfNotRecording();
diff --git a/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs b/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs
index 35fa603..7c4dfcb 100644
--- a/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs
+++ b/Ghost.Graphics/D3D12/D3D12DescriptorAllocator.cs
@@ -19,7 +19,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
private bool _disposed;
- public unsafe D3D12DescriptorAllocator(D3D12RenderDevice device, int initialRtvCount = 256, int initialDsvCount = 256, int initialSrvCount = 200_000, int initialSamplerCount = 256)
+ public D3D12DescriptorAllocator(D3D12RenderDevice device, int initialRtvCount = 256, int initialDsvCount = 256, int initialSrvCount = 200_000, int initialSamplerCount = 256)
{
_rtvHeap = new D3D12DescriptorHeap("rtv", device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, initialRtvCount, initialRtvCount / 2);
_dsvHeap = new D3D12DescriptorHeap("dsv", device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, initialDsvCount, initialDsvCount / 2);
diff --git a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs
index 4fecc9c..f87700a 100644
--- a/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs
+++ b/Ghost.Graphics/D3D12/D3D12GraphicsEngine.cs
@@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
namespace Ghost.Graphics.D3D12;
-internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
+internal class D3D12GraphicsEngine : IGraphicsEngine
{
#if DEBUG
private readonly D3D12DebugLayer _debugLayer;
@@ -34,17 +34,17 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
public D3D12GraphicsEngine(IRenderSystem renderSystem)
{
#if DEBUG
- _debugLayer = new();
+ _debugLayer = new D3D12DebugLayer();
#endif
- _device = new();
- _shaderCompiler = new();
- _descriptorAllocator = new(_device);
+ _device = new D3D12RenderDevice();
+ _shaderCompiler = new DxcShaderCompiler();
+ _descriptorAllocator = new D3D12DescriptorAllocator(_device);
- _resourceDatabase = new(_descriptorAllocator);
- _pipelineLibrary = new(_device, _resourceDatabase);
- _resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
+ _resourceDatabase = new D3D12ResourceDatabase(_descriptorAllocator);
+ _pipelineLibrary = new D3D12PipelineLibrary(_device, _resourceDatabase);
+ _resourceAllocator = new D3D12ResourceAllocator(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
- _copyCommandBuffer = new(
+ _copyCommandBuffer = new D3D12CommandBuffer(
_device,
_pipelineLibrary,
_resourceDatabase,
@@ -136,6 +136,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
_copyCommandBuffer.End();
_resourceAllocator.ReleaseTempResources();
+ _descriptorAllocator.ResetCbvSrvUavDynamicHeap();
+ _descriptorAllocator.ResetDSVDynamicHeap();
+ _descriptorAllocator.ResetRTVDynamicHeap();
}
public void Dispose()
diff --git a/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs b/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs
index 3116caa..f911ee7 100644
--- a/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs
+++ b/Ghost.Graphics/D3D12/D3D12PipelineLibrary.cs
@@ -8,8 +8,6 @@ using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
-using Misaki.HighPerformance.LowLevel.Utilities;
-using Misaki.HighPerformance.Utilities;
using System.Runtime.InteropServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
@@ -40,7 +38,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
private UniquePtr _defaultRootSignature;
private readonly Dictionary _pipelineCache;
- private readonly Dictionary _cbufferInfoCache;
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
@@ -50,9 +47,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
_resourceDatabase = resourceDatabase;
_pipelineCache = new Dictionary();
- _cbufferInfoCache = new Dictionary();
- CreateDefaultRootSignature();
+ CreateDefaultRootSignature().ThrowIfFailed();
}
private Result CreateDefaultRootSignature()
@@ -140,36 +136,21 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
Desc_1_1 = rootSignatureDesc
};
- ID3DBlob* pSignature = default;
- ID3DBlob* pError = default;
+ using ComPtr pSignature = default;
+ using ComPtr pError = default;
- try
+ var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, pSignature.GetAddressOf(), pError.GetAddressOf());
+ if (serializeResult.FAILED)
{
- var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, &pSignature, &pError);
- if (serializeResult.FAILED)
- {
- var errorMsg = pError != null ? Marshal.PtrToStringUTF8((nint)pError->GetBufferPointer()) : "Unknown error";
- return Result.Failure($"Failed to serialize default root signature: {errorMsg}");
- }
-
- ID3D12RootSignature* pRootSignature = default;
- ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
- __uuidof(pRootSignature), (void**)&pRootSignature));
-
- _defaultRootSignature.Attach(pRootSignature);
+ var errorMsg = pError.Get() != null ? Marshal.PtrToStringUTF8((nint)pError.Get()->GetBufferPointer()) : "Unknown error";
+ return Result.Failure($"Failed to serialize default root signature: {errorMsg}");
}
- finally
- {
- if (pSignature != null)
- {
- pSignature->Release();
- }
- if (pError != null)
- {
- pError->Release();
- }
- }
+ ID3D12RootSignature* pRootSignature = default;
+ ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature.Get()->GetBufferPointer(), pSignature.Get()->GetBufferSize(),
+ __uuidof(pRootSignature), (void**)&pRootSignature));
+
+ _defaultRootSignature.Attach(pRootSignature);
return Result.Success();
}
@@ -337,8 +318,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
return Result.Failure(result.Message);
}
- _cbufferInfoCache[descriptor.PassId] = result.Value;
-
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
{
pRootSignature = _defaultRootSignature.Get(),
@@ -422,16 +401,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
return key;
}
- public Result GetCBufferInfo(ShaderPassKey passId)
- {
- if (_cbufferInfoCache.TryGetValue(passId, out var cbufferInfo))
- {
- return Result.Create(cbufferInfo, ResultStatus.Success);
- }
-
- return Result.Create(default(CBufferInfo), ResultStatus.NotFound);
- }
-
public Result, ResultStatus> GetGraphicsPSO(GraphicsPipelineKey key)
{
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
diff --git a/Ghost.Graphics/D3D12/D3D12Renderer.cs b/Ghost.Graphics/D3D12/D3D12Renderer.cs
index 14784df..223bd7e 100644
--- a/Ghost.Graphics/D3D12/D3D12Renderer.cs
+++ b/Ghost.Graphics/D3D12/D3D12Renderer.cs
@@ -31,7 +31,6 @@ internal class D3D12Renderer : IRenderer
}
private readonly D3D12GraphicsEngine _graphicsEngine;
- private readonly D3D12CommandQueue _commandQueue;
private readonly FrameResource[] _frameResources;
private uint _frameIndex;
@@ -60,7 +59,6 @@ internal class D3D12Renderer : IRenderer
public D3D12Renderer(D3D12GraphicsEngine graphicsEngine, D3D12ResourceAllocator resourceAllocator, D3D12ResourceDatabase resourceDatabase)
{
_graphicsEngine = graphicsEngine;
- _commandQueue = (D3D12CommandQueue)graphicsEngine.Device.GraphicsQueue;
_resourceAllocator = resourceAllocator;
_resourceDatabase = resourceDatabase;
@@ -153,7 +151,7 @@ internal class D3D12Renderer : IRenderer
_swapChain?.Resize(newSize.x, newSize.y);
_currentSize = newSize;
- // Update off-screen render target size
+ // Update off-screen render Target size
if (_swapChain != null)
{
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
@@ -170,7 +168,7 @@ internal class D3D12Renderer : IRenderer
if (frame.fenceValue > 0)
{
- _commandQueue.WaitForValue(frame.fenceValue);
+ _graphicsEngine.Device.GraphicsQueue.WaitForValue(frame.fenceValue);
}
if (_renderTarget.IsValid)
@@ -202,12 +200,12 @@ internal class D3D12Renderer : IRenderer
frame.commandBuffer.End();
- _commandQueue.Submit(frame.commandBuffer);
+ _graphicsEngine.Device.GraphicsQueue.Submit(frame.commandBuffer);
_swapChain?.Present();
}
- frame.fenceValue = _commandQueue.Signal(_frameIndex);
+ frame.fenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_frameIndex);
_frameIndex++;
}
@@ -257,7 +255,7 @@ internal class D3D12Renderer : IRenderer
// Handle swap chain back buffer transitions if needed
if (_swapChain != null)
{
- // Transition back buffer to render target
+ // Transition back buffer to render Target
cmd.ResourceBarrier(destination.AsResource(), ResourceState.Present, ResourceState.RenderTarget);
}
@@ -266,7 +264,7 @@ internal class D3D12Renderer : IRenderer
// FIX: Implement proper blit operation with shader
// This is a placeholder - in D3D12, you would typically:
- // 1. Set render target to the destination
+ // 1. Set render Target to the destination
// 2. Use a full-screen quad/triangle with a shader that samples from the source
// Handle swap chain back buffer transitions if needed
@@ -284,7 +282,7 @@ internal class D3D12Renderer : IRenderer
{
if (frame.fenceValue > 0)
{
- _commandQueue.WaitForValue(frame.fenceValue);
+ _graphicsEngine.Device.GraphicsQueue.WaitForValue(frame.fenceValue);
}
}
}
@@ -301,8 +299,8 @@ internal class D3D12Renderer : IRenderer
// NOTE: Testing only.
_pass.Cleanup(_resourceDatabase);
- // If using a swap chain, release the off-screen render target.
- // Otherwise, the render target is managed externally.
+ // If using a swap chain, release the off-screen render Target.
+ // Otherwise, the render Target is managed externally.
if (_swapChain != null)
{
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
diff --git a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs
index fc33db4..a5433c4 100644
--- a/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs
+++ b/Ghost.Graphics/D3D12/D3D12ResourceAllocator.cs
@@ -5,7 +5,7 @@ using Ghost.Graphics.Core;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Collections;
-using Misaki.HighPerformance.Mathematics;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
@@ -522,10 +522,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator
return D3D12_RESOURCE_STATE_COPY_DEST;
}
- // Default to Common, but check for specific roles
var state = D3D12_RESOURCE_STATE_COMMON;
+#if true
return state;
-
+#else
+ // D3D12 does not support state other than COMMON for buffers at creation.
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
{
// Vertex and Constant buffers can share this state
@@ -564,6 +565,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
// If it's a mix, start in common and let the user barrier
return D3D12_RESOURCE_STATE_COMMON;
+#endif
}
private static ResourceState D3D12StatesToRHIState(D3D12_RESOURCE_STATES states)
@@ -605,7 +607,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
private readonly D3D12ResourceDatabase _resourceDatabase;
private readonly D3D12PipelineLibrary _pipelineLibrary;
- private UnsafeQueue> _temResources;
+ private UnsafeQueue> _tempResources;
private bool _disposed;
@@ -633,7 +635,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
_resourceDatabase = resourceDatabase;
_pipelineLibrary = pipelineLibrary;
- _temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
+ _tempResources = new UnsafeQueue>(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
}
~D3D12ResourceAllocator()
@@ -648,7 +650,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
if (isTemp)
{
- _temResources.Enqueue(handle);
+ _tempResources.Enqueue(handle);
}
return handle;
@@ -714,13 +716,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
var initialState = DetermineInitialTextureState(desc.Usage);
D3D12MA_Allocation* pAllocation = default;
- ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
+ var iid = IID.IID_NULL;
+ ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, &iid, null));
var resourceDescriptor = ResourceViewGroup.Invalid;
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
{
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
- var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv);
+ // TODO: Maybe use non-shader-visible descriptor first then batch copy to shader-visible heap later?
+ var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.srv);
var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
var srvDesc = CreateTextureSrvDesc(pAllocation->GetResource(), mipLevels, desc.Slice, isCubeMap);
@@ -749,7 +753,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
{
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
- var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
+ var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.uav);
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
@@ -906,24 +910,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
ObjectDisposedException.ThrowIf(_disposed, this);
var shader = new Shader(descriptor);
- foreach (var pass in descriptor.passes)
- {
- if (pass is not FullPassDescriptor fullPass)
- {
- continue;
- }
-
- // TODO: Cache the pass key because we hash it multiple times right now.
- var passKey = new ShaderPassKey(fullPass.Identifier);
- var cbr = _pipelineLibrary.GetCBufferInfo(passKey);
- if (cbr.Status != ResultStatus.Success)
- {
- return Identifier.Invalid;
- }
-
- _resourceDatabase.AddShaderPass(passKey, new ShaderPass(cbr.Value));
- }
-
return _resourceDatabase.AddShader(shader);
}
@@ -931,14 +917,14 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
{
ObjectDisposedException.ThrowIf(_disposed, this);
- while (_temResources.Count > 0)
+ while (_tempResources.Count > 0)
{
- var handle = _temResources.Peek();
- ref var info = ref _resourceDatabase.GetResourceInfo(handle, out var exist);
+ var handle = _tempResources.Peek();
+ ref var info = ref _resourceDatabase.GetResourceRecord(handle, out var exist);
if (!exist || !info.Allocated)
{
// Resource already released or invalid, just dequeue
- _temResources.Dequeue();
+ _tempResources.Dequeue();
continue;
}
@@ -950,7 +936,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
}
_resourceDatabase.ReleaseResource(handle);
- _temResources.Dequeue();
+ _tempResources.Dequeue();
}
}
@@ -961,20 +947,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
return;
}
-#if DEBUG || GHOST_EDITOR
- if (_temResources.Count > 0)
- {
- throw new InvalidOperationException($"ResourceAllocator is being disposed with {_temResources.Count} temp allocations still registered. Ensure all resources are released before disposing.");
- }
-#endif
+ Debug.Assert(_tempResources.Count == 0, "Temporary resources should be released before disposing the allocator.");
- foreach (var handle in _temResources)
+ foreach (var handle in _tempResources)
{
_resourceDatabase.ReleaseResource(handle);
}
_d3d12MA.Dispose();
- _temResources.Dispose();
+ _tempResources.Dispose();
_disposed = true;
GC.SuppressFinalize(this);
diff --git a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs
index 1660a02..816a22c 100644
--- a/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs
+++ b/Ghost.Graphics/D3D12/D3D12ResourceDatabase.cs
@@ -1,11 +1,11 @@
using Ghost.Core;
using Ghost.Graphics.Core;
+using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.Collections;
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
-using System.Diagnostics;
using System.Runtime.InteropServices;
using TerraFX.Interop.DirectX;
@@ -42,7 +42,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
public readonly bool isExternal;
public readonly bool Allocated => isExternal ? resourceUnion.resource.Get() != null : resourceUnion.allocation.Get() != null;
- public readonly ID3D12Resource* ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
+ public readonly SharedPtr ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
public ResourceRecord(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState state, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
{
@@ -131,7 +131,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
resource = default!;
}
- public unsafe Handle ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string? name = null)
+ public unsafe Handle ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string name = "")
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -139,16 +139,14 @@ internal class D3D12ResourceDatabase : IResourceDatabase
var handle = new Handle(id, generation);
#if DEBUG || GHOST_EDITOR
- if (name != null)
- {
- _resourceName[handle] = name;
- }
+ pResource->SetName(name);
+ _resourceName[handle] = name;
#endif
return handle;
}
- public unsafe Handle AddResource(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
+ public unsafe Handle AddResource(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string name = "")
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -156,10 +154,8 @@ internal class D3D12ResourceDatabase : IResourceDatabase
var handle = new Handle(id, generation);
#if DEBUG || GHOST_EDITOR
- if (name != null)
- {
- _resourceName[handle] = name;
- }
+ allocation->SetName(name);
+ _resourceName[handle] = name;
#endif
return handle;
@@ -184,7 +180,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
return ref info;
}
- public ref ResourceRecord GetResourceInfo(Handle handle, out bool exist)
+ public ref ResourceRecord GetResourceRecord(Handle handle, out bool exist)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
@@ -232,7 +228,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
{
ObjectDisposedException.ThrowIf(_disposed, this);
- ref var info = ref GetResourceInfo(handle, out var exist);
+ ref var info = ref GetResourceRecord(handle, out var exist);
if (!exist || !info.Allocated)
{
return -1;
@@ -254,7 +250,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
return null;
}
- public unsafe void ReleaseResource(Handle handle)
+ public void ReleaseResource(Handle handle)
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -269,14 +265,10 @@ internal class D3D12ResourceDatabase : IResourceDatabase
return;
}
- var refCount = info.Release(_descriptorAllocator);
+ info.Release(_descriptorAllocator);
+ //Debug.Assert(info.Release(_descriptorAllocator) == 0);
#if DEBUG || GHOST_EDITOR
_resourceName.Remove(handle, out var name);
- //if (refCount > 0)
- //{
- // throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource");
- //}
- //Debug.Assert(refCount == 0, "Resource released with non-zero reference count.");
#endif
_resources.Remove(handle.id, handle.generation);
@@ -405,34 +397,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
ReleaseResource(ref shader);
}
- public void AddShaderPass(ShaderPassKey passKey, ShaderPass pass)
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
- _shaderPasses.Add(passKey, pass);
- }
-
- public ShaderPass GetShaderPass(ShaderPassKey passKey)
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (!_shaderPasses.TryGetValue(passKey, out var pass))
- {
- throw new KeyNotFoundException($"Shader pass '{passKey}' not found.");
- }
-
- return pass;
- }
-
- public void RemoveShaderPass(ShaderPassKey passKey)
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
-
- if (_shaderPasses.Remove(passKey, out var pass))
- {
- ReleaseResource(ref pass);
- }
- }
-
public void Dispose()
{
static void ThrowMemoryLeakException(string resourceType, int count)
diff --git a/Ghost.Graphics/D3D12/D3D12SwapChain.cs b/Ghost.Graphics/D3D12/D3D12SwapChain.cs
index c458afd..570e530 100644
--- a/Ghost.Graphics/D3D12/D3D12SwapChain.cs
+++ b/Ghost.Graphics/D3D12/D3D12SwapChain.cs
@@ -7,6 +7,7 @@ using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
@@ -27,7 +28,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
private UniquePtr _swapChain;
private UnsafeArray> _backBuffers;
- private object? _compositionSurface;
+ private readonly object? _compositionSurface;
private bool _disposed;
@@ -48,20 +49,22 @@ internal unsafe class D3D12SwapChain : ISwapChain
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc)
{
+ Debug.Assert(desc.BufferCount >= 2);
+
_resourceDatabase = resourceDatabase;
_descriptorAllocator = descriptorAllocator;
_renderDevice = device;
- _backBuffers = new UnsafeArray>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent);
+ _backBuffers = new UnsafeArray>((int)desc.BufferCount, Allocator.Persistent);
- Width = desc.width;
- Height = desc.height;
- BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT;
+ Width = desc.Width;
+ Height = desc.Height;
+ BufferCount = desc.BufferCount;
CreateSwapChain(desc);
CreateBackBuffers();
- _compositionSurface = desc.target.compositionSurface;
+ _compositionSurface = desc.Target.CompositionSurface;
}
~D3D12SwapChain()
@@ -73,9 +76,9 @@ internal unsafe class D3D12SwapChain : ISwapChain
{
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
{
- Width = desc.width,
- Height = desc.height,
- Format = desc.format.ToDXGIFormat(),
+ Width = desc.Width,
+ Height = desc.Height,
+ Format = desc.Format.ToDXGIFormat(),
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
BufferUsage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT,
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT,
@@ -91,15 +94,15 @@ internal unsafe class D3D12SwapChain : ISwapChain
var pFactory = _renderDevice.DXGIFactory.Get();
var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get();
- switch (desc.target.type)
+ switch (desc.Target.Type)
{
case SwapChainTargetType.Composition:
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
// Set the composition surface
- if (desc.target.compositionSurface != null)
+ if (desc.Target.CompositionSurface != null)
{
- using var swapChainPanelNative = ISwapChainPanelNative.FromSwapChainPanel(desc.target.compositionSurface);
+ using var swapChainPanelNative = ISwapChainPanelNative.FromSwapChainPanel(desc.Target.CompositionSurface);
swapChainPanelNative.SetSwapChain((IntPtr)pTempSwapChain);
}
break;
@@ -112,7 +115,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
pFactory->CreateSwapChainForHwnd(
(IUnknown*)pCommandQueue,
- new HWND(desc.target.windowHandle.ToPointer()),
+ new HWND(desc.Target.WindowHandle.ToPointer()),
&swapChainDesc,
&swapChainFullscreenDesc,
null,
@@ -141,7 +144,12 @@ internal unsafe class D3D12SwapChain : ISwapChain
var rtv = _descriptorAllocator.AllocateRTV();
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
- var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, new ResourceViewGroup() { rtv = rtv });
+ var view = ResourceViewGroup.Invalid with
+ {
+ rtv = rtv
+ };
+
+ var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, view);
_backBuffers[i] = handle.AsTexture();
}
}
diff --git a/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs b/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs
index 31d8446..d32ed59 100644
--- a/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs
+++ b/Ghost.Graphics/D3D12/Utilities/D3D12DescriptorHeap.cs
@@ -164,12 +164,17 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
public void ReleaseDescriptors(int baseIndex, int count = 1)
{
+ if (baseIndex == _INVALID_DESCRIPTOR_INDEX)
+ {
+ return;
+ }
+
if (count == 0)
{
return;
}
- if (baseIndex < _dynamicHeapStart)
+ if (baseIndex >= _dynamicHeapStart)
{
// Dynamic allocations are not released individually.
return;
diff --git a/Ghost.Graphics/D3D12/Utilities/D3D12Utility.cs b/Ghost.Graphics/D3D12/Utilities/D3D12Utility.cs
index 21ff439..d75ea0a 100644
--- a/Ghost.Graphics/D3D12/Utilities/D3D12Utility.cs
+++ b/Ghost.Graphics/D3D12/Utilities/D3D12Utility.cs
@@ -10,6 +10,19 @@ internal unsafe static class D3D12Utility
{
public static void SetName(ref this T obj, ReadOnlySpan name)
where T : unmanaged, ID3D12Object.Interface
+ {
+ if (name.Length == 0)
+ {
+ return;
+ }
+
+ fixed (char* pName = name)
+ {
+ obj.SetName(pName);
+ }
+ }
+
+ public static void SetName(ref this D3D12MA_Allocation obj, ReadOnlySpan name)
{
fixed (char* pName = name)
{
diff --git a/Ghost.Graphics/Ghost.Graphics.csproj b/Ghost.Graphics/Ghost.Graphics.csproj
index 0acf480..a122b0b 100644
--- a/Ghost.Graphics/Ghost.Graphics.csproj
+++ b/Ghost.Graphics/Ghost.Graphics.csproj
@@ -10,10 +10,12 @@
True
+ True
True
+ True
@@ -52,4 +54,10 @@
+
+
+ ..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net10.0\Misaki.HighPerformance.LowLevel.dll
+
+
+
diff --git a/Ghost.Graphics/RHI/Common.cs b/Ghost.Graphics/RHI/Common.cs
index bb601bb..cbaea5c 100644
--- a/Ghost.Graphics/RHI/Common.cs
+++ b/Ghost.Graphics/RHI/Common.cs
@@ -154,7 +154,6 @@ public ref struct GraphicsPSODescriptor
get; set;
}
-
public ReadOnlySpan RtvFormats
{
get; set;
@@ -267,7 +266,6 @@ public struct RectDesc
{
get; set;
}
-
}
public struct SubResourceData
@@ -311,6 +309,24 @@ public struct PassDepthStencilDesc
}
+public struct BarrierDesc
+{
+ public Handle Resource
+ {
+ get; set;
+ }
+
+ public ResourceState StateBefore
+ {
+ get; set;
+ }
+
+ public ResourceState StateAfter
+ {
+ get; set;
+ }
+}
+
public struct ResourceDesc
{
[StructLayout(LayoutKind.Explicit)]
@@ -381,13 +397,13 @@ public struct ResourceDesc
}
///
-/// Render target description
+/// Render Target description
/// Supports either color OR depth rendering, not both
///
public struct RenderTargetDesc
{
///
- /// Width of the render target
+ /// Width of the render Target
///
public uint Width
{
@@ -395,7 +411,7 @@ public struct RenderTargetDesc
}
///
- /// Height of the render target
+ /// Height of the render Target
///
public uint Height
{
@@ -403,7 +419,7 @@ public struct RenderTargetDesc
}
///
- /// Slice of the render target
+ /// Slice of the render Target
///
public uint Slice
{
@@ -411,7 +427,7 @@ public struct RenderTargetDesc
}
///
- /// Type of render target
+ /// Type of render Target
///
public RenderTargetType Type
{
@@ -419,7 +435,7 @@ public struct RenderTargetDesc
}
///
- /// Target texture format
+ /// Target texture Format
///
public TextureFormat Format
{
@@ -435,7 +451,7 @@ public struct RenderTargetDesc
}
///
- /// Creation flags for the render target
+ /// Creation flags for the render Target
///
public RenderTargetCreationFlags CreationFlags
{
@@ -459,7 +475,7 @@ public struct RenderTargetDesc
}
///
- /// Creates a color render target
+ /// Creates a color render Target
///
public static RenderTargetDesc Color(uint width, uint height, uint slice = 1,
TextureFormat format = TextureFormat.R8G8B8A8_UNorm, TextureDimension dimension = TextureDimension.Texture2D,
@@ -481,7 +497,7 @@ public struct RenderTargetDesc
}
///
- /// Creates a depth render target
+ /// Creates a depth render Target
///
public static RenderTargetDesc Depth(uint width, uint height, uint slice = 1,
TextureFormat format = TextureFormat.D24_UNorm_S8_UInt, TextureDimension dimension = TextureDimension.Texture2D,
@@ -554,7 +570,7 @@ public struct TextureDesc
}
///
- /// Texture format
+ /// Texture Format
///
public TextureFormat Format
{
@@ -630,59 +646,82 @@ public struct SwapChainDesc
///
/// Width of the swap chain
///
- public uint width;
+ public uint Width
+ {
+ get; set;
+ }
///
/// Height of the swap chain
///
- public uint height;
-
- ///
- /// Back buffer format
- ///
- public TextureFormat format;
-
- ///
- /// Target for presentation (window handle or composition target)
- ///
- public SwapChainTarget target;
-
- public SwapChainDesc(uint width, uint height, SwapChainTarget target, TextureFormat format = TextureFormat.B8G8R8A8_UNorm, uint bufferCount = 2)
+ public uint Height
{
- this.width = width;
- this.height = height;
- this.format = format;
- this.target = target;
+ get; set;
+ }
+
+
+ ///
+ /// Back buffer Format
+ ///
+ public TextureFormat Format
+ {
+ get; set;
+ }
+
+
+ ///
+ /// Target for presentation (window handle or composition Target)
+ ///
+ public SwapChainTarget Target
+ {
+ get; set;
+ }
+
+ public uint BufferCount
+ {
+ get; set;
}
}
///
-/// Swap chain target (window handle or composition surface)
+/// Swap chain Target (window handle or composition surface)
///
public struct SwapChainTarget
{
///
/// Target type
///
- public SwapChainTargetType type;
+ public SwapChainTargetType Type
+ {
+ get; set;
+ }
+
///
/// Window handle for HWND targets
///
- public nint windowHandle;
+ public nint WindowHandle
+ {
+ get; set;
+ }
+
///
/// Composition surface for UWP/WinUI targets
///
- public object? compositionSurface;
+ public object? CompositionSurface
+ {
+ get; set;
+ }
+
public static SwapChainTarget FromWindowHandle(nint hwnd)
{
return new SwapChainTarget
{
- type = SwapChainTargetType.WindowHandle,
- windowHandle = hwnd,
- compositionSurface = null
+ Type = SwapChainTargetType.WindowHandle,
+ WindowHandle = hwnd,
+ CompositionSurface = null
};
}
@@ -690,9 +729,9 @@ public struct SwapChainTarget
{
return new SwapChainTarget
{
- type = SwapChainTargetType.Composition,
- windowHandle = nint.Zero,
- compositionSurface = surface
+ Type = SwapChainTargetType.Composition,
+ WindowHandle = 0,
+ CompositionSurface = surface
};
}
}
diff --git a/Ghost.Graphics/RHI/ICommandBuffer.cs b/Ghost.Graphics/RHI/ICommandBuffer.cs
index 359d225..c27e98f 100644
--- a/Ghost.Graphics/RHI/ICommandBuffer.cs
+++ b/Ghost.Graphics/RHI/ICommandBuffer.cs
@@ -53,21 +53,21 @@ public interface ICommandBuffer : IDisposable
void SetScissorRect(RectDesc rect);
///
- /// Sets the optional render targets and optional depth target for subsequent rendering operations.
+ /// Sets the optional render targets and optional depth Target for subsequent rendering operations.
///
///
/// To specify no render targets, provide an empty span for .
- /// Use for if no depth target is required.
+ /// Use for if no depth Target is required.
///
/// A read-only span of handles to textures that will be used as render targets.
/// The order of handles determines the order in which render targets are bound.
- /// A handle to the texture to be used as the depth target. Specify a invalid handle if no depth target is required.
+ /// A handle to the texture to be used as the depth Target. Specify a invalid handle if no depth Target is required.
void SetRenderTargets(ReadOnlySpan> renderTargets, Handle depthTarget);
///
- /// Begins a render pass with the specified render target
+ /// Begins a render pass with the specified render Target
///
- /// Render target descriptions
+ /// Render Target descriptions
/// Depth stencil description
/// Whether UAV writes are allowed during the render pass
void BeginRenderPass(ReadOnlySpan rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false);
@@ -78,12 +78,18 @@ public interface ICommandBuffer : IDisposable
void EndRenderPass();
///
- /// Inserts a resource barrier for state transitions
+ /// Inserts multiple resource barriers for state transitions.
///
- /// Resource to transition
- /// Current resource state
- /// Target resource state
- void ResourceBarrier(Handle resource, ResourceState before, ResourceState after);
+ /// Resource barrier descriptions
+ void ResourceBarrier(ReadOnlySpan barrierDescs);
+
+ ///
+ /// Inserts a resource barrier for state transitions.
+ ///
+ /// A handle to the GPU resource to transition.
+ /// The current state of the resource before the transition.
+ /// The desired state of the resource after the transition.
+ void ResourceBarrier(Handle resource, ResourceState stateBefore, ResourceState stateAfter);
///
/// Sets the pipeline state object
@@ -176,10 +182,10 @@ public interface ICommandBuffer : IDisposable
///
/// The texture resource to which the subresource data will be uploaded. Must be a valid, initialized texture handle.
/// The index of the first subresource in the texture to receive data. Must be less than the total number of subresources in the texture.
- /// A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.
+ /// A reference to the structure containing the subresource data to upload. The data must match the Format and layout expected by the texture.
/// The number of subresources to upload, starting from .
/// Must be greater than zero and not exceed the remaining subresources in the texture.
- void UploadTexture(Handle texture, params ReadOnlySpan subresources);
+ void UploadTexture(Handle texture, ReadOnlySpan subresources);
///
/// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer.
diff --git a/Ghost.Graphics/RHI/IPipelineLibrary.cs b/Ghost.Graphics/RHI/IPipelineLibrary.cs
index a9f5f89..62b720c 100644
--- a/Ghost.Graphics/RHI/IPipelineLibrary.cs
+++ b/Ghost.Graphics/RHI/IPipelineLibrary.cs
@@ -23,5 +23,4 @@ public interface IPipelineLibrary : IDisposable
void InitializeLibrary(string? filePath);
void SaveLibraryToDisk(string filePath);
Result CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled);
- Result GetCBufferInfo(ShaderPassKey passId);
}
diff --git a/Ghost.Graphics/RHI/IRenderer.cs b/Ghost.Graphics/RHI/IRenderer.cs
index 8260242..f8b0975 100644
--- a/Ghost.Graphics/RHI/IRenderer.cs
+++ b/Ghost.Graphics/RHI/IRenderer.cs
@@ -15,9 +15,9 @@ public interface IRenderer : IDisposable
}
///
- /// Sets the render target for this renderer
+ /// Sets the render Target for this renderer
///
- /// Render target to render into
+ /// Render Target to render into
public void SetRenderTarget(Handle renderTarget);
///
diff --git a/Ghost.Graphics/RHI/IResourceAllocator.cs b/Ghost.Graphics/RHI/IResourceAllocator.cs
index ba4e645..4525025 100644
--- a/Ghost.Graphics/RHI/IResourceAllocator.cs
+++ b/Ghost.Graphics/RHI/IResourceAllocator.cs
@@ -15,9 +15,9 @@ public interface IResourceAllocator : IDisposable
public Handle CreateTexture(ref readonly TextureDesc desc, bool tempResource = false);
///
- /// Creates a render target for off-screen rendering
+ /// Creates a render Target for off-screen rendering
///
- /// Render target description
+ /// Render Target description
/// A new texture handle point to the resource
public Handle CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false);
diff --git a/Ghost.Graphics/RHI/IResourceDatabase.cs b/Ghost.Graphics/RHI/IResourceDatabase.cs
index 639c346..fec83b6 100644
--- a/Ghost.Graphics/RHI/IResourceDatabase.cs
+++ b/Ghost.Graphics/RHI/IResourceDatabase.cs
@@ -11,6 +11,9 @@ public interface IResourceReleasable
void ReleaseResource(IResourceDatabase database);
}
+// 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.
public interface IResourceDatabase : IDisposable
{
/*
@@ -155,18 +158,4 @@ public interface IResourceDatabase : IDisposable
///
/// The identifier of the shader to release. Must refer to a valid, previously created shader.
void ReleaseShader(Identifier id);
-
- ///
- /// Adds a shader pass to the collection using the specified identifier.
- ///
- /// The unique identifier for the shader pass.
- /// The shader pass to add. Cannot be null.
- void AddShaderPass(ShaderPassKey passKey, ShaderPass pass);
-
- ///
- /// Retrieves the shader pass associated with the specified pass identifier.
- ///
- /// The unique identifier of the shader pass to retrieve.
- /// The corresponding to the specified identifier, or null if no matching shader pass is found.
- ShaderPass GetShaderPass(ShaderPassKey passKey);
}
diff --git a/Ghost.Graphics/RHI/RHIUtility.cs b/Ghost.Graphics/RHI/RHIUtility.cs
index ca9ba9c..a829160 100644
--- a/Ghost.Graphics/RHI/RHIUtility.cs
+++ b/Ghost.Graphics/RHI/RHIUtility.cs
@@ -22,8 +22,8 @@ internal static class RHIUtility
var packed = false;
var planar = false;
var bpe = 0;
-
- //switch (format)
+
+ //switch (Format)
//{
// case Format.BC1Typeless:
// case Format.BC1Unorm:
diff --git a/Ghost.Graphics/RenderPasses/MeshRenderPass.cs b/Ghost.Graphics/RenderPasses/MeshRenderPass.cs
index c6fb500..ab30860 100644
--- a/Ghost.Graphics/RenderPasses/MeshRenderPass.cs
+++ b/Ghost.Graphics/RenderPasses/MeshRenderPass.cs
@@ -5,23 +5,33 @@ using Ghost.Graphics.Core;
using Ghost.Graphics.RHI;
using Ghost.Graphics.Utilities;
using Ghost.SDL.Compiler;
-using Misaki.HighPerformance.Image;
using Misaki.HighPerformance.Mathematics;
-using Misaki.HighPerformance.Utilities;
-using TerraFX.Interop.Windows;
+using System.Runtime.InteropServices;
namespace Ghost.Graphics.RenderPasses;
///
/// Simplified bindless mesh render pass using high-level bindless APIs with fully bindless vertex/index buffer access
///
-internal unsafe class MeshRenderPass : IRenderPass
+internal class MeshRenderPass : IRenderPass
{
+ [StructLayout(LayoutKind.Sequential)]
+ private struct ShaderProperties_MyShader_Standard
+ {
+ public float4 color;
+ public uint texture1;
+ public uint texture2;
+ public uint texture3;
+ public uint texture4;
+ }
+
private Handle _mesh;
private Identifier _shader;
private Handle _material;
private Handle[]? _textures;
+ private GraphicsCompiledResult[]? _compileResults;
+
// Texture file paths for this demo
private readonly string[] _textureFiles = [
"C:/Users/Misaki/Downloads/Im/Icon.png",
@@ -34,9 +44,11 @@ internal unsafe class MeshRenderPass : IRenderPass
{
var shaderDescriptor = SDLCompiler.CompileShader("F:/csharp/GhostEngine/Ghost.Graphics/test.gshader", "C:/Users/Misaki/Downloads/Archive").GetValueOrThrow();
- foreach (var pass in shaderDescriptor.passes)
+ _compileResults = new GraphicsCompiledResult[shaderDescriptor.passes.Count];
+ for (var i = 0; i < shaderDescriptor.passes.Count; i++)
{
- var compileResult = ctx.ShaderCompiler.CompilePass(pass);
+ var pass = shaderDescriptor.passes[i];
+ var compileResult = ctx.ShaderCompiler.CompilePass(pass, shaderDescriptor.generatedCodePath);
if (compileResult.IsFailure || pass is not FullPassDescriptor fullPass)
{
continue;
@@ -55,18 +67,30 @@ internal unsafe class MeshRenderPass : IRenderPass
DsvFormat = TextureFormat.Unknown,
};
- ctx.PipelineLibrary.CompilePSO(in psoDes, in compileResult.GetValueRef()).GetValueOrThrow();
+ _compileResults[i] = compileResult.Value;
+ ctx.PipelineLibrary.CompilePSO(in psoDes, in _compileResults[i]).GetValueOrThrow();
}
MeshBuilder.CreateCube(0.75f, default, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent, out var vertices, out var indices);
- _mesh = ctx.CreateMesh(vertices, indices);
+ _mesh = ctx.CreateMesh(vertices, indices, true);
ctx.UpdateObjectData(_mesh, float4x4.identity);
- ctx.UploadMesh(_mesh, true);
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
_material = ctx.ResourceAllocator.CreateMaterial(_shader);
+ ref var matRef = ref ctx.ResourceDatabase.GetMaterialReference(_material);
+ var matProps = new ShaderProperties_MyShader_Standard
+ {
+ color = new float4(1.0f, 1.0f, 1.0f, 1.0f),
+ texture1 = 0,
+ texture2 = 1,
+ texture3 = 2,
+ texture4 = 3,
+ };
+
+ matRef.SetPropertyCache(in matProps);
+
//_textures = new Handle[_textureFiles.Length];
//for (var i = 0; i < _textureFiles.Length; i++)
//{
@@ -107,5 +131,13 @@ internal unsafe class MeshRenderPass : IRenderPass
resourceDatabase.ReleaseResource(texture.AsResource());
}
}
+
+ if (_compileResults != null)
+ {
+ for (var i = 0; i < _compileResults.Length; i++)
+ {
+ _compileResults[i].Dispose();
+ }
+ }
}
}
diff --git a/Ghost.Graphics/RenderPasses/ShaderCode.hlsl b/Ghost.Graphics/RenderPasses/ShaderCode.hlsl
index 359caf9..2d4af10 100644
--- a/Ghost.Graphics/RenderPasses/ShaderCode.hlsl
+++ b/Ghost.Graphics/RenderPasses/ShaderCode.hlsl
@@ -1,15 +1,7 @@
#include GENERATED_CODE_PATH
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Properties.hlsl"
-
-struct Vertex
-{
- float4 position;
- float4 normal;
- float4 tangent;
- float4 color;
- float4 uv;
-};
+#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl"
struct PixelInput
{
@@ -26,24 +18,8 @@ void MSMain(
out vertices PixelInput outVerts[3],
out indices uint3 outTris[1])
{
-#if 0
- // Fetch bindless buffers
- ByteAddressBuffer vertexBuffer = ResourceDescriptorHeap[g_PerObjectData.vertexBuffer];
- ByteAddressBuffer indexBuffer = ResourceDescriptorHeap[g_PerObjectData.indexBuffer];
-
- // Compute the triangle’s vertex indices
uint vertexId = groupThreadID.x;
- uint indexOffset = (groupID.x * 3 + vertexId) * 4; // uint32 index
- uint vertexIndex = indexBuffer.Load(indexOffset);
-
- // Load vertex attributes
- uint vertexOffset = vertexIndex * 80; // 80 bytes per vertex
- Vertex v;
- v.position = asfloat(vertexBuffer.Load4(vertexOffset + 0));
- v.normal = asfloat(vertexBuffer.Load4(vertexOffset + 16));
- v.tangent = asfloat(vertexBuffer.Load4(vertexOffset + 32));
- v.color = asfloat(vertexBuffer.Load4(vertexOffset + 48));
- v.uv = asfloat(vertexBuffer.Load4(vertexOffset + 64));
+ Vertex v = LoadVertexData(vertexId, groupID.x, g_PerObjectData.vertexBuffer, g_PerObjectData.indexBuffer);
SetMeshOutputCounts(3, 1);
//v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position));
@@ -58,50 +34,16 @@ void MSMain(
{
outTris[0] = uint3(0, 1, 2);
}
-#else
- // 1. Tell the hardware how much data to expect
- SetMeshOutputCounts(3, 1);
-
- // 2. Hardcoded Clip Space Positions (X, Y, Z, W)
- // Visible range: X[-1, 1], Y[-1, 1], Z[0, 1]
- // W must be 1.0
- float4 positions[3] =
- {
- float4(0.0f, 0.5f, 0.5f, 1.0f), // Top
- float4(0.5f, -0.5f, 0.5f, 1.0f), // Bottom Right
- float4(-0.5f, -0.5f, 0.5f, 1.0f) // Bottom Left
- };
-
- float4 colors[3] =
- {
- float4(g_PerObjectData.vertexBuffer, 0.0f, 0.0f, 1.0f), // Red
- float4(0.0f, g_PerObjectData.indexBuffer, 0.0f, 1.0f), // Green
- float4(0.0f, 0.0f, 0.0f, 1.0f) // Blue
- };
-
- uint gtid = groupThreadID.x;
-
- // 3. Write Vertex Data (Parallel)
- outVerts[gtid].position = positions[gtid];
- outVerts[gtid].color = colors[gtid];
-
- // 4. Write Index Data (Only 1st thread needs to do this)
- if (gtid == 0)
- {
- // Clockwise winding (Standard for DX12)
- outTris[0] = uint3(0, 1, 2);
- }
-#endif
}
float4 PSMain(PixelInput input) : SV_TARGET
{
- //float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy);
- //float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy);
- //float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy);
- //float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy);
+ //float4 color1 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture1, 0, input.uv.xy);
+ //float4 color2 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture2, 0, input.uv.xy);
+ //float4 color3 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture3, 0, input.uv.xy);
+ //float4 color4 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture4, 0, input.uv.xy);
//float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
- return g_PerMaterialData.color + input.color;;
+ return g_PerMaterialData.color + input.color;
//return input.color;
}
diff --git a/Ghost.Graphics/RenderSystem.cs b/Ghost.Graphics/RenderSystem.cs
index 94357ab..18ddaad 100644
--- a/Ghost.Graphics/RenderSystem.cs
+++ b/Ghost.Graphics/RenderSystem.cs
@@ -48,11 +48,6 @@ public interface IFenceSynchronizer
public interface IRenderSystem : IFenceSynchronizer, IDisposable
{
- RenderingConfig Config
- {
- get;
- }
-
IGraphicsEngine GraphicsEngine
{
get;
@@ -80,8 +75,8 @@ internal class RenderSystem : IRenderSystem
public FrameResource()
{
- cpuReadyEvent = new(false);
- gpuReadyEvent = new(true);
+ cpuReadyEvent = new AutoResetEvent(false);
+ gpuReadyEvent = new AutoResetEvent(true);
}
public void Dispose()
@@ -105,7 +100,6 @@ internal class RenderSystem : IRenderSystem
private bool _isRunning;
private bool _disposed;
- public RenderingConfig Config => _config;
public IGraphicsEngine GraphicsEngine => _graphicsEngine;
public bool IsRunning => _isRunning;
@@ -123,16 +117,16 @@ internal class RenderSystem : IRenderSystem
_ => throw new NotSupportedException($"Graphics API {config.GraphicsAPI} is not supported.")
};
- _shutdownEvent = new(false);
+ _shutdownEvent = new AutoResetEvent(false);
// Create frame resources for synchronization
_frameResources = new FrameResource[config.FrameBufferCount];
for (var i = 0; i < config.FrameBufferCount; i++)
{
- _frameResources[i] = new();
+ _frameResources[i] = new FrameResource();
}
- _renderThread = new(RenderLoop)
+ _renderThread = new Thread(RenderLoop)
{
IsBackground = true,
Name = "Graphics Render Thread",
diff --git a/Ghost.Graphics/Utilities/DxcShaderCompiler.cs b/Ghost.Graphics/Utilities/DxcShaderCompiler.cs
index 6638569..2369f8b 100644
--- a/Ghost.Graphics/Utilities/DxcShaderCompiler.cs
+++ b/Ghost.Graphics/Utilities/DxcShaderCompiler.cs
@@ -138,7 +138,7 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
_compiler.Attach(pCompiler);
_utils.Attach(pUtils);
- _compiledResults = new();
+ _compiledResults = new Dictionary();
}
~DxcShaderCompiler()
@@ -153,10 +153,10 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
try
{
- // Create DXC _utils.Get() to parse pReflection data
+ // Create DXC _utils.Get() to parse reflection data
var dxcuID = CLSID.CLSID_DxcUtils;
- // Create pReflection interface from blob
+ // Create reflection interface from blob
var reflectionBuffer = new DxcBuffer
{
Ptr = pDxcReflectionBlob->GetBufferPointer(),
@@ -242,137 +242,109 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
}
}
- public Result Compile(ref readonly CompilerConfig config, Allocator allocator)
+ public Result Compile(ref readonly CompilerConfig config, Allocator allocator)
{
ObjectDisposedException.ThrowIf(_disposed, this);
- IDxcIncludeHandler* pIncludeHandler = default;
- IDxcBlobEncoding* pSourceBlob = default;
+ using ComPtr includeHandler = default;
+ using ComPtr sourceBlob = default;
+
+ // Create DXC _compiler.Get() and _utils.Get()
+ var dxccID = CLSID.CLSID_DxcCompiler;
+ var dxcuID = CLSID.CLSID_DxcUtils;
+
+ ThrowIfFailed(_utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf()));
+
+ // Create source blob
+ fixed (char* pPath = config.shaderPath)
+ {
+ if (_utils.Get()->LoadFile(pPath, null, sourceBlob.GetAddressOf()).FAILED)
+ {
+ return Result.Failure($"Failed to load shader file: {config.shaderPath}");
+ }
+ }
+
+ var argsArray = GetCompilerArguments(in config);
+ var argPtrs = stackalloc char*[argsArray.Count];
+ for (var i = 0; i < argsArray.Count; i++)
+ {
+ argPtrs[i] = (char*)Marshal.StringToHGlobalUni(argsArray[i]);
+ }
+
+ using ComPtr result = default;
try
{
- // Create DXC _compiler.Get() and _utils.Get()
- var dxccID = CLSID.CLSID_DxcCompiler;
- var dxcuID = CLSID.CLSID_DxcUtils;
-
-
- ThrowIfFailed(_utils.Get()->CreateDefaultIncludeHandler(&pIncludeHandler));
-
- // Create source blob
- fixed (char* pPath = config.shaderPath)
+ // Compile shader
+ var buffer = new DxcBuffer
{
- if (_utils.Get()->LoadFile(pPath, null, &pSourceBlob).FAILED)
+ Ptr = sourceBlob.Get()->GetBufferPointer(),
+ Size = sourceBlob.Get()->GetBufferSize(),
+ Encoding = DXC_CP_UTF8
+ };
+
+ var (iid, ppv) = Win32Utility.IID_PPV_ARGS(&result);
+ ThrowIfFailed(_compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, includeHandler, iid, ppv));
+
+ // Check compilation result
+ HRESULT hrStatus;
+ result.Get()->GetStatus(&hrStatus);
+ if (hrStatus.FAILED)
+ {
+ // Get error messages
+ IDxcBlobEncoding* pErrorBlob = default;
+ result.Get()->GetErrorBuffer(&pErrorBlob);
+
+ if (pErrorBlob != null)
{
- return Result.Failure($"Failed to load shader file: {config.shaderPath}");
+ var errorMessage = Marshal.PtrToStringUTF8((IntPtr)pErrorBlob->GetBufferPointer());
+ pErrorBlob->Release();
+
+ return Result.Failure($"DXC shader compilation failed:\n{errorMessage}");
+ }
+ else
+ {
+ return Result.Failure("DXC shader compilation failed with unknown error.");
}
}
- var argsArray = GetCompilerArguments(in config);
- var argPtrs = stackalloc char*[argsArray.Count];
- for (var i = 0; i < argsArray.Count; i++)
+ // Get compiled bytecode
+ using ComPtr bytecodeBlob = default;
+ ThrowIfFailed(result.Get()->GetResult(bytecodeBlob.GetAddressOf()));
+
+ ShaderReflectionData reflectionData = default;
+ if (config.options.HasFlag(CompilerOption.KeepReflections))
{
- argPtrs[i] = (char*)Marshal.StringToHGlobalUni(argsArray[i]);
+ using ComPtr reflection = default;
+ (iid, ppv) = Win32Utility.IID_PPV_ARGS(&reflection);
+
+ if (result.Get()->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, iid, ppv, null).SUCCEEDED)
+ {
+ reflectionData = PerformDXCReflection(reflection).GetValueOrDefault();
+ }
}
- IDxcResult* pResult = default;
+ var bytecodeSize = bytecodeBlob.Get()->GetBufferSize();
+ var bytecode = new UnsafeArray((int)bytecodeSize, allocator);
- try
+ NativeMemory.Copy(bytecodeBlob.Get()->GetBufferPointer(), bytecode.GetUnsafePtr(), bytecodeSize);
+
+ return new ShaderCompileResult
{
- // Compile shader
- var buffer = new DxcBuffer
- {
- Ptr = pSourceBlob->GetBufferPointer(),
- Size = pSourceBlob->GetBufferSize(),
- Encoding = DXC_CP_UTF8
- };
-
- ThrowIfFailed(_compiler.Get()->Compile(&buffer, argPtrs, (uint)argsArray.Count, pIncludeHandler, __uuidof(pResult), (void**)&pResult));
-
- // Check compilation pResult
- HRESULT hrStatus;
- pResult->GetStatus(&hrStatus);
- if (hrStatus.FAILED)
- {
- // Get error messages
- IDxcBlobEncoding* pErrorBlob = default;
- pResult->GetErrorBuffer(&pErrorBlob);
-
- if (pErrorBlob != null)
- {
- var errorMessage = Marshal.PtrToStringUTF8((IntPtr)pErrorBlob->GetBufferPointer());
- pErrorBlob->Release();
-
- return Result.Failure($"DXC shader compilation failed:\n{errorMessage}");
- }
- else
- {
- return Result.Failure("DXC shader compilation failed with unknown error.");
- }
- }
-
- // Get compiled bytecode
- IDxcBlob* pBytecodeBlob = default;
- try
- {
- ThrowIfFailed(pResult->GetResult(&pBytecodeBlob));
-
- ShaderReflectionData reflection = default;
- if (config.options.HasFlag(CompilerOption.KeepReflections))
- {
- IDxcBlob* pReflection = default;
- if ((pResult->GetOutput(DXC_OUT_KIND.DXC_OUT_REFLECTION, __uuidof(), (void**)&pReflection, null).SUCCEEDED))
- {
- reflection = PerformDXCReflection(pReflection).GetValueOrDefault();
- }
-
- if (pReflection != null)
- {
- pReflection->Release();
- }
- }
-
- var bytecodeSize = pBytecodeBlob->GetBufferSize();
- var bytecode = new UnsafeArray((int)bytecodeSize, allocator);
-
- NativeMemory.Copy(pBytecodeBlob->GetBufferPointer(), bytecode.GetUnsafePtr(), bytecodeSize);
-
- return new CompileResult
- {
- bytecode = bytecode,
- reflectionData = reflection,
- };
- }
- finally
- {
- if (pBytecodeBlob != null)
- {
- pBytecodeBlob->Release();
- }
- }
- }
- finally
- {
- for (var i = 0; i < argsArray.Count; i++)
- {
- Marshal.FreeHGlobal((nint)argPtrs[i]);
- }
-
- if (pResult != null)
- {
- pResult->Release();
- }
- }
+ bytecode = bytecode,
+ reflectionData = reflectionData,
+ };
}
finally
{
- if (pIncludeHandler != null)
+ for (var i = 0; i < argsArray.Count; i++)
{
- pIncludeHandler->Release();
+ Marshal.FreeHGlobal((nint)argPtrs[i]);
}
}
}
- public Result CompilePass(IPassDescriptor descriptor)
+ public Result CompilePass(IPassDescriptor descriptor, string? generatedCodePath)
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -381,14 +353,14 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
return Result.Failure("FullPassDescriptor expected.");
}
- CompileResult tsResult = default;
+ ShaderCompileResult tsResult = default;
var tsEntry = fullDescriptor.taskShader;
if (tsEntry.IsCreated)
{
var config = new CompilerConfig
{
defines = fullDescriptor.defines.AsSpan(),
- include = fullDescriptor.generatedCodePath,
+ include = generatedCodePath,
shaderPath = tsEntry.shader,
entryPoint = tsEntry.entry,
stage = ShaderStage.TaskShader,
@@ -406,14 +378,14 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
tsResult = result.Value;
}
- CompileResult msResult;
+ ShaderCompileResult msResult;
var msEntry = fullDescriptor.meshShader;
if (msEntry.IsCreated)
{
var config = new CompilerConfig
{
defines = fullDescriptor.defines.AsSpan(),
- include = fullDescriptor.generatedCodePath,
+ include = generatedCodePath,
shaderPath = msEntry.shader,
entryPoint = msEntry.entry,
stage = ShaderStage.MeshShader,
@@ -435,14 +407,14 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
return Result.Failure("Mesh shader expected.");
}
- CompileResult psResult;
+ ShaderCompileResult psResult;
var psEntry = fullDescriptor.pixelShader;
if (psEntry.IsCreated)
{
var config = new CompilerConfig
{
defines = fullDescriptor.defines.AsSpan(),
- include = fullDescriptor.generatedCodePath,
+ include = generatedCodePath,
shaderPath = psEntry.shader,
entryPoint = psEntry.entry,
stage = ShaderStage.PixelShader,
diff --git a/Ghost.Graphics/Utilities/MeshBuilder.cs b/Ghost.Graphics/Utilities/MeshBuilder.cs
index 9ba4541..1c22a7f 100644
--- a/Ghost.Graphics/Utilities/MeshBuilder.cs
+++ b/Ghost.Graphics/Utilities/MeshBuilder.cs
@@ -231,7 +231,7 @@ public unsafe static class MeshBuilder
public static void ComputeTangents(UnsafeList vertices, UnsafeList indices)
{
using var scope = AllocationManager.CreateStackScope();
- var bitangents = new UnsafeArray(vertices.Count, Allocator.Stack);
+ using var bitangents = new UnsafeArray(vertices.Count, Allocator.Stack);
for (var i = 0; i < indices.Count; i += 3)
{
diff --git a/Ghost.Graphics/test.gshader b/Ghost.Graphics/test.gshader
index 3070a85..d9dffdf 100644
--- a/Ghost.Graphics/test.gshader
+++ b/Ghost.Graphics/test.gshader
@@ -3,10 +3,10 @@ shader "MyShader/Standard"
properties
{
float4 color = float4(1, 1, 1, 1);
- tex2d_b texture1 = tex2d_b(black);
- tex2d_b texture2 = tex2d_b(white);
- tex2d_b texture3 = tex2d_b(grey);
- tex2d_b texture4 = tex2d_b(normal);
+ tex2d texture1 = tex2d(black);
+ tex2d texture2 = tex2d(white);
+ tex2d texture3 = tex2d(grey);
+ tex2d texture4 = tex2d(normal);
}
pass "Forward"
@@ -23,4 +23,4 @@ shader "MyShader/Standard"
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
}
-}
\ No newline at end of file
+}
diff --git a/Ghost.Shader.Test/Program.cs b/Ghost.Shader.Test/Program.cs
index 5ab5816..3829415 100644
--- a/Ghost.Shader.Test/Program.cs
+++ b/Ghost.Shader.Test/Program.cs
@@ -30,11 +30,7 @@ if (model == null)
}
var descriptor = SDLCompiler.ResolveShader(model);
-
-foreach (var pass in descriptor.passes)
-{
- SDLCompiler.GeneratePass(pass, "C:/Users/Misaki/Downloads/Archive");
-}
+SDLCompiler.GenerateShaderCode(descriptor, "C:/Users/Misaki/Downloads/Archive");
Console.WriteLine("Shader compiled successfully:");
diff --git a/Ghost.Shader/BuiltIn/Common.hlsl b/Ghost.Shader/BuiltIn/Common.hlsl
index 724f68a..e9bc3c3 100644
--- a/Ghost.Shader/BuiltIn/Common.hlsl
+++ b/Ghost.Shader/BuiltIn/Common.hlsl
@@ -1,97 +1,95 @@
-#ifndef COMMON_HLSL
-#define COMMON_HLSL
-
-#undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level.
+#ifndef BUILTIN_COMMON_HLSL
+#define BUILTIN_COMMON_HLSL
+struct Vertex
+{
+ float4 position;
+ float4 normal;
+ float4 tangent;
+ float4 uv;
+ float4 color;
+};
// Resource descriptor heap definitions
-#if defined(USE_TRADITIONAL_BINDLESS)
-#define GLOBAL_TEXTURE2D_HEAP_SIZE 32768
-#define GLOBAL_TEXTURE3D_HEAP_SIZE 32
-#define GLOBAL_TEXTURECUBE_HEAP_SIZE 32
-#define GLOBAL_TEXTURE2D_ARRAY_HEAP_SIZE 256
-#define GLOBAL_TEXTURECUBE_ARRAY_HEAP_SIZE 32
-#define GLOBAL_SAMPLER_HEAP_SIZE 32
-
-#define GLOBAL_TEXTURE2D_HEAP GlobalTexture2DHeap
-#define GLOBAL_TEXTURE3D_HEAP GlobalTexture3DHeap
-#define GLOBAL_TEXTURECUBE_HEAP GlobalTextureCubeHeap
-#define GLOBAL_TEXTURE2D_ARRAY_HEAP GlobalTexture2DArrayHeap
-#define GLOBAL_TEXTURECUBE_ARRAY_HEAP GlobalTextureCubeArrayHeap
-#define GLOBAL_SAMPLER_HEAP GlobalSamplerHeap
-#else
#define GLOBAL_TEXTURE2D_HEAP ResourceDescriptorHeap
#define GLOBAL_TEXTURE3D_HEAP ResourceDescriptorHeap
#define GLOBAL_TEXTURECUBE_HEAP ResourceDescriptorHeap
#define GLOBAL_TEXTURE2D_ARRAY_HEAP ResourceDescriptorHeap
#define GLOBAL_TEXTURECUBE_ARRAY_HEAP ResourceDescriptorHeap
+#define GLOBAL_BUFFER_HEAP ResourceDescriptorHeap
#define GLOBAL_SAMPLER_HEAP SamplerDescriptorHeap
-#endif
-
// Bindless resource type definitions
-#define TEXTURE2D_BINDLESS uint
-#define TEXTURE3D_BINDLESS uint
-#define TEXTURECUBE_BINDLESS uint
-#define TEXTURE2D_ARRAY_BINDLESS uint
-#define TEXTURECUBE_ARRAY_BINDLESS uint
+#define TEXTURE2D uint
+#define TEXTURE3D uint
+#define TEXTURECUBE uint
+#define TEXTURE2D_ARRAY uint
+#define TEXTURECUBE_ARRAY uint
-#define SAMPLER_BINDLESS uint
+#define SAMPLER uint
-#define STRUCT_BUFFER_BINDLESS uint
-#define BYTE_ADDRESS_BUFFER_BINDLESS uint
-
-#define TEXTURE2D Texture2D
-#define TEXTURE3D Texture3D
-#define TEXTURECUBE TextureCube
-#define TEXTURE2D_ARRAY Texture2DArray
-#define TEXTURECUBE_ARRAY TextureCubeArray
-
-#define SAMPLER SamplerState
-
-#define STRUCT_BUFFER(type) StructuredBuffer
-#define BYTE_ADDRESS_BUFFER ByteAddressBuffer
+#define STRUCT_BUFFER uint
+#define BYTE_ADDRESS_BUFFER uint
// Texture and sampler access macros
-#define GET_TEXTURE2D_BINDLESS(id) GLOBAL_TEXTURE2D_HEAP[id]
-#define GET_TEXTURE2D_ARRAY_BINDLESS(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id]
-#define GET_TEXTURE3D_BINDLESS(id) GLOBAL_TEXTURE3D_HEAP[id]
-#define GET_TEXTURECUBE_BINDLESS(id) GLOBAL_TEXTURECUBE_HEAP[id]
-#define GET_TEXTURECUBE_ARRAY_BINDLESS(id) GLOBAL_TEXTURECUBE_ARRAY_HEAP[id]
-#define GET_SAMPLER_BINDLESS(id) GLOBAL_SAMPLER_HEAP[id]
-
-
-// Texture sampling macros
-
-#define SAMPLE_TEXTURE2D(tex, samp, uv) tex.Sample(samp, uv)
-#define SAMPLE_TEXTURE2D_LEVEL(tex, samp, uv, level) tex.SampleLevel(samp, uv, level)
-#define SAMPLE_TEXTURE2D_BINDLESS(texId, sampId, uv) SampleTexture2DBindless(texId, sampId, uv)
-#define SAMPLE_TEXTURE2D_LEVEL_BINDLESS(texId, sampId, uv, level) SampleTexture2DLevelBindless(texId, sampId, uv, level)
-
-#define SAMPLE_TEXTURE2D_ARRAY(tex, samp, uv, index) tex.Sample(samp, uv, index)
-#define SAMPLE_TEXTURE2D_ARRAY_BINDLESS(texId, sampId, uv, index) GET_TEXTURE2D_ARRAY_BINDLESS(texId).Sample(GET_SAMPLER_BINDLESS(sampId), uv, index)
-
-static inline float4 SampleTexture2DBindless(uint texId, uint sampId, float2 uv)
-{
- Texture2D tex = GET_TEXTURE2D_BINDLESS(texId);
- SamplerState samp = GET_SAMPLER_BINDLESS(sampId);
- return tex.Sample(samp, uv);
-}
-
-static inline float4 SampleTexture2DLevelBindless(uint texId, uint sampId, float2 uv, float level)
-{
- Texture2D tex = GET_TEXTURE2D_BINDLESS(texId);
- SamplerState samp = GET_SAMPLER_BINDLESS(sampId);
- return tex.SampleLevel(samp, uv, level);
-}
-
-
+#define GET_TEXTURE2D(id) GLOBAL_TEXTURE2D_HEAP[id]
+#define GET_TEXTURE2D_ARRAY(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id]
+#define GET_TEXTURE3D(id) GLOBAL_TEXTURE3D_HEAP[id]
+#define GET_TEXTURECUBE(id) GLOBAL_TEXTURECUBE_HEAP[id]
+#define GET_TEXTURECUBE_ARRAY(id) GLOBAL_TEXTURECUBE_ARRAY_HEAP[id]
+#define GET_BUFFER(id) GLOBAL_BUFFER_HEAP[id]
+#define GET_SAMPLER(id) GLOBAL_SAMPLER_HEAP[id]
#define MESH_SHADER_THREADS(x) [NumThreads(x, 1, 1)]
-#endif // COMMON_HLSL
+
+inline float4 SampleTexture2D(uint texId, uint sampId, float2 uv)
+{
+ Texture2D tex = GET_TEXTURE2D(texId);
+ SamplerState samp = GET_SAMPLER(sampId);
+ return tex.Sample(samp, uv);
+}
+
+inline float4 SampleTexture2DLevel(uint texId, uint sampId, float2 uv, float level)
+{
+ Texture2D tex = GET_TEXTURE2D(texId);
+ SamplerState samp = GET_SAMPLER(sampId);
+ return tex.SampleLevel(samp, uv, level);
+}
+
+inline float4 SampleTextureArray(uint texId, uint sampId, float3 uv)
+{
+ Texture2DArray tex = GET_TEXTURE2D_ARRAY(texId);
+ SamplerState samp = GET_SAMPLER(sampId);
+ return tex.Sample(samp, uvw.xyz);
+}
+
+
+inline Vertex LoadVertexData(uint vertexID, uint groupID, BYTE_ADDRESS_BUFFER vertexBuffer, BYTE_ADDRESS_BUFFER indexBuffer)
+{
+ // Fetch bindless buffers
+ ByteAddressBuffer vertexBuffer = GET_BUFFER(vertexBuffer);
+ ByteAddressBuffer indexBuffer = GET_BUFFER(indexBuffer);
+
+ // Compute the triangle’s vertex indices
+ uint indexOffset = (groupID * 3 + vertexID) * 4; // uint32 index
+ uint vertexIndex = indexBuffer.Load(indexOffset);
+
+ // Load vertex attributes
+ uint vertexOffset = vertexIndex * 80; // 80 bytes per vertex
+ Vertex v;
+ v.position = asfloat(vertexBuffer.Load4(vertexOffset + 0));
+ v.normal = asfloat(vertexBuffer.Load4(vertexOffset + 16));
+ v.tangent = asfloat(vertexBuffer.Load4(vertexOffset + 32));
+ v.uv = asfloat(vertexBuffer.Load4(vertexOffset + 48));
+ v.color = asfloat(vertexBuffer.Load4(vertexOffset + 64));
+
+ return v;
+}
+
+#endif // BUILTIN_COMMON_HLSL
diff --git a/Ghost.Shader/BuiltIn/Properties.hlsl b/Ghost.Shader/BuiltIn/Properties.hlsl
index 81dc13b..e0e22df 100644
--- a/Ghost.Shader/BuiltIn/Properties.hlsl
+++ b/Ghost.Shader/BuiltIn/Properties.hlsl
@@ -1,5 +1,5 @@
-#ifndef PROPERTIES_HLSL
-#define PROPERTIES_HLSL
+#ifndef BUILTIN_PROPERTIES_HLSL
+#define BUILTIN_PROPERTIES_HLSL
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl"
@@ -48,4 +48,4 @@ TextureCubeArray GlobalTextureCubeArrayHeap[GLOBAL_TEXTURECUBE_ARRAY_HEAP_SIZE]
SamplerState GlobalSamplerHeap[GLOBAL_SAMPLER_HEAP_SIZE] : register(s0);
#endif
-#endif
\ No newline at end of file
+#endif // BUILTIN_PROPERTIES_HLSL
\ No newline at end of file
diff --git a/Ghost.Shader/Compiler/Parser/IncludesBlock.cs b/Ghost.Shader/Compiler/Parser/IncludesBlock.cs
deleted file mode 100644
index 57f99b3..0000000
--- a/Ghost.Shader/Compiler/Parser/IncludesBlock.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-namespace Ghost.SDL.Compiler.Parser;
-
-internal class IncludesBlock : IBlockParser, List>
-{
- public static bool ShouldEnter(Token token)
- {
- return token.Match(TokenType.Keyword, TokenLexicon.KnownKeywords.INCLUDES);
- }
-
- public static List Parse(TokenStreamSlice stream)
- {
- stream.Expect(TokenType.Keyword);
- stream.Expect(TokenType.LBrace);
-
- var includes = new List();
-
- var bodyStream = stream.Slice(stream.Remaining - 1);
- while (bodyStream.HasMore)
- {
- var includeToken = bodyStream.Expect(TokenType.StringLiteral);
- includes.Add(includeToken);
- bodyStream.Expect(TokenType.Semicolon);
- }
-
- stream.Expect(TokenType.RBrace);
-
- return includes;
- }
-
- public static List? SemanticAnalysis(List? syntax, List errors)
- {
- if (syntax == null || syntax.Count == 0)
- {
- return null;
- }
-
- var includes = new List(syntax.Count);
- foreach (var includeToken in syntax)
- {
- var path = includeToken.lexeme;
- if (File.Exists(path))
- {
- includes.Add(path);
- }
- else
- {
- errors.Add(new SDLError
- {
- message = $"Included file '{path}' not found.",
- line = includeToken.line,
- column = includeToken.column
- });
- continue;
- }
- }
-
- return includes;
- }
-}
diff --git a/Ghost.Shader/Compiler/Parser/PassBlock.cs b/Ghost.Shader/Compiler/Parser/PassBlock.cs
index c890b91..bfbc62b 100644
--- a/Ghost.Shader/Compiler/Parser/PassBlock.cs
+++ b/Ghost.Shader/Compiler/Parser/PassBlock.cs
@@ -27,10 +27,6 @@ internal class PassBlock : IBlockParser
{
pass.defines = DefinesBlock.Parse(bodyStream.SliceNextBlock());
}
- else if (IncludesBlock.ShouldEnter(nextToken))
- {
- pass.includes = IncludesBlock.Parse(bodyStream.SliceNextBlock());
- }
else if (KeywordsBlock.ShouldEnter(nextToken))
{
pass.keywords = KeywordsBlock.Parse(bodyStream.SliceNextBlock());
@@ -39,10 +35,6 @@ internal class PassBlock : IBlockParser
{
pass.localPipeline = PipelineBlock.Parse(bodyStream.SliceNextBlock());
}
- else if (PropertiesBlock.ShouldEnter(nextToken))
- {
- pass.localProperties = PropertiesBlock.Parse(bodyStream.SliceNextBlock());
- }
else if (nextToken.Match(TokenType.Identifier))
{
var func = ParseUtility.ParseFunction(ref bodyStream, TokenType.StringLiteral);
@@ -72,23 +64,10 @@ internal class PassBlock : IBlockParser
{
name = syntax.name.lexeme,
defines = DefinesBlock.SemanticAnalysis(syntax.defines, errors),
- includes = IncludesBlock.SemanticAnalysis(syntax.includes, errors),
keywords = KeywordsBlock.SemanticAnalysis(syntax.keywords, errors),
- localProperties = PropertiesBlock.SemanticAnalysis(syntax.localProperties, errors),
localPipeline = PipelineBlock.SemanticAnalysis(syntax.localPipeline, errors),
};
- if (semantic.localProperties != null
- && semantic.localProperties.Any(p => p.scope == PropertyScope.Global))
- {
- errors.Add(new SDLError
- {
- message = "Global properties cannot be declared inside a pass. Move them to the shader properties block.",
- line = syntax.name.line,
- column = syntax.name.column
- });
- }
-
if (syntax.functionCalls != null)
{
foreach (var func in syntax.functionCalls)
diff --git a/Ghost.Shader/Compiler/Parser/PropertiesBlock.cs b/Ghost.Shader/Compiler/Parser/PropertiesBlock.cs
index f81c222..1ed2cb7 100644
--- a/Ghost.Shader/Compiler/Parser/PropertiesBlock.cs
+++ b/Ghost.Shader/Compiler/Parser/PropertiesBlock.cs
@@ -73,9 +73,9 @@ internal class PropertiesBlock : IBlockParser ParseTextureDefault(syntax[0], errors)),
- [ShaderPropertyType.Texture3DBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
- [ShaderPropertyType.TextureCubeBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
+ [ShaderPropertyType.Texture2D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
+ [ShaderPropertyType.Texture3D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
+ [ShaderPropertyType.TextureCube] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
};
private static float ParseFloatValue(Token token, List errors)
@@ -166,6 +166,7 @@ internal class PropertiesBlock : IBlockParser ShaderPropertyType.Float2,
TokenLexicon.KnownTypes.FLOAT3 => ShaderPropertyType.Float3,
TokenLexicon.KnownTypes.FLOAT4 => ShaderPropertyType.Float4,
+ TokenLexicon.KnownTypes.FLOAT4X4 => ShaderPropertyType.Float4x4,
TokenLexicon.KnownTypes.INT => ShaderPropertyType.Int,
TokenLexicon.KnownTypes.INT2 => ShaderPropertyType.Int2,
TokenLexicon.KnownTypes.INT3 => ShaderPropertyType.Int3,
@@ -178,9 +179,9 @@ internal class PropertiesBlock : IBlockParser ShaderPropertyType.Bool2,
TokenLexicon.KnownTypes.BOOL3 => ShaderPropertyType.Bool3,
TokenLexicon.KnownTypes.BOOL4 => ShaderPropertyType.Bool4,
- TokenLexicon.KnownTypes.TEXTURE2D_BINDLESS => ShaderPropertyType.Texture2DBindless,
- TokenLexicon.KnownTypes.TEXTURE3D_BINDLESS => ShaderPropertyType.Texture3DBindless,
- TokenLexicon.KnownTypes.TEXTURECUBE_BINDLESS => ShaderPropertyType.TextureCubeBindless,
+ TokenLexicon.KnownTypes.TEXTURE2D => ShaderPropertyType.Texture2D,
+ TokenLexicon.KnownTypes.TEXTURE3D => ShaderPropertyType.Texture3D,
+ TokenLexicon.KnownTypes.TEXTURECUBE => ShaderPropertyType.TextureCube,
_ => ShaderPropertyType.None,
};
}
diff --git a/Ghost.Shader/Compiler/SDLCompiler.cs b/Ghost.Shader/Compiler/SDLCompiler.cs
index 981a2b5..40abd8a 100644
--- a/Ghost.Shader/Compiler/SDLCompiler.cs
+++ b/Ghost.Shader/Compiler/SDLCompiler.cs
@@ -54,7 +54,7 @@ internal static class SDLCompiler
public static SDLSemantics? SemanticAnalysis(SDLSyntax syntax, out List errors)
{
- errors = new();
+ errors = new List();
if (string.IsNullOrWhiteSpace(syntax.name.lexeme))
{
@@ -145,31 +145,23 @@ internal static class SDLCompiler
};
}
- private static List MergeProperties(List? semantics, List? parent)
+ private static uint CalculateCBufferSize(List properties)
{
- var result = new List();
- if (parent != null)
- {
- result.AddRange(parent);
- }
+ var currentOffset = 0u;
- if (semantics != null)
+ foreach (var prop in properties)
{
- foreach (var prop in semantics)
+ var size = prop.type.GetSize();
+
+ if ((currentOffset % 16) + size > 16)
{
- if (prop.scope == PropertyScope.Local)
- {
- result.Add(new PropertyDescriptor
- {
- name = prop.name,
- type = prop.type,
- defaultValue = prop.defaultValue
- });
- }
+ currentOffset = (currentOffset + 15u) & ~15u;
}
+
+ currentOffset += size;
}
- return result.DistinctBy(p => p.name).ToList();
+ return (currentOffset + 15u) & ~15u;
}
// TODO: Implement shader inheritance resolution, including property and pass merging.
@@ -181,19 +173,23 @@ internal static class SDLCompiler
name = semantics.name
};
- var shaderGlobalProperties = semantics.properties?.Where(p => p.scope == PropertyScope.Global).Select(p => new PropertyDescriptor
- {
- name = p.name,
- type = p.type,
- defaultValue = p.defaultValue
- }).ToList();
+ var shaderGlobalProperties = semantics.properties?
+ .Where(p => p.scope == PropertyScope.Global)
+ .Select(p => new PropertyDescriptor
+ {
+ name = p.name,
+ type = p.type,
+ defaultValue = p.defaultValue
+ }).ToList();
- var shaderLocalProperties = semantics.properties?.Where(p => p.scope == PropertyScope.Local).Select(p => new PropertyDescriptor
- {
- name = p.name,
- type = p.type,
- defaultValue = p.defaultValue
- }).ToList();
+ var shaderLocalProperties = semantics.properties?
+ .Where(p => p.scope == PropertyScope.Local)
+ .Select(p => new PropertyDescriptor
+ {
+ name = p.name,
+ type = p.type,
+ defaultValue = p.defaultValue
+ }).ToList();
if (shaderGlobalProperties != null)
{
@@ -201,13 +197,18 @@ internal static class SDLCompiler
descriptor.globalProperties.AddRange(shaderGlobalProperties);
}
+ if (shaderLocalProperties != null)
+ {
+ descriptor.properties ??= new List();
+ descriptor.properties.AddRange(shaderLocalProperties);
+ descriptor.cbufferSize = CalculateCBufferSize(descriptor.properties);
+ }
+
if (semantics.passes != null)
{
foreach (var pass in semantics.passes)
{
var localPipeline = MeragePipeline(pass.localPipeline, PipelineDescriptor.Default);
- var localProperties = MergeProperties(pass.localProperties, shaderLocalProperties); // TODO: Merge with base shader properties if inheritance is implemented.
-
var fullPass = new FullPassDescriptor
{
uniqueIdentifier = GetPassUniqueId(semantics, pass),
@@ -217,9 +218,7 @@ internal static class SDLCompiler
pixelShader = pass.pixelShader,
localPipeline = localPipeline,
defines = pass.defines,
- includes = pass.includes,
keywords = pass.keywords,
- properties = localProperties
};
descriptor.passes.Add(fullPass);
@@ -258,24 +257,14 @@ internal static class SDLCompiler
return Result.Failure("Failed to generate global properties: " + globalPropResult.Message);
}
- foreach (var pass in desc.passes)
+ var generatedResult = GenerateShaderCode(desc, generatedOutputDirectory);
+ if (generatedResult.IsFailure)
{
- if (pass is not FullPassDescriptor fullPass)
- {
- continue;
- }
-
- fullPass.includes ??= new List();
- fullPass.includes.Add(globalPropResult.Value);
- var generatedResult = GeneratePass(fullPass, generatedOutputDirectory);
- if (generatedResult.IsFailure)
- {
- return Result.Failure("Failed to generate pass files: " + generatedResult.Message);
- }
-
- fullPass.generatedCodePath = generatedResult.Value;
+ return Result.Failure("Failed to generate pass files: " + generatedResult.Message);
}
+ desc.generatedCodePath = generatedResult.Value;
+
return desc;
}
catch (Exception ex)
@@ -305,28 +294,23 @@ internal static class SDLCompiler
ShaderPropertyType.Bool3 => "bool3",
ShaderPropertyType.Bool4 => "bool4",
// NOTE: Textures here are bindless, represented as uint (descriptor index).
- ShaderPropertyType.Texture2DBindless => "TEXTURE2D_BINDLESS",
- ShaderPropertyType.Texture3DBindless => "TEXTURE3D_BINDLESS",
- ShaderPropertyType.TextureCubeBindless => "TEXTURECUBE_BINDLESS",
- ShaderPropertyType.Texture2DArrayBindless => "TEXTURE2D_ARRAY_BINDLESS",
- ShaderPropertyType.TextureCubeArrayBindless => "TEXTURECUBE_ARRAY_BINDLESS",
+ ShaderPropertyType.Texture2D => "TEXTURE2D_BINDLESS",
+ ShaderPropertyType.Texture3D => "TEXTURE3D_BINDLESS",
+ ShaderPropertyType.TextureCube => "TEXTURECUBE_BINDLESS",
+ ShaderPropertyType.Texture2DArray => "TEXTURE2D_ARRAY_BINDLESS",
+ ShaderPropertyType.TextureCubeArray => "TEXTURECUBE_ARRAY_BINDLESS",
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}")
};
}
- public static Result GeneratePass(IPassDescriptor descriptor, string targetDirectory)
+ public static Result GenerateShaderCode(ShaderDescriptor descriptor, string targetDirectory)
{
- if (descriptor is not FullPassDescriptor fullPass)
- {
- return Result.Failure("Only full pass descriptors are supported for compilation.");
- }
-
if (!Directory.Exists(targetDirectory))
{
return Result.Failure("Target directory does not exist.");
}
- var outputFileName = fullPass.uniqueIdentifier.Replace(' ', '_');
+ var outputFileName = descriptor.name.Replace('/', '_');
var outputFilePath = Path.Combine(targetDirectory, outputFileName + ".g.hlsl");
var outputDirectory = Path.GetDirectoryName(outputFilePath);
@@ -346,30 +330,17 @@ internal static class SDLCompiler
#define {fileDefine}
#include ""F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl""");
- if (fullPass.includes != null)
- {
- foreach (var include in fullPass.includes)
- {
- sb.Append($@"
-#include ""{include}""");
- }
- sb.AppendLine();
- }
-
- if (fullPass.properties != null)
- {
- sb.Append(@"
+ sb.Append(@"
struct PerMaterialData
{");
- foreach (var prop in fullPass.properties)
- {
- sb.Append($@"
+ foreach (var prop in descriptor.properties)
+ {
+ sb.Append($@"
{ShaderPropertyTypeToHLSLType(prop.type)} {prop.name};");
- }
- sb.Append(@"
-};");
}
+ sb.Append(@"
+};");
sb.AppendLine();
sb.AppendLine(@$"
@@ -414,4 +385,4 @@ struct GlobalData
return globalFilePath;
}
-}
\ No newline at end of file
+}
diff --git a/Ghost.Shader/Compiler/SDLSemantics.cs b/Ghost.Shader/Compiler/SDLSemantics.cs
index 4fa4360..e09b71c 100644
--- a/Ghost.Shader/Compiler/SDLSemantics.cs
+++ b/Ghost.Shader/Compiler/SDLSemantics.cs
@@ -32,9 +32,7 @@ internal class PassSemantic
public ShaderEntryPoint meshShader;
public ShaderEntryPoint pixelShader;
public List? defines;
- public List? includes;
public List? keywords;
- public List? localProperties;
public PipelineSemantic? localPipeline;
}
diff --git a/Ghost.Shader/Compiler/SDLSyntax.cs b/Ghost.Shader/Compiler/SDLSyntax.cs
index 439d93a..c067c5b 100644
--- a/Ghost.Shader/Compiler/SDLSyntax.cs
+++ b/Ghost.Shader/Compiler/SDLSyntax.cs
@@ -36,9 +36,7 @@ internal class PassSyntax
{
public Token name;
public PipelineSyntax? localPipeline;
- public PropertiesSyntax? localProperties;
public List? defines;
- public List? includes;
public List? keywords;
public List? functionCalls;
}
diff --git a/Ghost.Shader/Compiler/Token.cs b/Ghost.Shader/Compiler/Token.cs
index 1b943af..ae25f8a 100644
--- a/Ghost.Shader/Compiler/Token.cs
+++ b/Ghost.Shader/Compiler/Token.cs
@@ -153,6 +153,7 @@ internal static class TokenLexicon
public const string FLOAT2 = "float2";
public const string FLOAT3 = "float3";
public const string FLOAT4 = "float4";
+ public const string FLOAT4X4 = "float4x4";
public const string INT = "int";
public const string INT2 = "int2";
@@ -170,11 +171,11 @@ internal static class TokenLexicon
public const string BOOL4 = "bool4";
// Texture types
- public const string TEXTURE2D_BINDLESS = "tex2d_b";
- public const string TEXTURE2D_ARRAY_BINDLESS = "tex2d_arr_b";
- public const string TEXTURE3D_BINDLESS = "tex3d_b";
- public const string TEXTURECUBE_BINDLESS = "texcube_b";
- public const string TEXTURECUBE_ARRAY_BINDLESS = "texcube_arr_b";
+ public const string TEXTURE2D = "tex2d";
+ public const string TEXTURE2D_ARRAY = "tex2d_arr";
+ public const string TEXTURE3D = "tex3d";
+ public const string TEXTURECUBE = "texcube";
+ public const string TEXTURECUBE_ARRAY = "texcube_arr";
}
public static class KnownTextureValue
@@ -211,12 +212,12 @@ internal static class TokenLexicon
private static readonly HashSet s_types = new()
{
- KnownTypes.FLOAT, KnownTypes.FLOAT2, KnownTypes.FLOAT3, KnownTypes.FLOAT4,
+ KnownTypes.FLOAT, KnownTypes.FLOAT2, KnownTypes.FLOAT3, KnownTypes.FLOAT4, KnownTypes.FLOAT4X4,
KnownTypes.INT, KnownTypes.INT2, KnownTypes.INT3, KnownTypes.INT4,
KnownTypes.UINT, KnownTypes.UINT2, KnownTypes.UINT3, KnownTypes.UINT4,
KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4,
- KnownTypes.TEXTURE2D_BINDLESS, KnownTypes.TEXTURE2D_ARRAY_BINDLESS, KnownTypes.TEXTURE3D_BINDLESS,
- KnownTypes.TEXTURECUBE_BINDLESS, KnownTypes.TEXTURECUBE_ARRAY_BINDLESS,
+ KnownTypes.TEXTURE2D, KnownTypes.TEXTURE2D_ARRAY, KnownTypes.TEXTURE3D,
+ KnownTypes.TEXTURECUBE, KnownTypes.TEXTURECUBE_ARRAY,
};
private static readonly HashSet s_textureDefaultValues = new()