Add sampler support and refactor resource handling

Enhanced shader and resource systems with `Sampler` support, including updates to `ShaderPropertyType`, HLSL code, and resource management. Refactored `Result` structs for better type safety and added new enums for texture and comparison settings. Improved `MeshRenderPass` to dynamically load textures and samplers. Updated SDL compiler and token lexicon for `Sampler` handling. Embedded debug info in project files and streamlined resource state tracking.
This commit is contained in:
2025-11-29 18:27:47 +09:00
parent bd97d233cb
commit 0ec318a9ab
30 changed files with 463 additions and 166 deletions

View File

@@ -16,6 +16,7 @@ public enum ShaderPropertyType
Bool, Bool2, Bool3, Bool4, Bool, Bool2, Bool3, Bool4,
Texture2D, Texture3D, TextureCube, Texture2D, Texture3D, TextureCube,
Texture2DArray, TextureCubeArray, Texture2DArray, TextureCubeArray,
Sampler
} }
public struct ShaderEntryPoint public struct ShaderEntryPoint
@@ -133,6 +134,7 @@ public static class ShaderDescriptorExtensions
ShaderPropertyType.TextureCube => 4, ShaderPropertyType.TextureCube => 4,
ShaderPropertyType.Texture2DArray => 4, ShaderPropertyType.Texture2DArray => 4,
ShaderPropertyType.TextureCubeArray => 4, ShaderPropertyType.TextureCubeArray => 4,
ShaderPropertyType.Sampler => 4,
_ => 0, _ => 0,
}; };
} }

View File

@@ -1,5 +1,3 @@
using System.Runtime.CompilerServices;
namespace Ghost.Core; namespace Ghost.Core;
public readonly struct Result public readonly struct Result
@@ -39,11 +37,13 @@ public readonly struct Result
} }
public static Result<T, S> Create<T, S>(T value, S status) public static Result<T, S> Create<T, S>(T value, S status)
where S : Enum
{ {
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) public static RefResult<T, S> CreateRef<T, S>(ref T value, S status)
where S : Enum
{ {
return new RefResult<T, S>(ref value, status); return new RefResult<T, S>(ref value, status);
} }
@@ -105,6 +105,7 @@ public enum ResultStatus : byte
} }
public readonly struct Result<T, S> public readonly struct Result<T, S>
where S : Enum
{ {
private readonly T _value; private readonly T _value;
private readonly S _status; private readonly S _status;
@@ -127,6 +128,7 @@ public readonly struct Result<T, S>
} }
public readonly ref struct RefResult<T, S> public readonly ref struct RefResult<T, S>
where S : Enum
{ {
private readonly ref T _value; private readonly ref T _value;
private readonly S _status; private readonly S _status;
@@ -173,6 +175,23 @@ public static class ResultExtensions
return result.IsSuccess ? result.Value : defaultValue; return result.IsSuccess ? result.Value : defaultValue;
} }
public static T GetValueOrThrow<T, S>(this Result<T, S> result, S expect)
where S : Enum
{
if (result.Status?.Equals(expect) ?? false)
{
throw new InvalidOperationException($"Operation failed: expected status {expect}, but got {result.Status}");
}
return result.Value;
}
public static T? GetValueOrDefault<T, S>(this Result<T, S> result, S expect, T? defaultValue = default)
where S : Enum
{
return (result.Status?.Equals(expect) ?? false) ? defaultValue : result.Value;
}
public static Result OnSuccess(this Result result, Action action) public static Result OnSuccess(this Result result, Action action)
{ {
if (result.IsSuccess) if (result.IsSuccess)

View File

@@ -83,7 +83,7 @@ public static partial class AssetDatabase
var metaFileResult = GetMetaFilePath(assetPath); var metaFileResult = GetMetaFilePath(assetPath);
if (!metaFileResult.IsSuccess) if (!metaFileResult.IsSuccess)
{ {
return metaFileResult; return Result.Failure(metaFileResult.Message);
} }
if (File.Exists(metaFileResult.Value)) if (File.Exists(metaFileResult.Value))

View File

@@ -87,10 +87,22 @@
<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|x86'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" /> <DebugType>embedded</DebugType>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" /> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <DebugType>embedded</DebugType>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" /> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
</Project> </Project>

View File

@@ -2,7 +2,7 @@
"profiles": { "profiles": {
"Ghost.Graphics.Test (Package)": { "Ghost.Graphics.Test (Package)": {
"commandName": "MsixPackage", "commandName": "MsixPackage",
"nativeDebugging": false "nativeDebugging": true
}, },
"Ghost.Graphics.Test (Unpackaged)": { "Ghost.Graphics.Test (Unpackaged)": {
"commandName": "Project" "commandName": "Project"

View File

@@ -45,6 +45,8 @@ public sealed partial class GraphicsTestWindow : Window
{ {
Width = (uint)AppWindow.Size.Width, Width = (uint)AppWindow.Size.Width,
Height = (uint)AppWindow.Size.Height, Height = (uint)AppWindow.Size.Height,
BufferCount = 2,
Format = TextureFormat.B8G8R8A8_UNorm,
Target = SwapChainTarget.FromCompositionSurface(Panel) Target = SwapChainTarget.FromCompositionSurface(Panel)
}); });
_renderer.SetSwapChain(_swapChain); _renderer.SetSwapChain(_swapChain);

View File

@@ -106,34 +106,35 @@ public struct Material : IResourceReleasable, IHandleType
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly unsafe Result<ResultStatus> SetPropertyCache<T>(ref readonly T data) public readonly unsafe ResultStatus SetPropertyCache<T>(ref readonly T data)
where T : unmanaged where T : unmanaged
{ {
if (sizeof(T) != _cBufferCache.Size) if (sizeof(T) != _cBufferCache.Size)
{ {
return new Result<ResultStatus>(false, ResultStatus.InvalidArgument); return ResultStatus.InvalidArgument;
} }
Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data); Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data);
return Result.Success(ResultStatus.Success); return ResultStatus.Success;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly unsafe Result<ResultStatus> SetRawPropertyCache(ReadOnlySpan<byte> data) public readonly unsafe ResultStatus SetRawPropertyCache(ReadOnlySpan<byte> data)
{ {
if (data.Length != _cBufferCache.Size) if (data.Length != _cBufferCache.Size)
{ {
return new Result<ResultStatus>(false, ResultStatus.InvalidArgument); return ResultStatus.InvalidArgument;
} }
Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data); Unsafe.WriteUnaligned(_cBufferCache.CpuData.GetUnsafePtr(), data);
return Result.Success(ResultStatus.Success); return ResultStatus.Success;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly void UploadData(ICommandBuffer cmb) public readonly void UploadData(ICommandBuffer cmb)
{ {
cmb.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan()); cmb.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
cmb.ResourceBarrier(_cBufferCache.GpuResource.AsResource(), ResourceState.VertexAndConstantBuffer);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -8,7 +8,7 @@ using Misaki.HighPerformance.Mathematics;
namespace Ghost.Graphics.Core; namespace Ghost.Graphics.Core;
public unsafe readonly ref struct RenderingContext public readonly unsafe ref struct RenderingContext
{ {
private readonly IGraphicsEngine _engine; private readonly IGraphicsEngine _engine;
private readonly ICommandBuffer _directCmd; private readonly ICommandBuffer _directCmd;
@@ -144,8 +144,8 @@ public unsafe readonly ref struct RenderingContext
localToWorld = localToWorld, localToWorld = localToWorld,
worldBoundsMin = meshData.BoundingBox.Min, worldBoundsMin = meshData.BoundingBox.Min,
worldBoundsMax = meshData.BoundingBox.Max, worldBoundsMax = meshData.BoundingBox.Max,
vertexBuffer = (uint)_engine.ResourceDatabase.GetBindlessIndex(meshData.VertexBuffer.AsResource()), vertexBuffer = _engine.ResourceDatabase.GetBindlessIndex(meshData.VertexBuffer.AsResource()).GetValueOrThrow(ResultStatus.Success),
indexBuffer = (uint)_engine.ResourceDatabase.GetBindlessIndex(meshData.IndexBuffer.AsResource()), indexBuffer = _engine.ResourceDatabase.GetBindlessIndex(meshData.IndexBuffer.AsResource()).GetValueOrThrow(ResultStatus.Success),
}; };
var bufferHandle = meshData.ObjectDataBuffer.AsResource(); var bufferHandle = meshData.ObjectDataBuffer.AsResource();

View File

@@ -6,6 +6,8 @@ public readonly struct GPUResource : IHandleType;
public readonly struct Texture : IHandleType; public readonly struct Texture : IHandleType;
public readonly struct GraphicsBuffer : IHandleType; public readonly struct GraphicsBuffer : IHandleType;
public readonly struct Sampler : IIdentifierType;
public static class ResourceHandleExtensions public static class ResourceHandleExtensions
{ {
public static Handle<GPUResource> AsResource(this Handle<Texture> texture) public static Handle<GPUResource> AsResource(this Handle<Texture> texture)

View File

@@ -234,6 +234,12 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
resourceRecord.state = stateAfter; resourceRecord.state = stateAfter;
} }
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState stateAfter)
{
var stateBefore = _resourceDatabase.GetResourceState(resource);
ResourceBarrier(resource, stateBefore, stateAfter);
}
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget) public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@@ -511,6 +517,8 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var pResource = _resourceDatabase.GetResource(buffer.AsResource()); var pResource = _resourceDatabase.GetResource(buffer.AsResource());
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes); _commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
// D3D12 transition resource to COPY_DEST when copying
_resourceDatabase.SetResourceState(buffer.AsResource(), ResourceState.CopyDest);
} }
public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<SubResourceData> subresources) public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<SubResourceData> subresources)

View File

@@ -1,5 +1,4 @@
using Ghost.Core; using Ghost.Core;
using Ghost.Graphics.D3D12.Utilities;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX; using TerraFX.Interop.DirectX;
@@ -34,7 +33,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
#region RTV Methods #region RTV Methods
public Identifier<RTVDesc> AllocateRTV(bool dynamic = false) public Identifier<RTVDescriptor> AllocateRTV(bool dynamic = false)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -44,10 +43,10 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate RTV descriptor"); throw new InvalidOperationException("Failed to allocate RTV descriptor");
} }
return new Identifier<RTVDesc>(index); return new Identifier<RTVDescriptor>(index);
} }
public Identifier<RTVDesc>[] AllocateRTVs(int count, bool dynamic = false) public Identifier<RTVDescriptor>[] AllocateRTVs(int count, bool dynamic = false)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -57,32 +56,32 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException($"Failed to allocate {count} RTV descriptors"); throw new InvalidOperationException($"Failed to allocate {count} RTV descriptors");
} }
var descriptors = new Identifier<RTVDesc>[count]; var descriptors = new Identifier<RTVDescriptor>[count];
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var index = baseIndex + i; var index = baseIndex + i;
descriptors[i] = new Identifier<RTVDesc>(index); descriptors[i] = new Identifier<RTVDescriptor>(index);
} }
return descriptors; return descriptors;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<RTVDesc> descriptor) public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<RTVDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _rtvHeap.GetCpuHandle(descriptor.value); return _rtvHeap.GetCpuHandle(descriptor.value);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Release(Identifier<RTVDesc> descriptor) public void Release(Identifier<RTVDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_rtvHeap.ReleaseDescriptor(descriptor.value); _rtvHeap.ReleaseDescriptor(descriptor.value);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Release(ReadOnlySpan<Identifier<RTVDesc>> descriptors) public void Release(ReadOnlySpan<Identifier<RTVDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -93,14 +92,14 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MakePersistent(Identifier<RTVDesc> descriptor) public void MakePersistent(Identifier<RTVDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_rtvHeap.CopyToPersistentHeap(descriptor.value); _rtvHeap.CopyToPersistentHeap(descriptor.value);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MakePersistent(ReadOnlySpan<Identifier<RTVDesc>> descriptors) public void MakePersistent(ReadOnlySpan<Identifier<RTVDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors) foreach (var descriptor in descriptors)
@@ -120,7 +119,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
#region DSV Methods #region DSV Methods
public Identifier<DSVDesc> AllocateDSV(bool dynamic = false) public Identifier<DSVDescriptor> AllocateDSV(bool dynamic = false)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -130,10 +129,10 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException("Failed to allocate DSV descriptor"); throw new InvalidOperationException("Failed to allocate DSV descriptor");
} }
return new Identifier<DSVDesc>(index); return new Identifier<DSVDescriptor>(index);
} }
public Identifier<DSVDesc>[] AllocateDSVs(int count, bool dynamic = false) public Identifier<DSVDescriptor>[] AllocateDSVs(int count, bool dynamic = false)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -143,29 +142,29 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException($"Failed to allocate {count} DSV descriptors"); throw new InvalidOperationException($"Failed to allocate {count} DSV descriptors");
} }
var descriptors = new Identifier<DSVDesc>[count]; var descriptors = new Identifier<DSVDescriptor>[count];
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var index = baseIndex + i; var index = baseIndex + i;
descriptors[i] = new Identifier<DSVDesc>(index); descriptors[i] = new Identifier<DSVDescriptor>(index);
} }
return descriptors; return descriptors;
} }
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<DSVDesc> descriptor) public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<DSVDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _dsvHeap.GetCpuHandle(descriptor.value); return _dsvHeap.GetCpuHandle(descriptor.value);
} }
public void Release(Identifier<DSVDesc> descriptor) public void Release(Identifier<DSVDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_dsvHeap.ReleaseDescriptor(descriptor.value); _dsvHeap.ReleaseDescriptor(descriptor.value);
} }
public void Release(ReadOnlySpan<Identifier<DSVDesc>> descriptors) public void Release(ReadOnlySpan<Identifier<DSVDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -176,14 +175,14 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MakePersistent(Identifier<DSVDesc> descriptor) public void MakePersistent(Identifier<DSVDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_dsvHeap.CopyToPersistentHeap(descriptor.value); _dsvHeap.CopyToPersistentHeap(descriptor.value);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MakePersistent(ReadOnlySpan<Identifier<DSVDesc>> descriptors) public void MakePersistent(ReadOnlySpan<Identifier<DSVDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors) foreach (var descriptor in descriptors)
@@ -203,7 +202,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
#region CBV_SRV_UAV Methods #region CBV_SRV_UAV Methods
public Identifier<CbvSrvUavDesc> AllocateCbvSrvUav(bool dynamic = false) public Identifier<CbvSrvUavDescriptor> AllocateCbvSrvUav(bool dynamic = false)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -214,10 +213,10 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
} }
_cbvSrvUavHeap.CopyToShaderVisibleHeap(index); _cbvSrvUavHeap.CopyToShaderVisibleHeap(index);
return new Identifier<CbvSrvUavDesc>(index); return new Identifier<CbvSrvUavDescriptor>(index);
} }
public Identifier<CbvSrvUavDesc>[] AllocateSRVs(int count, bool dynamic = false) public Identifier<CbvSrvUavDescriptor>[] AllocateSRVs(int count, bool dynamic = false)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -227,42 +226,42 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException($"Failed to allocate {count} CBV/SRV/UAV descriptors"); throw new InvalidOperationException($"Failed to allocate {count} CBV/SRV/UAV descriptors");
} }
var descriptors = new Identifier<CbvSrvUavDesc>[count]; var descriptors = new Identifier<CbvSrvUavDescriptor>[count];
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var index = baseIndex + i; var index = baseIndex + i;
descriptors[i] = new Identifier<CbvSrvUavDesc>(index); descriptors[i] = new Identifier<CbvSrvUavDescriptor>(index);
} }
_cbvSrvUavHeap.CopyToShaderVisibleHeap(baseIndex, count); _cbvSrvUavHeap.CopyToShaderVisibleHeap(baseIndex, count);
return descriptors; return descriptors;
} }
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<CbvSrvUavDesc> descriptor) public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<CbvSrvUavDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _cbvSrvUavHeap.GetCpuHandle(descriptor.value); return _cbvSrvUavHeap.GetCpuHandle(descriptor.value);
} }
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(Identifier<CbvSrvUavDesc> descriptor) public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(Identifier<CbvSrvUavDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _cbvSrvUavHeap.GetCpuHandleShaderVisible(descriptor.value); return _cbvSrvUavHeap.GetCpuHandleShaderVisible(descriptor.value);
} }
public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Identifier<CbvSrvUavDesc> descriptor) public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Identifier<CbvSrvUavDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _cbvSrvUavHeap.GetGpuHandle(descriptor.value); return _cbvSrvUavHeap.GetGpuHandle(descriptor.value);
} }
public void Release(Identifier<CbvSrvUavDesc> descriptor) public void Release(Identifier<CbvSrvUavDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_cbvSrvUavHeap.ReleaseDescriptor(descriptor.value); _cbvSrvUavHeap.ReleaseDescriptor(descriptor.value);
} }
public void Release(ReadOnlySpan<Identifier<CbvSrvUavDesc>> descriptors) public void Release(ReadOnlySpan<Identifier<CbvSrvUavDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -273,14 +272,14 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MakePersistent(Identifier<CbvSrvUavDesc> descriptor) public void MakePersistent(Identifier<CbvSrvUavDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_cbvSrvUavHeap.CopyToPersistentHeap(descriptor.value); _cbvSrvUavHeap.CopyToPersistentHeap(descriptor.value);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MakePersistent(ReadOnlySpan<Identifier<CbvSrvUavDesc>> descriptors) public void MakePersistent(ReadOnlySpan<Identifier<CbvSrvUavDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
foreach (var descriptor in descriptors) foreach (var descriptor in descriptors)
@@ -300,7 +299,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
#region Sampler Methods #region Sampler Methods
public Identifier<SamplerDesc> AllocateSampler() public Identifier<SamplerDescriptor> AllocateSampler()
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -311,10 +310,10 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
} }
_samplerHeap.CopyToShaderVisibleHeap(index); _samplerHeap.CopyToShaderVisibleHeap(index);
return new Identifier<SamplerDesc>(index); return new Identifier<SamplerDescriptor>(index);
} }
public Identifier<SamplerDesc>[] AllocateSamplers(int count) public Identifier<SamplerDescriptor>[] AllocateSamplers(int count)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -324,42 +323,42 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
throw new InvalidOperationException($"Failed to allocate {count} Sampler descriptors"); throw new InvalidOperationException($"Failed to allocate {count} Sampler descriptors");
} }
var descriptors = new Identifier<SamplerDesc>[count]; var descriptors = new Identifier<SamplerDescriptor>[count];
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var index = baseIndex + i; var index = baseIndex + i;
descriptors[i] = new Identifier<SamplerDesc>(index); descriptors[i] = new Identifier<SamplerDescriptor>(index);
} }
_samplerHeap.CopyToShaderVisibleHeap(baseIndex, count); _samplerHeap.CopyToShaderVisibleHeap(baseIndex, count);
return descriptors; return descriptors;
} }
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<SamplerDesc> descriptor) public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(Identifier<SamplerDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _samplerHeap.GetCpuHandle(descriptor.value); return _samplerHeap.GetCpuHandle(descriptor.value);
} }
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(Identifier<SamplerDesc> descriptor) public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(Identifier<SamplerDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _samplerHeap.GetCpuHandleShaderVisible(descriptor.value); return _samplerHeap.GetCpuHandleShaderVisible(descriptor.value);
} }
public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Identifier<SamplerDesc> descriptor) public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(Identifier<SamplerDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
return _samplerHeap.GetGpuHandle(descriptor.value); return _samplerHeap.GetGpuHandle(descriptor.value);
} }
public void Release(Identifier<SamplerDesc> descriptor) public void Release(Identifier<SamplerDescriptor> descriptor)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
_samplerHeap.ReleaseDescriptor(descriptor.value); _samplerHeap.ReleaseDescriptor(descriptor.value);
} }
public void Release(ReadOnlySpan<Identifier<SamplerDesc>> descriptors) public void Release(ReadOnlySpan<Identifier<SamplerDescriptor>> descriptors)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);

View File

@@ -8,7 +8,7 @@ using TerraFX.Interop.DirectX;
using static TerraFX.Aliases.D3D12_Alias; using static TerraFX.Aliases.D3D12_Alias;
namespace Ghost.Graphics.D3D12.Utilities; namespace Ghost.Graphics.D3D12;
internal unsafe struct D3D12DescriptorHeap : IDisposable internal unsafe struct D3D12DescriptorHeap : IDisposable
{ {

View File

@@ -2,6 +2,7 @@ using Ghost.Core;
using Ghost.Core.Graphics; using Ghost.Core.Graphics;
using Ghost.Core.Utilities; using Ghost.Core.Utilities;
using Ghost.Graphics.Core; using Ghost.Graphics.Core;
using Ghost.Graphics.D3D12.Utilities;
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;
@@ -851,6 +852,35 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
return CreateBuffer(in desc, isTemp); return CreateBuffer(in desc, isTemp);
} }
public Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (_resourceDatabase.TryGetSampler(in desc, out var id))
{
return id;
}
var samplerDesc = new D3D12_SAMPLER_DESC
{
Filter = desc.FilterMode.ToD3D12Filter(),
AddressU = desc.AddressU.ToD3D12TextureAddressMode(),
AddressV = desc.AddressV.ToD3D12TextureAddressMode(),
AddressW = desc.AddressW.ToD3D12TextureAddressMode(),
MipLODBias = desc.MipLODBias,
MaxAnisotropy = desc.MaxAnisotropy,
ComparisonFunc = desc.ComparisonFunc.ToD3D12ComparisonFunc(),
MinLOD = desc.MinLOD,
MaxLOD = desc.MaxLOD,
};
var samplerDescriptor = _descriptorAllocator.AllocateSampler();
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(samplerDescriptor);
_device.NativeDevice.Get()->CreateSampler(&samplerDesc, cpuHandle);
return _resourceDatabase.CreateSampler(in desc, samplerDescriptor.value);
}
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices) public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);

View File

@@ -97,26 +97,30 @@ internal class D3D12ResourceDatabase : IResourceDatabase
private readonly Dictionary<Handle<GPUResource>, string> _resourceName; private readonly Dictionary<Handle<GPUResource>, string> _resourceName;
#endif #endif
private UnsafeHashMap<SamplerDesc, Identifier<Sampler>> _samplers;
private UnsafeSlotMap<Mesh> _meshes; private UnsafeSlotMap<Mesh> _meshes;
private UnsafeSlotMap<Material> _materials; private UnsafeSlotMap<Material> _materials;
private readonly DynamicArray<Shader?> _shaders; // NOTE: We use a simple list since shader is not frequently added/removed. This can save 4 bytes for each ecs component. private readonly DynamicArray<Shader?> _shaders; // NOTE: We use a simple list since shader is not frequently added/removed. This can save 4 bytes for each ecs component.
private readonly Dictionary<ShaderPassKey, ShaderPass> _shaderPasses; // NOTE: The reason we use Dictionary here is that ShaderPassKey is a presistence identifier across multiple application sessions. private readonly Dictionary<ShaderPassKey, ShaderPass> _shaderPasses; // NOTE: The reason we use Dictionary here is that ShaderPassKey is a presistence identifier across multiple application sessions.
private int _lastSamplerId;
private bool _disposed; private bool _disposed;
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator) public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
{ {
_descriptorAllocator = descriptorAllocator;
_resources = new UnsafeSlotMap<ResourceRecord>(64, Allocator.Persistent, AllocationOption.Clear); _resources = new UnsafeSlotMap<ResourceRecord>(64, Allocator.Persistent, AllocationOption.Clear);
#if DEBUG || GHOST_EDITOR #if DEBUG || GHOST_EDITOR
_resourceName = new Dictionary<Handle<GPUResource>, string>(64); _resourceName = new Dictionary<Handle<GPUResource>, string>(64);
#endif #endif
_samplers = new UnsafeHashMap<SamplerDesc, Identifier<Sampler>>(32, Allocator.Persistent);
_meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent, AllocationOption.Clear); _meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent, AllocationOption.Clear);
_materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent, AllocationOption.Clear); _materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent, AllocationOption.Clear);
_shaders = new DynamicArray<Shader?>(16); _shaders = new DynamicArray<Shader?>(16);
_shaderPasses = new Dictionary<ShaderPassKey, ShaderPass>(16); _shaderPasses = new Dictionary<ShaderPassKey, ShaderPass>(16);
_descriptorAllocator = descriptorAllocator; _lastSamplerId = -1;
} }
~D3D12ResourceDatabase() ~D3D12ResourceDatabase()
@@ -224,17 +228,17 @@ internal class D3D12ResourceDatabase : IResourceDatabase
return GetResourceRecord(handle).desc; return GetResourceRecord(handle).desc;
} }
public int GetBindlessIndex(Handle<GPUResource> handle) public Result<uint, ResultStatus> GetBindlessIndex(Handle<GPUResource> handle)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
ref var info = ref GetResourceRecord(handle, out var exist); ref var info = ref GetResourceRecord(handle, out var exist);
if (!exist || !info.Allocated) if (!exist || !info.Allocated)
{ {
return -1; return Result.Create(0u, ResultStatus.NotFound);
} }
return info.viewGroup.srv.value; return Result.Create((uint)info.viewGroup.srv.value, ResultStatus.NotFound);
} }
public string? GetResourceName(Handle<GPUResource> handle) public string? GetResourceName(Handle<GPUResource> handle)
@@ -266,7 +270,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
} }
info.Release(_descriptorAllocator); info.Release(_descriptorAllocator);
//Debug.Assert(info.Release(_descriptorAllocator) == 0); //System.Diagnostics.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);
#endif #endif
@@ -274,6 +278,27 @@ internal class D3D12ResourceDatabase : IResourceDatabase
_resources.Remove(handle.id, handle.generation); _resources.Remove(handle.id, handle.generation);
} }
public Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc, int id)
{
ObjectDisposedException.ThrowIf(_disposed, this);
if (_samplers.ContainsKey(desc))
{
throw new InvalidOperationException("Sampler already exists.");
}
var identifier = new Identifier<Sampler>(id);
_samplers.Add(desc, identifier);
return identifier;
}
public bool TryGetSampler(ref readonly SamplerDesc desc, out Identifier<Sampler> id)
{
ObjectDisposedException.ThrowIf(_disposed, this);
return _samplers.TryGetValue(desc, out id);
}
public Handle<Mesh> AddMesh(ref readonly Mesh mesh) public Handle<Mesh> AddMesh(ref readonly Mesh mesh)
{ {
ObjectDisposedException.ThrowIf(_disposed, this); ObjectDisposedException.ThrowIf(_disposed, this);
@@ -444,6 +469,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
} }
_resources.Dispose(); _resources.Dispose();
_samplers.Dispose();
_meshes.Dispose(); _meshes.Dispose();
_materials.Dispose(); _materials.Dispose();

View File

@@ -81,7 +81,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
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 = desc.BufferCount,
Scaling = DXGI_SCALING_STRETCH, Scaling = DXGI_SCALING_STRETCH,
SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD, SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD,
AlphaMode = DXGI_ALPHA_MODE_IGNORE, AlphaMode = DXGI_ALPHA_MODE_IGNORE,

View File

@@ -2,27 +2,27 @@ using Ghost.Core;
namespace Ghost.Graphics.D3D12; namespace Ghost.Graphics.D3D12;
internal readonly struct RTVDesc : IIdentifierType; internal readonly struct RTVDescriptor : IIdentifierType;
internal readonly struct DSVDesc : IIdentifierType; internal readonly struct DSVDescriptor : IIdentifierType;
internal readonly struct CbvSrvUavDesc : IIdentifierType; internal readonly struct CbvSrvUavDescriptor : IIdentifierType;
internal readonly struct SamplerDesc : IIdentifierType; internal readonly struct SamplerDescriptor : IIdentifierType;
internal struct ResourceViewGroup internal struct ResourceViewGroup
{ {
public Identifier<RTVDesc> rtv; public Identifier<RTVDescriptor> rtv;
public Identifier<DSVDesc> dsv; public Identifier<DSVDescriptor> dsv;
public Identifier<CbvSrvUavDesc> srv; public Identifier<CbvSrvUavDescriptor> srv;
public Identifier<CbvSrvUavDesc> cbv; public Identifier<CbvSrvUavDescriptor> cbv;
public Identifier<CbvSrvUavDesc> uav; public Identifier<CbvSrvUavDescriptor> uav;
public Identifier<SamplerDesc> sampler; public Identifier<SamplerDescriptor> sampler;
public static ResourceViewGroup Invalid => new() public static ResourceViewGroup Invalid => new()
{ {
rtv = Identifier<RTVDesc>.Invalid, rtv = Identifier<RTVDescriptor>.Invalid,
dsv = Identifier<DSVDesc>.Invalid, dsv = Identifier<DSVDescriptor>.Invalid,
srv = Identifier<CbvSrvUavDesc>.Invalid, srv = Identifier<CbvSrvUavDescriptor>.Invalid,
cbv = Identifier<CbvSrvUavDesc>.Invalid, cbv = Identifier<CbvSrvUavDescriptor>.Invalid,
uav = Identifier<CbvSrvUavDesc>.Invalid, uav = Identifier<CbvSrvUavDescriptor>.Invalid,
sampler = Identifier<SamplerDesc>.Invalid, sampler = Identifier<SamplerDescriptor>.Invalid,
}; };
} }

View File

@@ -88,6 +88,64 @@ internal unsafe static class D3D12Utility
}; };
} }
public static ResourceState ToResourceState(this D3D12_RESOURCE_STATES states)
{
return states switch
{
D3D12_RESOURCE_STATE_COMMON => ResourceState.Common,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER => ResourceState.VertexAndConstantBuffer,
D3D12_RESOURCE_STATE_INDEX_BUFFER => ResourceState.IndexBuffer,
D3D12_RESOURCE_STATE_RENDER_TARGET => ResourceState.RenderTarget,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS => ResourceState.UnorderedAccess,
D3D12_RESOURCE_STATE_DEPTH_WRITE => ResourceState.DepthWrite,
D3D12_RESOURCE_STATE_DEPTH_READ => ResourceState.DepthRead,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE => ResourceState.PixelShaderResource,
D3D12_RESOURCE_STATE_COPY_DEST => ResourceState.CopyDest,
D3D12_RESOURCE_STATE_COPY_SOURCE => ResourceState.CopySource,
_ => throw new ArgumentException($"Unknown D3D12 resource state: {states}")
};
}
public static D3D12_FILTER ToD3D12Filter(this TextureFilterMode filterMode)
{
return filterMode switch
{
TextureFilterMode.Point => D3D12_FILTER_MIN_MAG_MIP_POINT,
TextureFilterMode.Bilinear => D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT,
TextureFilterMode.Trilinear => D3D12_FILTER_MIN_MAG_MIP_LINEAR,
TextureFilterMode.Anisotropic => D3D12_FILTER_ANISOTROPIC,
_ => throw new ArgumentException($"Unknown texture filter mode: {filterMode}")
};
}
public static D3D12_TEXTURE_ADDRESS_MODE ToD3D12TextureAddressMode(this TextureAddressMode addressMode)
{
return addressMode switch
{
TextureAddressMode.Repeat => D3D12_TEXTURE_ADDRESS_MODE_WRAP,
TextureAddressMode.Mirror => D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
TextureAddressMode.Clamp => D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
TextureAddressMode.Border => D3D12_TEXTURE_ADDRESS_MODE_BORDER,
TextureAddressMode.MirrorOnce => D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
_ => throw new ArgumentException($"Unknown texture address mode: {addressMode}")
};
}
public static D3D12_COMPARISON_FUNC ToD3D12ComparisonFunc(this ComparisonFunction func)
{
return func switch
{
ComparisonFunction.Never => D3D12_COMPARISON_FUNC_NEVER,
ComparisonFunction.Less => D3D12_COMPARISON_FUNC_LESS,
ComparisonFunction.Equal => D3D12_COMPARISON_FUNC_EQUAL,
ComparisonFunction.LessEqual => D3D12_COMPARISON_FUNC_LESS_EQUAL,
ComparisonFunction.Greater => D3D12_COMPARISON_FUNC_GREATER,
ComparisonFunction.NotEqual => D3D12_COMPARISON_FUNC_NOT_EQUAL,
ComparisonFunction.GreaterEqual => D3D12_COMPARISON_FUNC_GREATER_EQUAL,
ComparisonFunction.Always => D3D12_COMPARISON_FUNC_ALWAYS,
_ => throw new ArgumentException($"Unknown comparison function: {func}")
};
}
public static D3D12_RASTERIZER_DESC D3D12_RASTERIZER_DESC_CREATE( public static D3D12_RASTERIZER_DESC D3D12_RASTERIZER_DESC_CREATE(

View File

@@ -11,11 +11,13 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<IsAotCompatible>True</IsAotCompatible> <IsAotCompatible>True</IsAotCompatible>
<IsTrimmable>True</IsTrimmable> <IsTrimmable>True</IsTrimmable>
<DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<IsAotCompatible>True</IsAotCompatible> <IsAotCompatible>True</IsAotCompatible>
<IsTrimmable>True</IsTrimmable> <IsTrimmable>True</IsTrimmable>
<DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -10,14 +10,6 @@ using TerraFX.Interop.DirectX;
namespace Ghost.Graphics.RHI; namespace Ghost.Graphics.RHI;
public interface IRHIObject
{
string Name
{
get; set;
}
}
public readonly struct ShaderPassKey public readonly struct ShaderPassKey
{ {
public readonly ulong value; public readonly ulong value;
@@ -603,6 +595,57 @@ public struct TextureDesc
} }
} }
/// <summary>
/// Describes the parameters used to configure a texture sampler for graphics rendering operations.
/// </summary>
public record struct SamplerDesc
{
public TextureFilterMode FilterMode
{
get; set;
}
public TextureAddressMode AddressU
{
get; set;
}
public TextureAddressMode AddressV
{
get; set;
}
public TextureAddressMode AddressW
{
get; set;
}
public ComparisonFunction ComparisonFunc
{
get; set;
}
public float MipLODBias
{
get; set;
}
public uint MaxAnisotropy
{
get; set;
}
public float MinLOD
{
get; set;
}
public float MaxLOD
{
get; set;
}
}
/// <summary> /// <summary>
/// Buffer description /// Buffer description
/// </summary> /// </summary>
@@ -865,3 +908,32 @@ public enum PrimitiveTopology
Line, Line,
Triangle, Triangle,
} }
public enum TextureFilterMode
{
Point,
Bilinear,
Trilinear,
Anisotropic
}
public enum TextureAddressMode
{
Repeat,
Mirror,
Clamp,
Border,
MirrorOnce
}
public enum ComparisonFunction
{
Never,
Less,
Equal,
LessEqual,
Greater,
NotEqual,
GreaterEqual,
Always
}

View File

@@ -91,6 +91,13 @@ public interface ICommandBuffer : IDisposable
/// <param name="stateAfter">The desired state of the resource after 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); void ResourceBarrier(Handle<GPUResource> resource, ResourceState stateBefore, ResourceState stateAfter);
/// <summary>
/// Inserts a resource barrier for state transitions. The current state is tracked internally.
/// </summary>
/// <param name="resource">A handle to the GPU resource to transition.</param>
/// <param name="stateAfter">The desired state of the resource after the transition.</param>
void ResourceBarrier(Handle<GPUResource> resource, ResourceState stateAfter);
/// <summary> /// <summary>
/// Sets the pipeline state object /// Sets the pipeline state object
/// </summary> /// </summary>

View File

@@ -11,22 +11,29 @@ public interface IResourceAllocator : IDisposable
/// Creates a texture resource /// Creates a texture resource
/// </summary> /// </summary>
/// <param name="desc">Texture description</param> /// <param name="desc">Texture description</param>
/// <returns>A new texture handle point to the resource</returns> /// <returns>An <see cref="Handle{Texture}"/> point to the resource</returns>
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false); 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>An <see cref="Handle{Texture}"/> point to the resource</returns>
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false); Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool tempResource = false);
/// <summary> /// <summary>
/// Creates a buffer resource /// Creates a buffer resource
/// </summary> /// </summary>
/// <param name="desc">Buffer description</param> /// <param name="desc">Buffer description</param>
/// <returns>A new buffer handle point to the resource</returns> /// <returns>An <see cref="Handle{GraphicsBuffer}"/> point to the resource</returns>
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool tempResource = false); Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool tempResource = false);
/// <summary>
/// Creates a new sampler object using the specified sampler description.
/// </summary>
/// <param name="desc">A read-only reference to a <see cref="SamplerDesc"/> structure that defines the properties of the sampler to be created.</param>
/// <returns>An <see cref="Identifier{Sampler}"/> that uniquely identifies the created sampler object.</returns>
Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc);
/// <summary> /// <summary>
/// Creates a new mesh from the specified vertex and index data. /// Creates a new mesh from the specified vertex and index data.
@@ -34,19 +41,19 @@ public interface IResourceAllocator : IDisposable
/// <param name="vertices">A UnsafeList containing the vertices that define the geometry of the mesh. Must contain at least one vertex.</param> /// <param name="vertices">A UnsafeList containing the vertices that define the geometry of the mesh. Must contain at least one vertex.</param>
/// <param name="indices">A UnsafeList containing the indices that specify how vertices are connected to form primitives. Must contain at least one index.</param> /// <param name="indices">A UnsafeList containing the indices that specify how vertices are connected to form primitives. Must contain at least one index.</param>
/// <returns>An <see cref="Identifier{Mesh}"/> representing the newly created mesh.</returns> /// <returns>An <see cref="Identifier{Mesh}"/> representing the newly created mesh.</returns>
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices); Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices);
/// <summary> /// <summary>
/// Creates a new material instance using the specified shader. /// Creates a new material instance using the specified shader.
/// </summary> /// </summary>
/// <param name="shader">The identifier of the shader to associate with the new material. Cannot be null.</param> /// <param name="shader">The identifier of the shader to associate with the new material. Cannot be null.</param>
/// <returns>An <see cref="Identifier{Material}"/> representing the newly created material.</returns> /// <returns>An <see cref="Identifier{Material}"/> representing the newly created material.</returns>
public Handle<Material> CreateMaterial(Identifier<Shader> shader); Handle<Material> CreateMaterial(Identifier<Shader> shader);
/// <summary> /// <summary>
/// Creates a new shader and returns its unique identifier. /// Creates a new shader and returns its unique identifier.
/// </summary> /// </summary>
/// <returns>An <see cref="Identifier{Shader}"/> representing the newly created shader.</returns> /// <returns>An <see cref="Identifier{Shader}"/> representing the newly created shader.</returns>
/// <param name="descriptor">The viewGroup containing the shader's properties and passes.</param> /// <param name="descriptor">The viewGroup containing the shader's properties and passes.</param>
public Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor); Identifier<Shader> CreateGraphicsShader(ShaderDescriptor descriptor);
} }

View File

@@ -60,7 +60,7 @@ public interface IResourceDatabase : IDisposable
/// </summary> /// </summary>
/// <param name="handle">A handle to the GPU resource for which to obtain the bindless index. Must reference a valid, currently registered resource.</param> /// <param name="handle">A handle to the GPU resource for which to obtain the bindless index. Must reference a valid, currently registered resource.</param>
/// <returns>The bindless index corresponding to the specified GPU resource handle. -1 if the resource does not support bindless access or is not found.</returns> /// <returns>The bindless index corresponding to the specified GPU resource handle. -1 if the resource does not support bindless access or is not found.</returns>
int GetBindlessIndex(Handle<GPUResource> handle); Result<uint, ResultStatus> GetBindlessIndex(Handle<GPUResource> handle);
/// <summary> /// <summary>
/// Retrieves the name of the GPU resource associated with the specified handle. /// Retrieves the name of the GPU resource associated with the specified handle.
@@ -78,6 +78,23 @@ public interface IResourceDatabase : IDisposable
/// <param name="handle">The handle of the resource to be removed.</param> /// <param name="handle">The handle of the resource to be removed.</param>
void ReleaseResource(Handle<GPUResource> handle); void ReleaseResource(Handle<GPUResource> handle);
/// <summary>
/// Retrieves an existing sampler identifier that matches the specified description, or creates a new one if none
/// exists.
/// </summary>
/// <param name="desc">A read-only reference to a <see cref="SamplerDesc"/> structure that defines the properties of the sampler to retrieve or create.</param>
/// <param name="id">An integer identifier to associate with the sampler.</param>
/// <returns>An <see cref="Identifier{Sampler}"/> representing the sampler that matches the specified description.
/// If a matching sampler does not exist, a new sampler is created and its identifier is returned.</returns>
Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc, int id);
/// <summary>
/// Determines whether a sampler with the specified identifier exists.
/// </summary>
/// <param name="id">The identifier of the sampler to check for existence.</param>
/// <returns>true if a sampler with the given identifier exists; otherwise, false.</returns>
bool TryGetSampler(ref readonly SamplerDesc desc, out Identifier<Sampler> id);
/// <summary> /// <summary>
/// Adds a mesh to the resource database and returns its handle. /// Adds a mesh to the resource database and returns its handle.
/// </summary> /// </summary>

View File

@@ -5,7 +5,9 @@ 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 System.Diagnostics;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ghost.Graphics.RenderPasses; namespace Ghost.Graphics.RenderPasses;
@@ -23,6 +25,11 @@ internal class MeshRenderPass : IRenderPass
public uint texture2; public uint texture2;
public uint texture3; public uint texture3;
public uint texture4; public uint texture4;
public uint tex_sampler;
private uint _padding1;
private uint _padding2;
private uint _padding3;
} }
private Handle<Mesh> _mesh; private Handle<Mesh> _mesh;
@@ -48,8 +55,8 @@ internal class MeshRenderPass : IRenderPass
for (var i = 0; i < shaderDescriptor.passes.Count; i++) for (var i = 0; i < shaderDescriptor.passes.Count; i++)
{ {
var pass = shaderDescriptor.passes[i]; var pass = shaderDescriptor.passes[i];
var compileResult = ctx.ShaderCompiler.CompilePass(pass, shaderDescriptor.generatedCodePath); var compiled = ctx.ShaderCompiler.CompilePass(pass, shaderDescriptor.generatedCodePath).GetValueOrThrow();
if (compileResult.IsFailure || pass is not FullPassDescriptor fullPass) if (pass is not FullPassDescriptor fullPass)
{ {
continue; continue;
} }
@@ -67,7 +74,7 @@ internal class MeshRenderPass : IRenderPass
DsvFormat = TextureFormat.Unknown, DsvFormat = TextureFormat.Unknown,
}; };
_compileResults[i] = compileResult.Value; _compileResults[i] = compiled;
ctx.PipelineLibrary.CompilePSO(in psoDes, in _compileResults[i]).GetValueOrThrow(); ctx.PipelineLibrary.CompilePSO(in psoDes, in _compileResults[i]).GetValueOrThrow();
} }
@@ -79,38 +86,51 @@ internal class MeshRenderPass : IRenderPass
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor); _shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
_material = ctx.ResourceAllocator.CreateMaterial(_shader); _material = ctx.ResourceAllocator.CreateMaterial(_shader);
_textures = new Handle<Texture>[_textureFiles.Length];
for (var i = 0; i < _textureFiles.Length; i++)
{
using var stream = File.OpenRead(_textureFiles[i]);
using var imageData = ImageResult.FromStream(stream, ColorComponents.RGBA);
var desc = new TextureDesc
{
Width = imageData.Width,
Height = imageData.Height,
Dimension = TextureDimension.Texture2D,
Format = TextureFormat.R8G8B8A8_UNorm,
MipLevels = 1,
Slice = 1,
Usage = TextureUsage.ShaderResource,
};
_textures[i] = ctx.CreateTexture(ref desc);
ctx.UploadTexture(_textures[i], imageData.AsSpan());
}
var samplerDesc = new SamplerDesc
{
AddressU = TextureAddressMode.Repeat,
AddressV = TextureAddressMode.Repeat,
AddressW = TextureAddressMode.Repeat,
FilterMode = TextureFilterMode.Bilinear,
MaxAnisotropy = 16,
};
var sampler = ctx.ResourceAllocator.CreateSampler(in samplerDesc);
ref var matRef = ref ctx.ResourceDatabase.GetMaterialReference(_material); ref var matRef = ref ctx.ResourceDatabase.GetMaterialReference(_material);
var matProps = new ShaderProperties_MyShader_Standard var matProps = new ShaderProperties_MyShader_Standard
{ {
color = new float4(1.0f, 1.0f, 1.0f, 1.0f), color = new float4(1.0f, 1.0f, 1.0f, 1.0f),
texture1 = 0, texture1 = ctx.ResourceDatabase.GetBindlessIndex(_textures[0].AsResource()).GetValueOrThrow(ResultStatus.Success),
texture2 = 1, texture2 = ctx.ResourceDatabase.GetBindlessIndex(_textures[1].AsResource()).GetValueOrThrow(ResultStatus.Success),
texture3 = 2, texture3 = ctx.ResourceDatabase.GetBindlessIndex(_textures[2].AsResource()).GetValueOrThrow(ResultStatus.Success),
texture4 = 3, texture4 = ctx.ResourceDatabase.GetBindlessIndex(_textures[3].AsResource()).GetValueOrThrow(ResultStatus.Success),
tex_sampler = (uint)sampler.value,
}; };
matRef.SetPropertyCache(in matProps); Debug.Assert(matRef.SetPropertyCache(in matProps) == ResultStatus.Success);
matRef.UploadData(ctx.DirectCommandBuffer);
//_textures = new Handle<Texture>[_textureFiles.Length];
//for (var i = 0; i < _textureFiles.Length; i++)
//{
// using var stream = File.OpenRead(_textureFiles[i]);
// using var imageData = ImageResult.FromStream(stream);
// var desc = new TextureDesc
// {
// Width = imageData.Width,
// Height = imageData.Height,
// Dimension = TextureDimension.Texture2D,
// Format = TextureFormat.R8G8B8A8_UNorm,
// MipLevels = 1,
// Slice = 1,
// Usage = TextureUsage.ShaderResource,
// };
// _textures[i] = ctx.CreateTexture(ref desc);
// ctx.UploadTexture(_textures[i], new Span<byte>(imageData.Data, (int)imageData.Size));
//}
} }
public void Execute(ref readonly RenderingContext ctx) public void Execute(ref readonly RenderingContext ctx)

View File

@@ -38,12 +38,12 @@ void MSMain(
float4 PSMain(PixelInput input) : SV_TARGET float4 PSMain(PixelInput input) : SV_TARGET
{ {
//float4 color1 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture1, 0, input.uv.xy); float4 color1 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture1, g_PerMaterialData.tex_sampler, input.uv.xy);
//float4 color2 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture2, 0, input.uv.xy); float4 color2 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture2, g_PerMaterialData.tex_sampler, input.uv.xy);
//float4 color3 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture3, 0, input.uv.xy); float4 color3 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture3, g_PerMaterialData.tex_sampler, input.uv.xy);
//float4 color4 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture4, 0, input.uv.xy); float4 color4 = SAMPLE_TEXTURE2D(g_PerMaterialData.texture4, g_PerMaterialData.tex_sampler, 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 * blendedColor;
//return input.color; //return input.color;
} }

View File

@@ -7,6 +7,7 @@ shader "MyShader/Standard"
tex2d texture2 = tex2d(white); tex2d texture2 = tex2d(white);
tex2d texture3 = tex2d(grey); tex2d texture3 = tex2d(grey);
tex2d texture4 = tex2d(normal); tex2d texture4 = tex2d(normal);
sampler tex_sampler;
} }
pass "Forward" pass "Forward"

View File

@@ -10,6 +10,8 @@ struct Vertex
float4 color; float4 color;
}; };
#define SIZEOF_VERTEX 80 // bytes
// Resource descriptor heap definitions // Resource descriptor heap definitions
#define GLOBAL_TEXTURE2D_HEAP ResourceDescriptorHeap #define GLOBAL_TEXTURE2D_HEAP ResourceDescriptorHeap
@@ -44,50 +46,52 @@ struct Vertex
#define GET_BUFFER(id) GLOBAL_BUFFER_HEAP[id] #define GET_BUFFER(id) GLOBAL_BUFFER_HEAP[id]
#define GET_SAMPLER(id) GLOBAL_SAMPLER_HEAP[id] #define GET_SAMPLER(id) GLOBAL_SAMPLER_HEAP[id]
#define SAMPLE_TEXTURE2D(texId, sampId, uv) SampleTexture2D(texId, sampId, uv)
#define SAMPLE_TEXTURE2D_LEVEL(texId, sampId, uv, level) SampleTexture2DLevel(texId, sampId, uv, level)
#define SAMPLE_TEXTURE2D_ARRAY(texId, sampId, uvw) SampleTextureArray(texId, sampId, uvw)
#define MESH_SHADER_THREADS(x) [NumThreads(x, 1, 1)] #define MESH_SHADER_THREADS(x) [NumThreads(x, 1, 1)]
inline float4 SampleTexture2D(uint texId, uint sampId, float2 uv) static inline float4 SampleTexture2D(uint texId, uint sampId, float2 uv)
{ {
Texture2D tex = GET_TEXTURE2D(texId); Texture2D tex = GET_TEXTURE2D(texId);
SamplerState samp = GET_SAMPLER(sampId); SamplerState samp = GET_SAMPLER(sampId);
return tex.Sample(samp, uv); return tex.Sample(samp, uv);
} }
inline float4 SampleTexture2DLevel(uint texId, uint sampId, float2 uv, float level) static inline float4 SampleTexture2DLevel(uint texId, uint sampId, float2 uv, float level)
{ {
Texture2D tex = GET_TEXTURE2D(texId); Texture2D tex = GET_TEXTURE2D(texId);
SamplerState samp = GET_SAMPLER(sampId); SamplerState samp = GET_SAMPLER(sampId);
return tex.SampleLevel(samp, uv, level); return tex.SampleLevel(samp, uv, level);
} }
inline float4 SampleTextureArray(uint texId, uint sampId, float3 uv) static inline float4 SampleTextureArray(uint texId, uint sampId, float3 uvw)
{ {
Texture2DArray tex = GET_TEXTURE2D_ARRAY(texId); Texture2DArray tex = GET_TEXTURE2D_ARRAY(texId);
SamplerState samp = GET_SAMPLER(sampId); SamplerState samp = GET_SAMPLER(sampId);
return tex.Sample(samp, uvw.xyz); return tex.Sample(samp, uvw);
} }
static inline Vertex LoadVertexData(uint vertexID, uint groupID, BYTE_ADDRESS_BUFFER vertexBuffer, BYTE_ADDRESS_BUFFER indexBuffer)
inline Vertex LoadVertexData(uint vertexID, uint groupID, BYTE_ADDRESS_BUFFER vertexBuffer, BYTE_ADDRESS_BUFFER indexBuffer)
{ {
// Fetch bindless buffers // Fetch bindless buffers
ByteAddressBuffer vertexBuffer = GET_BUFFER(vertexBuffer); ByteAddressBuffer vertices = GET_BUFFER(vertexBuffer);
ByteAddressBuffer indexBuffer = GET_BUFFER(indexBuffer); ByteAddressBuffer indices = GET_BUFFER(indexBuffer);
// Compute the triangles vertex indices // Compute the triangles vertex indices
uint indexOffset = (groupID * 3 + vertexID) * 4; // uint32 index uint indexOffset = (groupID * 3 + vertexID) * 4; // uint32 index
uint vertexIndex = indexBuffer.Load(indexOffset); uint vertexIndex = indices.Load(indexOffset);
// Load vertex attributes // Load vertex attributes
uint vertexOffset = vertexIndex * 80; // 80 bytes per vertex uint vertexOffset = vertexIndex * SIZEOF_VERTEX;
Vertex v; Vertex v;
v.position = asfloat(vertexBuffer.Load4(vertexOffset + 0)); v.position = asfloat(vertices.Load4(vertexOffset + 0));
v.normal = asfloat(vertexBuffer.Load4(vertexOffset + 16)); v.normal = asfloat(vertices.Load4(vertexOffset + 16));
v.tangent = asfloat(vertexBuffer.Load4(vertexOffset + 32)); v.tangent = asfloat(vertices.Load4(vertexOffset + 32));
v.uv = asfloat(vertexBuffer.Load4(vertexOffset + 48)); v.uv = asfloat(vertices.Load4(vertexOffset + 48));
v.color = asfloat(vertexBuffer.Load4(vertexOffset + 64)); v.color = asfloat(vertices.Load4(vertexOffset + 64));
return v; return v;
} }

View File

@@ -14,9 +14,9 @@ struct PerObjectData
{ {
float4x4 localToWorld; float4x4 localToWorld;
float3 worldBoundsMin; float3 worldBoundsMin;
BYTE_ADDRESS_BUFFER_BINDLESS vertexBuffer; BYTE_ADDRESS_BUFFER vertexBuffer;
float3 worldBoundsMax; float3 worldBoundsMax;
BYTE_ADDRESS_BUFFER_BINDLESS indexBuffer; BYTE_ADDRESS_BUFFER indexBuffer;
}; };
cbuffer GlobalConstants : register(b0) cbuffer GlobalConstants : register(b0)

View File

@@ -182,6 +182,9 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
TokenLexicon.KnownTypes.TEXTURE2D => ShaderPropertyType.Texture2D, TokenLexicon.KnownTypes.TEXTURE2D => ShaderPropertyType.Texture2D,
TokenLexicon.KnownTypes.TEXTURE3D => ShaderPropertyType.Texture3D, TokenLexicon.KnownTypes.TEXTURE3D => ShaderPropertyType.Texture3D,
TokenLexicon.KnownTypes.TEXTURECUBE => ShaderPropertyType.TextureCube, TokenLexicon.KnownTypes.TEXTURECUBE => ShaderPropertyType.TextureCube,
TokenLexicon.KnownTypes.TEXTURECUBE_ARRAY => ShaderPropertyType.TextureCubeArray,
TokenLexicon.KnownTypes.TEXTURE2D_ARRAY => ShaderPropertyType.Texture2DArray,
TokenLexicon.KnownTypes.SAMPLER => ShaderPropertyType.Sampler,
_ => ShaderPropertyType.None, _ => ShaderPropertyType.None,
}; };
} }

View File

@@ -257,7 +257,7 @@ internal static class SDLCompiler
return Result.Failure("Failed to generate global properties: " + globalPropResult.Message); return Result.Failure("Failed to generate global properties: " + globalPropResult.Message);
} }
var generatedResult = GenerateShaderCode(desc, generatedOutputDirectory); var generatedResult = GenerateShaderCode(desc, generatedOutputDirectory, globalPropResult.Value);
if (generatedResult.IsFailure) if (generatedResult.IsFailure)
{ {
return Result.Failure("Failed to generate pass files: " + generatedResult.Message); return Result.Failure("Failed to generate pass files: " + generatedResult.Message);
@@ -269,7 +269,7 @@ internal static class SDLCompiler
} }
catch (Exception ex) catch (Exception ex)
{ {
return Result.Failure("Failed to generate shader files: " + ex.Message); return Result.Failure("Failed to compile shader: " + ex.Message);
} }
} }
@@ -294,16 +294,17 @@ 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.Texture2D => "TEXTURE2D_BINDLESS", ShaderPropertyType.Texture2D => "TEXTURE2D",
ShaderPropertyType.Texture3D => "TEXTURE3D_BINDLESS", ShaderPropertyType.Texture3D => "TEXTURE3D",
ShaderPropertyType.TextureCube => "TEXTURECUBE_BINDLESS", ShaderPropertyType.TextureCube => "TEXTURECUBE",
ShaderPropertyType.Texture2DArray => "TEXTURE2D_ARRAY_BINDLESS", ShaderPropertyType.Texture2DArray => "TEXTURE2D_ARRAY",
ShaderPropertyType.TextureCubeArray => "TEXTURECUBE_ARRAY_BINDLESS", ShaderPropertyType.TextureCubeArray => "TEXTURECUBE_ARRAY",
ShaderPropertyType.Sampler => "SAMPLER",
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}") _ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}")
}; };
} }
public static Result<string> GenerateShaderCode(ShaderDescriptor descriptor, string targetDirectory) public static Result<string> GenerateShaderCode(ShaderDescriptor descriptor, string targetDirectory, string globalDataPath)
{ {
if (!Directory.Exists(targetDirectory)) if (!Directory.Exists(targetDirectory))
{ {
@@ -329,7 +330,8 @@ internal static class SDLCompiler
#ifndef {fileDefine} #ifndef {fileDefine}
#define {fileDefine} #define {fileDefine}
#include ""F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl"""); #include ""F:/csharp/GhostEngine/Ghost.Shader/BuiltIn/Common.hlsl""
#include ""{globalDataPath}""");
sb.Append(@" sb.Append(@"
struct PerMaterialData struct PerMaterialData

View File

@@ -176,6 +176,8 @@ internal static class TokenLexicon
public const string TEXTURE3D = "tex3d"; public const string TEXTURE3D = "tex3d";
public const string TEXTURECUBE = "texcube"; public const string TEXTURECUBE = "texcube";
public const string TEXTURECUBE_ARRAY = "texcube_arr"; public const string TEXTURECUBE_ARRAY = "texcube_arr";
public const string SAMPLER = "sampler";
} }
public static class KnownTextureValue public static class KnownTextureValue
@@ -218,6 +220,7 @@ internal static class TokenLexicon
KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4, KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4,
KnownTypes.TEXTURE2D, KnownTypes.TEXTURE2D_ARRAY, KnownTypes.TEXTURE3D, KnownTypes.TEXTURE2D, KnownTypes.TEXTURE2D_ARRAY, KnownTypes.TEXTURE3D,
KnownTypes.TEXTURECUBE, KnownTypes.TEXTURECUBE_ARRAY, KnownTypes.TEXTURECUBE, KnownTypes.TEXTURECUBE_ARRAY,
KnownTypes.SAMPLER,
}; };
private static readonly HashSet<string> s_textureDefaultValues = new() private static readonly HashSet<string> s_textureDefaultValues = new()