using Ghost.Core; using Ghost.Core.Graphics; using Ghost.Graphics.Core; using Ghost.Graphics.D3D12.Utilities; using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Utilities; using System.IO.Hashing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using TerraFX.Interop.DirectX; namespace Ghost.Graphics.RHI; public readonly struct 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 override int GetHashCode() { return value.GetHashCode(); } } 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 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 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 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 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 Target { get; set; } public Handle 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 { get; set; } public Color128 ClearColor { get; set; } } public struct PassDepthStencilDesc { public Handle Texture { get; set; } public float ClearDepth { get; set; } public byte ClearStencil { get; set; } } public struct BarrierDesc { public Handle 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 }; } internal static ResourceDesc FromD3D12(D3D12_RESOURCE_DESC desc) { if (desc.Dimension == D3D12_RESOURCE_DIMENSION.D3D12_RESOURCE_DIMENSION_BUFFER) { return Buffer(new BufferDesc { Size = (uint)desc.Width, Stride = 0, Usage = BufferUsage.None, MemoryType = ResourceMemoryType.Default }); } else { return Texture(new TextureDesc { Width = (uint)desc.Width, Height = desc.Height, Slice = desc.DepthOrArraySize, Format = desc.Format.ToTextureFormat(), Dimension = desc.Dimension.ToTextureDimension(), MipLevels = desc.MipLevels, Usage = TextureUsage.None, }); } } } /// /// Render Target description /// Supports either color OR depth rendering, not both /// public struct RenderTargetDesc { /// /// Width of the render Target /// public uint Width { get; set; } /// /// Height of the render Target /// public uint Height { get; set; } /// /// Slice of the render Target /// public uint Slice { get; set; } /// /// Type of render Target /// public RenderTargetType Type { get; set; } /// /// Target texture Format /// public TextureFormat Format { get; set; } /// /// Texture dimension /// public TextureDimension Dimension { get; set; } /// /// Creation flags for the render Target /// public RenderTargetCreationFlags CreationFlags { get; set; } /// /// Number of mip levels. 0 to generate full mip chain /// public uint MipLevels { get; set; } /// /// Number of samples for MSAA /// public uint SampleCount { get; set; } /// /// Creates a color render Target /// public static RenderTargetDesc Color(uint width, uint height, uint slice = 1, TextureFormat format = TextureFormat.R8G8B8A8_UNorm, TextureDimension dimension = TextureDimension.Texture2D, 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 }; } /// /// Creates a depth render Target /// public static RenderTargetDesc Depth(uint width, uint height, uint slice = 1, TextureFormat format = TextureFormat.D24_UNorm_S8_UInt, TextureDimension dimension = TextureDimension.Texture2D, 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, }; } } /// /// Texture description /// public struct TextureDesc { /// /// Width of the texture /// public uint Width { get; set; } /// /// Height of the texture /// public uint Height { get; set; } /// /// Slice of the texture /// public uint Slice { get; set; } /// /// Texture Format /// public TextureFormat Format { get; set; } /// /// Texture dimension /// public TextureDimension Dimension { get; set; } /// /// Number of mip levels. 0 to generate full mip chain /// public uint MipLevels { get; set; } /// /// Texture usage flags /// public TextureUsage Usage { get; set; } } /// /// Describes the parameters used to configure a texture sampler for graphics rendering operations. /// 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; } } /// /// Buffer description /// public struct BufferDesc { /// /// Size of the buffer in bytes /// public ulong Size { get; set; } public uint Stride { get; set; } /// /// Buffer usage flags /// public BufferUsage Usage { get; set; } /// /// Memory type for the buffer /// public ResourceMemoryType MemoryType { get; set; } } public struct CommandError { public int CommandIndex { get; set; } public string CommandName { get; set; } public ErrorStatus Status { get; set; } } /// /// Swap chain description /// public struct SwapChainDesc { /// /// Width of the swap chain /// public uint Width { get; set; } /// /// Height of the swap chain /// public uint Height { get; set; } /// /// Back buffer Format /// public TextureFormat Format { get; set; } /// /// Target for presentation (window handle or composition Target) /// public SwapChainTarget Target { get; set; } } /// /// Swap chain Target (window handle or composition surface) /// public struct SwapChainTarget { /// /// Target type /// public SwapChainTargetType Type { get; set; } /// /// Window handle for HWND targets /// public nint WindowHandle { get; set; } /// /// Composition surface for UWP/WinUI targets /// 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 }