Editor/Prism/Text/LanguageDb/HlslLanguage.cs

HLSL language database used by the editor. It defines keyword sets, built-in types, object types with their member-method docs, semantics, and builds a LanguageDefinition describing HLSL for syntax highlighting, completion and tooling.

Reflection
using Editor.Prism.Core;

namespace Editor.Prism.Text.LanguageDb;

/// <summary>One member method of a built-in object type, with every overload the docs list.</summary>
/// <param name="Name">The method name as written after the dot.</param>
/// <param name="Signatures">Full signature strings for signature help.</param>
/// <param name="Description">A single sentence for the completion list and hover popup.</param>
/// <param name="MinShaderModel">Lowest shader model providing the method.</param>
/// <param name="Stages">Stages the method may be called from.</param>
public sealed record TypeMemberDoc(
	string Name,
	string[] Signatures,
	string Description,
	ShaderModel MinShaderModel,
	StageMask Stages )
{
	/// <summary>The first signature, or the bare name.</summary>
	public string Signature => Signatures is { Length: > 0 } ? Signatures[0] : Name;

	/// <summary>True when the method compiles on the s&amp;box target in at least one stage.</summary>
	public bool IsAvailableOnTarget => Stages != StageMask.None && MinShaderModel <= ShaderModel.Target;

	/// <inheritdoc/>
	public override string ToString() => Signature;
}

/// <summary>One built-in object type — a texture, buffer, sampler, patch or stream.</summary>
/// <param name="Name">The type name without its template arguments.</param>
/// <param name="TemplateArity">0, 1 for <c>&lt;T&gt;</c>, or 2 for <c>&lt;T, Samples&gt;</c>.</param>
/// <param name="Description">A single sentence for the hover popup.</param>
/// <param name="MinShaderModel">Lowest shader model providing the type.</param>
/// <param name="Writable">True for UAV types.</param>
/// <param name="Deprecated">True for the Direct3D 9 sampler types DXC removed.</param>
/// <param name="Members">Names of the member methods this type exposes, in declaration order.</param>
public sealed record ObjectTypeDoc(
	string Name,
	int TemplateArity,
	string Description,
	ShaderModel MinShaderModel,
	bool Writable,
	bool Deprecated,
	IReadOnlyList<string> Members )
{
	/// <inheritdoc/>
	public override string ToString() => TemplateArity > 0 ? Name + "<…>" : Name;
}

/// <summary>One HLSL semantic, system-value or legacy.</summary>
/// <param name="Name">The semantic name without its optional trailing index.</param>
/// <param name="IsSystemValue">True for the <c>SV_</c> family.</param>
/// <param name="Indexed">True when a trailing integer index is legal.</param>
/// <param name="Type">The HLSL type the semantic carries.</param>
/// <param name="Description">A single sentence for the hover popup.</param>
/// <param name="MinShaderModel">Lowest shader model providing the semantic.</param>
/// <param name="Stages">Stages that may read or write the semantic.</param>
public sealed record SemanticDoc(
	string Name,
	bool IsSystemValue,
	bool Indexed,
	string Type,
	string Description,
	ShaderModel MinShaderModel,
	StageMask Stages )
{
	/// <inheritdoc/>
	public override string ToString() => Indexed ? Name + "[n]" : Name;
}

/// <summary>
/// The HLSL language database: every keyword, modifier, built-in type, object type with its member
/// methods, semantic, attribute and preprocessor directive the editor recognises. Sourced from the
/// Direct3D HLSL reference and cross-checked against what s&amp;box's DXC front end actually accepts.
/// </summary>
public static class HlslLanguage
{
	private static readonly ShaderModel Sm1 = new( 1, 0 );
	private static readonly ShaderModel Sm4 = new( 4, 0 );
	private static readonly ShaderModel Sm4_1 = new( 4, 1 );
	private static readonly ShaderModel Sm5 = new( 5, 0 );
	private static readonly ShaderModel Sm5_1 = new( 5, 1 );

	// ------------------------------------------------------------------------------------------
	// Word classes
	// ------------------------------------------------------------------------------------------

	/// <summary>Control-flow keywords.</summary>
	public static readonly IReadOnlySet<string> ControlKeywords = Set(
		"break", "case", "continue", "default", "discard", "do", "else", "for", "if",
		"return", "switch", "while" );

	/// <summary>Declaration keywords and effect-framework leftovers that must still highlight.</summary>
	public static readonly IReadOnlySet<string> Keywords = Set(
		"asm", "asm_fragment", "cbuffer", "class", "compile", "compile_fragment", "CompileShader",
		"enum", "export", "fxgroup", "interface", "namespace", "operator", "packoffset", "pass",
		"pixelfragment", "register", "sizeof", "struct", "tbuffer", "technique", "technique10",
		"technique11", "template", "this", "typedef", "typename", "using", "vertexfragment",
		"const_cast", "static_cast", "reinterpret_cast",
		"line", "lineadj", "point", "triangle", "triangleadj",
		"BlendState", "DepthStencilState", "RasterizerState", "DepthStencilView", "RenderTargetView",
		"VertexShader", "PixelShader", "GeometryShader", "HullShader", "Hullshader", "DomainShader",
		"ComputeShader", "stateblock", "stateblock_state", "sampler_state" );

	/// <summary>Storage, interpolation, parameter and matrix-layout modifiers.</summary>
	public static readonly IReadOnlySet<string> Modifiers = Set(
		"extern", "nointerpolation", "precise", "shared", "groupshared", "static", "uniform",
		"volatile", "const", "row_major", "column_major", "linear", "centroid", "noperspective",
		"sample", "in", "out", "inout", "inline", "snorm", "unorm", "unsigned",
		"globallycoherent", "reordercoherent",
		"vertices", "indices", "primitives", "payload" );

	/// <summary>Literal keywords.</summary>
	public static readonly IReadOnlySet<string> Literals = Set( "true", "false", "NULL" );

	/// <summary>Scalar type names, before vector and matrix expansion.</summary>
	public static readonly IReadOnlySet<string> ScalarTypes = Set(
		"bool", "int", "uint", "dword", "half", "float", "double",
		"min16float", "min10float", "min16int", "min12int", "min16uint",
		"int8_t", "uint8_t", "int16_t", "uint16_t", "int32_t", "uint32_t", "int64_t", "uint64_t",
		"float16_t", "float32_t", "float64_t" );

	/// <summary>Every built-in type spelling, scalars plus the full vector and matrix grids.</summary>
	public static readonly IReadOnlySet<string> BuiltinTypes = BuildBuiltinTypes();

	/// <summary>Object type names: textures, buffers, samplers, patches, streams, heaps.</summary>
	public static readonly IReadOnlySet<string> ObjectTypeNames;

	/// <summary>Preprocessor directive names, without the leading <c>#</c>.</summary>
	public static readonly IReadOnlySet<string> PreprocessorDirectives = Set(
		"define", "elif", "else", "endif", "error", "if", "ifdef", "ifndef", "include",
		"line", "pragma", "undef", "warning", "elifdef", "elifndef" );

	/// <summary><c>#pragma</c> sub-directive names.</summary>
	public static readonly IReadOnlySet<string> PragmaNames = Set(
		"def", "message", "pack_matrix", "warning", "once", "dxc", "exclude_renderers", "ruby" );

	/// <summary>Macros DXC and the s&amp;box preprocessor define for you.</summary>
	public static readonly IReadOnlySet<string> PredefinedMacros = Set(
		"__FILE__", "__LINE__", "__DATE__", "__TIME__", "__HLSL_VERSION",
		"__SHADER_TARGET_MAJOR", "__SHADER_TARGET_MINOR", "__SHADER_TARGET_STAGE",
		"__SHADER_STAGE_VERTEX", "__SHADER_STAGE_PIXEL", "__SHADER_STAGE_GEOMETRY",
		"__SHADER_STAGE_HULL", "__SHADER_STAGE_DOMAIN", "__SHADER_STAGE_COMPUTE",
		"__SHADER_STAGE_AMPLIFICATION", "__SHADER_STAGE_MESH", "__SHADER_STAGE_LIBRARY",
		"__spirv__", "PROGRAM" );

	/// <summary>Statement, function and entry-point attribute names legal inside <c>[ ]</c>.</summary>
	public static readonly IReadOnlySet<string> Attributes = Set(
		"branch", "flatten", "forcecase", "call",
		"unroll", "loop", "fastopt", "allow_uav_condition",
		"numthreads", "maxvertexcount", "instance", "earlydepthstencil",
		"domain", "partitioning", "outputtopology", "outputcontrolpoints", "patchconstantfunc",
		"maxtessfactor", "clipplanes", "shader", "RootSignature", "WaveSize",
		"WaveOpsIncludeHelperLanes", "NodeLaunch", "NodeIsProgramEntry", "NodeID",
		"NodeLocalRootArgumentsTableIndex", "NodeShareInputOf", "NodeDispatchGrid",
		"NodeMaxDispatchGrid", "NodeMaxRecursionDepth", "raypayload", "noinline" );

	/// <summary>Multi-character operators, longest first.</summary>
	public static readonly IReadOnlyList<string> Operators = new[]
	{
		"<<=", ">>=",
		"->", "::", "++", "--", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=",
		"==", "!=", "<=", ">=", "&&", "||", "<<", ">>", "..",
		"+", "-", "*", "/", "%", "=", "<", ">", "!", "&", "|", "^", "~", "?", ":", ".", "#"
	};

	// ------------------------------------------------------------------------------------------
	// Object types and their member methods
	// ------------------------------------------------------------------------------------------

	private static readonly Dictionary<string, TypeMemberDoc> s_members = new( 128, StringComparer.Ordinal );
	private static readonly List<TypeMemberDoc> s_memberList = new( 128 );
	private static readonly Dictionary<string, ObjectTypeDoc> s_objects = new( 64, StringComparer.Ordinal );
	private static readonly List<ObjectTypeDoc> s_objectList = new( 64 );
	private static readonly Dictionary<string, SemanticDoc> s_semantics = new( 80, StringComparer.Ordinal );
	private static readonly List<SemanticDoc> s_semanticList = new( 80 );

	/// <summary>Every built-in object type, in declaration order.</summary>
	public static IReadOnlyList<ObjectTypeDoc> ObjectTypes => s_objectList;

	/// <summary>Every member method of every built-in object type, deduplicated by name.</summary>
	public static IReadOnlyList<TypeMemberDoc> MemberMethods => s_memberList;

	/// <summary>Every semantic, system-value and legacy.</summary>
	public static IReadOnlyList<SemanticDoc> Semantics => s_semanticList;

	/// <summary>Semantic names, without their optional trailing index.</summary>
	public static readonly IReadOnlySet<string> SemanticNames;

	/// <summary>O(1) object-type lookup.</summary>
	public static bool TryGetObjectType( string name, out ObjectTypeDoc type )
	{
		type = null;
		return !string.IsNullOrEmpty( name ) && s_objects.TryGetValue( name, out type );
	}

	/// <summary>O(1) member-method lookup across every object type.</summary>
	public static bool TryGetMember( string name, out TypeMemberDoc member )
	{
		member = null;
		return !string.IsNullOrEmpty( name ) && s_members.TryGetValue( name, out member );
	}

	/// <summary>True when the name is a member method of any built-in object type.</summary>
	public static bool IsMemberMethod( string name ) => TryGetMember( name, out _ );

	/// <summary>O(1) semantic lookup; a trailing index is stripped before matching.</summary>
	public static bool TryGetSemantic( string name, out SemanticDoc semantic )
	{
		semantic = null;

		if ( string.IsNullOrEmpty( name ) )
			return false;

		if ( s_semantics.TryGetValue( name, out semantic ) )
			return true;

		var end = name.Length;
		while ( end > 0 && name[end - 1] >= '0' && name[end - 1] <= '9' )
			end--;

		if ( end == name.Length || end == 0 )
			return false;

		return s_semantics.TryGetValue( name.Substring( 0, end ), out semantic );
	}

	/// <summary>The member methods of one object type, resolved to their documentation.</summary>
	public static IEnumerable<TypeMemberDoc> MembersOf( ObjectTypeDoc type )
	{
		if ( type?.Members is null )
			yield break;

		foreach ( var name in type.Members )
		{
			if ( s_members.TryGetValue( name, out var member ) )
				yield return member;
		}
	}

	/// <summary>The member methods of one object type by name. Empty for an unknown type.</summary>
	public static IEnumerable<TypeMemberDoc> MembersOf( string typeName )
	{
		return TryGetObjectType( typeName, out var type ) ? MembersOf( type ) : Array.Empty<TypeMemberDoc>();
	}

	/// <summary>The shared HLSL language definition.</summary>
	public static readonly LanguageDefinition Definition;

	// ------------------------------------------------------------------------------------------

	private static HashSet<string> Set( params string[] words ) => new( words, StringComparer.Ordinal );

	private static HashSet<string> BuildBuiltinTypes()
	{
		var set = new HashSet<string>( StringComparer.Ordinal )
		{
			"void", "string", "vector", "matrix",
			"uint8_t4_packed", "int8_t4_packed"
		};

		string[] bases =
		{
			"bool", "int", "uint", "dword", "half", "float", "double",
			"min16float", "min10float", "min16int", "min12int", "min16uint",
			"int8_t", "uint8_t", "int16_t", "uint16_t", "int32_t", "uint32_t", "int64_t", "uint64_t",
			"float16_t", "float32_t", "float64_t"
		};

		foreach ( var b in bases )
		{
			set.Add( b );

			for ( var n = 1; n <= 4; n++ )
			{
				set.Add( b + n );

				for ( var c = 1; c <= 4; c++ )
					set.Add( b + n + "x" + c );
			}
		}

		return set;
	}

	private static void M( string name, string signature, string description,
		ShaderModel minSm, StageMask stages = StageMask.All )
	{
		M( name, new[] { signature }, description, minSm, stages );
	}

	private static void M( string name, string[] signatures, string description,
		ShaderModel minSm, StageMask stages = StageMask.All )
	{
		if ( s_members.ContainsKey( name ) )
			return;

		var member = new TypeMemberDoc( name, signatures, description, minSm, stages );
		s_members.Add( name, member );
		s_memberList.Add( member );
	}

	private static void O( string name, int arity, string description, ShaderModel minSm,
		bool writable, bool deprecated, params string[] members )
	{
		if ( s_objects.ContainsKey( name ) )
			return;

		var type = new ObjectTypeDoc( name, arity, description, minSm, writable, deprecated, members );
		s_objects.Add( name, type );
		s_objectList.Add( type );
	}

	private static void S( string name, bool systemValue, bool indexed, string type,
		string description, ShaderModel minSm, StageMask stages )
	{
		if ( s_semantics.ContainsKey( name ) )
			return;

		var semantic = new SemanticDoc( name, systemValue, indexed, type, description, minSm, stages );
		s_semantics.Add( name, semantic );
		s_semanticList.Add( semantic );
	}

	static HlslLanguage()
	{
		BuildMembers();
		BuildObjectTypes();
		BuildSemantics();

		var objectNames = new HashSet<string>( StringComparer.Ordinal );
		foreach ( var type in s_objectList )
			objectNames.Add( type.Name );

		// Types that behave like object types for highlighting but carry no member table.
		objectNames.Add( "ResourceDescriptorHeap" );
		objectNames.Add( "SamplerDescriptorHeap" );
		objectNames.Add( "RayDesc" );
		objectNames.Add( "BuiltInTriangleIntersectionAttributes" );
		objectNames.Add( "SAMPLER_FEEDBACK_MIN_MIP" );
		objectNames.Add( "SAMPLER_FEEDBACK_MIP_REGION_USED" );
		objectNames.Add( "NodeOutput" );
		objectNames.Add( "NodeOutputArray" );
		objectNames.Add( "EmptyNodeOutput" );
		objectNames.Add( "DispatchNodeInputRecord" );
		objectNames.Add( "ThreadNodeInputRecord" );
		objectNames.Add( "GroupNodeInputRecords" );
		objectNames.Add( "RWDispatchNodeInputRecord" );
		objectNames.Add( "ThreadNodeOutputRecords" );
		objectNames.Add( "GroupNodeOutputRecords" );

		ObjectTypeNames = objectNames;

		var semanticNames = new HashSet<string>( StringComparer.Ordinal );
		foreach ( var semantic in s_semanticList )
			semanticNames.Add( semantic.Name );

		SemanticNames = semanticNames;

		Definition = new LanguageDefinition
		{
			Id = "hlsl",
			DisplayName = "HLSL",
			FileExtensions = new[] { "hlsl", "hlsli", "fxc", "fx", "inc" },
			Keywords = Keywords,
			ControlKeywords = ControlKeywords,
			Modifiers = Modifiers,
			BuiltinTypes = BuiltinTypes,
			ObjectTypes = ObjectTypeNames,
			Literals = Literals,
			Attributes = Attributes,
			Semantics = SemanticNames,
			PreprocessorDirectives = PreprocessorDirectives,
			PredefinedMacros = PredefinedMacros,
			ExtraIntrinsics = new HashSet<string>( StringComparer.Ordinal ),
			Operators = Operators,
			Punctuation = "()[]{},;",
			Comments = CommentRules.CFamily,
			CompletionTriggers = new[] { '.', '#', '[', ':', '<' },
			IncludeSearchPaths = SboxSymbols.IncludeSearchPaths,
			VirtualIncludes = SboxSymbols.VirtualIncludes,
			SupportsAnnotations = true,
			SupportsModules = false,
			SupportsAngleBracketIncludes = false,
			HasVfxBlocks = false,
			HasSboxSymbols = true
		};
	}

	private static void BuildMembers()
	{
		M( "GetDimensions", new[]
		{
			"void GetDimensions( out uint Width, out uint Height )",
			"void GetDimensions( uint MipLevel, out uint Width, out uint Height, out uint NumberOfLevels )",
			"void GetDimensions( out float Width, out float Height )",
			"void GetDimensions( out uint numStructs, out uint stride )",
			"void GetDimensions( out uint dim )"
		}, "Queries the size of the resource, and for textures the mip count.", Sm4 );

		M( "Load", new[]
		{
			"T Load( int3 Location )",
			"T Load( int3 Location, int2 Offset )",
			"T Load( int3 Location, int2 Offset, out uint Status )",
			"T Load( int2 Location, int SampleIndex )",
			"T Load( int Location )",
			"uint Load( uint address )"
		}, "Reads a texel or element with no filtering. For textures the last coordinate component is the mip level.", Sm4 );

		M( "Load2", "uint2 Load2( uint address )", "Reads two 32-bit words from a byte-address buffer; the address must be a multiple of four.", Sm5 );
		M( "Load3", "uint3 Load3( uint address )", "Reads three 32-bit words from a byte-address buffer.", Sm5 );
		M( "Load4", "uint4 Load4( uint address )", "Reads four 32-bit words from a byte-address buffer.", Sm5 );

		M( "Sample", new[]
		{
			"T Sample( SamplerState S, float2 Location )",
			"T Sample( SamplerState S, float2 Location, int2 Offset )",
			"T Sample( SamplerState S, float2 Location, int2 Offset, float Clamp )",
			"T Sample( SamplerState S, float2 Location, int2 Offset, float Clamp, out uint Status )"
		}, "Filtered sample using implicit derivatives. Pixel stage only — use SampleLevel or SampleGrad elsewhere.", Sm4, StageMask.Pixel );

		M( "SampleBias", new[]
		{
			"T SampleBias( SamplerState S, float2 Location, float Bias )",
			"T SampleBias( SamplerState S, float2 Location, float Bias, int2 Offset )",
			"T SampleBias( SamplerState S, float2 Location, float Bias, int2 Offset, float Clamp )"
		}, "Filtered sample with a bias added to the computed mip level. Pixel stage only.", Sm4, StageMask.Pixel );

		M( "SampleLevel", new[]
		{
			"T SampleLevel( SamplerState S, float2 Location, float LOD )",
			"T SampleLevel( SamplerState S, float2 Location, float LOD, int2 Offset )",
			"T SampleLevel( SamplerState S, float2 Location, float LOD, int2 Offset, out uint Status )"
		}, "Filtered sample at an explicit mip level. Legal in every stage.", Sm4 );

		M( "SampleGrad", new[]
		{
			"T SampleGrad( SamplerState S, float2 Location, float2 DDX, float2 DDY )",
			"T SampleGrad( SamplerState S, float2 Location, float2 DDX, float2 DDY, int2 Offset )",
			"T SampleGrad( SamplerState S, float2 Location, float2 DDX, float2 DDY, int2 Offset, float Clamp )"
		}, "Filtered sample using explicit gradients. Legal in every stage.", Sm4 );

		M( "SampleCmp", new[]
		{
			"float SampleCmp( SamplerComparisonState S, float2 Location, float CompareValue )",
			"float SampleCmp( SamplerComparisonState S, float2 Location, float CompareValue, int2 Offset )",
			"float SampleCmp( SamplerComparisonState S, float2 Location, float CompareValue, int2 Offset, float Clamp )"
		}, "Comparison sample for shadow maps, using implicit derivatives. Pixel stage only.", Sm4, StageMask.Pixel );

		M( "SampleCmpLevelZero", new[]
		{
			"float SampleCmpLevelZero( SamplerComparisonState S, float2 Location, float CompareValue )",
			"float SampleCmpLevelZero( SamplerComparisonState S, float2 Location, float CompareValue, int2 Offset )"
		}, "Comparison sample restricted to mip 0. Legal in every stage.", Sm4 );

		M( "SampleCmpLevel", new[]
		{
			"float SampleCmpLevel( SamplerComparisonState S, float2 Location, float CompareValue, float LOD )",
			"float SampleCmpLevel( SamplerComparisonState S, float2 Location, float CompareValue, float LOD, int2 Offset )"
		}, "Comparison sample at an explicit mip level.", ShaderModel.Sm6_7 );

		M( "CalculateLevelOfDetail", "float CalculateLevelOfDetail( SamplerState S, float2 x )",
			"Computes the mip level the hardware would pick, clamped to the resource's mip range. Pixel stage only.", Sm4_1, StageMask.Pixel );
		M( "CalculateLevelOfDetailUnclamped", "float CalculateLevelOfDetailUnclamped( SamplerState S, float2 x )",
			"Computes the mip level the hardware would pick, unclamped. Pixel stage only.", Sm4_1, StageMask.Pixel );

		M( "Gather", new[]
		{
			"vector<T,4> Gather( SamplerState S, float2 Location )",
			"vector<T,4> Gather( SamplerState S, float2 Location, int2 Offset )"
		}, "Returns the four red components that bilinear filtering would blend. Counter-clockwise from the lower-left texel.", Sm4_1 );

		M( "GatherRed", "vector<T,4> GatherRed( SamplerState S, float2 Location [, int2 Offset] )", "Gathers the four red components of the bilinear footprint.", Sm5 );
		M( "GatherGreen", "vector<T,4> GatherGreen( SamplerState S, float2 Location [, int2 Offset] )", "Gathers the four green components of the bilinear footprint.", Sm5 );
		M( "GatherBlue", "vector<T,4> GatherBlue( SamplerState S, float2 Location [, int2 Offset] )", "Gathers the four blue components of the bilinear footprint.", Sm5 );
		M( "GatherAlpha", "vector<T,4> GatherAlpha( SamplerState S, float2 Location [, int2 Offset] )", "Gathers the four alpha components of the bilinear footprint.", Sm5 );
		M( "GatherCmp", "float4 GatherCmp( SamplerComparisonState S, float2 Location, float CompareValue [, int2 Offset] )", "Gathers four comparison results from the bilinear footprint.", Sm5 );
		M( "GatherCmpRed", "float4 GatherCmpRed( SamplerComparisonState S, float2 Location, float CompareValue [, int2 Offset] )", "Gathers four red comparison results.", Sm5 );
		M( "GatherCmpGreen", "float4 GatherCmpGreen( SamplerComparisonState S, float2 Location, float CompareValue [, int2 Offset] )", "Gathers four green comparison results.", Sm5 );
		M( "GatherCmpBlue", "float4 GatherCmpBlue( SamplerComparisonState S, float2 Location, float CompareValue [, int2 Offset] )", "Gathers four blue comparison results.", Sm5 );
		M( "GatherCmpAlpha", "float4 GatherCmpAlpha( SamplerComparisonState S, float2 Location, float CompareValue [, int2 Offset] )", "Gathers four alpha comparison results.", Sm5 );

		M( "GetSamplePosition", "float2 GetSamplePosition( int SampleIndex )", "Position of the given MSAA sample within the pixel.", Sm4_1 );

		M( "Store", "void Store( uint address, uint value )", "Writes one 32-bit word to a byte-address buffer.", Sm5, StageMask.Compute | StageMask.Pixel );
		M( "Store2", "void Store2( uint address, uint2 value )", "Writes two 32-bit words to a byte-address buffer.", Sm5, StageMask.Compute | StageMask.Pixel );
		M( "Store3", "void Store3( uint address, uint3 value )", "Writes three 32-bit words to a byte-address buffer.", Sm5, StageMask.Compute | StageMask.Pixel );
		M( "Store4", "void Store4( uint address, uint4 value )", "Writes four 32-bit words to a byte-address buffer.", Sm5, StageMask.Compute | StageMask.Pixel );

		M( "IncrementCounter", "uint IncrementCounter()", "Atomically increments the hidden counter of an RWStructuredBuffer and returns the pre-increment value.", Sm5, StageMask.Compute | StageMask.Pixel );
		M( "DecrementCounter", "uint DecrementCounter()", "Atomically decrements the hidden counter of an RWStructuredBuffer and returns the post-decrement value.", Sm5, StageMask.Compute | StageMask.Pixel );
		M( "Append", new[] { "void Append( T value )", "void Append( T streamDataElement )" },
			"Appends a value to an AppendStructuredBuffer, or a vertex to a geometry-shader stream.", Sm4 );
		M( "Consume", "T Consume()", "Removes and returns a value from a ConsumeStructuredBuffer.", Sm5, StageMask.Compute );
		M( "RestartStrip", "void RestartStrip()", "Ends the current primitive strip in a geometry-shader stream.", Sm4, StageMask.Geometry );

		M( "WriteSamplerFeedback", "void WriteSamplerFeedback( Texture2D tex, SamplerState s, float2 location [, float clamp] )", "Records a sampler-feedback entry for an implicit-LOD sample.", ShaderModel.Sm6_5, StageMask.Pixel );
		M( "WriteSamplerFeedbackBias", "void WriteSamplerFeedbackBias( Texture2D tex, SamplerState s, float2 location, float bias [, float clamp] )", "Records a sampler-feedback entry for a biased sample.", ShaderModel.Sm6_5, StageMask.Pixel );
		M( "WriteSamplerFeedbackGrad", "void WriteSamplerFeedbackGrad( Texture2D tex, SamplerState s, float2 location, float2 ddx, float2 ddy [, float clamp] )", "Records a sampler-feedback entry for a gradient sample.", ShaderModel.Sm6_5 );
		M( "WriteSamplerFeedbackLevel", "void WriteSamplerFeedbackLevel( Texture2D tex, SamplerState s, float2 location, float lod )", "Records a sampler-feedback entry for an explicit-LOD sample.", ShaderModel.Sm6_5 );

		M( "mips", "T mips[mipSlice][pos]", "Two-level subscript that reads an explicit mip level of a texture.", Sm5 );
		M( "sample", "T sample[sampleSlice][pos]", "Two-level subscript that reads an explicit MSAA sample.", Sm5 );
		M( "Length", "uint Length", "The control-point count of an InputPatch or OutputPatch.", Sm5 );

		// RayQuery — inline ray tracing, SM 6.5.
		M( "TraceRayInline", "void TraceRayInline( RaytracingAccelerationStructure AccelerationStructure, uint RayFlags, uint InstanceInclusionMask, RayDesc Ray )", "Begins an inline traversal on this RayQuery.", ShaderModel.Sm6_5, StageMask.None );
		M( "Proceed", "bool Proceed()", "Advances inline traversal; true while shader-visible work remains.", ShaderModel.Sm6_5, StageMask.None );
		M( "Abort", "void Abort()", "Terminates inline traversal immediately.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateType", "CANDIDATE_TYPE CandidateType()", "CANDIDATE_NON_OPAQUE_TRIANGLE or CANDIDATE_PROCEDURAL_PRIMITIVE.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateProceduralPrimitiveNonOpaque", "bool CandidateProceduralPrimitiveNonOpaque()", "Whether the candidate procedural primitive is non-opaque.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateTriangleRayT", "float CandidateTriangleRayT()", "Hit T of the candidate triangle.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateInstanceIndex", "uint CandidateInstanceIndex()", "Top-level instance index of the candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateInstanceID", "uint CandidateInstanceID()", "User instance ID of the candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateInstanceContributionToHitGroupIndex", "uint CandidateInstanceContributionToHitGroupIndex()", "Hit-group contribution of the candidate instance.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateGeometryIndex", "uint CandidateGeometryIndex()", "Geometry index of the candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidatePrimitiveIndex", "uint CandidatePrimitiveIndex()", "Primitive index of the candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateObjectRayOrigin", "float3 CandidateObjectRayOrigin()", "Object-space ray origin for the candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateObjectRayDirection", "float3 CandidateObjectRayDirection()", "Object-space ray direction for the candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateObjectToWorld3x4", "float3x4 CandidateObjectToWorld3x4()", "Candidate object-to-world matrix.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateObjectToWorld4x3", "float4x3 CandidateObjectToWorld4x3()", "Candidate object-to-world matrix, transposed.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateWorldToObject3x4", "float3x4 CandidateWorldToObject3x4()", "Candidate world-to-object matrix.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateWorldToObject4x3", "float4x3 CandidateWorldToObject4x3()", "Candidate world-to-object matrix, transposed.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateTriangleBarycentrics", "float2 CandidateTriangleBarycentrics()", "Barycentrics of the candidate triangle hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CandidateTriangleFrontFace", "bool CandidateTriangleFrontFace()", "Whether the candidate triangle hit is front-facing.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommitNonOpaqueTriangleHit", "void CommitNonOpaqueTriangleHit()", "Commits the current non-opaque triangle candidate.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommitProceduralPrimitiveHit", "void CommitProceduralPrimitiveHit( float tHit )", "Commits a procedural-primitive hit at tHit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedStatus", "COMMITTED_STATUS CommittedStatus()", "COMMITTED_NOTHING, COMMITTED_TRIANGLE_HIT or COMMITTED_PROCEDURAL_PRIMITIVE_HIT.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedRayT", "float CommittedRayT()", "T of the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedInstanceIndex", "uint CommittedInstanceIndex()", "Instance index of the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedInstanceID", "uint CommittedInstanceID()", "User instance ID of the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedInstanceContributionToHitGroupIndex", "uint CommittedInstanceContributionToHitGroupIndex()", "Hit-group contribution of the committed instance.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedGeometryIndex", "uint CommittedGeometryIndex()", "Geometry index of the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedPrimitiveIndex", "uint CommittedPrimitiveIndex()", "Primitive index of the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedObjectRayOrigin", "float3 CommittedObjectRayOrigin()", "Object-space ray origin for the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedObjectRayDirection", "float3 CommittedObjectRayDirection()", "Object-space ray direction for the committed hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedObjectToWorld3x4", "float3x4 CommittedObjectToWorld3x4()", "Committed object-to-world matrix.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedObjectToWorld4x3", "float4x3 CommittedObjectToWorld4x3()", "Committed object-to-world matrix, transposed.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedWorldToObject3x4", "float3x4 CommittedWorldToObject3x4()", "Committed world-to-object matrix.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedWorldToObject4x3", "float4x3 CommittedWorldToObject4x3()", "Committed world-to-object matrix, transposed.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedTriangleBarycentrics", "float2 CommittedTriangleBarycentrics()", "Barycentrics of the committed triangle hit.", ShaderModel.Sm6_5, StageMask.None );
		M( "CommittedTriangleFrontFace", "bool CommittedTriangleFrontFace()", "Whether the committed triangle hit is front-facing.", ShaderModel.Sm6_5, StageMask.None );
	}

	private static void BuildObjectTypes()
	{
		string[] srvTexture2D =
		{
			"GetDimensions", "Load", "Sample", "SampleBias", "SampleLevel", "SampleGrad", "SampleCmp",
			"SampleCmpLevelZero", "SampleCmpLevel", "CalculateLevelOfDetail", "CalculateLevelOfDetailUnclamped",
			"Gather", "GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha",
			"GatherCmp", "GatherCmpRed", "GatherCmpGreen", "GatherCmpBlue", "GatherCmpAlpha", "mips"
		};

		string[] srvTextureNoGather =
		{
			"GetDimensions", "Load", "Sample", "SampleBias", "SampleLevel", "SampleGrad", "SampleCmp",
			"SampleCmpLevelZero", "CalculateLevelOfDetail", "CalculateLevelOfDetailUnclamped", "mips"
		};

		string[] cubeMethods =
		{
			"GetDimensions", "Sample", "SampleBias", "SampleLevel", "SampleGrad", "SampleCmp",
			"SampleCmpLevelZero", "CalculateLevelOfDetail", "CalculateLevelOfDetailUnclamped",
			"Gather", "GatherRed", "GatherGreen", "GatherBlue", "GatherAlpha", "GatherCmp"
		};

		string[] msMethods = { "GetDimensions", "Load", "GetSamplePosition", "sample" };
		string[] rwTexture = { "GetDimensions" };
		string[] bufferMethods = { "Load", "GetDimensions" };
		string[] byteAddress = { "Load", "Load2", "Load3", "Load4", "GetDimensions" };
		string[] rwByteAddress = { "Load", "Load2", "Load3", "Load4", "Store", "Store2", "Store3", "Store4", "GetDimensions" };
		string[] structured = { "Load", "GetDimensions" };
		string[] rwStructured = { "Load", "GetDimensions", "IncrementCounter", "DecrementCounter" };
		string[] patch = { "Length" };
		string[] stream = { "Append", "RestartStrip" };
		string[] feedback = { "WriteSamplerFeedback", "WriteSamplerFeedbackBias", "WriteSamplerFeedbackGrad", "WriteSamplerFeedbackLevel" };

		string[] rayQuery =
		{
			"TraceRayInline", "Proceed", "Abort", "CandidateType", "CandidateProceduralPrimitiveNonOpaque",
			"CandidateTriangleRayT", "CandidateInstanceIndex", "CandidateInstanceID",
			"CandidateInstanceContributionToHitGroupIndex", "CandidateGeometryIndex", "CandidatePrimitiveIndex",
			"CandidateObjectRayOrigin", "CandidateObjectRayDirection", "CandidateObjectToWorld3x4",
			"CandidateObjectToWorld4x3", "CandidateWorldToObject3x4", "CandidateWorldToObject4x3",
			"CandidateTriangleBarycentrics", "CandidateTriangleFrontFace", "CommitNonOpaqueTriangleHit",
			"CommitProceduralPrimitiveHit", "CommittedStatus", "CommittedRayT", "CommittedInstanceIndex",
			"CommittedInstanceID", "CommittedInstanceContributionToHitGroupIndex", "CommittedGeometryIndex",
			"CommittedPrimitiveIndex", "CommittedObjectRayOrigin", "CommittedObjectRayDirection",
			"CommittedObjectToWorld3x4", "CommittedObjectToWorld4x3", "CommittedWorldToObject3x4",
			"CommittedWorldToObject4x3", "CommittedTriangleBarycentrics", "CommittedTriangleFrontFace"
		};

		O( "Buffer", 1, "A typed shader-resource buffer of scalars or vectors.", Sm4, false, false, bufferMethods );
		O( "RWBuffer", 1, "A writable typed buffer.", Sm5, true, false, bufferMethods );
		O( "ByteAddressBuffer", 0, "A raw shader-resource buffer addressed in bytes; addresses must be a multiple of four.", Sm5, false, false, byteAddress );
		O( "RWByteAddressBuffer", 0, "A writable raw buffer with atomics.", Sm5, true, false, rwByteAddress );
		O( "StructuredBuffer", 1, "A shader-resource buffer of structs.", Sm5, false, false, structured );
		O( "RWStructuredBuffer", 1, "A writable structured buffer with a hidden counter.", Sm5, true, false, rwStructured );
		O( "AppendStructuredBuffer", 1, "A structured buffer written through Append.", Sm5, true, false, "Append", "GetDimensions" );
		O( "ConsumeStructuredBuffer", 1, "A structured buffer read through Consume.", Sm5, true, false, "Consume", "GetDimensions" );

		O( "Texture1D", 1, "A one-dimensional texture.", Sm4, false, false, srvTextureNoGather );
		O( "Texture1DArray", 1, "An array of one-dimensional textures.", Sm4, false, false, srvTextureNoGather );
		O( "Texture2D", 1, "A two-dimensional texture. The default element type is float4.", Sm4, false, false, srvTexture2D );
		O( "Texture2DArray", 1, "An array of two-dimensional textures.", Sm4, false, false, srvTexture2D );
		O( "Texture2DMS", 2, "A multisampled two-dimensional texture; the second template argument is the sample count.", Sm4, false, false, msMethods );
		O( "Texture2DMSArray", 2, "An array of multisampled two-dimensional textures.", Sm4, false, false, msMethods );
		O( "Texture3D", 1, "A volume texture.", Sm4, false, false, srvTextureNoGather );
		O( "TextureCube", 1, "A cube texture.", Sm4, false, false, cubeMethods );
		O( "TextureCubeArray", 1, "An array of cube textures.", Sm4_1, false, false, cubeMethods );

		O( "RWTexture1D", 1, "A writable one-dimensional texture.", Sm5, true, false, rwTexture );
		O( "RWTexture1DArray", 1, "A writable array of one-dimensional textures.", Sm5, true, false, rwTexture );
		O( "RWTexture2D", 1, "A writable two-dimensional texture.", Sm5, true, false, rwTexture );
		O( "RWTexture2DArray", 1, "A writable array of two-dimensional textures.", Sm5, true, false, rwTexture );
		O( "RWTexture3D", 1, "A writable volume texture.", Sm5, true, false, rwTexture );
		O( "RWTexture2DMS", 2, "A writable multisampled texture.", ShaderModel.Sm6_7, true, false, msMethods );
		O( "RWTexture2DMSArray", 2, "A writable array of multisampled textures.", ShaderModel.Sm6_7, true, false, msMethods );

		O( "RasterizerOrderedBuffer", 1, "A rasterizer-ordered typed buffer.", Sm5_1, true, false, bufferMethods );
		O( "RasterizerOrderedByteAddressBuffer", 0, "A rasterizer-ordered raw buffer.", Sm5_1, true, false, rwByteAddress );
		O( "RasterizerOrderedStructuredBuffer", 1, "A rasterizer-ordered structured buffer.", Sm5_1, true, false, rwStructured );
		O( "RasterizerOrderedTexture1D", 1, "A rasterizer-ordered one-dimensional texture.", Sm5_1, true, false, rwTexture );
		O( "RasterizerOrderedTexture1DArray", 1, "A rasterizer-ordered one-dimensional texture array.", Sm5_1, true, false, rwTexture );
		O( "RasterizerOrderedTexture2D", 1, "A rasterizer-ordered two-dimensional texture.", Sm5_1, true, false, rwTexture );
		O( "RasterizerOrderedTexture2DArray", 1, "A rasterizer-ordered two-dimensional texture array.", Sm5_1, true, false, rwTexture );
		O( "RasterizerOrderedTexture3D", 1, "A rasterizer-ordered volume texture.", Sm5_1, true, false, rwTexture );

		O( "SamplerState", 0, "Filtering and addressing state for a texture sample.", Sm4, false, false );
		O( "SamplerComparisonState", 0, "Filtering, addressing and comparison state for shadow-map sampling.", Sm4, false, false );

		O( "ConstantBuffer", 1, "A constant buffer view over a struct.", Sm5_1, false, false );
		O( "TextureBuffer", 1, "A texture buffer view over a struct.", Sm5_1, false, false );

		O( "InputPatch", 2, "The control points a hull shader reads. s&box rejects hull programs.", Sm5, false, false, patch );
		O( "OutputPatch", 2, "The control points a hull shader writes. s&box rejects hull programs.", Sm5, false, false, patch );
		O( "PointStream", 1, "A geometry-shader point output stream.", Sm4, true, false, stream );
		O( "LineStream", 1, "A geometry-shader line output stream.", Sm4, true, false, stream );
		O( "TriangleStream", 1, "A geometry-shader triangle output stream.", Sm4, true, false, stream );

		O( "RaytracingAccelerationStructure", 0, "A top- or bottom-level acceleration structure.", ShaderModel.Sm6_3, false, false );
		O( "RayQuery", 2, "Inline ray tracing state; template arguments are the ray flags and query flags.", ShaderModel.Sm6_5, false, false, rayQuery );
		O( "FeedbackTexture2D", 1, "A sampler-feedback map for a two-dimensional texture.", ShaderModel.Sm6_5, true, false, feedback );
		O( "FeedbackTexture2DArray", 1, "A sampler-feedback map for a two-dimensional texture array.", ShaderModel.Sm6_5, true, false, feedback );

		O( "sampler", 0, "Direct3D 9 sampler. DXC and Shader Model 6 removed it — declare a Texture and a SamplerState instead.", Sm1, false, true );
		O( "sampler1D", 0, "Direct3D 9 one-dimensional sampler. Removed by DXC.", Sm1, false, true );
		O( "sampler2D", 0, "Direct3D 9 two-dimensional sampler. Removed by DXC.", Sm1, false, true );
		O( "sampler3D", 0, "Direct3D 9 volume sampler. Removed by DXC.", Sm1, false, true );
		O( "samplerCUBE", 0, "Direct3D 9 cube sampler. Removed by DXC.", Sm1, false, true );
		O( "texture", 0, "Direct3D 9 texture. Removed by DXC.", Sm1, false, true );
	}

	private static void BuildSemantics()
	{
		const StageMask all = StageMask.All;
		const StageMask vs = StageMask.Vertex;
		const StageMask ps = StageMask.Pixel;
		const StageMask gs = StageMask.Geometry;
		const StageMask cs = StageMask.Compute;

		// Legacy / user semantics.
		S( "BINORMAL", false, true, "float4", "Binormal vertex stream.", Sm1, vs );
		S( "BLENDINDICES", false, true, "uint4", "Skinning bone indices.", Sm1, vs );
		S( "BLENDWEIGHT", false, true, "float4", "Skinning bone weights.", Sm1, vs );
		S( "COLOR", false, true, "float4", "Diffuse or specular colour. DXC treats it as a user semantic, not SV_Target.", Sm1, all );
		S( "NORMAL", false, true, "float4", "Normal vector vertex stream.", Sm1, vs );
		S( "POSITION", false, true, "float4", "Object-space vertex position. DXC treats it as a user semantic, not SV_Position.", Sm1, vs );
		S( "POSITIONT", false, false, "float4", "Pre-transformed vertex position.", Sm1, vs );
		S( "PSIZE", false, true, "float", "Point size.", Sm1, vs );
		S( "TANGENT", false, true, "float4", "Tangent vertex stream.", Sm1, vs );
		S( "TEXCOORD", false, true, "float4", "Texture coordinates. In s&box, TEXCOORD0-7 and 11 are taken; 13 and up are free for custom interpolators.", Sm1, all );
		S( "FOG", false, false, "float", "Legacy per-vertex fog factor.", Sm1, vs );
		S( "TESSFACTOR", false, true, "float", "Legacy tessellation factor.", Sm1, vs );
		S( "DEPTH", false, true, "float", "Legacy pixel-shader depth output. Use SV_Depth.", Sm1, ps );
		S( "VFACE", false, false, "float", "Legacy back-face flag. Use SV_IsFrontFace.", Sm1, ps );
		S( "VPOS", false, false, "float2", "Legacy screen-space pixel location. Use SV_Position.", Sm1, ps );

		// System values.
		S( "SV_ClipDistance", true, true, "float", "Signed distance to a user clip plane; rasterisation only happens where the interpolated distance is at least zero.", Sm4, all );
		S( "SV_CullDistance", true, true, "float", "Signed distance to a user cull plane; a primitive is discarded when every vertex is negative.", Sm4, all );
		S( "SV_Coverage", true, false, "uint", "The MSAA coverage mask. Output needs ps_4_1, input needs ps_5_0.", Sm4_1, ps );
		S( "SV_Depth", true, false, "float", "Pixel-shader depth output.", Sm4, ps );
		S( "SV_DepthGreaterEqual", true, false, "float", "Depth output constrained to be at least the rasteriser value, so early-Z stays enabled.", Sm5, ps );
		S( "SV_DepthLessEqual", true, false, "float", "Depth output constrained to be at most the rasteriser value, so early-Z stays enabled.", Sm5, ps );
		S( "SV_DispatchThreadID", true, false, "uint3", "Global thread offset within the dispatch.", Sm5, cs );
		S( "SV_DomainLocation", true, false, "float3", "Location on the patch being evaluated. Domain shader only; s&box rejects domain programs.", Sm5, StageMask.None );
		S( "SV_GroupID", true, false, "uint3", "Group offset within the dispatch.", Sm5, cs );
		S( "SV_GroupIndex", true, false, "uint", "Flattened index of a thread within its group.", Sm5, cs );
		S( "SV_GroupThreadID", true, false, "uint3", "Thread offset within its group.", Sm5, cs );
		S( "SV_GSInstanceID", true, false, "uint", "Geometry-shader instance index; a geometry shader may be invoked up to 32 times per primitive.", Sm5, gs );
		S( "SV_InnerCoverage", true, false, "uint", "Underestimated conservative-rasterisation coverage.", ShaderModel.Sm6_0, ps );
		S( "SV_InsideTessFactor", true, false, "float", "Tessellation amount inside a patch. Hull and domain only; s&box rejects both.", Sm5, StageMask.None );
		S( "SV_InstanceID", true, false, "uint", "Per-instance identifier generated by the runtime.", Sm4, all );
		S( "SV_IsFrontFace", true, false, "bool", "Whether the triangle is front-facing.", Sm4, ps );
		S( "SV_OutputControlPointID", true, false, "uint", "Control point index inside a hull shader. s&box rejects hull programs.", Sm5, StageMask.None );
		S( "SV_Position", true, false, "float4", "Clip-space position on output; the pixel centre, offset by 0.5, on pixel-shader input.", Sm4, all );
		S( "SV_PrimitiveID", true, false, "uint", "Per-primitive identifier generated by the runtime.", Sm4, gs | ps );
		S( "SV_RenderTargetArrayIndex", true, false, "uint", "Render-target array slice for the primitive.", Sm4, gs | ps );
		S( "SV_SampleIndex", true, false, "uint", "Sample-frequency index; forces per-sample shading.", Sm5, ps );
		S( "SV_StencilRef", true, false, "uint", "Pixel-shader stencil reference output.", ShaderModel.Sm6_0, ps );
		S( "SV_Target", true, true, "float4", "The value written to render target n, where n is 0 to 7.", Sm4, ps );
		S( "SV_TessFactor", true, false, "float", "Tessellation amount on each patch edge. Hull and domain only; s&box rejects both.", Sm5, StageMask.None );
		S( "SV_VertexID", true, false, "uint", "Per-vertex identifier generated by the runtime.", Sm4, vs );
		S( "SV_ViewportArrayIndex", true, false, "uint", "Viewport index for the primitive being written out.", Sm4, gs | ps );
		S( "SV_ShadingRate", true, false, "uint", "Variable-rate-shading rate written from the vertex or geometry stage and read by the pixel stage.", ShaderModel.Sm6_4, vs | gs | ps );
		S( "SV_Barycentrics", true, false, "float3", "Barycentric weights of the pixel within its triangle; pairs with GetAttributeAtVertex.", ShaderModel.Sm6_1, ps );
		S( "SV_ViewID", true, false, "uint", "View index for view instancing.", ShaderModel.Sm6_1, all );
		S( "SV_CullPrimitive", true, false, "bool", "Per-primitive cull flag in a mesh shader.", ShaderModel.Sm6_5, StageMask.None );
		S( "SV_StartVertexLocation", true, false, "int", "The BaseVertexLocation of the draw.", ShaderModel.Sm6_8, vs );
		S( "SV_StartInstanceLocation", true, false, "uint", "The StartInstanceLocation of the draw.", ShaderModel.Sm6_8, vs );
		S( "SV_DispatchGrid", true, false, "uint3", "Work-graph dispatch grid carried in a record.", ShaderModel.Sm6_8, StageMask.None );
	}
}