protected bool TryDiscoverStructure(string setName, string name, out StructureDefinition sd) { ITypeSymbol type = Compilation.FindTypeByMetadataName(name); if (type == null) { sd = null; return(false); // throw new ShaderGenerationException("Unable to obtain compilation type metadata for " + name); } else if (type.OriginalDefinition.DeclaringSyntaxReferences.Length == 0) { if (TryReflectStructure(setName, type, out sd)) { AddStructure(setName, sd); return(true); } } else { SyntaxNode declaringSyntax = type.OriginalDefinition.DeclaringSyntaxReferences[0].GetSyntax(); if (declaringSyntax is StructDeclarationSyntax sds) { if (ShaderSyntaxWalker.TryGetStructDefinition(Compilation.GetSemanticModel(sds.SyntaxTree), sds, out sd)) { AddStructure(setName, sd); return(true); } } } sd = null; return(false); }
protected void WriteStructure(StringBuilder sb, StructureDefinition sd) { bool fragmentSemantics = sd.Name.EndsWith(FragmentSemanticsSuffix); sb.AppendLine($"struct {CSharpToShaderType(sd.Name)}"); sb.AppendLine("{"); HlslSemanticTracker tracker = new HlslSemanticTracker(); StringBuilder fb = new StringBuilder(); foreach (FieldDefinition field in sd.Fields) { fb.Append(CSharpToShaderType(field.Type.Name.Trim())); fb.Append(' '); fb.Append(CorrectIdentifier(field.Name.Trim())); int arrayCount = field.ArrayElementCount; if (arrayCount > 0) { fb.Append('['); fb.Append(arrayCount); fb.Append(']'); } fb.Append(HlslSemantic(field.SemanticType, fragmentSemantics, ref tracker)); fb.Append(';'); sb.Append(" "); sb.AppendLine(fb.ToString()); fb.Clear(); } sb.AppendLine("};"); sb.AppendLine(); }
protected void ValidateRequiredSemantics(string setName, ShaderFunction function, ShaderFunctionType type) { if (type == ShaderFunctionType.VertexEntryPoint) { StructureDefinition outputType = GetRequiredStructureType(setName, function.ReturnType); foreach (FieldDefinition field in outputType.Fields) { if (field.SemanticType == SemanticType.None) { throw new ShaderGenerationException("Function return type is missing semantics on field: " + field.Name); } } } if (type != ShaderFunctionType.Normal) { foreach (ParameterDefinition pd in function.Parameters) { StructureDefinition pType = GetRequiredStructureType(setName, pd.Type); foreach (FieldDefinition field in pType.Fields) { if (field.SemanticType == SemanticType.None) { throw new ShaderGenerationException( $"Function parameter {pd.Name}'s type is missing semantics on field: {field.Name}"); } } } } }
public int GetTypeSize(TypeReference tr) { if (s_knownTypeSizes.TryGetValue(tr.Name, out int ret)) { return(ret); } else if (tr.TypeInfo.Type.TypeKind == TypeKind.Enum) { string enumBaseType = ((INamedTypeSymbol)tr.TypeInfo.Type).EnumUnderlyingType.GetFullMetadataName(); if (s_knownTypeSizes.TryGetValue(enumBaseType, out int enumRet)) { return(enumRet); } else { throw new InvalidOperationException($"Unknown enum base type: {enumBaseType}"); } } else { StructureDefinition sd = GetStructureDefinition(tr); if (sd == null) { throw new InvalidOperationException("Unable to determine the size for type: " + tr.Name); } return(sd.Alignment.CSharpSize); } }
private bool TryReflectStructure(string setName, ITypeSymbol name, out StructureDefinition sd) { if (name.TypeKind == TypeKind.Struct) { var fields = name.GetMembers().OfType <IFieldSymbol>().Select(ReflectField).ToArray(); sd = new StructureDefinition(name, fields); return(true); } sd = null; return(false); }
public bool Matches(StructureDefinition sd) { if (ValueType.FixedSize > 0 && ValueType.TypeInfo is IArrayTypeSymbol array) { return(SymbolEqualityComparer.Default.Equals(sd.Type, array.ElementType)); } else { return(SymbolEqualityComparer.Default.Equals(sd.Type, ValueType.TypeInfo)); } }
internal virtual void AddStructure(string setName, StructureDefinition sd) { if (sd == null) { throw new ArgumentNullException(nameof(sd)); } List <StructureDefinition> structures = GetContext(setName).Structures; if (!structures.Any(old => old.Name == sd.Name)) { structures.Add(sd); } }
protected virtual StructureDefinition GetRequiredStructureType(string setName, TypeReference type) { StructureDefinition result = GetContext(setName).Structures.SingleOrDefault(sd => sd.Name == type.Name); if (result == null) { if (!TryDiscoverStructure(setName, type.Name, out result)) { throw new ShaderGenerationException("Type referred by was not discovered: " + type.Name); } } return(result); }
private void ValidateAlignedStruct(string setName, TypeReference tr) { StructureDefinition def = GetContext(setName).Structures.SingleOrDefault(sd => sd.Name == tr.Name); if (def != null) { if (!def.CSharpMatchesShaderAlignment) { throw new ShaderGenerationException( $"Structure type {tr.Name} cannot be used as a resource because its alignment is not consistent between C# and shader languages."); } foreach (FieldDefinition fd in def.Fields) { ValidateAlignedStruct(setName, fd.Type); } } }
internal void ForceTypeDiscovery(string setName, TypeReference tr, out StructureDefinition sd) { if (ShaderPrimitiveTypes.IsPrimitiveType(tr.Name)) { sd = null; return; } if (tr.TypeInfo.TypeKind == TypeKind.Enum) { INamedTypeSymbol enumBaseType = ((INamedTypeSymbol)tr.TypeInfo).EnumUnderlyingType; if (enumBaseType != null && enumBaseType.SpecialType != SpecialType.System_Int32 && enumBaseType.SpecialType != SpecialType.System_UInt32) { throw new ShaderGenerationException("Resource type's field had an invalid enum base type: " + enumBaseType.ToDisplayString()); } sd = null; return; } if (tr.TypeInfo is IArrayTypeSymbol arrayType) { ForceTypeDiscovery(setName, new TypeReference(arrayType.ElementType.GetFullMetadataName(), arrayType.ElementType), out sd); return; } ITypeSymbol type = tr.TypeInfo; string name = tr.Name; if (type is INamedTypeSymbol namedTypeSymb && namedTypeSymb.TypeArguments.Length == 1) { name = Utilities.GetFullTypeName(namedTypeSymb.TypeArguments[0], out _); } if (!TryDiscoverStructure(setName, name, out sd)) { throw new ShaderGenerationException("" + "Resource type's field could not be resolved: " + name); } foreach (FieldDefinition field in sd.Fields) { ForceTypeDiscovery(setName, field.Type); if (field.IsBuiltIn) { GetContext(setName).BuiltIns.Add(field); } } }
protected void ValidateRequiredSemantics(string setName, ShaderFunction function, ShaderFunctionType type) { StructureDefinition outputType = null; if (function.ReturnType.TypeInfo.TypeKind == TypeKind.Struct && function.ReturnType.TypeInfo.SpecialType != SpecialType.System_Void && !ShaderPrimitiveTypes.IsPrimitiveType(function.ReturnType.TypeInfo.GetFullMetadataName())) { outputType = GetRequiredStructureType(setName, function.ReturnType); } foreach (ParameterDefinition pd in function.Parameters) { GetRequiredStructureType(setName, pd.Type); } if (type == ShaderFunctionType.FragmentEntryPoint) { if (outputType != null) { foreach (FieldDefinition field in outputType.Fields) { if (field.SemanticType == SemanticType.None) { throw new ShaderGenerationException("Function return type is missing semantics on field: " + field.Name); } } } } else if (type == ShaderFunctionType.VertexEntryPoint) { foreach (ParameterDefinition pd in function.Parameters) { StructureDefinition pType = GetRequiredStructureType(setName, pd.Type); foreach (FieldDefinition field in pType.Fields) { if (field.SemanticType == SemanticType.None) { //throw new ShaderGenerationException( // $"Function parameter {pd.Name}'s type is missing semantics on field: {field.Name}"); } } } } }
private static void Traverse( Compilation compilation, List <StructureDefinition> allDefs, StructureDefinition current, List <StructureDefinition> results) { foreach (FieldDefinition field in current.Fields) { StructureDefinition fieldTypeDef = allDefs.SingleOrDefault(sd => sd.Name == field.Type.Name); if (fieldTypeDef != null) { Traverse(compilation, allDefs, fieldTypeDef, results); } } if (!results.Contains(current)) { results.Add(current); } }
private StructureDefinition CreateOutputStructure(string setName, StructureDefinition sd) { if (sd.Name.EndsWith(FragmentSemanticsSuffix)) { return(sd); } string newName = sd.Name + FragmentSemanticsSuffix; List <StructureDefinition> synthesizedStructures = GetSynthesizedStructures(setName); StructureDefinition existing = synthesizedStructures.SingleOrDefault(ssd => ssd.Name == newName); if (existing != null) { return(existing); } StructureDefinition clone = new StructureDefinition(newName, sd.Fields); synthesizedStructures.Add(clone); return(clone); }
public static bool TryGetStructDefinition(SemanticModel model, StructDeclarationSyntax node, out StructureDefinition sd) { string fullNestedTypePrefix = Utilities.GetFullNestedTypePrefix(node, out bool nested); string structName = node.Identifier.ToFullString().Trim(); if (!string.IsNullOrEmpty(fullNestedTypePrefix)) { string joiner = nested ? "+" : "."; structName = fullNestedTypePrefix + joiner + structName; } List <FieldDefinition> fields = new List <FieldDefinition>(); foreach (MemberDeclarationSyntax member in node.Members) { if (member is FieldDeclarationSyntax fds && !fds.Modifiers.Any(x => x.IsKind(SyntaxKind.ConstKeyword))) { VariableDeclarationSyntax varDecl = fds.Declaration; foreach (VariableDeclaratorSyntax vds in varDecl.Variables) { string fieldName = vds.Identifier.Text.Trim(); string typeName = model.GetFullTypeName(varDecl.Type, out bool isArray); int arrayElementCount = 0; if (isArray) { arrayElementCount = GetArrayCountValue(vds, model); } TypeReference tr = new TypeReference(typeName, model.GetTypeInfo(varDecl.Type)); SemanticType semanticType = GetSemanticType(vds); fields.Add(new FieldDefinition(fieldName, tr, semanticType, arrayElementCount)); } } } sd = new StructureDefinition(structName.Trim(), fields.ToArray()); return(true); }
public int GetTypeSize(TypeReference tr) { if (s_knownTypeSizes.TryGetValue(tr.Name, out int ret)) { return(ret); } else { StructureDefinition sd = GetStructureDefinition(tr); int totalSize = 0; foreach (FieldDefinition fd in sd.Fields) { totalSize += GetTypeSize(fd.Type); } if (totalSize == 0) { throw new InvalidOperationException("Unable to determine the size fo type: " + tr.Name); } return(totalSize); } }
protected void WriteStructure(StringBuilder sb, StructureDefinition sd) { sb.AppendLine($"struct {CSharpToShaderType(sd.Name)}"); sb.AppendLine("{"); StringBuilder fb = new StringBuilder(); foreach (FieldDefinition field in sd.Fields) { fb.Append(CSharpToShaderType(field.Type.Name.Trim())); fb.Append(' '); fb.Append(CorrectIdentifier(field.Name.Trim())); int arrayCount = field.ArrayElementCount; if (arrayCount > 0) { fb.Append('['); fb.Append(arrayCount); fb.Append(']'); } fb.Append(';'); sb.Append(" "); sb.AppendLine(fb.ToString()); fb.Clear(); } sb.AppendLine("};"); sb.AppendLine(); }
public static bool TryGetStructDefinition(SemanticModel model, StructDeclarationSyntax node, out StructureDefinition sd) { //string fullNestedTypePrefix = Utilities.GetFullNestedTypePrefix(node, out bool nested); //string structName = node.Identifier.ToFullString().Trim(); //if (!string.IsNullOrEmpty(fullNestedTypePrefix)) //{ // string joiner = nested ? "+" : "."; // structName = fullNestedTypePrefix + joiner + structName; //} int structCSharpSize = 0; int structShaderSize = 0; int structCSharpAlignment = 0; int structShaderAlignment = 0; List <FieldDefinition> fields = new List <FieldDefinition>(); foreach (MemberDeclarationSyntax member in node.Members) { if (member is FieldDeclarationSyntax fds && !fds.Modifiers.Any(x => x.IsKind(SyntaxKind.ConstKeyword))) { VariableDeclarationSyntax varDecl = fds.Declaration; foreach (VariableDeclaratorSyntax vds in varDecl.Variables) { string fieldName = vds.Identifier.Text.Trim(); string typeName = model.GetFullTypeName(varDecl.Type, out bool isArray); int arrayElementCount = 0; if (isArray) { arrayElementCount = GetArrayCountValue(vds, model); } TypeInfo typeInfo = model.GetTypeInfo(varDecl.Type); AlignmentInfo fieldSizeAndAlignment; int fixedSize = 1; if (typeInfo.Type.Kind == SymbolKind.ArrayType) { var arraySize = fds.DescendantNodes().OfType <AttributeSyntax>().FirstOrDefault( attrSyntax => attrSyntax.Name.ToString().EndsWith("ArraySize")); fixedSize = (int)model.GetConstantValue(arraySize.ArgumentList.Arguments.First().Expression).Value; ITypeSymbol elementType = ((IArrayTypeSymbol)typeInfo.Type).ElementType; AlignmentInfo elementSizeAndAlignment = TypeSizeCache.Get(elementType); fieldSizeAndAlignment = new AlignmentInfo( elementSizeAndAlignment.CSharpSize * arrayElementCount, elementSizeAndAlignment.ShaderSize * arrayElementCount, elementSizeAndAlignment.CSharpAlignment, elementSizeAndAlignment.ShaderAlignment); } else { fieldSizeAndAlignment = TypeSizeCache.Get(typeInfo.Type); } structCSharpSize += structCSharpSize % fieldSizeAndAlignment.CSharpAlignment; structCSharpSize += fieldSizeAndAlignment.CSharpSize; structCSharpAlignment = Math.Max(structCSharpAlignment, fieldSizeAndAlignment.CSharpAlignment); structShaderSize += structShaderSize % fieldSizeAndAlignment.ShaderAlignment; structShaderSize += fieldSizeAndAlignment.ShaderSize; structShaderAlignment = Math.Max(structShaderAlignment, fieldSizeAndAlignment.ShaderAlignment); TypeReference tr = new TypeReference(typeName, model.GetTypeInfo(varDecl.Type).Type, fixedSize); SemanticType semanticType = GetSemanticType(vds); if (semanticType == SemanticType.None) { var geometrySemantic = GetGeometrySemantic(vds); if (geometrySemantic != GeometrySemantic.None) { fields.Add(new FieldDefinition(fieldName, tr, geometrySemantic, arrayElementCount, fieldSizeAndAlignment)); continue; } } fields.Add(new FieldDefinition(fieldName, tr, semanticType, arrayElementCount, fieldSizeAndAlignment)); } } } var type = model.GetDeclaredSymbol(node); sd = new StructureDefinition( type, fields.ToArray(), new AlignmentInfo(structCSharpSize, structShaderSize, structCSharpAlignment, structShaderAlignment)); return(true); }
protected override string GenerateFullTextCore(string setName, ShaderFunction function) { BackendContext context = GetContext(setName); StringBuilder sb = new StringBuilder(); ShaderFunctionAndBlockSyntax entryPoint = context.Functions.SingleOrDefault( sfabs => sfabs.Function.Name == function.Name); if (entryPoint == null) { throw new ShaderGenerationException("Couldn't find given function: " + function.Name); } ValidateRequiredSemantics(setName, entryPoint.Function, function.Type); StructureDefinition input = GetRequiredStructureType(setName, entryPoint.Function.Parameters[0].Type); WriteVersionHeader(sb); StructureDefinition[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, context.Structures); foreach (StructureDefinition sd in orderedStructures) { WriteStructure(sb, sd); } foreach (ResourceDefinition rd in context.Resources) { switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: WriteUniform(sb, rd); break; case ShaderResourceKind.Texture2D: WriteTexture2D(sb, rd); break; case ShaderResourceKind.TextureCube: WriteTextureCube(sb, rd); break; case ShaderResourceKind.Sampler: WriteSampler(sb, rd); break; default: throw new ShaderGenerationException("Illegal resource kind: " + rd.ResourceKind); } } FunctionCallGraphDiscoverer fcgd = new FunctionCallGraphDiscoverer( Compilation, new TypeAndMethodName { TypeName = function.DeclaringType, MethodName = function.Name }); fcgd.GenerateFullGraph(); TypeAndMethodName[] orderedFunctionList = fcgd.GetOrderedCallList(); foreach (TypeAndMethodName name in orderedFunctionList) { ShaderFunctionAndBlockSyntax f = context.Functions.Single( sfabs => sfabs.Function.DeclaringType == name.TypeName && sfabs.Function.Name == name.MethodName); if (!f.Function.IsEntryPoint) { sb.AppendLine(new ShaderMethodVisitor(Compilation, setName, f.Function, this).VisitFunction(f.Block)); } } string result = new ShaderMethodVisitor(Compilation, setName, entryPoint.Function, this) .VisitFunction(entryPoint.Block); sb.AppendLine(result); WriteMainFunction(setName, sb, entryPoint.Function); return(sb.ToString()); }
private void WriteMainFunction(string setName, StringBuilder sb, ShaderFunction entryFunction) { ParameterDefinition input = entryFunction.Parameters[0]; StructureDefinition inputType = GetRequiredStructureType(setName, input.Type); StructureDefinition outputType = entryFunction.Type == ShaderFunctionType.VertexEntryPoint ? GetRequiredStructureType(setName, entryFunction.ReturnType) : null; // Hacky but meh // Declare "in" variables int inVarIndex = 0; string fragCoordName = null; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.FragmentEntryPoint && fragCoordName == null && field.SemanticType == SemanticType.Position) { fragCoordName = field.Name; } else { WriteInOutVariable( sb, true, entryFunction.Type == ShaderFunctionType.VertexEntryPoint, CSharpToShaderType(field.Type.Name), CorrectIdentifier(field.Name), inVarIndex); inVarIndex += 1; } } string mappedReturnType = CSharpToShaderType(entryFunction.ReturnType.Name); // Declare "out" variables if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { bool skippedFirstPositionSemantic = false; int outVarIndex = 0; foreach (FieldDefinition field in outputType.Fields) { if (field.SemanticType == SemanticType.Position && !skippedFirstPositionSemantic) { skippedFirstPositionSemantic = true; continue; } else { WriteInOutVariable( sb, false, true, CSharpToShaderType(field.Type.Name), "out_" + CorrectIdentifier(field.Name), outVarIndex); outVarIndex += 1; } } } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint); if (mappedReturnType != "vec4" && mappedReturnType != "void") { throw new ShaderGenerationException("Fragment shader must return a System.Numerics.Vector4 value, or no value."); } if (mappedReturnType == "vec4") { WriteInOutVariable(sb, false, false, "vec4", "_outputColor_", 0); } } sb.AppendLine(); string inTypeName = CSharpToShaderType(inputType.Name); sb.AppendLine($"void main()"); sb.AppendLine("{"); sb.AppendLine($" {inTypeName} {CorrectIdentifier("input")};"); // Assign synthetic "in" variables (with real field name) to structure passed to actual function. int inoutIndex = 0; bool foundSystemPosition = false; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = {CorrectIdentifier(field.Name)};"); } else { if (field.SemanticType == SemanticType.Position && !foundSystemPosition) { Debug.Assert(field.Name == fragCoordName); foundSystemPosition = true; sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = gl_FragCoord;"); } else { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = fsin_{inoutIndex++};"); } } } // Call actual function. if (mappedReturnType != "void") { sb.AppendLine($" {mappedReturnType} {CorrectIdentifier("output")} = {entryFunction.Name}({CorrectIdentifier("input")});"); } else { sb.Append($" {entryFunction.Name}({CorrectIdentifier("input")});"); } // Assign output fields to synthetic "out" variables with normalized "fsin_#" names. if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { inoutIndex = 0; FieldDefinition positionSemanticField = null; foreach (FieldDefinition field in outputType.Fields) { if (positionSemanticField == null && field.SemanticType == SemanticType.Position) { positionSemanticField = field; } else { sb.AppendLine($" fsin_{inoutIndex++} = {CorrectIdentifier("output")}.{CorrectIdentifier(field.Name)};"); } } if (positionSemanticField == null) { // TODO: Should be caught earlier. throw new ShaderGenerationException("At least one vertex output must have a position semantic."); } sb.AppendLine($" gl_Position = {CorrectIdentifier("output")}.{CorrectIdentifier(positionSemanticField.Name)};"); EmitGlPositionCorrection(sb); } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint); if (mappedReturnType == "vec4") { sb.AppendLine($" _outputColor_ = {CorrectIdentifier("output")};"); } } sb.AppendLine("}"); }
protected override string GenerateFullTextCore(string setName, ShaderFunction function) { Debug.Assert(function.IsEntryPoint); StringBuilder sb = new StringBuilder(); BackendContext setContext = GetContext(setName); ShaderFunctionAndBlockSyntax entryPoint = setContext.Functions.SingleOrDefault( sfabs => sfabs.Function.Name == function.Name); if (entryPoint == null) { throw new ShaderGenerationException("Couldn't find given function: " + function.Name); } ValidateRequiredSemantics(setName, entryPoint.Function, function.Type); StructureDefinition input = GetRequiredStructureType(setName, entryPoint.Function.Parameters[0].Type); if (function.Type == ShaderFunctionType.VertexEntryPoint) { // HLSL vertex outputs needs to have semantics applied to the structure fields. StructureDefinition output = CreateOutputStructure(setName, GetRequiredStructureType(setName, entryPoint.Function.ReturnType)); setContext.Functions.Remove(entryPoint); entryPoint = entryPoint.WithReturnType(new TypeReference(output.Name)); setContext.Functions.Add(entryPoint); } if (function.Type == ShaderFunctionType.FragmentEntryPoint) { // HLSL pixel shader inputs also need these semantics. StructureDefinition modifiedInput = CreateOutputStructure(setName, input); setContext.Functions.Remove(entryPoint); entryPoint = entryPoint.WithParameter(0, new TypeReference(modifiedInput.Name)); setContext.Functions.Add(entryPoint); } StructureDefinition[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, setContext.Structures); foreach (StructureDefinition sd in orderedStructures) { WriteStructure(sb, sd); } foreach (StructureDefinition sd in GetSynthesizedStructures(setName)) { WriteStructure(sb, sd); } FunctionCallGraphDiscoverer fcgd = new FunctionCallGraphDiscoverer( Compilation, new TypeAndMethodName { TypeName = function.DeclaringType, MethodName = function.Name }); fcgd.GenerateFullGraph(); TypeAndMethodName[] orderedFunctionList = fcgd.GetOrderedCallList(); List <ResourceDefinition[]> resourcesBySet = setContext.Resources.GroupBy(rd => rd.Set) .Select(g => g.ToArray()).ToList(); int uniformBinding = 0, textureBinding = 0, samplerBinding = 0; int setIndex = 0; foreach (ResourceDefinition[] set in resourcesBySet) { Debug.Assert(set[0].Set == setIndex); setIndex += 1; foreach (ResourceDefinition rd in set) { switch (rd.ResourceKind) { case ShaderResourceKind.Uniform: WriteUniform(sb, rd, uniformBinding++); break; case ShaderResourceKind.Texture2D: WriteTexture2D(sb, rd, textureBinding++); break; case ShaderResourceKind.TextureCube: WriteTextureCube(sb, rd, textureBinding++); break; case ShaderResourceKind.Sampler: WriteSampler(sb, rd, samplerBinding++); break; default: throw new ShaderGenerationException("Illegal resource kind: " + rd.ResourceKind); } } } foreach (TypeAndMethodName name in orderedFunctionList) { ShaderFunctionAndBlockSyntax f = setContext.Functions.Single( sfabs => sfabs.Function.DeclaringType == name.TypeName && sfabs.Function.Name == name.MethodName); if (!f.Function.IsEntryPoint) { sb.AppendLine(new HlslMethodVisitor(Compilation, setName, f.Function, this).VisitFunction(f.Block)); } } string result = new HlslMethodVisitor(Compilation, setName, entryPoint.Function, this) .VisitFunction(entryPoint.Block); sb.AppendLine(result); return(sb.ToString()); }
private void WriteMainFunction(string setName, StringBuilder sb, ShaderFunction entryFunction) { ParameterDefinition input = entryFunction.Parameters[0]; StructureDefinition inputType = GetRequiredStructureType(setName, input.Type); StructureDefinition outputType = entryFunction.ReturnType.Name != "System.Numerics.Vector4" && entryFunction.ReturnType.Name != "System.Void" ? GetRequiredStructureType(setName, entryFunction.ReturnType) : null; // Declare "in" variables int inVarIndex = 0; string fragCoordName = null; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.FragmentEntryPoint && fragCoordName == null && field.SemanticType == SemanticType.SystemPosition) { fragCoordName = field.Name; } else { WriteInOutVariable( sb, true, entryFunction.Type == ShaderFunctionType.VertexEntryPoint, CSharpToShaderType(field.Type.Name), CorrectIdentifier(field.Name), inVarIndex); inVarIndex += 1; } } string mappedReturnType = CSharpToShaderType(entryFunction.ReturnType.Name); // Declare "out" variables if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { int outVarIndex = 0; foreach (FieldDefinition field in outputType.Fields) { if (field.SemanticType == SemanticType.SystemPosition) { continue; } else { WriteInOutVariable( sb, false, true, CSharpToShaderType(field.Type.Name), "out_" + CorrectIdentifier(field.Name), outVarIndex); outVarIndex += 1; } } } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint); if (mappedReturnType == "vec4") { WriteInOutVariable(sb, false, false, "vec4", "_outputColor_", 0); } else if (mappedReturnType != "void") { // Composite struct -- declare an out variable for each. int colorTargetIndex = 0; foreach (FieldDefinition field in outputType.Fields) { Debug.Assert(field.SemanticType == SemanticType.ColorTarget); Debug.Assert(field.Type.Name == "System.Numerics.Vector4"); int index = colorTargetIndex++; sb.AppendLine($" layout(location = {index}) out vec4 _outputColor_{index};"); } } } sb.AppendLine(); string inTypeName = CSharpToShaderType(inputType.Name); sb.AppendLine($"void main()"); sb.AppendLine("{"); sb.AppendLine($" {inTypeName} {CorrectIdentifier("input")};"); // Assign synthetic "in" variables (with real field name) to structure passed to actual function. int inoutIndex = 0; bool foundSystemPosition = false; foreach (FieldDefinition field in inputType.Fields) { if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = {CorrectIdentifier(field.Name)};"); } else { if (field.SemanticType == SemanticType.SystemPosition && !foundSystemPosition) { Debug.Assert(field.Name == fragCoordName); foundSystemPosition = true; sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = gl_FragCoord;"); } else { sb.AppendLine($" {CorrectIdentifier("input")}.{CorrectIdentifier(field.Name)} = fsin_{inoutIndex++};"); } } } // Call actual function. if (mappedReturnType != "void") { sb.AppendLine($" {mappedReturnType} {CorrectIdentifier("output")} = {entryFunction.Name}({CorrectIdentifier("input")});"); } else { sb.Append($" {entryFunction.Name}({CorrectIdentifier("input")});"); } // Assign output fields to synthetic "out" variables with normalized "fsin_#" names. if (entryFunction.Type == ShaderFunctionType.VertexEntryPoint) { inoutIndex = 0; FieldDefinition systemPositionField = null; foreach (FieldDefinition field in outputType.Fields) { if (systemPositionField == null && field.SemanticType == SemanticType.SystemPosition) { systemPositionField = field; } else { sb.AppendLine($" fsin_{inoutIndex++} = {CorrectIdentifier("output")}.{CorrectIdentifier(field.Name)};"); } } if (systemPositionField == null) { // TODO: Should be caught earlier. throw new ShaderGenerationException("Vertex functions must output a SystemPosition semantic."); } sb.AppendLine($" gl_Position = {CorrectIdentifier("output")}.{CorrectIdentifier(systemPositionField.Name)};"); EmitGlPositionCorrection(sb); } else { Debug.Assert(entryFunction.Type == ShaderFunctionType.FragmentEntryPoint); if (mappedReturnType == "vec4") { sb.AppendLine($" _outputColor_ = {CorrectIdentifier("output")};"); } else if (mappedReturnType != "void") { // Composite struct -- assign each field to output int colorTargetIndex = 0; foreach (FieldDefinition field in outputType.Fields) { Debug.Assert(field.SemanticType == SemanticType.ColorTarget); sb.AppendLine($" _outputColor_{colorTargetIndex++} = {CorrectIdentifier("output")}.{CorrectIdentifier(field.Name)};"); } } } sb.AppendLine("}"); }
public static bool TryGetStructDefinition(SemanticModel model, StructDeclarationSyntax node, out StructureDefinition sd) { string fullNestedTypePrefix = Utilities.GetFullNestedTypePrefix(node, out bool nested); string structName = node.Identifier.ToFullString().Trim(); if (!string.IsNullOrEmpty(fullNestedTypePrefix)) { string joiner = nested ? "+" : "."; structName = fullNestedTypePrefix + joiner + structName; } int structCSharpSize = 0; int structShaderSize = 0; int structCSharpAlignment = 0; int structShaderAlignment = 0; List <FieldDefinition> fields = new List <FieldDefinition>(); foreach (MemberDeclarationSyntax member in node.Members) { if (member is FieldDeclarationSyntax fds && !fds.Modifiers.Any(x => x.IsKind(SyntaxKind.ConstKeyword))) { VariableDeclarationSyntax varDecl = fds.Declaration; foreach (VariableDeclaratorSyntax vds in varDecl.Variables) { string fieldName = vds.Identifier.Text.Trim(); string typeName = model.GetFullTypeName(varDecl.Type, out bool isArray); int arrayElementCount = 0; if (isArray) { arrayElementCount = GetArrayCountValue(vds, model); } TypeInfo typeInfo = model.GetTypeInfo(varDecl.Type); AlignmentInfo fieldSizeAndAlignment; if (typeInfo.Type.Kind == SymbolKind.ArrayType) { ITypeSymbol elementType = ((IArrayTypeSymbol)typeInfo.Type).ElementType; AlignmentInfo elementSizeAndAlignment = TypeSizeCache.Get(elementType); fieldSizeAndAlignment = new AlignmentInfo( elementSizeAndAlignment.CSharpSize * arrayElementCount, elementSizeAndAlignment.ShaderSize * arrayElementCount, elementSizeAndAlignment.CSharpAlignment, elementSizeAndAlignment.ShaderAlignment); } else { fieldSizeAndAlignment = TypeSizeCache.Get(typeInfo.Type); } structCSharpSize += structCSharpSize % fieldSizeAndAlignment.CSharpAlignment; structCSharpSize += fieldSizeAndAlignment.CSharpSize; structCSharpAlignment = Math.Max(structCSharpAlignment, fieldSizeAndAlignment.CSharpAlignment); structShaderSize += structShaderSize % fieldSizeAndAlignment.ShaderAlignment; structShaderSize += fieldSizeAndAlignment.ShaderSize; structShaderAlignment = Math.Max(structShaderAlignment, fieldSizeAndAlignment.ShaderAlignment); TypeReference tr = new TypeReference(typeName, model.GetTypeInfo(varDecl.Type).Type); SemanticType semanticType = GetSemanticType(vds); fields.Add(new FieldDefinition(fieldName, tr, semanticType, arrayElementCount, fieldSizeAndAlignment)); } } } sd = new StructureDefinition( structName.Trim(), fields.ToArray(), new AlignmentInfo(structCSharpSize, structShaderSize, structCSharpAlignment, structShaderAlignment)); return(true); }