using Ghost.Core; using Ghost.Graphics.Core; using Ghost.Graphics.RHI; using System.Runtime.CompilerServices; namespace Ghost.Graphics.RenderGraphModule; internal enum RenderGraphResourceType : int { Texture, Buffer, // AccelerationStructure, Count } /// /// Specifies how texture dimensions are determined. /// public enum RGTextureSizeMode : byte { /// /// Fixed pixel dimensions (width, height). /// Absolute, /// /// Scale relative to view state (scaleX * viewportWidth, scaleY * viewportHeight). /// Relative } /// /// View state information for resolving relative texture sizes. /// public struct ViewState : IEquatable { public uint viewportWidth; public uint viewportHeight; public ViewState(uint width, uint height) { viewportWidth = width; viewportHeight = height; } public readonly bool Equals(ViewState other) { return viewportWidth == other.viewportWidth && viewportHeight == other.viewportHeight; } public override readonly bool Equals(object? obj) { return obj is ViewState other && Equals(other); } public override readonly int GetHashCode() { return HashCode.Combine(viewportWidth, viewportHeight); } public static bool operator ==(ViewState left, ViewState right) { return left.Equals(right); } public static bool operator !=(ViewState left, ViewState right) { return !left.Equals(right); } } /// /// Render graph texture descriptor with support for relative sizing and clear operations. /// public struct RGTextureDesc : IEquatable { public RGTextureSizeMode sizeMode; // Size specification (union-like - only one set is used based on sizeMode) public uint width; // For Absolute mode public uint height; // For Absolute mode public float scaleX; // For Relative mode public float scaleY; // For Relative mode // Common texture properties public TextureFormat format; public TextureDimension dimension; public uint mipLevels; public uint slice; public TextureUsage usage; public bool clearAtFirstUse; public bool discardAtLastUse; // Clear operation support public Color128 clearColor; public float clearDepth; public byte clearStencil; /// /// Creates a texture descriptor with absolute dimensions. /// public static RGTextureDesc Absolute( uint width, uint height, TextureFormat format, Color128 clearColor = default, bool clearAtFirstUse = true, bool discardAtLastUse = true, TextureDimension dimension = TextureDimension.Texture2D, uint mipLevels = 1, uint slice = 1, TextureUsage usage = TextureUsage.RenderTarget | TextureUsage.ShaderResource) { return new RGTextureDesc { sizeMode = RGTextureSizeMode.Absolute, width = width, height = height, format = format, clearColor = clearColor, clearAtFirstUse = clearAtFirstUse, discardAtLastUse = discardAtLastUse, clearDepth = 1.0f, clearStencil = 0, dimension = dimension, mipLevels = mipLevels, slice = slice, usage = usage }; } /// /// Creates a texture descriptor with relative dimensions (uniform scale). /// public static RGTextureDesc Relative( float scale, TextureFormat format, Color128 clearColor = default, bool clearAtFirstUse = true, bool discardAtLastUse = true, TextureDimension dimension = TextureDimension.Texture2D, uint mipLevels = 1, uint slice = 1, TextureUsage usage = TextureUsage.RenderTarget | TextureUsage.ShaderResource) { return new RGTextureDesc { sizeMode = RGTextureSizeMode.Relative, scaleX = scale, scaleY = scale, format = format, clearColor = clearColor, clearAtFirstUse = clearAtFirstUse, discardAtLastUse = discardAtLastUse, clearDepth = 1.0f, clearStencil = 0, dimension = dimension, mipLevels = mipLevels, slice = slice, usage = usage }; } /// /// Creates a texture descriptor with relative dimensions (non-uniform scale). /// public static RGTextureDesc Relative( float scaleX, float scaleY, TextureFormat format, Color128 clearColor = default, bool clearAtFirstUse = true, bool discardAtLastUse = true, TextureDimension dimension = TextureDimension.Texture2D, uint mipLevels = 1, uint slice = 1, TextureUsage usage = TextureUsage.RenderTarget | TextureUsage.ShaderResource) { return new RGTextureDesc { sizeMode = RGTextureSizeMode.Relative, scaleX = scaleX, scaleY = scaleY, format = format, clearColor = clearColor, clearAtFirstUse = clearAtFirstUse, discardAtLastUse = discardAtLastUse, clearDepth = 1.0f, clearStencil = 0, dimension = dimension, mipLevels = mipLevels, slice = slice, usage = usage }; } /// /// Creates a depth texture descriptor with relative dimensions. /// public static RGTextureDesc RelativeDepth( float scale, float clearDepth = 1.0f, byte clearStencil = 0, bool clearAtFirstUse = true, bool discardAtLastUse = true, TextureFormat format = TextureFormat.D32_Float) { return new RGTextureDesc { sizeMode = RGTextureSizeMode.Relative, scaleX = scale, scaleY = scale, format = format, clearColor = default, clearDepth = clearDepth, clearStencil = clearStencil, clearAtFirstUse = clearAtFirstUse, discardAtLastUse = discardAtLastUse, dimension = TextureDimension.Texture2D, mipLevels = 1, slice = 1, usage = TextureUsage.DepthStencil | TextureUsage.ShaderResource }; } /// /// Creates an RGTextureDesc from an RHI TextureDesc (for imported textures). /// public static RGTextureDesc FromTextureDesc(in TextureDesc desc) { return new RGTextureDesc { sizeMode = RGTextureSizeMode.Absolute, width = desc.Width, height = desc.Height, format = desc.Format, clearColor = default, clearDepth = 1.0f, clearStencil = 0, clearAtFirstUse = false, discardAtLastUse = false, dimension = desc.Dimension, mipLevels = desc.MipLevels, slice = desc.Slice, usage = desc.Usage }; } /// /// Converts to RHI TextureDesc using resolved dimensions. /// public readonly TextureDesc ToTextureDesc(uint resolvedWidth, uint resolvedHeight) { return new TextureDesc { Width = resolvedWidth, Height = resolvedHeight, Format = format, Dimension = dimension, MipLevels = mipLevels, Slice = slice, Usage = usage }; } public readonly bool Equals(RGTextureDesc other) { return sizeMode == other.sizeMode && format == other.format && dimension == other.dimension && mipLevels == other.mipLevels && slice == other.slice && usage == other.usage && clearAtFirstUse == other.clearAtFirstUse && discardAtLastUse == other.discardAtLastUse && (sizeMode == RGTextureSizeMode.Absolute ? width == other.width && height == other.height : scaleX == other.scaleX && scaleY == other.scaleY); } public override readonly bool Equals(object? obj) { return obj is RGTextureDesc other && Equals(other); } public override readonly int GetHashCode() { if (sizeMode == RGTextureSizeMode.Absolute) { return HashCode.Combine(sizeMode, width, height, format, dimension, mipLevels, slice, usage); } else { return HashCode.Combine(sizeMode, scaleX, scaleY, format, dimension, mipLevels, slice, usage); } } public static bool operator ==(RGTextureDesc left, RGTextureDesc right) { return left.Equals(right); } public static bool operator !=(RGTextureDesc left, RGTextureDesc right) { return !left.Equals(right); } } public struct RGResource; public struct RGTexture; public struct RGBuffer; public static class RGResourceExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Identifier AsResource(this Identifier texture) { return new Identifier(texture.Value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Identifier AsResource(this Identifier buffer) { return new Identifier(buffer.Value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Identifier AsTexture(this Identifier resource) { return new Identifier(resource.Value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static Identifier AsBuffer(this Identifier resource) { return new Identifier(resource.Value); } } /// /// Hints for how a buffer will be used in a pass. /// Used to determine correct resource state transitions. /// [Flags] public enum BufferHint { /// /// No special usage - buffer will be used as shader resource (SRV) or UAV based on AccessFlags. /// None = 0, /// /// Buffer will be used as indirect argument buffer (ExecuteIndirect). /// Requires ResourceState.IndirectArgument. /// IndirectArgument = 1 << 0, } internal readonly struct TextureAccess { public readonly Identifier id; public readonly AccessFlags accessFlags; public TextureAccess(Identifier id, AccessFlags accessFlags) { this.id = id; this.accessFlags = accessFlags; } } /// /// Tracks buffer access information including usage hints. /// internal readonly struct BufferAccess { public readonly Identifier id; public readonly AccessFlags accessFlags; public readonly BufferHint hint; public BufferAccess(Identifier id, AccessFlags accessFlags, BufferHint hint = BufferHint.None) { this.id = id; this.accessFlags = accessFlags; this.hint = hint; } } ///// ///// Descriptor for creating a texture resource. ///// //public readonly struct TextureDescriptor : IEquatable //{ // public readonly int width; // public readonly int height; // public readonly TextureFormat format; // public readonly string name; // public TextureDescriptor(int width, int height, TextureFormat format, string name) // { // this.width = width; // this.height = height; // this.format = format; // this.name = name; // } // public readonly bool Equals(TextureDescriptor other) // { // return width == other.width && // height == other.height && // format == other.format && // name == other.name; // } // public override readonly bool Equals(object? obj) => obj is TextureDescriptor other && Equals(other); // public override readonly int GetHashCode() => HashCode.Combine(width, height, format, name); // public static bool operator ==(TextureDescriptor left, TextureDescriptor right) // { // return left.Equals(right); // } // public static bool operator !=(TextureDescriptor left, TextureDescriptor right) // { // return !(left == right); // } //} //public readonly struct BufferDescriptor : IEquatable //{ // public readonly uint sizeInBytes; // public readonly uint stride; // public readonly BufferUsage usage; // public readonly string name; // public BufferDescriptor(uint sizeInBytes, uint stride, BufferUsage usage, string name) // { // this.sizeInBytes = sizeInBytes; // this.stride = stride; // this.usage = usage; // this.name = name; // } // public readonly bool Equals(BufferDescriptor other) // { // return sizeInBytes == other.sizeInBytes && // stride == other.stride && // usage == other.usage && // name == other.name; // } // public override readonly bool Equals(object? obj) => obj is BufferDescriptor other && Equals(other); // public override readonly int GetHashCode() => HashCode.Combine(sizeInBytes, name); // public static bool operator ==(BufferDescriptor left, BufferDescriptor right) // { // return left.Equals(right); // } // public static bool operator !=(BufferDescriptor left, BufferDescriptor right) // { // return !(left == right); // } //} /// /// Base interface for pass data that can be stored in the blackboard. /// public interface IPassData { } /// /// Information about a render target attachment in a native render pass. /// internal struct RenderTargetInfo { public Identifier texture; public AccessFlags access; public AttachmentLoadOp loadOp; public AttachmentStoreOp storeOp; public Color128 clearColor; } /// /// Information about a depth-stencil attachment in a native render pass. /// internal struct DepthStencilInfo { public Identifier texture; public AccessFlags access; public AttachmentLoadOp loadOp; public AttachmentStoreOp storeOp; public float clearDepth; public byte clearStencil; }