using Ghost.Core; using Ghost.Core.Graphics; using Ghost.Graphics.Core; using Misaki.HighPerformance.Mathematics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ghost.Graphics.RHI; public readonly struct ShaderVariant; public readonly struct GraphicsPipeline; public readonly struct PassPipelineHash : IEquatable { public readonly UInt128 value; public PassPipelineHash(ReadOnlySpan rtvFormats, TextureFormat dsvFormat) { if (rtvFormats.Length > 8) { throw new ArgumentException($"RTV formats length exceeds maximum supported count of {8}."); } // layout: // 0..64 8 RTV formats (8 bits each) // 64..72 DSV format (8 bits) var rtvPart = 0UL; for (var i = 0; i < rtvFormats.Length; i++) { rtvPart |= ((ulong)(byte)rtvFormats[i]) << (i * 8); } value = new UInt128(rtvPart, (ulong)dsvFormat); } public bool Equals(PassPipelineHash other) => value == other.value; public override bool Equals(object? obj) => obj is PassPipelineHash other && Equals(other); public override int GetHashCode() => value.GetHashCode(); public static bool operator ==(PassPipelineHash left, PassPipelineHash right) => left.Equals(right); public static bool operator !=(PassPipelineHash left, PassPipelineHash right) => !(left == right); } public ref struct GraphicsPSODescriptor { public Key64 VariantKey { get; set; } public PipelineState PipelineOption { 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; } /// /// Specifies how to load the render target at the start of the render pass. /// public AttachmentLoadOp LoadOp { get; set; } /// /// Specifies how to store the render target at the end of the render pass. /// public AttachmentStoreOp StoreOp { get; set; } } public struct PassDepthStencilDesc { public Handle Texture { get; set; } public float ClearDepth { get; set; } public byte ClearStencil { get; set; } /// /// Specifies how to load the depth buffer at the start of the render pass. /// public AttachmentLoadOp DepthLoadOp { get; set; } /// /// Specifies how to store the depth buffer at the end of the render pass. /// public AttachmentStoreOp DepthStoreOp { get; set; } /// /// Specifies how to load the stencil buffer at the start of the render pass. /// public AttachmentLoadOp StencilLoadOp { get; set; } /// /// Specifies how to store the stencil buffer at the end of the render pass. /// public AttachmentStoreOp StencilStoreOp { 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 }; } } /// /// 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 space 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; } public float ScaleX { get; set; } public float ScaleY { 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 space /// 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 = 0 }; } 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 } /// /// Specifies how to load attachment contents at the start of a render pass. /// public enum AttachmentLoadOp { /// /// Load existing contents from memory. Use when you need to preserve previous data. /// Load, /// /// Clear the attachment to a specified value. Use when you want to start with a clean slate. /// Clear, /// /// Don't care about previous contents. Use when you'll overwrite all pixels (fullscreen pass). /// On tile-based deferred renderers (TBDR), this can save significant memory bandwidth. /// DontCare } /// /// Specifies how to store attachment contents at the end of a render pass. /// public enum AttachmentStoreOp { /// /// Store the contents to memory for later use. /// Store, /// /// Discard the contents (not needed after this pass). /// On tile-based deferred renderers (TBDR), this can save significant memory bandwidth. /// DontCare }