Refactor and optimize rendering pipeline
- Added `<IsTrimmable>` property in project files for trimming. - Replaced bindless texture types with non-bindless equivalents. - Refactored `ShaderDescriptor` and `ShaderPass` for better modularity. - Introduced `ShaderDescriptorExtensions` for property size calculations. - Simplified constant buffer handling in `Material.cs`. - Improved resource management in `D3D12` components. - Added support for static meshes and optimized resource barriers. - Refactored shader code generation and property merging in `SDLCompiler`. - Removed unused or redundant code (e.g., `IncludesBlock` parser). - Updated comments, documentation, and error handling for clarity.
This commit is contained in:
@@ -10,17 +10,18 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<IsAotCompatible>True</IsAotCompatible>
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
<DefineConstants>$(DefineConstants);PLATEFORME_WIN64</DefineConstants>
|
<DefineConstants>$(DefineConstants);PLATEFORME_WIN64</DefineConstants>
|
||||||
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<IsAotCompatible>True</IsAotCompatible>
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
<DefineConstants>$(DefineConstants);PLATEFORME_WIN64</DefineConstants>
|
<DefineConstants>$(DefineConstants);PLATEFORME_WIN64</DefineConstants>
|
||||||
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Misaki.HighPerformance" Version="1.0.1" />
|
<PackageReference Include="Misaki.HighPerformance" Version="1.0.1" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.1.0" />
|
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.2.5" />
|
||||||
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.2.1" />
|
|
||||||
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" />
|
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" />
|
||||||
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
|
<PackageReference Include="System.IO.Hashing" Version="10.0.0" />
|
||||||
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.5" />
|
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.5" />
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ public enum ShaderPropertyType
|
|||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Float, Float2, Float3, Float4,
|
Float, Float2, Float3, Float4,
|
||||||
|
Float4x4,
|
||||||
Int, Int2, Int3, Int4,
|
Int, Int2, Int3, Int4,
|
||||||
UInt, UInt2, UInt3, UInt4,
|
UInt, UInt2, UInt3, UInt4,
|
||||||
Bool, Bool2, Bool3, Bool4,
|
Bool, Bool2, Bool3, Bool4,
|
||||||
Texture2DBindless, Texture3DBindless, TextureCubeBindless,
|
Texture2D, Texture3D, TextureCube,
|
||||||
Texture2DArrayBindless, TextureCubeArrayBindless,
|
Texture2DArray, TextureCubeArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct ShaderEntryPoint
|
public struct ShaderEntryPoint
|
||||||
@@ -77,11 +78,8 @@ public class FullPassDescriptor : IPassDescriptor
|
|||||||
public ShaderEntryPoint taskShader;
|
public ShaderEntryPoint taskShader;
|
||||||
public ShaderEntryPoint meshShader;
|
public ShaderEntryPoint meshShader;
|
||||||
public ShaderEntryPoint pixelShader;
|
public ShaderEntryPoint pixelShader;
|
||||||
public string? generatedCodePath;
|
|
||||||
public List<string>? defines;
|
public List<string>? defines;
|
||||||
public List<string>? includes;
|
|
||||||
public List<KeywordsGroup>? keywords;
|
public List<KeywordsGroup>? keywords;
|
||||||
public List<PropertyDescriptor>? properties;
|
|
||||||
public PipelineDescriptor localPipeline;
|
public PipelineDescriptor localPipeline;
|
||||||
|
|
||||||
public string Identifier => uniqueIdentifier;
|
public string Identifier => uniqueIdentifier;
|
||||||
@@ -100,6 +98,42 @@ public class FallbackPassDescriptor : IPassDescriptor
|
|||||||
public class ShaderDescriptor
|
public class ShaderDescriptor
|
||||||
{
|
{
|
||||||
public string name = string.Empty;
|
public string name = string.Empty;
|
||||||
|
public string? generatedCodePath;
|
||||||
|
public uint cbufferSize;
|
||||||
public List<PropertyDescriptor> globalProperties = new();
|
public List<PropertyDescriptor> globalProperties = new();
|
||||||
|
public List<PropertyDescriptor> properties = new();
|
||||||
public List<IPassDescriptor> passes = new();
|
public List<IPassDescriptor> passes = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ghost.Core;
|
namespace Ghost.Core;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
|
|
||||||
namespace Ghost.Core;
|
namespace Ghost.Core;
|
||||||
|
|
||||||
@@ -44,6 +43,11 @@ public readonly struct Result
|
|||||||
return new Result<T, S>(value, status);
|
return new Result<T, S>(value, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RefResult<T, S> CreateRef<T, S>(ref T value, S status)
|
||||||
|
{
|
||||||
|
return new RefResult<T, S>(ref value, status);
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() => IsSuccess ? "OK" : $"Error: {Message}";
|
public override string ToString() => IsSuccess ? "OK" : $"Error: {Message}";
|
||||||
|
|
||||||
public static implicit operator bool(Result result) => result.IsSuccess;
|
public static implicit operator bool(Result result) => result.IsSuccess;
|
||||||
@@ -68,16 +72,6 @@ public readonly struct Result<T>
|
|||||||
_message = message;
|
_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<T> Success(T value)
|
public static Result<T> Success(T value)
|
||||||
{
|
{
|
||||||
return new Result<T>(true, value);
|
return new Result<T>(true, value);
|
||||||
@@ -92,9 +86,7 @@ public readonly struct Result<T>
|
|||||||
|
|
||||||
public static implicit operator Result<T>(T? data) => data is not null ? Success(data) : Failure(null);
|
public static implicit operator Result<T>(T? data) => data is not null ? Success(data) : Failure(null);
|
||||||
public static implicit operator Result<T>(Result result) => result.IsSuccess ? Success(default!) : Failure(result.Message);
|
public static implicit operator Result<T>(Result result) => result.IsSuccess ? Success(default!) : Failure(result.Message);
|
||||||
|
|
||||||
public static implicit operator bool(Result<T> result) => result.IsSuccess;
|
public static implicit operator bool(Result<T> result) => result.IsSuccess;
|
||||||
public static implicit operator Result(Result<T> result) => result.IsSuccess ? Result.Success() : Result.Failure(result.Message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ResultStatus : byte
|
public enum ResultStatus : byte
|
||||||
@@ -126,11 +118,6 @@ public readonly struct Result<T, S>
|
|||||||
_status = status;
|
_status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref readonly T GetValueRef()
|
|
||||||
{
|
|
||||||
return ref Unsafe.AsRef(in _value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Result<T, S> Create(T value, S status)
|
public static Result<T, S> Create(T value, S status)
|
||||||
{
|
{
|
||||||
return new Result<T, S>(value, status);
|
return new Result<T, S>(value, status);
|
||||||
@@ -139,6 +126,28 @@ public readonly struct Result<T, S>
|
|||||||
public override string ToString() => $"Value: {_value}, Status: {_status}";
|
public override string ToString() => $"Value: {_value}, Status: {_status}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly ref struct RefResult<T, S>
|
||||||
|
{
|
||||||
|
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<T, S> Create(ref T value, S status)
|
||||||
|
{
|
||||||
|
return new RefResult<T, S>(ref value, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() => $"Value: {_value}, Status: {_status}";
|
||||||
|
}
|
||||||
|
|
||||||
public static class ResultExtensions
|
public static class ResultExtensions
|
||||||
{
|
{
|
||||||
public static void ThrowIfFailed(this Result result)
|
public static void ThrowIfFailed(this Result result)
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ internal static unsafe partial class Win32Utility
|
|||||||
public static Guid* IID_NULL
|
public static Guid* IID_NULL
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static IID_PPV IID_PPV_ARGS<T>(ComPtr<T> comPtr)
|
public static IID_PPV IID_PPV_ARGS<T>(ComPtr<T>* comPtr)
|
||||||
where T : unmanaged, IUnknown.Interface
|
where T : unmanaged, IUnknown.Interface
|
||||||
{
|
{
|
||||||
return new IID_PPV(Windows.__uuidof<T>(), comPtr.PPV());
|
return new IID_PPV(Windows.__uuidof<T>(), (void**)comPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -80,27 +80,6 @@ internal static unsafe partial class Win32Utility
|
|||||||
return Result.Failure($"{op} failed with code {hr}");
|
return Result.Failure($"{op} failed with code {hr}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Guid* IID<T>(this ComPtr<T> comPtr)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
return Windows.__uuidof<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static Guid* IID<T>(this T ptr)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
return Windows.__uuidof<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static void** PPV<T>(ref this ComPtr<T> comPtr)
|
|
||||||
where T : unmanaged, IUnknown.Interface
|
|
||||||
{
|
|
||||||
return (void**)comPtr.GetAddressOf();
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void** ReleaseAndGetVoidAddressOf<T>(ref this ComPtr<T> comPtr)
|
public static void** ReleaseAndGetVoidAddressOf<T>(ref this ComPtr<T> comPtr)
|
||||||
where T : unmanaged, IUnknown.Interface
|
where T : unmanaged, IUnknown.Interface
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||||
|
<ResourceDictionary Source="ms-appx:///Microsoft.UI.Xaml/DensityStyles/Compact.xaml" />
|
||||||
<core:ControlsDictionary />
|
<core:ControlsDictionary />
|
||||||
<ResourceDictionary Source="/Themes/Override.xaml" />
|
<ResourceDictionary Source="/Themes/Override.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
|
||||||
<ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" />
|
<ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" />
|
||||||
<ProjectReference Include="..\Ghost.Entities\Ghost.Entities.csproj" />
|
|
||||||
<ProjectReference Include="..\Ghost.Test.Core\Ghost.Test.Core.csproj" />
|
<ProjectReference Include="..\Ghost.Test.Core\Ghost.Test.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -84,9 +83,14 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||||
<PublishTrimmed>False</PublishTrimmed>
|
|
||||||
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
|
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"Ghost.Graphics.Test (Package)": {
|
"Ghost.Graphics.Test (Package)": {
|
||||||
"commandName": "MsixPackage",
|
"commandName": "MsixPackage",
|
||||||
"nativeDebugging": true
|
"nativeDebugging": false
|
||||||
},
|
},
|
||||||
"Ghost.Graphics.Test (Unpackaged)": {
|
"Ghost.Graphics.Test (Unpackaged)": {
|
||||||
"commandName": "Project"
|
"commandName": "Project"
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
using Ghost.Graphics;
|
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using TerraFX.Interop.WinRT;
|
|
||||||
using WinRT;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.Test.Windows;
|
namespace Ghost.Graphics.Test.Windows;
|
||||||
|
|
||||||
public sealed partial class GraphicsTestWindow : Window
|
public sealed partial class GraphicsTestWindow : Window
|
||||||
{
|
{
|
||||||
|
private bool _isFirstActivationHandled = false;
|
||||||
|
|
||||||
private IRenderSystem? _renderSystem;
|
private IRenderSystem? _renderSystem;
|
||||||
private IRenderer? _renderer;
|
private IRenderer? _renderer;
|
||||||
private ISwapChain? _swapChain;
|
private ISwapChain? _swapChain;
|
||||||
@@ -18,33 +17,46 @@ public sealed partial class GraphicsTestWindow : Window
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Panel.Loaded += SwapChainPanel_Loaded;
|
Activated += GraphicsTestWindow_Activated;
|
||||||
Panel.Unloaded += SwapChainPanel_Unloaded;
|
Closed += GraphicsTestWindow_Closed;
|
||||||
|
|
||||||
Panel.SizeChanged += SwapChainPanel_SizeChanged;
|
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
|
#if DEBUG
|
||||||
AllocationManager.EnableDebugLayer();
|
AllocationManager.EnableDebugLayer();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_renderSystem = new RenderSystem(new()
|
_renderSystem = new RenderSystem(new RenderingConfig()
|
||||||
{
|
{
|
||||||
FrameBufferCount = 2,
|
FrameBufferCount = 2,
|
||||||
GraphicsAPI = GraphicsAPI.Direct3D12
|
GraphicsAPI = GraphicsAPI.Direct3D12
|
||||||
});
|
});
|
||||||
_renderer = _renderSystem.GraphicsEngine.CreateRenderer();
|
_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);
|
_renderer.SetSwapChain(_swapChain);
|
||||||
|
|
||||||
_renderSystem.Start();
|
_renderSystem.Start();
|
||||||
CompositionTarget.Rendering += OnRendering;
|
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;
|
CompositionTarget.Rendering -= OnRendering;
|
||||||
_renderSystem?.Stop();
|
_renderSystem?.Stop();
|
||||||
@@ -52,6 +64,10 @@ public sealed partial class GraphicsTestWindow : Window
|
|||||||
_renderer?.Dispose();
|
_renderer?.Dispose();
|
||||||
_swapChain?.Dispose();
|
_swapChain?.Dispose();
|
||||||
_renderSystem?.Dispose();
|
_renderSystem?.Dispose();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
AllocationManager.Dispose();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||||
@@ -69,7 +85,7 @@ public sealed partial class GraphicsTestWindow : Window
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_renderSystem.CPUFenceValue < _renderSystem.GPUFenceValue + _renderSystem.Config.FrameBufferCount)
|
if (_renderSystem.CPUFenceValue < _renderSystem.GPUFenceValue + _renderSystem.MaxFrameLatency)
|
||||||
{
|
{
|
||||||
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, () =>
|
DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.High, () =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using Misaki.HighPerformance.LowLevel.Collections;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.Contracts;
|
namespace Ghost.Graphics.Contracts;
|
||||||
|
|
||||||
public struct CompileResult : IDisposable
|
public struct ShaderCompileResult : IDisposable
|
||||||
{
|
{
|
||||||
public UnsafeArray<byte> bytecode;
|
public UnsafeArray<byte> bytecode;
|
||||||
public ShaderReflectionData reflectionData;
|
public ShaderReflectionData reflectionData;
|
||||||
@@ -21,9 +21,9 @@ public struct CompileResult : IDisposable
|
|||||||
|
|
||||||
public struct GraphicsCompiledResult : IDisposable
|
public struct GraphicsCompiledResult : IDisposable
|
||||||
{
|
{
|
||||||
public CompileResult tsResult;
|
public ShaderCompileResult tsResult;
|
||||||
public CompileResult msResult;
|
public ShaderCompileResult msResult;
|
||||||
public CompileResult psResult;
|
public ShaderCompileResult psResult;
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -143,7 +143,7 @@ public readonly struct ShaderReflectionData
|
|||||||
|
|
||||||
public interface IShaderCompiler : IDisposable
|
public interface IShaderCompiler : IDisposable
|
||||||
{
|
{
|
||||||
Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator);
|
Result<ShaderCompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator);
|
||||||
Result<GraphicsCompiledResult> CompilePass(IPassDescriptor descriptor);
|
Result<GraphicsCompiledResult> CompilePass(IPassDescriptor descriptor, string? generatedCodePath);
|
||||||
Result<GraphicsCompiledResult> LoadCompiledCache(ShaderPassKey key);
|
Result<GraphicsCompiledResult> LoadCompiledCache(ShaderPassKey key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ using Ghost.Core;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
|
||||||
using Misaki.HighPerformance.Mathematics;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
@@ -12,29 +10,38 @@ internal struct CBufferCache : IResourceReleasable
|
|||||||
{
|
{
|
||||||
private UnsafeArray<byte> _cpuData;
|
private UnsafeArray<byte> _cpuData;
|
||||||
private Handle<GraphicsBuffer> _gpuResource;
|
private Handle<GraphicsBuffer> _gpuResource;
|
||||||
|
private uint _size;
|
||||||
private uint _alignedSize;
|
private uint _alignedSize;
|
||||||
|
|
||||||
public readonly UnsafeArray<byte> CpuData => _cpuData;
|
public readonly UnsafeArray<byte> CpuData => _cpuData;
|
||||||
public readonly Handle<GraphicsBuffer> GpuResource => _gpuResource;
|
public readonly Handle<GraphicsBuffer> GpuResource => _gpuResource;
|
||||||
|
public readonly uint Size => _size;
|
||||||
public readonly uint AlignedSize => _alignedSize;
|
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<GraphicsBuffer> buffer, uint bufferSize)
|
public CBufferCache(Handle<GraphicsBuffer> buffer, uint bufferSize)
|
||||||
{
|
{
|
||||||
|
_size = bufferSize;
|
||||||
_alignedSize = (bufferSize + 255u) & ~255u;
|
_alignedSize = (bufferSize + 255u) & ~255u;
|
||||||
|
|
||||||
_cpuData = new((int)AlignedSize, Allocator.Persistent);
|
_cpuData = new UnsafeArray<byte>((int)AlignedSize, Allocator.Persistent);
|
||||||
_gpuResource = buffer;
|
_gpuResource = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseResource(IResourceDatabase database)
|
public void ReleaseResource(IResourceDatabase database)
|
||||||
{
|
{
|
||||||
|
if (!IsCreated)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_cpuData.Dispose();
|
_cpuData.Dispose();
|
||||||
|
|
||||||
database.ReleaseResource(GpuResource.AsResource());
|
database.ReleaseResource(GpuResource.AsResource());
|
||||||
_gpuResource = Handle<GraphicsBuffer>.Invalid;
|
_gpuResource = Handle<GraphicsBuffer>.Invalid;
|
||||||
|
|
||||||
|
_size = 0;
|
||||||
_alignedSize = 0;
|
_alignedSize = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,183 +49,96 @@ internal struct CBufferCache : IResourceReleasable
|
|||||||
public struct Material : IResourceReleasable, IHandleType
|
public struct Material : IResourceReleasable, IHandleType
|
||||||
{
|
{
|
||||||
private Identifier<Shader> _shader;
|
private Identifier<Shader> _shader;
|
||||||
private UnsafeArray<CBufferCache> _materialPropertiesCache; // One per shader pass
|
private CBufferCache _cBufferCache;
|
||||||
|
|
||||||
|
internal readonly CBufferCache CBufferCache => _cBufferCache;
|
||||||
|
|
||||||
public readonly Identifier<Shader> Shader => _shader;
|
public readonly Identifier<Shader> Shader => _shader;
|
||||||
|
|
||||||
internal ref CBufferCache GetPassCache(int passIndex)
|
public Result SetShader(Identifier<Shader> shaderId, IResourceAllocator allocator, IResourceDatabase database)
|
||||||
{
|
|
||||||
return ref _materialPropertiesCache[passIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetShader(Identifier<Shader> shaderId, IResourceAllocator allocator, IResourceDatabase database)
|
|
||||||
{
|
{
|
||||||
if (!shaderId.IsValid)
|
if (!shaderId.IsValid)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Shader ID is invalid.");
|
return Result.Failure("Shader ID is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_cBufferCache.ReleaseResource(database);
|
||||||
_shader = shaderId;
|
_shader = shaderId;
|
||||||
|
|
||||||
var shader = database.GetShaderReference(shaderId);
|
var shader = database.GetShaderReference(shaderId);
|
||||||
_materialPropertiesCache = new UnsafeArray<CBufferCache>(shader.PassCount, Allocator.Persistent);
|
if (shader.CBufferSize != 0)
|
||||||
for (var i = 0; i < shader.PassCount; i++)
|
|
||||||
{
|
{
|
||||||
var pass = database.GetShaderPass(shader.GetPassKey(i));
|
|
||||||
var cbufferInfo = pass.CBuffer;
|
|
||||||
|
|
||||||
if (cbufferInfo.SizeInBytes == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var desc = new BufferDesc
|
var desc = new BufferDesc
|
||||||
{
|
{
|
||||||
Size = cbufferInfo.SizeInBytes,
|
Size = shader.CBufferSize,
|
||||||
Usage = BufferUsage.Constant,
|
Usage = BufferUsage.Constant,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
MemoryType = ResourceMemoryType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var buffer = allocator.CreateBuffer(ref desc);
|
var buffer = allocator.CreateBuffer(ref desc);
|
||||||
_materialPropertiesCache[i] = new CBufferCache(buffer, cbufferInfo.SizeInBytes);
|
_cBufferCache = new CBufferCache(buffer, shader.CBufferSize);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
|
||||||
{
|
|
||||||
foreach (var cache in _materialPropertiesCache)
|
|
||||||
{
|
|
||||||
cache.ReleaseResource(database);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_materialPropertiesCache.Dispose();
|
return Result.Success();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ref struct MaterialAccessor
|
|
||||||
{
|
|
||||||
private ref Material _materialData;
|
|
||||||
private readonly Shader _shader;
|
|
||||||
|
|
||||||
private readonly IResourceDatabase _resourceDatabase;
|
|
||||||
|
|
||||||
public MaterialAccessor(Handle<Material> material, IResourceDatabase resourceDatabase)
|
|
||||||
{
|
|
||||||
_resourceDatabase = resourceDatabase;
|
|
||||||
|
|
||||||
_materialData = ref resourceDatabase.GetMaterialReference(material);
|
|
||||||
_shader = resourceDatabase.GetShaderReference(_materialData.Shader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly unsafe void WriteToCache<T>(string propertyName, in T value)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly unsafe Result<T, ResultStatus> GetPropertyCache<T>()
|
||||||
where T : unmanaged
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
foreach (var index in _shader.GetPropertyPassIndices(propertyName))
|
if (sizeof(T) != _cBufferCache.Size)
|
||||||
{
|
{
|
||||||
var passKey = _shader.GetPassKey(index);
|
return Result.Create(default(T), ResultStatus.InvalidArgument);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a float property in the material's constant buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">The name of the property to set.</param>
|
|
||||||
/// <param name="value">The Value to set for the property.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void SetFloat(string propertyName, in float value)
|
|
||||||
{
|
|
||||||
WriteToCache(propertyName, in value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a uint property in the material's constant buffer (useful for texture indices).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">The name of the property to set.</param>
|
|
||||||
/// <param name="value">The Value to set for the property.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void SetUInt(string propertyName, in uint value)
|
|
||||||
{
|
|
||||||
WriteToCache(propertyName, in value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a Vector property in the material's constant buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">The name of the property to set.</param>
|
|
||||||
/// <param name="value">The Value to set for the property.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void SetVector(string propertyName, in float4 value)
|
|
||||||
{
|
|
||||||
WriteToCache(propertyName, in value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a Matrix property in the material's constant buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">The name of the property to set.</param>
|
|
||||||
/// <param name="value">The Value to set for the property.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void SetMatrix(string propertyName, in float4x4 value)
|
|
||||||
{
|
|
||||||
WriteToCache(propertyName, in value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets a texture index for a shader property (for bindless texture access)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">The name of the shader property (e.g., "_TextureIndex1")</param>
|
|
||||||
/// <param name="texture">The bindless texture to reference</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public readonly void SetTextureBindless(string propertyName, Handle<Texture> 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.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetUInt(propertyName, (uint)bindlessIndex);
|
return Result.Create(*(T*)_cBufferCache.CpuData.GetUnsafePtr(), ResultStatus.Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the mesh buffer indices for bindless vertex and index buffer access
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mesh">The mesh whose buffer indices to set</param>
|
|
||||||
/// <param name="vertexBufferIndexProperty">The name of the vertex buffer index property</param>
|
|
||||||
/// <param name="indexBufferIndexProperty">The name of the index buffer index property</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly void SetBufferBindless(string propertyName, Handle<GraphicsBuffer> buffer)
|
public readonly Span<byte> GetRawPropertyCache()
|
||||||
{
|
{
|
||||||
var bindlessIndex = _resourceDatabase.GetBindlessIndex(buffer.AsResource());
|
if (_cBufferCache.Size == 0)
|
||||||
if (bindlessIndex == -1)
|
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The provided buffer does not have a valid bindless index. Ensure the buffer is created with bindless support.");
|
return Span<byte>.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetUInt(propertyName, (uint)bindlessIndex);
|
return _cBufferCache.CpuData.AsSpan(0, (int)_cBufferCache.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Uploads all cached material data to the GPU using the specified command buffer.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cmb">The command buffer used to perform the upload operations to the GPU. Cannot be null.</param>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly void UploadMaterialData(ICommandBuffer cmb)
|
public readonly unsafe Result<ResultStatus> SetPropertyCache<T>(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);
|
return new Result<ResultStatus>(false, ResultStatus.InvalidArgument);
|
||||||
cmb.UploadBuffer<byte>(cache.GpuResource, cache.CpuData.AsSpan());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data);
|
||||||
|
return Result.Success(ResultStatus.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public readonly unsafe Result<ResultStatus> SetRawPropertyCache(ReadOnlySpan<byte> data)
|
||||||
|
{
|
||||||
|
if (data.Length != _cBufferCache.Size)
|
||||||
|
{
|
||||||
|
return new Result<ResultStatus>(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ namespace Ghost.Graphics.Core;
|
|||||||
|
|
||||||
public struct Mesh : IResourceReleasable, IHandleType
|
public struct Mesh : IResourceReleasable, IHandleType
|
||||||
{
|
{
|
||||||
|
private UnsafeList<Vertex> _vertices;
|
||||||
|
private UnsafeList<uint> _indices;
|
||||||
|
|
||||||
internal bool IsMeshDataDirty
|
internal bool IsMeshDataDirty
|
||||||
{
|
{
|
||||||
get; private set;
|
get; private set;
|
||||||
@@ -21,10 +24,10 @@ public struct Mesh : IResourceReleasable, IHandleType
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public UnsafeList<Vertex> Vertices
|
public UnsafeList<Vertex> Vertices
|
||||||
{
|
{
|
||||||
readonly get => field;
|
readonly get => _vertices;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
field = value;
|
_vertices = value;
|
||||||
VertexCount = value.Count;
|
VertexCount = value.Count;
|
||||||
IsMeshDataDirty = true;
|
IsMeshDataDirty = true;
|
||||||
}
|
}
|
||||||
@@ -35,10 +38,10 @@ public struct Mesh : IResourceReleasable, IHandleType
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public UnsafeList<uint> Indices
|
public UnsafeList<uint> Indices
|
||||||
{
|
{
|
||||||
readonly get => field;
|
readonly get => _indices;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
field = value;
|
_indices = value;
|
||||||
IndexCount = value.Count;
|
IndexCount = value.Count;
|
||||||
IsMeshDataDirty = true;
|
IsMeshDataDirty = true;
|
||||||
}
|
}
|
||||||
@@ -100,8 +103,8 @@ public struct Mesh : IResourceReleasable, IHandleType
|
|||||||
|
|
||||||
internal Mesh(ReadOnlySpan<Vertex> vertices, ReadOnlySpan<uint> indices, Handle<GraphicsBuffer> vertexBuffer, Handle<GraphicsBuffer> indexBuffer)
|
internal Mesh(ReadOnlySpan<Vertex> vertices, ReadOnlySpan<uint> indices, Handle<GraphicsBuffer> vertexBuffer, Handle<GraphicsBuffer> indexBuffer)
|
||||||
{
|
{
|
||||||
Vertices = new(vertices.Length, Allocator.Persistent);
|
Vertices = new UnsafeList<Vertex>(vertices.Length, Allocator.Persistent);
|
||||||
Indices = new(indices.Length, Allocator.Persistent);
|
Indices = new UnsafeList<uint>(indices.Length, Allocator.Persistent);
|
||||||
Vertices.CopyFrom(vertices);
|
Vertices.CopyFrom(vertices);
|
||||||
Indices.CopyFrom(indices);
|
Indices.CopyFrom(indices);
|
||||||
VertexBuffer = vertexBuffer;
|
VertexBuffer = vertexBuffer;
|
||||||
@@ -112,8 +115,8 @@ public struct Mesh : IResourceReleasable, IHandleType
|
|||||||
|
|
||||||
public readonly void ReleaseCpuResources()
|
public readonly void ReleaseCpuResources()
|
||||||
{
|
{
|
||||||
Vertices.Dispose();
|
_vertices.Dispose();
|
||||||
Indices.Dispose();
|
_indices.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
||||||
|
|||||||
@@ -56,13 +56,32 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
queue.WaitIdle();
|
queue.WaitIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices, bool staticMesh)
|
||||||
{
|
{
|
||||||
var mesh = ResourceAllocator.CreateMesh(vertices, indices);
|
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;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Handle<Mesh> CreateMesh(ReadOnlySpan<Vertex> vertices, ReadOnlySpan<uint> indices)
|
public Handle<Mesh> CreateMesh(ReadOnlySpan<Vertex> vertices, ReadOnlySpan<uint> indices, bool staticMesh)
|
||||||
{
|
{
|
||||||
var vertexList = new UnsafeList<Vertex>(vertices.Length, Allocator.Persistent);
|
var vertexList = new UnsafeList<Vertex>(vertices.Length, Allocator.Persistent);
|
||||||
var indexList = new UnsafeList<uint>(indices.Length, Allocator.Persistent);
|
var indexList = new UnsafeList<uint>(indices.Length, Allocator.Persistent);
|
||||||
@@ -70,12 +89,7 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
vertexList.CopyFrom(vertices);
|
vertexList.CopyFrom(vertices);
|
||||||
indexList.CopyFrom(indices);
|
indexList.CopyFrom(indices);
|
||||||
|
|
||||||
return CreateMesh(vertexList, indexList);
|
return CreateMesh(vertexList, indexList, staticMesh);
|
||||||
}
|
|
||||||
|
|
||||||
public MaterialAccessor GetMaterialAccessor(Handle<Material> material)
|
|
||||||
{
|
|
||||||
return new MaterialAccessor(material, ResourceDatabase);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make one memory pool for upload.
|
// TODO: Make one memory pool for upload.
|
||||||
@@ -108,12 +122,12 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
|
|
||||||
if (needVertexTransition)
|
if (needVertexTransition)
|
||||||
{
|
{
|
||||||
_directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.VertexAndConstantBuffer);
|
_directCmd.ResourceBarrier(meshData.VertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needIndexTransition)
|
if (needIndexTransition)
|
||||||
{
|
{
|
||||||
_directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, ResourceState.IndexBuffer);
|
_directCmd.ResourceBarrier(meshData.IndexBuffer.AsResource(), ResourceState.CopyDest, indexState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (markMeshStatic)
|
if (markMeshStatic)
|
||||||
@@ -177,7 +191,7 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
slicePitch = slicePitch
|
slicePitch = slicePitch
|
||||||
};
|
};
|
||||||
|
|
||||||
_directCmd.UploadTexture(texture, subresourceData);
|
_directCmd.UploadTexture(texture, [subresourceData]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needTransition)
|
if (needTransition)
|
||||||
@@ -194,10 +208,15 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
ref var materialRef = ref ResourceDatabase.GetMaterialReference(material);
|
ref var materialRef = ref ResourceDatabase.GetMaterialReference(material);
|
||||||
var shader = ResourceDatabase.GetShaderReference(materialRef.Shader);
|
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
|
var hash = new GraphicsPipelineHash
|
||||||
{
|
{
|
||||||
Id = passKey,
|
Id = keyResult.Value.Identifier,
|
||||||
RtvCount = 1,
|
RtvCount = 1,
|
||||||
DsvFormat = TextureFormat.Unknown,
|
DsvFormat = TextureFormat.Unknown,
|
||||||
};
|
};
|
||||||
@@ -209,20 +228,13 @@ public unsafe readonly ref struct RenderingContext
|
|||||||
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_OBJECT_BUFFER_SLOT, meshRef.ObjectDataBuffer);
|
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_OBJECT_BUFFER_SLOT, meshRef.ObjectDataBuffer);
|
||||||
|
|
||||||
// NOTE: We use fixed root signature layout for bindless rendering.
|
// NOTE: We use fixed root signature layout for bindless rendering.
|
||||||
ref var cache = ref materialRef.GetPassCache(passIndex);
|
var cache = materialRef.CBufferCache;
|
||||||
if (cache.IsCreated)
|
if (cache.IsCreated)
|
||||||
{
|
{
|
||||||
_directCmd.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
|
_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.
|
var threadGroupCountX = ((uint)meshRef.IndexCount + numThreadsX - 1) / numThreadsX;
|
||||||
// TODO: Maybe handle the traditional bindless model?
|
_directCmd.DispatchMesh(threadGroupCountX, 1, 1);
|
||||||
#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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,45 +3,44 @@ using Ghost.Core.Graphics;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Core;
|
namespace Ghost.Graphics.Core;
|
||||||
|
|
||||||
public class ShaderPass : IResourceReleasable
|
public struct ShaderPass : IResourceReleasable
|
||||||
{
|
{
|
||||||
private CBufferInfo _cbufferInfo;
|
public ShaderPassKey Identifier
|
||||||
// NOTE: This is for per pass cbuffer only. Global, per view, and per mesh cbuffers are fixed.
|
|
||||||
private readonly Dictionary<string, int> _propertyLookup;
|
|
||||||
|
|
||||||
public CBufferInfo CBuffer => _cbufferInfo;
|
|
||||||
|
|
||||||
public ShaderPass(CBufferInfo info)
|
|
||||||
{
|
{
|
||||||
_cbufferInfo = info;
|
get; init;
|
||||||
|
|
||||||
var capacity = info.Properties?.Count ?? 0;
|
|
||||||
_propertyLookup = new Dictionary<string, int>(capacity);
|
|
||||||
for (var i = 0; i < capacity; i++)
|
|
||||||
{
|
|
||||||
_propertyLookup[info.Properties![i].Name] = i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -52,46 +51,43 @@ public class ShaderPass : IResourceReleasable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Shader : IResourceReleasable, IIdentifierType
|
public class Shader : IResourceReleasable, IIdentifierType
|
||||||
{
|
{
|
||||||
private UnsafeArray<ShaderPassKey> _passIDs;
|
private readonly uint _cbufferSize;
|
||||||
|
private UnsafeArray<ShaderPass> _passes;
|
||||||
// TODO: Optmize lookups with a better data structure if needed
|
// TODO: Optmize lookups with a better data structure if needed
|
||||||
private readonly Dictionary<string, int> _passLookup; // pass name to index
|
private readonly Dictionary<string, int> _passLookup; // pass name to index
|
||||||
private readonly Dictionary<string, List<int>> _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)
|
internal Shader(ShaderDescriptor descriptor)
|
||||||
{
|
{
|
||||||
_passIDs = new UnsafeArray<ShaderPassKey>(descriptor.passes.Count, Allocator.Persistent);
|
_cbufferSize = descriptor.cbufferSize;
|
||||||
_passLookup = new(descriptor.passes.Count);
|
_passes = new UnsafeArray<ShaderPass>(descriptor.passes.Count, Allocator.Persistent);
|
||||||
_propertyLookup = new(descriptor.passes.Count);
|
_passLookup = new Dictionary<string, int>(descriptor.passes.Count);
|
||||||
|
|
||||||
for (var i = 0; i < descriptor.passes.Count; i++)
|
for (var i = 0; i < descriptor.passes.Count; i++)
|
||||||
{
|
{
|
||||||
var pass = descriptor.passes[i];
|
var pass = descriptor.passes[i];
|
||||||
|
|
||||||
|
// TODO: Handle inherited passes
|
||||||
|
if (pass is not FullPassDescriptor fullPass)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var passKey = new ShaderPassKey(pass.Identifier);
|
var passKey = new ShaderPassKey(pass.Identifier);
|
||||||
|
|
||||||
_passIDs[i] = passKey;
|
_passes[i] = new ShaderPass
|
||||||
_passLookup[pass.Name] = i;
|
|
||||||
|
|
||||||
if (pass is FullPassDescriptor fullPass)
|
|
||||||
{
|
{
|
||||||
if (fullPass.properties == null)
|
Identifier = passKey,
|
||||||
{
|
ZTest = fullPass.localPipeline.zTest,
|
||||||
continue;
|
ZWrite = fullPass.localPipeline.zWrite,
|
||||||
}
|
Cull = fullPass.localPipeline.cull,
|
||||||
|
Blend = fullPass.localPipeline.blend,
|
||||||
|
ColorMask = fullPass.localPipeline.colorMask
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var property in fullPass.properties)
|
_passLookup[pass.Name] = i;
|
||||||
{
|
|
||||||
ref var passIndices = ref CollectionsMarshal.GetValueRefOrAddDefault(_propertyLookup, property.name, out var exists);
|
|
||||||
if (!exists || passIndices == null)
|
|
||||||
{
|
|
||||||
passIndices = new List<int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
passIndices.Add(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: handle inherited passes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,38 +96,26 @@ public class Shader : IResourceReleasable, IIdentifierType
|
|||||||
return _passLookup.GetValueOrDefault(passName, -1);
|
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<ShaderPass, ResultStatus> TryGetPassKey(string passName, out int passIndex)
|
||||||
{
|
{
|
||||||
var index = _passLookup.GetValueOrDefault(passName, -1);
|
var index = _passLookup.GetValueOrDefault(passName, -1);
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
{
|
{
|
||||||
passIndex = -1;
|
passIndex = -1;
|
||||||
passID = new(0);
|
return Result.CreateRef(ref Unsafe.NullRef<ShaderPass>(), ResultStatus.NotFound);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
passIndex = index;
|
passIndex = index;
|
||||||
passID = _passIDs[index];
|
return Result.CreateRef(ref _passes[index], ResultStatus.Success);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IReadOnlyCollection<int> GetPropertyPassIndices(string propertyName)
|
|
||||||
{
|
|
||||||
if (_propertyLookup.TryGetValue(propertyName, out var passIndices))
|
|
||||||
{
|
|
||||||
return passIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Array.Empty<int>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
void IResourceReleasable.ReleaseResource(IResourceDatabase database)
|
||||||
{
|
{
|
||||||
_passIDs.Dispose();
|
_passes.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Ghost.Graphics.Core;
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct Vertex
|
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 DXGI_FORMAT ALIGNED_FORMAT = DXGI_FORMAT.DXGI_FORMAT_R32G32B32A32_FLOAT;
|
||||||
public const int COUNT = 5;
|
public const int COUNT = 5;
|
||||||
|
|||||||
@@ -173,17 +173,65 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
|
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after)
|
public void ResourceBarrier(ReadOnlySpan<BarrierDesc> barrierDescs)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
IncrementCommandCount();
|
IncrementCommandCount();
|
||||||
|
|
||||||
var d3d12Resource = _resourceDatabase.GetResource(resource);
|
var count = 0u;
|
||||||
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
|
var pBarriers = stackalloc D3D12_RESOURCE_BARRIER[barrierDescs.Length];
|
||||||
before.ToD3D12States(), after.ToD3D12States());
|
|
||||||
|
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<GPUResource> 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);
|
_commandList.Get()->ResourceBarrier(1, &barrier);
|
||||||
|
resourceRecord.state = stateAfter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
||||||
@@ -465,7 +513,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
|
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
|
public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<SubResourceData> subresources)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
ThrowIfNotRecording();
|
ThrowIfNotRecording();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
|||||||
|
|
||||||
private bool _disposed;
|
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);
|
_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);
|
_dsvHeap = new D3D12DescriptorHeap("dsv", device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, initialDsvCount, initialDsvCount / 2);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
internal class D3D12GraphicsEngine : IGraphicsEngine
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private readonly D3D12DebugLayer _debugLayer;
|
private readonly D3D12DebugLayer _debugLayer;
|
||||||
@@ -34,17 +34,17 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
public D3D12GraphicsEngine(IRenderSystem renderSystem)
|
public D3D12GraphicsEngine(IRenderSystem renderSystem)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
_debugLayer = new();
|
_debugLayer = new D3D12DebugLayer();
|
||||||
#endif
|
#endif
|
||||||
_device = new();
|
_device = new D3D12RenderDevice();
|
||||||
_shaderCompiler = new();
|
_shaderCompiler = new DxcShaderCompiler();
|
||||||
_descriptorAllocator = new(_device);
|
_descriptorAllocator = new D3D12DescriptorAllocator(_device);
|
||||||
|
|
||||||
_resourceDatabase = new(_descriptorAllocator);
|
_resourceDatabase = new D3D12ResourceDatabase(_descriptorAllocator);
|
||||||
_pipelineLibrary = new(_device, _resourceDatabase);
|
_pipelineLibrary = new D3D12PipelineLibrary(_device, _resourceDatabase);
|
||||||
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
|
_resourceAllocator = new D3D12ResourceAllocator(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
|
||||||
|
|
||||||
_copyCommandBuffer = new(
|
_copyCommandBuffer = new D3D12CommandBuffer(
|
||||||
_device,
|
_device,
|
||||||
_pipelineLibrary,
|
_pipelineLibrary,
|
||||||
_resourceDatabase,
|
_resourceDatabase,
|
||||||
@@ -136,6 +136,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
|||||||
|
|
||||||
_copyCommandBuffer.End();
|
_copyCommandBuffer.End();
|
||||||
_resourceAllocator.ReleaseTempResources();
|
_resourceAllocator.ReleaseTempResources();
|
||||||
|
_descriptorAllocator.ResetCbvSrvUavDynamicHeap();
|
||||||
|
_descriptorAllocator.ResetDSVDynamicHeap();
|
||||||
|
_descriptorAllocator.ResetRTVDynamicHeap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ using Ghost.Graphics.RHI;
|
|||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
|
||||||
using Misaki.HighPerformance.Utilities;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
@@ -40,7 +38,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
|||||||
private UniquePtr<ID3D12RootSignature> _defaultRootSignature;
|
private UniquePtr<ID3D12RootSignature> _defaultRootSignature;
|
||||||
|
|
||||||
private readonly Dictionary<GraphicsPipelineKey, D3D12PipelineState> _pipelineCache;
|
private readonly Dictionary<GraphicsPipelineKey, D3D12PipelineState> _pipelineCache;
|
||||||
private readonly Dictionary<ShaderPassKey, CBufferInfo> _cbufferInfoCache;
|
|
||||||
|
|
||||||
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||||
|
|
||||||
@@ -50,9 +47,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
|||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
|
||||||
_pipelineCache = new Dictionary<GraphicsPipelineKey, D3D12PipelineState>();
|
_pipelineCache = new Dictionary<GraphicsPipelineKey, D3D12PipelineState>();
|
||||||
_cbufferInfoCache = new Dictionary<ShaderPassKey, CBufferInfo>();
|
|
||||||
|
|
||||||
CreateDefaultRootSignature();
|
CreateDefaultRootSignature().ThrowIfFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result CreateDefaultRootSignature()
|
private Result CreateDefaultRootSignature()
|
||||||
@@ -140,36 +136,21 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
|||||||
Desc_1_1 = rootSignatureDesc
|
Desc_1_1 = rootSignatureDesc
|
||||||
};
|
};
|
||||||
|
|
||||||
ID3DBlob* pSignature = default;
|
using ComPtr<ID3DBlob> pSignature = default;
|
||||||
ID3DBlob* pError = default;
|
using ComPtr<ID3DBlob> pError = default;
|
||||||
|
|
||||||
try
|
var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, pSignature.GetAddressOf(), pError.GetAddressOf());
|
||||||
|
if (serializeResult.FAILED)
|
||||||
{
|
{
|
||||||
var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, &pSignature, &pError);
|
var errorMsg = pError.Get() != null ? Marshal.PtrToStringUTF8((nint)pError.Get()->GetBufferPointer()) : "Unknown error";
|
||||||
if (serializeResult.FAILED)
|
return Result.Failure($"Failed to serialize default root signature: {errorMsg}");
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (pSignature != null)
|
|
||||||
{
|
|
||||||
pSignature->Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pError != null)
|
ID3D12RootSignature* pRootSignature = default;
|
||||||
{
|
ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature.Get()->GetBufferPointer(), pSignature.Get()->GetBufferSize(),
|
||||||
pError->Release();
|
__uuidof(pRootSignature), (void**)&pRootSignature));
|
||||||
}
|
|
||||||
}
|
_defaultRootSignature.Attach(pRootSignature);
|
||||||
|
|
||||||
return Result.Success();
|
return Result.Success();
|
||||||
}
|
}
|
||||||
@@ -337,8 +318,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
|||||||
return Result.Failure(result.Message);
|
return Result.Failure(result.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cbufferInfoCache[descriptor.PassId] = result.Value;
|
|
||||||
|
|
||||||
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
||||||
{
|
{
|
||||||
pRootSignature = _defaultRootSignature.Get(),
|
pRootSignature = _defaultRootSignature.Get(),
|
||||||
@@ -422,16 +401,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<CBufferInfo, ResultStatus> 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<SharedPtr<ID3D12PipelineState>, ResultStatus> GetGraphicsPSO(GraphicsPipelineKey key)
|
public Result<SharedPtr<ID3D12PipelineState>, ResultStatus> GetGraphicsPSO(GraphicsPipelineKey key)
|
||||||
{
|
{
|
||||||
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ internal class D3D12Renderer : IRenderer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly D3D12GraphicsEngine _graphicsEngine;
|
private readonly D3D12GraphicsEngine _graphicsEngine;
|
||||||
private readonly D3D12CommandQueue _commandQueue;
|
|
||||||
private readonly FrameResource[] _frameResources;
|
private readonly FrameResource[] _frameResources;
|
||||||
private uint _frameIndex;
|
private uint _frameIndex;
|
||||||
|
|
||||||
@@ -60,7 +59,6 @@ internal class D3D12Renderer : IRenderer
|
|||||||
public D3D12Renderer(D3D12GraphicsEngine graphicsEngine, D3D12ResourceAllocator resourceAllocator, D3D12ResourceDatabase resourceDatabase)
|
public D3D12Renderer(D3D12GraphicsEngine graphicsEngine, D3D12ResourceAllocator resourceAllocator, D3D12ResourceDatabase resourceDatabase)
|
||||||
{
|
{
|
||||||
_graphicsEngine = graphicsEngine;
|
_graphicsEngine = graphicsEngine;
|
||||||
_commandQueue = (D3D12CommandQueue)graphicsEngine.Device.GraphicsQueue;
|
|
||||||
_resourceAllocator = resourceAllocator;
|
_resourceAllocator = resourceAllocator;
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
|
|
||||||
@@ -153,7 +151,7 @@ internal class D3D12Renderer : IRenderer
|
|||||||
_swapChain?.Resize(newSize.x, newSize.y);
|
_swapChain?.Resize(newSize.x, newSize.y);
|
||||||
_currentSize = newSize;
|
_currentSize = newSize;
|
||||||
|
|
||||||
// Update off-screen render target size
|
// Update off-screen render Target size
|
||||||
if (_swapChain != null)
|
if (_swapChain != null)
|
||||||
{
|
{
|
||||||
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
|
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
|
||||||
@@ -170,7 +168,7 @@ internal class D3D12Renderer : IRenderer
|
|||||||
|
|
||||||
if (frame.fenceValue > 0)
|
if (frame.fenceValue > 0)
|
||||||
{
|
{
|
||||||
_commandQueue.WaitForValue(frame.fenceValue);
|
_graphicsEngine.Device.GraphicsQueue.WaitForValue(frame.fenceValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_renderTarget.IsValid)
|
if (_renderTarget.IsValid)
|
||||||
@@ -202,12 +200,12 @@ internal class D3D12Renderer : IRenderer
|
|||||||
|
|
||||||
frame.commandBuffer.End();
|
frame.commandBuffer.End();
|
||||||
|
|
||||||
_commandQueue.Submit(frame.commandBuffer);
|
_graphicsEngine.Device.GraphicsQueue.Submit(frame.commandBuffer);
|
||||||
_swapChain?.Present();
|
_swapChain?.Present();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.fenceValue = _commandQueue.Signal(_frameIndex);
|
frame.fenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_frameIndex);
|
||||||
_frameIndex++;
|
_frameIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +255,7 @@ internal class D3D12Renderer : IRenderer
|
|||||||
// Handle swap chain back buffer transitions if needed
|
// Handle swap chain back buffer transitions if needed
|
||||||
if (_swapChain != null)
|
if (_swapChain != null)
|
||||||
{
|
{
|
||||||
// Transition back buffer to render target
|
// Transition back buffer to render Target
|
||||||
cmd.ResourceBarrier(destination.AsResource(), ResourceState.Present, ResourceState.RenderTarget);
|
cmd.ResourceBarrier(destination.AsResource(), ResourceState.Present, ResourceState.RenderTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +264,7 @@ internal class D3D12Renderer : IRenderer
|
|||||||
|
|
||||||
// FIX: Implement proper blit operation with shader
|
// FIX: Implement proper blit operation with shader
|
||||||
// This is a placeholder - in D3D12, you would typically:
|
// 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
|
// 2. Use a full-screen quad/triangle with a shader that samples from the source
|
||||||
|
|
||||||
// Handle swap chain back buffer transitions if needed
|
// Handle swap chain back buffer transitions if needed
|
||||||
@@ -284,7 +282,7 @@ internal class D3D12Renderer : IRenderer
|
|||||||
{
|
{
|
||||||
if (frame.fenceValue > 0)
|
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.
|
// NOTE: Testing only.
|
||||||
_pass.Cleanup(_resourceDatabase);
|
_pass.Cleanup(_resourceDatabase);
|
||||||
|
|
||||||
// If using a swap chain, release the off-screen render target.
|
// If using a swap chain, release the off-screen render Target.
|
||||||
// Otherwise, the render target is managed externally.
|
// Otherwise, the render Target is managed externally.
|
||||||
if (_swapChain != null)
|
if (_swapChain != null)
|
||||||
{
|
{
|
||||||
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
|
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Ghost.Graphics.Core;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
@@ -522,10 +522,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
return D3D12_RESOURCE_STATE_COPY_DEST;
|
return D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to Common, but check for specific roles
|
|
||||||
var state = D3D12_RESOURCE_STATE_COMMON;
|
var state = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
#if true
|
||||||
return state;
|
return state;
|
||||||
|
#else
|
||||||
|
// D3D12 does not support state other than COMMON for buffers at creation.
|
||||||
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
|
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
|
||||||
{
|
{
|
||||||
// Vertex and Constant buffers can share this state
|
// 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
|
// If it's a mix, start in common and let the user barrier
|
||||||
return D3D12_RESOURCE_STATE_COMMON;
|
return D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResourceState D3D12StatesToRHIState(D3D12_RESOURCE_STATES states)
|
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 D3D12ResourceDatabase _resourceDatabase;
|
||||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||||
|
|
||||||
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
private UnsafeQueue<Handle<GPUResource>> _tempResources;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -633,7 +635,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
_pipelineLibrary = pipelineLibrary;
|
_pipelineLibrary = pipelineLibrary;
|
||||||
|
|
||||||
_temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
_tempResources = new UnsafeQueue<Handle<GPUResource>>(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||||
}
|
}
|
||||||
|
|
||||||
~D3D12ResourceAllocator()
|
~D3D12ResourceAllocator()
|
||||||
@@ -648,7 +650,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
|
|
||||||
if (isTemp)
|
if (isTemp)
|
||||||
{
|
{
|
||||||
_temResources.Enqueue(handle);
|
_tempResources.Enqueue(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
@@ -714,13 +716,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
var initialState = DetermineInitialTextureState(desc.Usage);
|
var initialState = DetermineInitialTextureState(desc.Usage);
|
||||||
|
|
||||||
D3D12MA_Allocation* pAllocation = default;
|
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;
|
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||||
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
|
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
|
||||||
{
|
{
|
||||||
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
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 isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
|
||||||
var srvDesc = CreateTextureSrvDesc(pAllocation->GetResource(), mipLevels, desc.Slice, isCubeMap);
|
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))
|
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
||||||
{
|
{
|
||||||
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.uav);
|
||||||
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
|
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
|
||||||
|
|
||||||
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
||||||
@@ -906,24 +910,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
var shader = new Shader(descriptor);
|
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<Shader>.Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
_resourceDatabase.AddShaderPass(passKey, new ShaderPass(cbr.Value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return _resourceDatabase.AddShader(shader);
|
return _resourceDatabase.AddShader(shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,14 +917,14 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
while (_temResources.Count > 0)
|
while (_tempResources.Count > 0)
|
||||||
{
|
{
|
||||||
var handle = _temResources.Peek();
|
var handle = _tempResources.Peek();
|
||||||
ref var info = ref _resourceDatabase.GetResourceInfo(handle, out var exist);
|
ref var info = ref _resourceDatabase.GetResourceRecord(handle, out var exist);
|
||||||
if (!exist || !info.Allocated)
|
if (!exist || !info.Allocated)
|
||||||
{
|
{
|
||||||
// Resource already released or invalid, just dequeue
|
// Resource already released or invalid, just dequeue
|
||||||
_temResources.Dequeue();
|
_tempResources.Dequeue();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -950,7 +936,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
_resourceDatabase.ReleaseResource(handle);
|
_resourceDatabase.ReleaseResource(handle);
|
||||||
_temResources.Dequeue();
|
_tempResources.Dequeue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,20 +947,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG || GHOST_EDITOR
|
Debug.Assert(_tempResources.Count == 0, "Temporary resources should be released before disposing the allocator.");
|
||||||
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
|
|
||||||
|
|
||||||
foreach (var handle in _temResources)
|
foreach (var handle in _tempResources)
|
||||||
{
|
{
|
||||||
_resourceDatabase.ReleaseResource(handle);
|
_resourceDatabase.ReleaseResource(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
_d3d12MA.Dispose();
|
_d3d12MA.Dispose();
|
||||||
_temResources.Dispose();
|
_tempResources.Dispose();
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
|
using Ghost.Graphics.D3D12.Utilities;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.Collections;
|
using Misaki.HighPerformance.Collections;
|
||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
public readonly bool isExternal;
|
public readonly bool isExternal;
|
||||||
|
|
||||||
public readonly bool Allocated => isExternal ? resourceUnion.resource.Get() != null : resourceUnion.allocation.Get() != null;
|
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<ID3D12Resource> ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
|
||||||
|
|
||||||
public ResourceRecord(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState state, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
|
public ResourceRecord(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState state, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
|
||||||
{
|
{
|
||||||
@@ -131,7 +131,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
resource = default!;
|
resource = default!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string? name = null)
|
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string name = "")
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -139,16 +139,14 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
var handle = new Handle<GPUResource>(id, generation);
|
var handle = new Handle<GPUResource>(id, generation);
|
||||||
|
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
if (name != null)
|
pResource->SetName(name);
|
||||||
{
|
_resourceName[handle] = name;
|
||||||
_resourceName[handle] = name;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe Handle<GPUResource> AddResource(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
|
public unsafe Handle<GPUResource> AddResource(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string name = "")
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -156,10 +154,8 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
var handle = new Handle<GPUResource>(id, generation);
|
var handle = new Handle<GPUResource>(id, generation);
|
||||||
|
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
if (name != null)
|
allocation->SetName(name);
|
||||||
{
|
_resourceName[handle] = name;
|
||||||
_resourceName[handle] = name;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
@@ -184,7 +180,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
return ref info;
|
return ref info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref ResourceRecord GetResourceInfo(Handle<GPUResource> handle, out bool exist)
|
public ref ResourceRecord GetResourceRecord(Handle<GPUResource> handle, out bool exist)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
|
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
|
||||||
@@ -232,7 +228,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
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)
|
if (!exist || !info.Allocated)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
@@ -254,7 +250,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void ReleaseResource(Handle<GPUResource> handle)
|
public void ReleaseResource(Handle<GPUResource> handle)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -269,14 +265,10 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var refCount = info.Release(_descriptorAllocator);
|
info.Release(_descriptorAllocator);
|
||||||
|
//Debug.Assert(info.Release(_descriptorAllocator) == 0);
|
||||||
#if DEBUG || GHOST_EDITOR
|
#if DEBUG || GHOST_EDITOR
|
||||||
_resourceName.Remove(handle, out var name);
|
_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
|
#endif
|
||||||
|
|
||||||
_resources.Remove(handle.id, handle.generation);
|
_resources.Remove(handle.id, handle.generation);
|
||||||
@@ -405,34 +397,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
ReleaseResource(ref shader);
|
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
static void ThrowMemoryLeakException(string resourceType, int count)
|
static void ThrowMemoryLeakException(string resourceType, int count)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Ghost.Graphics.RHI;
|
|||||||
using Misaki.HighPerformance.LowLevel;
|
using Misaki.HighPerformance.LowLevel;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using TerraFX.Interop.DirectX;
|
using TerraFX.Interop.DirectX;
|
||||||
using TerraFX.Interop.Windows;
|
using TerraFX.Interop.Windows;
|
||||||
@@ -27,7 +28,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
private UniquePtr<IDXGISwapChain4> _swapChain;
|
private UniquePtr<IDXGISwapChain4> _swapChain;
|
||||||
private UnsafeArray<Handle<Texture>> _backBuffers;
|
private UnsafeArray<Handle<Texture>> _backBuffers;
|
||||||
|
|
||||||
private object? _compositionSurface;
|
private readonly object? _compositionSurface;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -48,20 +49,22 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
|
|
||||||
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc)
|
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc)
|
||||||
{
|
{
|
||||||
|
Debug.Assert(desc.BufferCount >= 2);
|
||||||
|
|
||||||
_resourceDatabase = resourceDatabase;
|
_resourceDatabase = resourceDatabase;
|
||||||
_descriptorAllocator = descriptorAllocator;
|
_descriptorAllocator = descriptorAllocator;
|
||||||
_renderDevice = device;
|
_renderDevice = device;
|
||||||
|
|
||||||
_backBuffers = new UnsafeArray<Handle<Texture>>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent);
|
_backBuffers = new UnsafeArray<Handle<Texture>>((int)desc.BufferCount, Allocator.Persistent);
|
||||||
|
|
||||||
Width = desc.width;
|
Width = desc.Width;
|
||||||
Height = desc.height;
|
Height = desc.Height;
|
||||||
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT;
|
BufferCount = desc.BufferCount;
|
||||||
|
|
||||||
CreateSwapChain(desc);
|
CreateSwapChain(desc);
|
||||||
CreateBackBuffers();
|
CreateBackBuffers();
|
||||||
|
|
||||||
_compositionSurface = desc.target.compositionSurface;
|
_compositionSurface = desc.Target.CompositionSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
~D3D12SwapChain()
|
~D3D12SwapChain()
|
||||||
@@ -73,9 +76,9 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
{
|
{
|
||||||
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
|
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
|
||||||
{
|
{
|
||||||
Width = desc.width,
|
Width = desc.Width,
|
||||||
Height = desc.height,
|
Height = desc.Height,
|
||||||
Format = desc.format.ToDXGIFormat(),
|
Format = desc.Format.ToDXGIFormat(),
|
||||||
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
|
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
|
||||||
BufferUsage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
BufferUsage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||||
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT,
|
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT,
|
||||||
@@ -91,15 +94,15 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
var pFactory = _renderDevice.DXGIFactory.Get();
|
var pFactory = _renderDevice.DXGIFactory.Get();
|
||||||
var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get();
|
var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get();
|
||||||
|
|
||||||
switch (desc.target.type)
|
switch (desc.Target.Type)
|
||||||
{
|
{
|
||||||
case SwapChainTargetType.Composition:
|
case SwapChainTargetType.Composition:
|
||||||
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
|
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
|
||||||
|
|
||||||
// Set the composition surface
|
// 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);
|
swapChainPanelNative.SetSwapChain((IntPtr)pTempSwapChain);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -112,7 +115,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
|
|
||||||
pFactory->CreateSwapChainForHwnd(
|
pFactory->CreateSwapChainForHwnd(
|
||||||
(IUnknown*)pCommandQueue,
|
(IUnknown*)pCommandQueue,
|
||||||
new HWND(desc.target.windowHandle.ToPointer()),
|
new HWND(desc.Target.WindowHandle.ToPointer()),
|
||||||
&swapChainDesc,
|
&swapChainDesc,
|
||||||
&swapChainFullscreenDesc,
|
&swapChainFullscreenDesc,
|
||||||
null,
|
null,
|
||||||
@@ -141,7 +144,12 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
var rtv = _descriptorAllocator.AllocateRTV();
|
var rtv = _descriptorAllocator.AllocateRTV();
|
||||||
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
|
_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();
|
_backBuffers[i] = handle.AsTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,12 +164,17 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
|
|
||||||
public void ReleaseDescriptors(int baseIndex, int count = 1)
|
public void ReleaseDescriptors(int baseIndex, int count = 1)
|
||||||
{
|
{
|
||||||
|
if (baseIndex == _INVALID_DESCRIPTOR_INDEX)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (baseIndex < _dynamicHeapStart)
|
if (baseIndex >= _dynamicHeapStart)
|
||||||
{
|
{
|
||||||
// Dynamic allocations are not released individually.
|
// Dynamic allocations are not released individually.
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -10,6 +10,19 @@ internal unsafe static class D3D12Utility
|
|||||||
{
|
{
|
||||||
public static void SetName<T>(ref this T obj, ReadOnlySpan<char> name)
|
public static void SetName<T>(ref this T obj, ReadOnlySpan<char> name)
|
||||||
where T : unmanaged, ID3D12Object.Interface
|
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<char> name)
|
||||||
{
|
{
|
||||||
fixed (char* pName = name)
|
fixed (char* pName = name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,10 +10,12 @@
|
|||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<IsAotCompatible>True</IsAotCompatible>
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<IsAotCompatible>True</IsAotCompatible>
|
<IsAotCompatible>True</IsAotCompatible>
|
||||||
|
<IsTrimmable>True</IsTrimmable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -52,4 +54,10 @@
|
|||||||
<Folder Include="RenderGraphModule\" />
|
<Folder Include="RenderGraphModule\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Misaki.HighPerformance.LowLevel">
|
||||||
|
<HintPath>..\..\Class\Misaki.HighPerformance\Misaki.HighPerformance.LowLevel\bin\Release\net10.0\Misaki.HighPerformance.LowLevel.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -154,7 +154,6 @@ public ref struct GraphicsPSODescriptor
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ReadOnlySpan<TextureFormat> RtvFormats
|
public ReadOnlySpan<TextureFormat> RtvFormats
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
@@ -267,7 +266,6 @@ public struct RectDesc
|
|||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct SubResourceData
|
public struct SubResourceData
|
||||||
@@ -311,6 +309,24 @@ public struct PassDepthStencilDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public struct BarrierDesc
|
||||||
|
{
|
||||||
|
public Handle<GraphicsBuffer> Resource
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceState StateBefore
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceState StateAfter
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct ResourceDesc
|
public struct ResourceDesc
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
@@ -381,13 +397,13 @@ public struct ResourceDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Render target description
|
/// Render Target description
|
||||||
/// Supports either color OR depth rendering, not both
|
/// Supports either color OR depth rendering, not both
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct RenderTargetDesc
|
public struct RenderTargetDesc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the render target
|
/// Width of the render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint Width
|
public uint Width
|
||||||
{
|
{
|
||||||
@@ -395,7 +411,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Height of the render target
|
/// Height of the render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint Height
|
public uint Height
|
||||||
{
|
{
|
||||||
@@ -403,7 +419,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Slice of the render target
|
/// Slice of the render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint Slice
|
public uint Slice
|
||||||
{
|
{
|
||||||
@@ -411,7 +427,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Type of render target
|
/// Type of render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RenderTargetType Type
|
public RenderTargetType Type
|
||||||
{
|
{
|
||||||
@@ -419,7 +435,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target texture format
|
/// Target texture Format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextureFormat Format
|
public TextureFormat Format
|
||||||
{
|
{
|
||||||
@@ -435,7 +451,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creation flags for the render target
|
/// Creation flags for the render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public RenderTargetCreationFlags CreationFlags
|
public RenderTargetCreationFlags CreationFlags
|
||||||
{
|
{
|
||||||
@@ -459,7 +475,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a color render target
|
/// Creates a color render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static RenderTargetDesc Color(uint width, uint height, uint slice = 1,
|
public static RenderTargetDesc Color(uint width, uint height, uint slice = 1,
|
||||||
TextureFormat format = TextureFormat.R8G8B8A8_UNorm, TextureDimension dimension = TextureDimension.Texture2D,
|
TextureFormat format = TextureFormat.R8G8B8A8_UNorm, TextureDimension dimension = TextureDimension.Texture2D,
|
||||||
@@ -481,7 +497,7 @@ public struct RenderTargetDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a depth render target
|
/// Creates a depth render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static RenderTargetDesc Depth(uint width, uint height, uint slice = 1,
|
public static RenderTargetDesc Depth(uint width, uint height, uint slice = 1,
|
||||||
TextureFormat format = TextureFormat.D24_UNorm_S8_UInt, TextureDimension dimension = TextureDimension.Texture2D,
|
TextureFormat format = TextureFormat.D24_UNorm_S8_UInt, TextureDimension dimension = TextureDimension.Texture2D,
|
||||||
@@ -554,7 +570,7 @@ public struct TextureDesc
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Texture format
|
/// Texture Format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextureFormat Format
|
public TextureFormat Format
|
||||||
{
|
{
|
||||||
@@ -630,59 +646,82 @@ public struct SwapChainDesc
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Width of the swap chain
|
/// Width of the swap chain
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint width;
|
public uint Width
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Height of the swap chain
|
/// Height of the swap chain
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public uint height;
|
public uint Height
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Back buffer format
|
|
||||||
/// </summary>
|
|
||||||
public TextureFormat format;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Target for presentation (window handle or composition target)
|
|
||||||
/// </summary>
|
|
||||||
public SwapChainTarget target;
|
|
||||||
|
|
||||||
public SwapChainDesc(uint width, uint height, SwapChainTarget target, TextureFormat format = TextureFormat.B8G8R8A8_UNorm, uint bufferCount = 2)
|
|
||||||
{
|
{
|
||||||
this.width = width;
|
get; set;
|
||||||
this.height = height;
|
}
|
||||||
this.format = format;
|
|
||||||
this.target = target;
|
|
||||||
|
/// <summary>
|
||||||
|
/// Back buffer Format
|
||||||
|
/// </summary>
|
||||||
|
public TextureFormat Format
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Target for presentation (window handle or composition Target)
|
||||||
|
/// </summary>
|
||||||
|
public SwapChainTarget Target
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint BufferCount
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Swap chain target (window handle or composition surface)
|
/// Swap chain Target (window handle or composition surface)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct SwapChainTarget
|
public struct SwapChainTarget
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target type
|
/// Target type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SwapChainTargetType type;
|
public SwapChainTargetType Type
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Window handle for HWND targets
|
/// Window handle for HWND targets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public nint windowHandle;
|
public nint WindowHandle
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Composition surface for UWP/WinUI targets
|
/// Composition surface for UWP/WinUI targets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object? compositionSurface;
|
public object? CompositionSurface
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static SwapChainTarget FromWindowHandle(nint hwnd)
|
public static SwapChainTarget FromWindowHandle(nint hwnd)
|
||||||
{
|
{
|
||||||
return new SwapChainTarget
|
return new SwapChainTarget
|
||||||
{
|
{
|
||||||
type = SwapChainTargetType.WindowHandle,
|
Type = SwapChainTargetType.WindowHandle,
|
||||||
windowHandle = hwnd,
|
WindowHandle = hwnd,
|
||||||
compositionSurface = null
|
CompositionSurface = null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -690,9 +729,9 @@ public struct SwapChainTarget
|
|||||||
{
|
{
|
||||||
return new SwapChainTarget
|
return new SwapChainTarget
|
||||||
{
|
{
|
||||||
type = SwapChainTargetType.Composition,
|
Type = SwapChainTargetType.Composition,
|
||||||
windowHandle = nint.Zero,
|
WindowHandle = 0,
|
||||||
compositionSurface = surface
|
CompositionSurface = surface
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,21 +53,21 @@ public interface ICommandBuffer : IDisposable
|
|||||||
void SetScissorRect(RectDesc rect);
|
void SetScissorRect(RectDesc rect);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// To specify no render targets, provide an empty span for <paramref name="renderTargets"/>.
|
/// To specify no render targets, provide an empty span for <paramref name="renderTargets"/>.
|
||||||
/// Use <see cref="Handle{Texture}.Invalid"/> for <paramref name="depthTarget"/> if no depth target is required.
|
/// Use <see cref="Handle{Texture}.Invalid"/> for <paramref name="depthTarget"/> if no depth Target is required.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="renderTargets">A read-only span of handles to textures that will be used as render targets.
|
/// <param name="renderTargets">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.</param>
|
/// The order of handles determines the order in which render targets are bound.</param>
|
||||||
/// <param name="depthTarget">A handle to the texture to be used as the depth target. Specify a invalid handle if no depth target is required.</param>
|
/// <param name="depthTarget">A handle to the texture to be used as the depth Target. Specify a invalid handle if no depth Target is required.</param>
|
||||||
void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget);
|
void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Begins a render pass with the specified render target
|
/// Begins a render pass with the specified render Target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rtDescs">Render target descriptions</param>
|
/// <param name="rtDescs">Render Target descriptions</param>
|
||||||
/// <param name="depthDesc">Depth stencil description</param>
|
/// <param name="depthDesc">Depth stencil description</param>
|
||||||
/// <param name="allowUAVWrites">Whether UAV writes are allowed during the render pass</param>
|
/// <param name="allowUAVWrites">Whether UAV writes are allowed during the render pass</param>
|
||||||
void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false);
|
void BeginRenderPass(ReadOnlySpan<PassRenderTargetDesc> rtDescs, PassDepthStencilDesc depthDesc, bool allowUAVWrites = false);
|
||||||
@@ -78,12 +78,18 @@ public interface ICommandBuffer : IDisposable
|
|||||||
void EndRenderPass();
|
void EndRenderPass();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inserts a resource barrier for state transitions
|
/// Inserts multiple resource barriers for state transitions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="resource">Resource to transition</param>
|
/// <param name="barrierDescs">Resource barrier descriptions</param>
|
||||||
/// <param name="before">Current resource state</param>
|
void ResourceBarrier(ReadOnlySpan<BarrierDesc> barrierDescs);
|
||||||
/// <param name="after">Target resource state</param>
|
|
||||||
void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after);
|
/// <summary>
|
||||||
|
/// Inserts a resource barrier for state transitions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resource">A handle to the GPU resource to transition.</param>
|
||||||
|
/// <param name="stateBefore">The current state of the resource before the transition.</param>
|
||||||
|
/// <param name="stateAfter">The desired state of the resource after the transition.</param>
|
||||||
|
void ResourceBarrier(Handle<GPUResource> resource, ResourceState stateBefore, ResourceState stateAfter);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the pipeline state object
|
/// Sets the pipeline state object
|
||||||
@@ -176,10 +182,10 @@ public interface ICommandBuffer : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="texture">The texture resource to which the subresource data will be uploaded. Must be a valid, initialized texture handle.</param>
|
/// <param name="texture">The texture resource to which the subresource data will be uploaded. Must be a valid, initialized texture handle.</param>
|
||||||
/// <param name="firstSubresource">The index of the first subresource in the texture to receive data. Must be less than the total number of subresources in the texture.</param>
|
/// <param name="firstSubresource">The index of the first subresource in the texture to receive data. Must be less than the total number of subresources in the texture.</param>
|
||||||
/// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.</param>
|
/// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the Format and layout expected by the texture.</param>
|
||||||
/// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>.
|
/// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>.
|
||||||
/// Must be greater than zero and not exceed the remaining subresources in the texture.</param>
|
/// Must be greater than zero and not exceed the remaining subresources in the texture.</param>
|
||||||
void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources);
|
void UploadTexture(Handle<Texture> texture, ReadOnlySpan<SubResourceData> subresources);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer.
|
/// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer.
|
||||||
|
|||||||
@@ -23,5 +23,4 @@ public interface IPipelineLibrary : IDisposable
|
|||||||
void InitializeLibrary(string? filePath);
|
void InitializeLibrary(string? filePath);
|
||||||
void SaveLibraryToDisk(string filePath);
|
void SaveLibraryToDisk(string filePath);
|
||||||
Result<GraphicsPipelineKey> CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled);
|
Result<GraphicsPipelineKey> CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled);
|
||||||
Result<CBufferInfo, ResultStatus> GetCBufferInfo(ShaderPassKey passId);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ public interface IRenderer : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the render target for this renderer
|
/// Sets the render Target for this renderer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="renderTarget">Render target to render into</param>
|
/// <param name="renderTarget">Render Target to render into</param>
|
||||||
public void SetRenderTarget(Handle<Texture> renderTarget);
|
public void SetRenderTarget(Handle<Texture> renderTarget);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ public interface IResourceAllocator : IDisposable
|
|||||||
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false);
|
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a render target for off-screen rendering
|
/// Creates a render Target for off-screen rendering
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="desc">Render target description</param>
|
/// <param name="desc">Render Target description</param>
|
||||||
/// <returns>A new texture handle point to the resource</returns>
|
/// <returns>A new texture handle point to the resource</returns>
|
||||||
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false);
|
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ public interface IResourceReleasable
|
|||||||
void ReleaseResource(IResourceDatabase database);
|
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
|
public interface IResourceDatabase : IDisposable
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -155,18 +158,4 @@ public interface IResourceDatabase : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The identifier of the shader to release. Must refer to a valid, previously created shader.</param>
|
/// <param name="id">The identifier of the shader to release. Must refer to a valid, previously created shader.</param>
|
||||||
void ReleaseShader(Identifier<Shader> id);
|
void ReleaseShader(Identifier<Shader> id);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a shader pass to the collection using the specified identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="passKey">The unique identifier for the shader pass.</param>
|
|
||||||
/// <param name="pass">The shader pass to add. Cannot be null.</param>
|
|
||||||
void AddShaderPass(ShaderPassKey passKey, ShaderPass pass);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the shader pass associated with the specified pass identifier.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="passKey">The unique identifier of the shader pass to retrieve.</param>
|
|
||||||
/// <returns>The <see cref="ShaderPass"/> corresponding to the specified identifier, or null if no matching shader pass is found.</returns>
|
|
||||||
ShaderPass GetShaderPass(ShaderPassKey passKey);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ internal static class RHIUtility
|
|||||||
var packed = false;
|
var packed = false;
|
||||||
var planar = false;
|
var planar = false;
|
||||||
var bpe = 0;
|
var bpe = 0;
|
||||||
|
|
||||||
//switch (format)
|
//switch (Format)
|
||||||
//{
|
//{
|
||||||
// case Format.BC1Typeless:
|
// case Format.BC1Typeless:
|
||||||
// case Format.BC1Unorm:
|
// case Format.BC1Unorm:
|
||||||
|
|||||||
@@ -5,23 +5,33 @@ using Ghost.Graphics.Core;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Ghost.Graphics.Utilities;
|
using Ghost.Graphics.Utilities;
|
||||||
using Ghost.SDL.Compiler;
|
using Ghost.SDL.Compiler;
|
||||||
using Misaki.HighPerformance.Image;
|
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
using Misaki.HighPerformance.Utilities;
|
using System.Runtime.InteropServices;
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderPasses;
|
namespace Ghost.Graphics.RenderPasses;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simplified bindless mesh render pass using high-level bindless APIs with fully bindless vertex/index buffer access
|
/// Simplified bindless mesh render pass using high-level bindless APIs with fully bindless vertex/index buffer access
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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> _mesh;
|
private Handle<Mesh> _mesh;
|
||||||
private Identifier<Shader> _shader;
|
private Identifier<Shader> _shader;
|
||||||
private Handle<Material> _material;
|
private Handle<Material> _material;
|
||||||
private Handle<Texture>[]? _textures;
|
private Handle<Texture>[]? _textures;
|
||||||
|
|
||||||
|
private GraphicsCompiledResult[]? _compileResults;
|
||||||
|
|
||||||
// Texture file paths for this demo
|
// Texture file paths for this demo
|
||||||
private readonly string[] _textureFiles = [
|
private readonly string[] _textureFiles = [
|
||||||
"C:/Users/Misaki/Downloads/Im/Icon.png",
|
"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();
|
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)
|
if (compileResult.IsFailure || pass is not FullPassDescriptor fullPass)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -55,18 +67,30 @@ internal unsafe class MeshRenderPass : IRenderPass
|
|||||||
DsvFormat = TextureFormat.Unknown,
|
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);
|
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.UpdateObjectData(_mesh, float4x4.identity);
|
||||||
ctx.UploadMesh(_mesh, true);
|
|
||||||
|
|
||||||
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
|
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
|
||||||
_material = ctx.ResourceAllocator.CreateMaterial(_shader);
|
_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<Texture>[_textureFiles.Length];
|
//_textures = new Handle<Texture>[_textureFiles.Length];
|
||||||
//for (var i = 0; i < _textureFiles.Length; i++)
|
//for (var i = 0; i < _textureFiles.Length; i++)
|
||||||
//{
|
//{
|
||||||
@@ -107,5 +131,13 @@ internal unsafe class MeshRenderPass : IRenderPass
|
|||||||
resourceDatabase.ReleaseResource(texture.AsResource());
|
resourceDatabase.ReleaseResource(texture.AsResource());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_compileResults != null)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < _compileResults.Length; i++)
|
||||||
|
{
|
||||||
|
_compileResults[i].Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,7 @@
|
|||||||
|
|
||||||
#include GENERATED_CODE_PATH
|
#include GENERATED_CODE_PATH
|
||||||
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Properties.hlsl"
|
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Properties.hlsl"
|
||||||
|
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl"
|
||||||
struct Vertex
|
|
||||||
{
|
|
||||||
float4 position;
|
|
||||||
float4 normal;
|
|
||||||
float4 tangent;
|
|
||||||
float4 color;
|
|
||||||
float4 uv;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PixelInput
|
struct PixelInput
|
||||||
{
|
{
|
||||||
@@ -26,24 +18,8 @@ void MSMain(
|
|||||||
out vertices PixelInput outVerts[3],
|
out vertices PixelInput outVerts[3],
|
||||||
out indices uint3 outTris[1])
|
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 vertexId = groupThreadID.x;
|
||||||
uint indexOffset = (groupID.x * 3 + vertexId) * 4; // uint32 index
|
Vertex v = LoadVertexData(vertexId, groupID.x, g_PerObjectData.vertexBuffer, g_PerObjectData.indexBuffer);
|
||||||
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));
|
|
||||||
|
|
||||||
SetMeshOutputCounts(3, 1);
|
SetMeshOutputCounts(3, 1);
|
||||||
//v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position));
|
//v.position = mul(g_PerViewData.cameraMatrix, mul(g_PerObjectData.localToWorld, v.position));
|
||||||
@@ -58,50 +34,16 @@ void MSMain(
|
|||||||
{
|
{
|
||||||
outTris[0] = uint3(0, 1, 2);
|
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 PSMain(PixelInput input) : SV_TARGET
|
||||||
{
|
{
|
||||||
//float4 color1 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture1, 0, input.uv.xy);
|
//float4 color1 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture1, 0, input.uv.xy);
|
||||||
//float4 color2 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture2, 0, input.uv.xy);
|
//float4 color2 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture2, 0, input.uv.xy);
|
||||||
//float4 color3 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture3, 0, input.uv.xy);
|
//float4 color3 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture3, 0, input.uv.xy);
|
||||||
//float4 color4 = SAMPLE_TEXTURE2D_BINDLESS(g_PerMaterialData.texture4, 0, input.uv.xy);
|
//float4 color4 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture4, 0, input.uv.xy);
|
||||||
|
|
||||||
//float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
//float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f;
|
||||||
return g_PerMaterialData.color + input.color;;
|
return g_PerMaterialData.color + input.color;
|
||||||
//return input.color;
|
//return input.color;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,11 +48,6 @@ public interface IFenceSynchronizer
|
|||||||
|
|
||||||
public interface IRenderSystem : IFenceSynchronizer, IDisposable
|
public interface IRenderSystem : IFenceSynchronizer, IDisposable
|
||||||
{
|
{
|
||||||
RenderingConfig Config
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
|
|
||||||
IGraphicsEngine GraphicsEngine
|
IGraphicsEngine GraphicsEngine
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
@@ -80,8 +75,8 @@ internal class RenderSystem : IRenderSystem
|
|||||||
|
|
||||||
public FrameResource()
|
public FrameResource()
|
||||||
{
|
{
|
||||||
cpuReadyEvent = new(false);
|
cpuReadyEvent = new AutoResetEvent(false);
|
||||||
gpuReadyEvent = new(true);
|
gpuReadyEvent = new AutoResetEvent(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -105,7 +100,6 @@ internal class RenderSystem : IRenderSystem
|
|||||||
private bool _isRunning;
|
private bool _isRunning;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public RenderingConfig Config => _config;
|
|
||||||
public IGraphicsEngine GraphicsEngine => _graphicsEngine;
|
public IGraphicsEngine GraphicsEngine => _graphicsEngine;
|
||||||
public bool IsRunning => _isRunning;
|
public bool IsRunning => _isRunning;
|
||||||
|
|
||||||
@@ -123,16 +117,16 @@ internal class RenderSystem : IRenderSystem
|
|||||||
_ => throw new NotSupportedException($"Graphics API {config.GraphicsAPI} is not supported.")
|
_ => throw new NotSupportedException($"Graphics API {config.GraphicsAPI} is not supported.")
|
||||||
};
|
};
|
||||||
|
|
||||||
_shutdownEvent = new(false);
|
_shutdownEvent = new AutoResetEvent(false);
|
||||||
|
|
||||||
// Create frame resources for synchronization
|
// Create frame resources for synchronization
|
||||||
_frameResources = new FrameResource[config.FrameBufferCount];
|
_frameResources = new FrameResource[config.FrameBufferCount];
|
||||||
for (var i = 0; i < config.FrameBufferCount; i++)
|
for (var i = 0; i < config.FrameBufferCount; i++)
|
||||||
{
|
{
|
||||||
_frameResources[i] = new();
|
_frameResources[i] = new FrameResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderThread = new(RenderLoop)
|
_renderThread = new Thread(RenderLoop)
|
||||||
{
|
{
|
||||||
IsBackground = true,
|
IsBackground = true,
|
||||||
Name = "Graphics Render Thread",
|
Name = "Graphics Render Thread",
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
_compiler.Attach(pCompiler);
|
_compiler.Attach(pCompiler);
|
||||||
_utils.Attach(pUtils);
|
_utils.Attach(pUtils);
|
||||||
|
|
||||||
_compiledResults = new();
|
_compiledResults = new Dictionary<ShaderPassKey, GraphicsCompiledResult>();
|
||||||
}
|
}
|
||||||
|
|
||||||
~DxcShaderCompiler()
|
~DxcShaderCompiler()
|
||||||
@@ -153,10 +153,10 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create DXC _utils.Get() to parse pReflection data
|
// Create DXC _utils.Get() to parse reflection data
|
||||||
var dxcuID = CLSID.CLSID_DxcUtils;
|
var dxcuID = CLSID.CLSID_DxcUtils;
|
||||||
|
|
||||||
// Create pReflection interface from blob
|
// Create reflection interface from blob
|
||||||
var reflectionBuffer = new DxcBuffer
|
var reflectionBuffer = new DxcBuffer
|
||||||
{
|
{
|
||||||
Ptr = pDxcReflectionBlob->GetBufferPointer(),
|
Ptr = pDxcReflectionBlob->GetBufferPointer(),
|
||||||
@@ -242,137 +242,109 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<CompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator)
|
public Result<ShaderCompileResult> Compile(ref readonly CompilerConfig config, Allocator allocator)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
IDxcIncludeHandler* pIncludeHandler = default;
|
using ComPtr<IDxcIncludeHandler> includeHandler = default;
|
||||||
IDxcBlobEncoding* pSourceBlob = default;
|
using ComPtr<IDxcBlobEncoding> 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<IDxcResult> result = default;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Create DXC _compiler.Get() and _utils.Get()
|
// Compile shader
|
||||||
var dxccID = CLSID.CLSID_DxcCompiler;
|
var buffer = new DxcBuffer
|
||||||
var dxcuID = CLSID.CLSID_DxcUtils;
|
|
||||||
|
|
||||||
|
|
||||||
ThrowIfFailed(_utils.Get()->CreateDefaultIncludeHandler(&pIncludeHandler));
|
|
||||||
|
|
||||||
// Create source blob
|
|
||||||
fixed (char* pPath = config.shaderPath)
|
|
||||||
{
|
{
|
||||||
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);
|
// Get compiled bytecode
|
||||||
var argPtrs = stackalloc char*[argsArray.Count];
|
using ComPtr<IDxcBlob> bytecodeBlob = default;
|
||||||
for (var i = 0; i < argsArray.Count; i++)
|
ThrowIfFailed(result.Get()->GetResult(bytecodeBlob.GetAddressOf()));
|
||||||
|
|
||||||
|
ShaderReflectionData reflectionData = default;
|
||||||
|
if (config.options.HasFlag(CompilerOption.KeepReflections))
|
||||||
{
|
{
|
||||||
argPtrs[i] = (char*)Marshal.StringToHGlobalUni(argsArray[i]);
|
using ComPtr<IDxcBlob> 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<byte>((int)bytecodeSize, allocator);
|
||||||
|
|
||||||
try
|
NativeMemory.Copy(bytecodeBlob.Get()->GetBufferPointer(), bytecode.GetUnsafePtr(), bytecodeSize);
|
||||||
|
|
||||||
|
return new ShaderCompileResult
|
||||||
{
|
{
|
||||||
// Compile shader
|
bytecode = bytecode,
|
||||||
var buffer = new DxcBuffer
|
reflectionData = reflectionData,
|
||||||
{
|
};
|
||||||
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<IDxcBlob>(), (void**)&pReflection, null).SUCCEEDED))
|
|
||||||
{
|
|
||||||
reflection = PerformDXCReflection(pReflection).GetValueOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pReflection != null)
|
|
||||||
{
|
|
||||||
pReflection->Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bytecodeSize = pBytecodeBlob->GetBufferSize();
|
|
||||||
var bytecode = new UnsafeArray<byte>((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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (pIncludeHandler != null)
|
for (var i = 0; i < argsArray.Count; i++)
|
||||||
{
|
{
|
||||||
pIncludeHandler->Release();
|
Marshal.FreeHGlobal((nint)argPtrs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Result<GraphicsCompiledResult> CompilePass(IPassDescriptor descriptor)
|
public Result<GraphicsCompiledResult> CompilePass(IPassDescriptor descriptor, string? generatedCodePath)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
@@ -381,14 +353,14 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
return Result.Failure("FullPassDescriptor expected.");
|
return Result.Failure("FullPassDescriptor expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileResult tsResult = default;
|
ShaderCompileResult tsResult = default;
|
||||||
var tsEntry = fullDescriptor.taskShader;
|
var tsEntry = fullDescriptor.taskShader;
|
||||||
if (tsEntry.IsCreated)
|
if (tsEntry.IsCreated)
|
||||||
{
|
{
|
||||||
var config = new CompilerConfig
|
var config = new CompilerConfig
|
||||||
{
|
{
|
||||||
defines = fullDescriptor.defines.AsSpan(),
|
defines = fullDescriptor.defines.AsSpan(),
|
||||||
include = fullDescriptor.generatedCodePath,
|
include = generatedCodePath,
|
||||||
shaderPath = tsEntry.shader,
|
shaderPath = tsEntry.shader,
|
||||||
entryPoint = tsEntry.entry,
|
entryPoint = tsEntry.entry,
|
||||||
stage = ShaderStage.TaskShader,
|
stage = ShaderStage.TaskShader,
|
||||||
@@ -406,14 +378,14 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
tsResult = result.Value;
|
tsResult = result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileResult msResult;
|
ShaderCompileResult msResult;
|
||||||
var msEntry = fullDescriptor.meshShader;
|
var msEntry = fullDescriptor.meshShader;
|
||||||
if (msEntry.IsCreated)
|
if (msEntry.IsCreated)
|
||||||
{
|
{
|
||||||
var config = new CompilerConfig
|
var config = new CompilerConfig
|
||||||
{
|
{
|
||||||
defines = fullDescriptor.defines.AsSpan(),
|
defines = fullDescriptor.defines.AsSpan(),
|
||||||
include = fullDescriptor.generatedCodePath,
|
include = generatedCodePath,
|
||||||
shaderPath = msEntry.shader,
|
shaderPath = msEntry.shader,
|
||||||
entryPoint = msEntry.entry,
|
entryPoint = msEntry.entry,
|
||||||
stage = ShaderStage.MeshShader,
|
stage = ShaderStage.MeshShader,
|
||||||
@@ -435,14 +407,14 @@ internal sealed unsafe partial class DxcShaderCompiler : IShaderCompiler
|
|||||||
return Result.Failure("Mesh shader expected.");
|
return Result.Failure("Mesh shader expected.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CompileResult psResult;
|
ShaderCompileResult psResult;
|
||||||
var psEntry = fullDescriptor.pixelShader;
|
var psEntry = fullDescriptor.pixelShader;
|
||||||
if (psEntry.IsCreated)
|
if (psEntry.IsCreated)
|
||||||
{
|
{
|
||||||
var config = new CompilerConfig
|
var config = new CompilerConfig
|
||||||
{
|
{
|
||||||
defines = fullDescriptor.defines.AsSpan(),
|
defines = fullDescriptor.defines.AsSpan(),
|
||||||
include = fullDescriptor.generatedCodePath,
|
include = generatedCodePath,
|
||||||
shaderPath = psEntry.shader,
|
shaderPath = psEntry.shader,
|
||||||
entryPoint = psEntry.entry,
|
entryPoint = psEntry.entry,
|
||||||
stage = ShaderStage.PixelShader,
|
stage = ShaderStage.PixelShader,
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ public unsafe static class MeshBuilder
|
|||||||
public static void ComputeTangents(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
public static void ComputeTangents(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
|
||||||
{
|
{
|
||||||
using var scope = AllocationManager.CreateStackScope();
|
using var scope = AllocationManager.CreateStackScope();
|
||||||
var bitangents = new UnsafeArray<float4>(vertices.Count, Allocator.Stack);
|
using var bitangents = new UnsafeArray<float4>(vertices.Count, Allocator.Stack);
|
||||||
|
|
||||||
for (var i = 0; i < indices.Count; i += 3)
|
for (var i = 0; i < indices.Count; i += 3)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ shader "MyShader/Standard"
|
|||||||
properties
|
properties
|
||||||
{
|
{
|
||||||
float4 color = float4(1, 1, 1, 1);
|
float4 color = float4(1, 1, 1, 1);
|
||||||
tex2d_b texture1 = tex2d_b(black);
|
tex2d texture1 = tex2d(black);
|
||||||
tex2d_b texture2 = tex2d_b(white);
|
tex2d texture2 = tex2d(white);
|
||||||
tex2d_b texture3 = tex2d_b(grey);
|
tex2d texture3 = tex2d(grey);
|
||||||
tex2d_b texture4 = tex2d_b(normal);
|
tex2d texture4 = tex2d(normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
pass "Forward"
|
pass "Forward"
|
||||||
@@ -23,4 +23,4 @@ shader "MyShader/Standard"
|
|||||||
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
|
ms("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "MSMain");
|
||||||
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
|
ps("F:/csharp/GhostEngine/Ghost.Graphics/RenderPasses/ShaderCode.hlsl", "PSMain");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,7 @@ if (model == null)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var descriptor = SDLCompiler.ResolveShader(model);
|
var descriptor = SDLCompiler.ResolveShader(model);
|
||||||
|
SDLCompiler.GenerateShaderCode(descriptor, "C:/Users/Misaki/Downloads/Archive");
|
||||||
foreach (var pass in descriptor.passes)
|
|
||||||
{
|
|
||||||
SDLCompiler.GeneratePass(pass, "C:/Users/Misaki/Downloads/Archive");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Shader compiled successfully:");
|
Console.WriteLine("Shader compiled successfully:");
|
||||||
|
|
||||||
|
|||||||
@@ -1,97 +1,95 @@
|
|||||||
#ifndef COMMON_HLSL
|
#ifndef BUILTIN_COMMON_HLSL
|
||||||
#define COMMON_HLSL
|
#define BUILTIN_COMMON_HLSL
|
||||||
|
|
||||||
#undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level.
|
|
||||||
|
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
float4 position;
|
||||||
|
float4 normal;
|
||||||
|
float4 tangent;
|
||||||
|
float4 uv;
|
||||||
|
float4 color;
|
||||||
|
};
|
||||||
|
|
||||||
// Resource descriptor heap definitions
|
// 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_TEXTURE2D_HEAP ResourceDescriptorHeap
|
||||||
#define GLOBAL_TEXTURE3D_HEAP ResourceDescriptorHeap
|
#define GLOBAL_TEXTURE3D_HEAP ResourceDescriptorHeap
|
||||||
#define GLOBAL_TEXTURECUBE_HEAP ResourceDescriptorHeap
|
#define GLOBAL_TEXTURECUBE_HEAP ResourceDescriptorHeap
|
||||||
#define GLOBAL_TEXTURE2D_ARRAY_HEAP ResourceDescriptorHeap
|
#define GLOBAL_TEXTURE2D_ARRAY_HEAP ResourceDescriptorHeap
|
||||||
#define GLOBAL_TEXTURECUBE_ARRAY_HEAP ResourceDescriptorHeap
|
#define GLOBAL_TEXTURECUBE_ARRAY_HEAP ResourceDescriptorHeap
|
||||||
|
#define GLOBAL_BUFFER_HEAP ResourceDescriptorHeap
|
||||||
#define GLOBAL_SAMPLER_HEAP SamplerDescriptorHeap
|
#define GLOBAL_SAMPLER_HEAP SamplerDescriptorHeap
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Bindless resource type definitions
|
// Bindless resource type definitions
|
||||||
|
|
||||||
#define TEXTURE2D_BINDLESS uint
|
#define TEXTURE2D uint
|
||||||
#define TEXTURE3D_BINDLESS uint
|
#define TEXTURE3D uint
|
||||||
#define TEXTURECUBE_BINDLESS uint
|
#define TEXTURECUBE uint
|
||||||
#define TEXTURE2D_ARRAY_BINDLESS uint
|
#define TEXTURE2D_ARRAY uint
|
||||||
#define TEXTURECUBE_ARRAY_BINDLESS uint
|
#define TEXTURECUBE_ARRAY uint
|
||||||
|
|
||||||
#define SAMPLER_BINDLESS uint
|
#define SAMPLER uint
|
||||||
|
|
||||||
#define STRUCT_BUFFER_BINDLESS uint
|
#define STRUCT_BUFFER uint
|
||||||
#define BYTE_ADDRESS_BUFFER_BINDLESS uint
|
#define BYTE_ADDRESS_BUFFER 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<type>
|
|
||||||
#define BYTE_ADDRESS_BUFFER ByteAddressBuffer
|
|
||||||
|
|
||||||
|
|
||||||
// Texture and sampler access macros
|
// Texture and sampler access macros
|
||||||
|
|
||||||
#define GET_TEXTURE2D_BINDLESS(id) GLOBAL_TEXTURE2D_HEAP[id]
|
#define GET_TEXTURE2D(id) GLOBAL_TEXTURE2D_HEAP[id]
|
||||||
#define GET_TEXTURE2D_ARRAY_BINDLESS(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id]
|
#define GET_TEXTURE2D_ARRAY(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id]
|
||||||
#define GET_TEXTURE3D_BINDLESS(id) GLOBAL_TEXTURE3D_HEAP[id]
|
#define GET_TEXTURE3D(id) GLOBAL_TEXTURE3D_HEAP[id]
|
||||||
#define GET_TEXTURECUBE_BINDLESS(id) GLOBAL_TEXTURECUBE_HEAP[id]
|
#define GET_TEXTURECUBE(id) GLOBAL_TEXTURECUBE_HEAP[id]
|
||||||
#define GET_TEXTURECUBE_ARRAY_BINDLESS(id) GLOBAL_TEXTURECUBE_ARRAY_HEAP[id]
|
#define GET_TEXTURECUBE_ARRAY(id) GLOBAL_TEXTURECUBE_ARRAY_HEAP[id]
|
||||||
#define GET_SAMPLER_BINDLESS(id) GLOBAL_SAMPLER_HEAP[id]
|
#define GET_BUFFER(id) GLOBAL_BUFFER_HEAP[id]
|
||||||
|
#define GET_SAMPLER(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 MESH_SHADER_THREADS(x) [NumThreads(x, 1, 1)]
|
#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
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#ifndef PROPERTIES_HLSL
|
#ifndef BUILTIN_PROPERTIES_HLSL
|
||||||
#define PROPERTIES_HLSL
|
#define BUILTIN_PROPERTIES_HLSL
|
||||||
|
|
||||||
#include "F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.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);
|
SamplerState GlobalSamplerHeap[GLOBAL_SAMPLER_HEAP_SIZE] : register(s0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif // BUILTIN_PROPERTIES_HLSL
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
namespace Ghost.SDL.Compiler.Parser;
|
|
||||||
|
|
||||||
internal class IncludesBlock : IBlockParser<List<Token>, List<string>>
|
|
||||||
{
|
|
||||||
public static bool ShouldEnter(Token token)
|
|
||||||
{
|
|
||||||
return token.Match(TokenType.Keyword, TokenLexicon.KnownKeywords.INCLUDES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Token> Parse(TokenStreamSlice stream)
|
|
||||||
{
|
|
||||||
stream.Expect(TokenType.Keyword);
|
|
||||||
stream.Expect(TokenType.LBrace);
|
|
||||||
|
|
||||||
var includes = new List<Token>();
|
|
||||||
|
|
||||||
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<string>? SemanticAnalysis(List<Token>? syntax, List<SDLError> errors)
|
|
||||||
{
|
|
||||||
if (syntax == null || syntax.Count == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var includes = new List<string>(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,10 +27,6 @@ internal class PassBlock : IBlockParser<PassSyntax, PassSemantic>
|
|||||||
{
|
{
|
||||||
pass.defines = DefinesBlock.Parse(bodyStream.SliceNextBlock());
|
pass.defines = DefinesBlock.Parse(bodyStream.SliceNextBlock());
|
||||||
}
|
}
|
||||||
else if (IncludesBlock.ShouldEnter(nextToken))
|
|
||||||
{
|
|
||||||
pass.includes = IncludesBlock.Parse(bodyStream.SliceNextBlock());
|
|
||||||
}
|
|
||||||
else if (KeywordsBlock.ShouldEnter(nextToken))
|
else if (KeywordsBlock.ShouldEnter(nextToken))
|
||||||
{
|
{
|
||||||
pass.keywords = KeywordsBlock.Parse(bodyStream.SliceNextBlock());
|
pass.keywords = KeywordsBlock.Parse(bodyStream.SliceNextBlock());
|
||||||
@@ -39,10 +35,6 @@ internal class PassBlock : IBlockParser<PassSyntax, PassSemantic>
|
|||||||
{
|
{
|
||||||
pass.localPipeline = PipelineBlock.Parse(bodyStream.SliceNextBlock());
|
pass.localPipeline = PipelineBlock.Parse(bodyStream.SliceNextBlock());
|
||||||
}
|
}
|
||||||
else if (PropertiesBlock.ShouldEnter(nextToken))
|
|
||||||
{
|
|
||||||
pass.localProperties = PropertiesBlock.Parse(bodyStream.SliceNextBlock());
|
|
||||||
}
|
|
||||||
else if (nextToken.Match(TokenType.Identifier))
|
else if (nextToken.Match(TokenType.Identifier))
|
||||||
{
|
{
|
||||||
var func = ParseUtility.ParseFunction(ref bodyStream, TokenType.StringLiteral);
|
var func = ParseUtility.ParseFunction(ref bodyStream, TokenType.StringLiteral);
|
||||||
@@ -72,23 +64,10 @@ internal class PassBlock : IBlockParser<PassSyntax, PassSemantic>
|
|||||||
{
|
{
|
||||||
name = syntax.name.lexeme,
|
name = syntax.name.lexeme,
|
||||||
defines = DefinesBlock.SemanticAnalysis(syntax.defines, errors),
|
defines = DefinesBlock.SemanticAnalysis(syntax.defines, errors),
|
||||||
includes = IncludesBlock.SemanticAnalysis(syntax.includes, errors),
|
|
||||||
keywords = KeywordsBlock.SemanticAnalysis(syntax.keywords, errors),
|
keywords = KeywordsBlock.SemanticAnalysis(syntax.keywords, errors),
|
||||||
localProperties = PropertiesBlock.SemanticAnalysis(syntax.localProperties, errors),
|
|
||||||
localPipeline = PipelineBlock.SemanticAnalysis(syntax.localPipeline, 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)
|
if (syntax.functionCalls != null)
|
||||||
{
|
{
|
||||||
foreach (var func in syntax.functionCalls)
|
foreach (var func in syntax.functionCalls)
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
|
|||||||
ParseBoolValue(syntax[3], errors))),
|
ParseBoolValue(syntax[3], errors))),
|
||||||
|
|
||||||
// Textures (single identifier argument)
|
// Textures (single identifier argument)
|
||||||
[ShaderPropertyType.Texture2DBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
|
[ShaderPropertyType.Texture2D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
|
||||||
[ShaderPropertyType.Texture3DBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
|
[ShaderPropertyType.Texture3D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
|
||||||
[ShaderPropertyType.TextureCubeBindless] = 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<SDLError> errors)
|
private static float ParseFloatValue(Token token, List<SDLError> errors)
|
||||||
@@ -166,6 +166,7 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
|
|||||||
TokenLexicon.KnownTypes.FLOAT2 => ShaderPropertyType.Float2,
|
TokenLexicon.KnownTypes.FLOAT2 => ShaderPropertyType.Float2,
|
||||||
TokenLexicon.KnownTypes.FLOAT3 => ShaderPropertyType.Float3,
|
TokenLexicon.KnownTypes.FLOAT3 => ShaderPropertyType.Float3,
|
||||||
TokenLexicon.KnownTypes.FLOAT4 => ShaderPropertyType.Float4,
|
TokenLexicon.KnownTypes.FLOAT4 => ShaderPropertyType.Float4,
|
||||||
|
TokenLexicon.KnownTypes.FLOAT4X4 => ShaderPropertyType.Float4x4,
|
||||||
TokenLexicon.KnownTypes.INT => ShaderPropertyType.Int,
|
TokenLexicon.KnownTypes.INT => ShaderPropertyType.Int,
|
||||||
TokenLexicon.KnownTypes.INT2 => ShaderPropertyType.Int2,
|
TokenLexicon.KnownTypes.INT2 => ShaderPropertyType.Int2,
|
||||||
TokenLexicon.KnownTypes.INT3 => ShaderPropertyType.Int3,
|
TokenLexicon.KnownTypes.INT3 => ShaderPropertyType.Int3,
|
||||||
@@ -178,9 +179,9 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
|
|||||||
TokenLexicon.KnownTypes.BOOL2 => ShaderPropertyType.Bool2,
|
TokenLexicon.KnownTypes.BOOL2 => ShaderPropertyType.Bool2,
|
||||||
TokenLexicon.KnownTypes.BOOL3 => ShaderPropertyType.Bool3,
|
TokenLexicon.KnownTypes.BOOL3 => ShaderPropertyType.Bool3,
|
||||||
TokenLexicon.KnownTypes.BOOL4 => ShaderPropertyType.Bool4,
|
TokenLexicon.KnownTypes.BOOL4 => ShaderPropertyType.Bool4,
|
||||||
TokenLexicon.KnownTypes.TEXTURE2D_BINDLESS => ShaderPropertyType.Texture2DBindless,
|
TokenLexicon.KnownTypes.TEXTURE2D => ShaderPropertyType.Texture2D,
|
||||||
TokenLexicon.KnownTypes.TEXTURE3D_BINDLESS => ShaderPropertyType.Texture3DBindless,
|
TokenLexicon.KnownTypes.TEXTURE3D => ShaderPropertyType.Texture3D,
|
||||||
TokenLexicon.KnownTypes.TEXTURECUBE_BINDLESS => ShaderPropertyType.TextureCubeBindless,
|
TokenLexicon.KnownTypes.TEXTURECUBE => ShaderPropertyType.TextureCube,
|
||||||
_ => ShaderPropertyType.None,
|
_ => ShaderPropertyType.None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ internal static class SDLCompiler
|
|||||||
|
|
||||||
public static SDLSemantics? SemanticAnalysis(SDLSyntax syntax, out List<SDLError> errors)
|
public static SDLSemantics? SemanticAnalysis(SDLSyntax syntax, out List<SDLError> errors)
|
||||||
{
|
{
|
||||||
errors = new();
|
errors = new List<SDLError>();
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(syntax.name.lexeme))
|
if (string.IsNullOrWhiteSpace(syntax.name.lexeme))
|
||||||
{
|
{
|
||||||
@@ -145,31 +145,23 @@ internal static class SDLCompiler
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<PropertyDescriptor> MergeProperties(List<PropertySemantic>? semantics, List<PropertyDescriptor>? parent)
|
private static uint CalculateCBufferSize(List<PropertyDescriptor> properties)
|
||||||
{
|
{
|
||||||
var result = new List<PropertyDescriptor>();
|
var currentOffset = 0u;
|
||||||
if (parent != null)
|
|
||||||
{
|
|
||||||
result.AddRange(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
currentOffset = (currentOffset + 15u) & ~15u;
|
||||||
{
|
|
||||||
result.Add(new PropertyDescriptor
|
|
||||||
{
|
|
||||||
name = prop.name,
|
|
||||||
type = prop.type,
|
|
||||||
defaultValue = prop.defaultValue
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentOffset += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.DistinctBy(p => p.name).ToList();
|
return (currentOffset + 15u) & ~15u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement shader inheritance resolution, including property and pass merging.
|
// TODO: Implement shader inheritance resolution, including property and pass merging.
|
||||||
@@ -181,19 +173,23 @@ internal static class SDLCompiler
|
|||||||
name = semantics.name
|
name = semantics.name
|
||||||
};
|
};
|
||||||
|
|
||||||
var shaderGlobalProperties = semantics.properties?.Where(p => p.scope == PropertyScope.Global).Select(p => new PropertyDescriptor
|
var shaderGlobalProperties = semantics.properties?
|
||||||
{
|
.Where(p => p.scope == PropertyScope.Global)
|
||||||
name = p.name,
|
.Select(p => new PropertyDescriptor
|
||||||
type = p.type,
|
{
|
||||||
defaultValue = p.defaultValue
|
name = p.name,
|
||||||
}).ToList();
|
type = p.type,
|
||||||
|
defaultValue = p.defaultValue
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
var shaderLocalProperties = semantics.properties?.Where(p => p.scope == PropertyScope.Local).Select(p => new PropertyDescriptor
|
var shaderLocalProperties = semantics.properties?
|
||||||
{
|
.Where(p => p.scope == PropertyScope.Local)
|
||||||
name = p.name,
|
.Select(p => new PropertyDescriptor
|
||||||
type = p.type,
|
{
|
||||||
defaultValue = p.defaultValue
|
name = p.name,
|
||||||
}).ToList();
|
type = p.type,
|
||||||
|
defaultValue = p.defaultValue
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
if (shaderGlobalProperties != null)
|
if (shaderGlobalProperties != null)
|
||||||
{
|
{
|
||||||
@@ -201,13 +197,18 @@ internal static class SDLCompiler
|
|||||||
descriptor.globalProperties.AddRange(shaderGlobalProperties);
|
descriptor.globalProperties.AddRange(shaderGlobalProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shaderLocalProperties != null)
|
||||||
|
{
|
||||||
|
descriptor.properties ??= new List<PropertyDescriptor>();
|
||||||
|
descriptor.properties.AddRange(shaderLocalProperties);
|
||||||
|
descriptor.cbufferSize = CalculateCBufferSize(descriptor.properties);
|
||||||
|
}
|
||||||
|
|
||||||
if (semantics.passes != null)
|
if (semantics.passes != null)
|
||||||
{
|
{
|
||||||
foreach (var pass in semantics.passes)
|
foreach (var pass in semantics.passes)
|
||||||
{
|
{
|
||||||
var localPipeline = MeragePipeline(pass.localPipeline, PipelineDescriptor.Default);
|
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
|
var fullPass = new FullPassDescriptor
|
||||||
{
|
{
|
||||||
uniqueIdentifier = GetPassUniqueId(semantics, pass),
|
uniqueIdentifier = GetPassUniqueId(semantics, pass),
|
||||||
@@ -217,9 +218,7 @@ internal static class SDLCompiler
|
|||||||
pixelShader = pass.pixelShader,
|
pixelShader = pass.pixelShader,
|
||||||
localPipeline = localPipeline,
|
localPipeline = localPipeline,
|
||||||
defines = pass.defines,
|
defines = pass.defines,
|
||||||
includes = pass.includes,
|
|
||||||
keywords = pass.keywords,
|
keywords = pass.keywords,
|
||||||
properties = localProperties
|
|
||||||
};
|
};
|
||||||
|
|
||||||
descriptor.passes.Add(fullPass);
|
descriptor.passes.Add(fullPass);
|
||||||
@@ -258,24 +257,14 @@ internal static class SDLCompiler
|
|||||||
return Result.Failure("Failed to generate global properties: " + globalPropResult.Message);
|
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)
|
return Result.Failure("Failed to generate pass files: " + generatedResult.Message);
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fullPass.includes ??= new List<string>();
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
desc.generatedCodePath = generatedResult.Value;
|
||||||
|
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -305,28 +294,23 @@ internal static class SDLCompiler
|
|||||||
ShaderPropertyType.Bool3 => "bool3",
|
ShaderPropertyType.Bool3 => "bool3",
|
||||||
ShaderPropertyType.Bool4 => "bool4",
|
ShaderPropertyType.Bool4 => "bool4",
|
||||||
// NOTE: Textures here are bindless, represented as uint (descriptor index).
|
// NOTE: Textures here are bindless, represented as uint (descriptor index).
|
||||||
ShaderPropertyType.Texture2DBindless => "TEXTURE2D_BINDLESS",
|
ShaderPropertyType.Texture2D => "TEXTURE2D_BINDLESS",
|
||||||
ShaderPropertyType.Texture3DBindless => "TEXTURE3D_BINDLESS",
|
ShaderPropertyType.Texture3D => "TEXTURE3D_BINDLESS",
|
||||||
ShaderPropertyType.TextureCubeBindless => "TEXTURECUBE_BINDLESS",
|
ShaderPropertyType.TextureCube => "TEXTURECUBE_BINDLESS",
|
||||||
ShaderPropertyType.Texture2DArrayBindless => "TEXTURE2D_ARRAY_BINDLESS",
|
ShaderPropertyType.Texture2DArray => "TEXTURE2D_ARRAY_BINDLESS",
|
||||||
ShaderPropertyType.TextureCubeArrayBindless => "TEXTURECUBE_ARRAY_BINDLESS",
|
ShaderPropertyType.TextureCubeArray => "TEXTURECUBE_ARRAY_BINDLESS",
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}")
|
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result<string> GeneratePass(IPassDescriptor descriptor, string targetDirectory)
|
public static Result<string> 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))
|
if (!Directory.Exists(targetDirectory))
|
||||||
{
|
{
|
||||||
return Result.Failure("Target directory does not exist.");
|
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 outputFilePath = Path.Combine(targetDirectory, outputFileName + ".g.hlsl");
|
||||||
var outputDirectory = Path.GetDirectoryName(outputFilePath);
|
var outputDirectory = Path.GetDirectoryName(outputFilePath);
|
||||||
|
|
||||||
@@ -346,30 +330,17 @@ internal static class SDLCompiler
|
|||||||
#define {fileDefine}
|
#define {fileDefine}
|
||||||
|
|
||||||
#include ""F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl""");
|
#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();
|
sb.Append(@"
|
||||||
}
|
|
||||||
|
|
||||||
if (fullPass.properties != null)
|
|
||||||
{
|
|
||||||
sb.Append(@"
|
|
||||||
struct PerMaterialData
|
struct PerMaterialData
|
||||||
{");
|
{");
|
||||||
foreach (var prop in fullPass.properties)
|
foreach (var prop in descriptor.properties)
|
||||||
{
|
{
|
||||||
sb.Append($@"
|
sb.Append($@"
|
||||||
{ShaderPropertyTypeToHLSLType(prop.type)} {prop.name};");
|
{ShaderPropertyTypeToHLSLType(prop.type)} {prop.name};");
|
||||||
}
|
|
||||||
sb.Append(@"
|
|
||||||
};");
|
|
||||||
}
|
}
|
||||||
|
sb.Append(@"
|
||||||
|
};");
|
||||||
|
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
sb.AppendLine(@$"
|
sb.AppendLine(@$"
|
||||||
@@ -414,4 +385,4 @@ struct GlobalData
|
|||||||
|
|
||||||
return globalFilePath;
|
return globalFilePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,7 @@ internal class PassSemantic
|
|||||||
public ShaderEntryPoint meshShader;
|
public ShaderEntryPoint meshShader;
|
||||||
public ShaderEntryPoint pixelShader;
|
public ShaderEntryPoint pixelShader;
|
||||||
public List<string>? defines;
|
public List<string>? defines;
|
||||||
public List<string>? includes;
|
|
||||||
public List<KeywordsGroup>? keywords;
|
public List<KeywordsGroup>? keywords;
|
||||||
public List<PropertySemantic>? localProperties;
|
|
||||||
public PipelineSemantic? localPipeline;
|
public PipelineSemantic? localPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,7 @@ internal class PassSyntax
|
|||||||
{
|
{
|
||||||
public Token name;
|
public Token name;
|
||||||
public PipelineSyntax? localPipeline;
|
public PipelineSyntax? localPipeline;
|
||||||
public PropertiesSyntax? localProperties;
|
|
||||||
public List<Token>? defines;
|
public List<Token>? defines;
|
||||||
public List<Token>? includes;
|
|
||||||
public List<FunctionCallDeclaration>? keywords;
|
public List<FunctionCallDeclaration>? keywords;
|
||||||
public List<FunctionCallDeclaration>? functionCalls;
|
public List<FunctionCallDeclaration>? functionCalls;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ internal static class TokenLexicon
|
|||||||
public const string FLOAT2 = "float2";
|
public const string FLOAT2 = "float2";
|
||||||
public const string FLOAT3 = "float3";
|
public const string FLOAT3 = "float3";
|
||||||
public const string FLOAT4 = "float4";
|
public const string FLOAT4 = "float4";
|
||||||
|
public const string FLOAT4X4 = "float4x4";
|
||||||
|
|
||||||
public const string INT = "int";
|
public const string INT = "int";
|
||||||
public const string INT2 = "int2";
|
public const string INT2 = "int2";
|
||||||
@@ -170,11 +171,11 @@ internal static class TokenLexicon
|
|||||||
public const string BOOL4 = "bool4";
|
public const string BOOL4 = "bool4";
|
||||||
|
|
||||||
// Texture types
|
// Texture types
|
||||||
public const string TEXTURE2D_BINDLESS = "tex2d_b";
|
public const string TEXTURE2D = "tex2d";
|
||||||
public const string TEXTURE2D_ARRAY_BINDLESS = "tex2d_arr_b";
|
public const string TEXTURE2D_ARRAY = "tex2d_arr";
|
||||||
public const string TEXTURE3D_BINDLESS = "tex3d_b";
|
public const string TEXTURE3D = "tex3d";
|
||||||
public const string TEXTURECUBE_BINDLESS = "texcube_b";
|
public const string TEXTURECUBE = "texcube";
|
||||||
public const string TEXTURECUBE_ARRAY_BINDLESS = "texcube_arr_b";
|
public const string TEXTURECUBE_ARRAY = "texcube_arr";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class KnownTextureValue
|
public static class KnownTextureValue
|
||||||
@@ -211,12 +212,12 @@ internal static class TokenLexicon
|
|||||||
|
|
||||||
private static readonly HashSet<string> s_types = new()
|
private static readonly HashSet<string> 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.INT, KnownTypes.INT2, KnownTypes.INT3, KnownTypes.INT4,
|
||||||
KnownTypes.UINT, KnownTypes.UINT2, KnownTypes.UINT3, KnownTypes.UINT4,
|
KnownTypes.UINT, KnownTypes.UINT2, KnownTypes.UINT3, KnownTypes.UINT4,
|
||||||
KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4,
|
KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4,
|
||||||
KnownTypes.TEXTURE2D_BINDLESS, KnownTypes.TEXTURE2D_ARRAY_BINDLESS, KnownTypes.TEXTURE3D_BINDLESS,
|
KnownTypes.TEXTURE2D, KnownTypes.TEXTURE2D_ARRAY, KnownTypes.TEXTURE3D,
|
||||||
KnownTypes.TEXTURECUBE_BINDLESS, KnownTypes.TEXTURECUBE_ARRAY_BINDLESS,
|
KnownTypes.TEXTURECUBE, KnownTypes.TEXTURECUBE_ARRAY,
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly HashSet<string> s_textureDefaultValues = new()
|
private static readonly HashSet<string> s_textureDefaultValues = new()
|
||||||
|
|||||||
Reference in New Issue
Block a user