Editor/Prism/Compiler/Backends/BackendCapabilities.cs

Record type that describes what shader backends can express. It stores max shader model, supported stages and various feature booleans, exposes checks for stage and capability support, and provides two predefined capability sets (Sbox and Slang).

Reflection
using Editor.Prism.Core;

namespace Editor.Prism.Compiler.Backends;

/// <summary>
/// What a backend can express.
/// <para>
/// Consulted during <em>validation</em>, not at emit time, so the user is told "this graph uses a
/// loop, which the strict-HLSL dialect cannot express" long before anything is written to disk.
/// </para>
/// </summary>
public sealed record BackendCapabilities(
	ShaderModel MaxShaderModel,
	StageMask Stages,
	bool Loops,
	bool RealBranching,
	bool StructMethods,
	bool Interpolators,
	bool Combos,
	int MaxVaryingSlots,
	int MaxSamplers )
{
	/// <summary>True when the backend can emit this stage.</summary>
	public bool Supports( ShaderStage stage ) => Stages.Contains( stage );

	/// <summary>True when the backend can provide a capability at its maximum shader model.</summary>
	public bool Supports( Capability capability )
	{
		if ( Capabilities.MinShaderModel( capability ) > MaxShaderModel ) return false;

		return capability switch
		{
			Capability.Loops => Loops,
			Capability.DynamicBranching => RealBranching,
			Capability.StructMethods => StructMethods,
			Capability.Interpolators => Interpolators,
			Capability.Combos => Combos,
			_ => true
		};
	}

	/// <summary>
	/// The s&amp;box VFX target: SM 6.0 Vulkan, no hull or domain stage (the engine's block parser
	/// throws on those), everything else available.
	/// </summary>
	public static readonly BackendCapabilities Sbox = new(
		ShaderModel.Sm6_0,
		StageMask.Vertex | StageMask.Pixel | StageMask.Geometry | StageMask.Compute,
		Loops: true,
		RealBranching: true,
		StructMethods: true,
		Interpolators: true,
		Combos: true,
		MaxVaryingSlots: PrismConstants.MaxVaryingSlots,
		MaxSamplers: PrismConstants.MaxSamplers );

	/// <summary>The portable Slang target: no engine combos, no engine interpolator budget.</summary>
	public static readonly BackendCapabilities Slang = new(
		ShaderModel.Sm6_5,
		StageMask.All,
		Loops: true,
		RealBranching: true,
		StructMethods: true,
		Interpolators: true,
		Combos: false,
		MaxVaryingSlots: 32,
		MaxSamplers: 32 );
}