Files
GhostEngine/Ghost.Graphics/RHI/Common.cs

992 lines
17 KiB
C#

using Ghost.Core;
using Ghost.Core.Graphics;
using Ghost.Graphics.Core;
using Misaki.HighPerformance.Mathematics;
using Misaki.HighPerformance.Utilities;
using System.IO.Hashing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ghost.Graphics.RHI;
public readonly struct ShaderPassKey : IEquatable<ShaderPassKey>
{
public readonly ulong value;
public ShaderPassKey(ulong value)
{
this.value = value;
}
public ShaderPassKey(string passId)
{
var passIdSpan = passId.AsSpan();
value = XxHash3.HashToUInt64(MemoryMarshal.AsBytes(passIdSpan));
}
public override string ToString()
{
return value.ToString("X16");
}
public bool Equals(ShaderPassKey other)
{
return value == other.value;
}
public override int GetHashCode()
{
return value.GetHashCode();
}
public override bool Equals(object? obj)
{
return obj is ShaderPassKey key && Equals(key);
}
public static bool operator ==(ShaderPassKey left, ShaderPassKey right)
{
return left.Equals(right);
}
public static bool operator !=(ShaderPassKey left, ShaderPassKey right)
{
return !(left == right);
}
}
public readonly struct GraphicsPipelineKey
{
public const int KEY_STRING_LENGTH = 17; // 16 chars + null terminator
public readonly ulong value;
public GraphicsPipelineKey(ulong value)
{
this.value = value;
}
public Result GetString(Span<char> destination)
{
if (!value.TryFormat(destination, out _, "X16"))
{
return Result.Failure("Failed to format GraphicsPipelineKey to string.");
}
destination[16] = '\0';
return Result.Success();
}
public override string ToString()
{
return value.ToString("X16");
}
public override int GetHashCode()
{
return value.GetHashCode();
}
}
internal struct GraphicsPipelineHash
{
[InlineArray(D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT)]
public struct rtv_array
{
public TextureFormat rtvFormats;
}
public ShaderPassKey Id
{
get; set;
}
public rtv_array RtvFormats;
public uint RtvCount
{
get; set;
}
public TextureFormat DsvFormat
{
get; set;
}
// Do we need to store blend state?
// TODO: Variants
public readonly GraphicsPipelineKey GetKey()
{
Span<ulong> data = stackalloc ulong[3 + D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT];
data[0] = Id.value;
data[1] = RtvCount;
data[2] = (ulong)DsvFormat;
for (var i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
{
data[3 + i] = (ulong)RtvFormats[i];
}
var bytes = MemoryMarshal.AsBytes(data);
return new GraphicsPipelineKey(XxHash3.HashToUInt64(bytes));
}
}
public ref struct GraphicsPSODescriptor
{
public ShaderPassKey PassId
{
get; set;
}
public ZTestOptions ZTest
{
get; set;
}
public ZWriteOptions ZWrite
{
get; set;
}
public CullOptions Cull
{
get; set;
}
public BlendOptions Blend
{
get; set;
}
public uint ColorMask
{
get; set;
}
public ReadOnlySpan<TextureFormat> RtvFormats
{
get; set;
}
public TextureFormat DsvFormat
{
get; set;
}
}
public readonly struct CBufferPropertyInfo
{
public string Name
{
get; init;
}
public uint StartOffset
{
get; init;
}
public uint Size
{
get; init;
}
}
public readonly struct CBufferInfo
{
public string Name
{
get; init;
}
public uint RegisterSlot
{
get; init;
}
public uint RegisterSpace
{
get; init;
}
public uint SizeInBytes
{
get; init;
}
public IReadOnlyList<CBufferPropertyInfo> Properties
{
get; init;
}
}
public struct RenderDesc
{
public float4x4 ViewMatrix
{
get; set;
}
public float4x4 ProjectionMatrix
{
get; set;
}
public float4 CameraPosition
{
get; set;
}
// The "Target" (Where to write pixels)
public Handle<Texture> Target
{
get; set;
}
public Handle<Texture> DepthTarget
{
get; set;
}
public RectDesc Viewport
{
get; set;
}
//public RenderPathID RenderPath;
//public LayerMask CullingMask;
}
public struct ViewportDesc
{
public float X
{
get; set;
}
public float Y
{
get; set;
}
public float Width
{
get; set;
}
public float Height
{
get; set;
}
public float MinDepth
{
get; set;
}
public float MaxDepth
{
get; set;
}
}
public struct RectDesc
{
public uint Left
{
get; set;
}
public uint Top
{
get; set;
}
public uint Right
{
get; set;
}
public uint Bottom
{
get; set;
}
}
public struct SubResourceData
{
public unsafe void* pData;
public uint rowPitch;
public uint slicePitch;
}
public struct PassRenderTargetDesc
{
public Handle<Texture> Texture
{
get; set;
}
public Color128 ClearColor
{
get; set;
}
}
public struct PassDepthStencilDesc
{
public Handle<Texture> Texture
{
get; set;
}
public float ClearDepth
{
get; set;
}
public byte ClearStencil
{
get; set;
}
}
public struct BarrierDesc
{
public Handle<GPUResource> Resource
{
get; set;
}
public ResourceState StateBefore
{
get; set;
}
public ResourceState StateAfter
{
get; set;
}
}
public struct ResourceDesc
{
[StructLayout(LayoutKind.Explicit)]
private struct resource_union
{
[FieldOffset(0)]
public TextureDesc textureDescription;
[FieldOffset(0)]
public BufferDesc bufferDescription;
}
private resource_union _desc;
public TextureDesc TextureDescription
{
readonly get => _desc.textureDescription;
set => _desc.textureDescription = value;
}
public BufferDesc BufferDescription
{
readonly get => _desc.bufferDescription;
set => _desc.bufferDescription = value;
}
public static ResourceDesc Buffer(BufferDesc desc)
{
return new ResourceDesc
{
BufferDescription = desc
};
}
public static ResourceDesc Texture(TextureDesc desc)
{
return new ResourceDesc
{
TextureDescription = desc
};
}
}
/// <summary>
/// Render Target description
/// Supports either color OR depth rendering, not both
/// </summary>
public struct RenderTargetDesc
{
/// <summary>
/// Width of the render Target
/// </summary>
public uint Width
{
get; set;
}
/// <summary>
/// Height of the render Target
/// </summary>
public uint Height
{
get; set;
}
/// <summary>
/// Slice of the render Target
/// </summary>
public uint Slice
{
get; set;
}
/// <summary>
/// Type of render Target
/// </summary>
public RenderTargetType Type
{
get; set;
}
/// <summary>
/// Target texture Format
/// </summary>
public TextureFormat Format
{
get; set;
}
/// <summary>
/// Texture dimension
/// </summary>
public TextureDimension Dimension
{
get; set;
}
/// <summary>
/// Creation flags for the render Target
/// </summary>
public RenderTargetCreationFlags CreationFlags
{
get; set;
}
/// <summary>
/// Number of mip levels. 0 to generate full mip chain
/// </summary>
public uint MipLevels
{
get; set;
}
/// <summary>
/// Number of samples for MSAA
/// </summary>
public uint SampleCount
{
get; set;
}
/// <summary>
/// Creates a color render Target
/// </summary>
public static RenderTargetDesc Color(uint width, uint height, uint slice = 1,
TextureFormat format = TextureFormat.R8G8B8A8_UNorm, TextureDimension dimension = TextureDimension.Texture2D,
RenderTargetCreationFlags creationFlags = RenderTargetCreationFlags.AllowUAV | RenderTargetCreationFlags.DynamicallyResolution | RenderTargetCreationFlags.GenerateMips,
uint mipLevels = 0u, uint sampleCount = 1)
{
return new RenderTargetDesc
{
Width = width,
Height = height,
Slice = slice,
Type = RenderTargetType.Color,
Format = format,
Dimension = dimension,
CreationFlags = creationFlags,
MipLevels = mipLevels,
SampleCount = sampleCount
};
}
/// <summary>
/// Creates a depth render Target
/// </summary>
public static RenderTargetDesc Depth(uint width, uint height, uint slice = 1,
TextureFormat format = TextureFormat.D24_UNorm_S8_UInt, TextureDimension dimension = TextureDimension.Texture2D,
RenderTargetCreationFlags creationFlags = RenderTargetCreationFlags.AllowUAV | RenderTargetCreationFlags.DynamicallyResolution,
uint mipLevels = 0u, uint sampleCount = 1)
{
return new RenderTargetDesc
{
Width = width,
Height = height,
Slice = slice,
Type = RenderTargetType.Depth,
Format = format,
Dimension = dimension,
CreationFlags = creationFlags,
MipLevels = mipLevels,
SampleCount = sampleCount
};
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TextureDesc ToTextureDescripton()
{
var usage = Type == RenderTargetType.Color ? TextureUsage.RenderTarget : TextureUsage.DepthStencil;
if (CreationFlags.HasFlag(RenderTargetCreationFlags.AllowUAV))
{
usage |= TextureUsage.UnorderedAccess;
}
return new TextureDesc
{
Width = Width,
Height = Height,
Slice = Slice,
Format = Format,
Dimension = Dimension,
MipLevels = MipLevels,
Usage = usage,
};
}
}
/// <summary>
/// Texture description
/// </summary>
public struct TextureDesc
{
/// <summary>
/// Width of the texture
/// </summary>
public uint Width
{
get; set;
}
/// <summary>
/// Height of the texture
/// </summary>
public uint Height
{
get; set;
}
/// <summary>
/// Slice of the texture
/// </summary>
public uint Slice
{
get; set;
}
/// <summary>
/// Texture Format
/// </summary>
public TextureFormat Format
{
get; set;
}
/// <summary>
/// Texture dimension
/// </summary>
public TextureDimension Dimension
{
get;
set;
}
/// <summary>
/// Number of mip levels. 0 to generate full mip chain
/// </summary>
public uint MipLevels
{
get; set;
}
/// <summary>
/// Texture usage flags
/// </summary>
public TextureUsage Usage
{
get; set;
}
}
/// <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>
/// Buffer description
/// </summary>
public struct BufferDesc
{
/// <summary>
/// Size of the buffer in bytes
/// </summary>
public ulong Size
{
get; set;
}
public uint Stride
{
get; set;
}
/// <summary>
/// Buffer usage flags
/// </summary>
public BufferUsage Usage
{
get; set;
}
/// <summary>
/// Memory type for the buffer
/// </summary>
public ResourceMemoryType MemoryType
{
get; set;
}
}
public struct CommandError
{
public int CommandIndex
{
get; set;
}
public string CommandName
{
get; set;
}
public ErrorStatus Status
{
get; set;
}
}
/// <summary>
/// Swap chain description
/// </summary>
public struct SwapChainDesc
{
/// <summary>
/// Width of the swap chain
/// </summary>
public uint Width
{
get; set;
}
/// <summary>
/// Height of the swap chain
/// </summary>
public uint Height
{
get; set;
}
public float ScaleX
{
get; set;
}
public float ScaleY
{
get; set;
}
/// <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;
}
}
/// <summary>
/// Swap chain Target (window handle or composition surface)
/// </summary>
public struct SwapChainTarget
{
/// <summary>
/// Target type
/// </summary>
public SwapChainTargetType Type
{
get; set;
}
/// <summary>
/// Window handle for HWND targets
/// </summary>
public nint WindowHandle
{
get; set;
}
/// <summary>
/// Composition surface for UWP/WinUI targets
/// </summary>
public object? CompositionSurface
{
get; set;
}
public static SwapChainTarget FromWindowHandle(nint hwnd)
{
return new SwapChainTarget
{
Type = SwapChainTargetType.WindowHandle,
WindowHandle = hwnd,
CompositionSurface = null
};
}
public static SwapChainTarget FromCompositionSurface(object surface)
{
return new SwapChainTarget
{
Type = SwapChainTargetType.Composition,
WindowHandle = 0,
CompositionSurface = surface
};
}
}
public enum SwapChainTargetType
{
WindowHandle,
Composition
}
[Flags]
public enum ResourceState
{
Common = 0,
VertexAndConstantBuffer = 1 << 0,
IndexBuffer = 1 << 1,
RenderTarget = 1 << 2,
UnorderedAccess = 1 << 3,
DepthWrite = 1 << 4,
DepthRead = 1 << 5,
PixelShaderResource = 1 << 6,
CopyDest = 1 << 7,
CopySource = 1 << 8,
GenericRead = 1 << 9,
IndirectArgument = 1 << 10,
NonPixelShaderResource = 1 << 11,
Present = 0,
}
public enum CommandQueueType
{
Graphics,
Compute,
Copy
}
public enum CommandBufferType
{
Graphics,
Compute,
Copy
}
public enum PipelineType
{
Graphics,
Compute
}
[Flags]
public enum RenderTargetCreationFlags
{
None = 0,
AllowUAV = 1 << 0,
AllowMSAA = 1 << 1,
DynamicallyResolution = 1 << 2,
GenerateMips = 1 << 3
}
public enum ResourceMemoryType
{
Default, // GPU memory
Upload, // CPU-to-GPU memory
Readback // GPU-to-CPU memory
}
[Flags]
public enum TextureUsage
{
None = 0,
ShaderResource = 1 << 0,
RenderTarget = 1 << 1,
DepthStencil = 1 << 2,
UnorderedAccess = 1 << 3
}
public enum TextureDimension
{
Unknown = -1,
None = 0,
Texture2D = 1,
Texture3D = 2,
TextureCube = 3,
Texture2DArray = 4,
TextureCubeArray = 5
}
public enum RenderTargetType
{
Color,
Depth
}
// TODO: Support compressed formats (BCn, ASTC, ETC2, etc)
public enum TextureFormat
{
Unknown,
R8G8B8A8_UNorm,
B8G8R8A8_UNorm,
R16G16B16A16_Float,
R32G32B32A32_Float,
D24_UNorm_S8_UInt,
D32_Float
}
[Flags]
public enum BufferUsage
{
None = 0,
Vertex = 1 << 0,
Index = 1 << 1,
IndirectArgument = 1 << 7,
Constant = 1 << 2,
ShaderResource = 1 << 3,
UnorderedAccess = 1 << 4,
Structured = 1 << 5,
Raw = 1 << 6,
Upload = 1 << 8,
Readback = 1 << 9,
}
public enum IndexType
{
UInt16,
UInt32
}
public enum PrimitiveTopology
{
Point,
Line,
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
}