Files
GhostEngine/Ghost.Graphics/RenderGraphModule/RenderGraphTypes.cs
Misaki 92b966fe0d Render graph integration and resource management refactor
Introduces a full-featured render graph system with pass culling, resource aliasing, and automatic barrier generation. Refactors resource and barrier APIs, improves error handling, and unifies result types. Renderer and render passes now use the new graph-based workflow. Updates shader includes, adds a blit shader, and improves HLSL parsing. Removes dynamic descriptor heaps in favor of persistent ones. Project file now includes the render graph module. Lays the foundation for advanced rendering features and improved memory efficiency.
2026-01-21 18:32:03 +09:00

501 lines
14 KiB
C#

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
}
/// <summary>
/// Specifies how texture dimensions are determined.
/// </summary>
public enum RGTextureSizeMode : byte
{
/// <summary>
/// Fixed pixel dimensions (width, height).
/// </summary>
Absolute,
/// <summary>
/// Scale relative to view state (scaleX * viewportWidth, scaleY * viewportHeight).
/// </summary>
Relative
}
/// <summary>
/// View state information for resolving relative texture sizes.
/// </summary>
public struct ViewState : IEquatable<ViewState>
{
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);
}
}
/// <summary>
/// Render graph texture descriptor with support for relative sizing and clear operations.
/// </summary>
public struct RGTextureDesc : IEquatable<RGTextureDesc>
{
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;
/// <summary>
/// Creates a texture descriptor with absolute dimensions.
/// </summary>
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
};
}
/// <summary>
/// Creates a texture descriptor with relative dimensions (uniform scale).
/// </summary>
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
};
}
/// <summary>
/// Creates a texture descriptor with relative dimensions (non-uniform scale).
/// </summary>
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
};
}
/// <summary>
/// Creates a depth texture descriptor with relative dimensions.
/// </summary>
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
};
}
/// <summary>
/// Creates an RGTextureDesc from an RHI TextureDesc (for imported textures).
/// </summary>
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
};
}
/// <summary>
/// Converts to RHI TextureDesc using resolved dimensions.
/// </summary>
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<RGResource> AsResource(this Identifier<RGTexture> texture)
{
return new Identifier<RGResource>(texture.Value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Identifier<RGResource> AsResource(this Identifier<RGBuffer> buffer)
{
return new Identifier<RGResource>(buffer.Value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Identifier<RGTexture> AsTexture(this Identifier<RGResource> resource)
{
return new Identifier<RGTexture>(resource.Value);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Identifier<RGBuffer> AsBuffer(this Identifier<RGResource> resource)
{
return new Identifier<RGBuffer>(resource.Value);
}
}
/// <summary>
/// Hints for how a buffer will be used in a pass.
/// Used to determine correct resource state transitions.
/// </summary>
[Flags]
public enum BufferHint
{
/// <summary>
/// No special usage - buffer will be used as shader resource (SRV) or UAV based on AccessFlags.
/// </summary>
None = 0,
/// <summary>
/// Buffer will be used as indirect argument buffer (ExecuteIndirect).
/// Requires ResourceState.IndirectArgument.
/// </summary>
IndirectArgument = 1 << 0,
}
internal readonly struct TextureAccess
{
public readonly Identifier<RGTexture> id;
public readonly AccessFlags accessFlags;
public TextureAccess(Identifier<RGTexture> id, AccessFlags accessFlags)
{
this.id = id;
this.accessFlags = accessFlags;
}
}
/// <summary>
/// Tracks buffer access information including usage hints.
/// </summary>
internal readonly struct BufferAccess
{
public readonly Identifier<RGBuffer> id;
public readonly AccessFlags accessFlags;
public readonly BufferHint hint;
public BufferAccess(Identifier<RGBuffer> id, AccessFlags accessFlags, BufferHint hint = BufferHint.None)
{
this.id = id;
this.accessFlags = accessFlags;
this.hint = hint;
}
}
///// <summary>
///// Descriptor for creating a texture resource.
///// </summary>
//public readonly struct TextureDescriptor : IEquatable<TextureDescriptor>
//{
// 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<BufferDescriptor>
//{
// 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);
// }
//}
/// <summary>
/// Base interface for pass data that can be stored in the blackboard.
/// </summary>
public interface IPassData
{
}
/// <summary>
/// Information about a render target attachment in a native render pass.
/// </summary>
internal struct RenderTargetInfo
{
public Identifier<RGTexture> texture;
public AccessFlags access;
public AttachmentLoadOp loadOp;
public AttachmentStoreOp storeOp;
public Color128 clearColor;
}
/// <summary>
/// Information about a depth-stencil attachment in a native render pass.
/// </summary>
internal struct DepthStencilInfo
{
public Identifier<RGTexture> texture;
public AccessFlags access;
public AttachmentLoadOp loadOp;
public AttachmentStoreOp storeOp;
public float clearDepth;
public byte clearStencil;
}