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}"); } } } } }
protected override void WriteVersionHeader(ShaderFunction function, StringBuilder sb) { string version = function.Type == ShaderFunctionType.ComputeEntryPoint ? "430" : "330 core"; sb.AppendLine($"#version {version}"); sb.AppendLine(); }
public override void VisitMethodDeclaration(MethodDeclarationSyntax node) { string functionName = node.Identifier.ToFullString(); List <ParameterDefinition> parameters = new List <ParameterDefinition>(); foreach (ParameterSyntax ps in node.ParameterList.Parameters) { parameters.Add(ParameterDefinition.GetParameterDefinition(_compilation, ps)); } TypeReference returnType = new TypeReference(GetModel(node).GetFullTypeName(node.ReturnType)); bool isVertexShader, isFragmentShader = false; isVertexShader = Utilities.GetMethodAttributes(node, "VertexShader").Any(); if (!isVertexShader) { isFragmentShader = Utilities.GetMethodAttributes(node, "FragmentShader").Any(); } ShaderFunctionType type = isVertexShader ? ShaderFunctionType.VertexEntryPoint : isFragmentShader ? ShaderFunctionType.FragmentEntryPoint : ShaderFunctionType.Normal; string nestedTypePrefix = Utilities.GetFullNestedTypePrefix(node, out bool nested); ShaderFunction sf = new ShaderFunction(nestedTypePrefix, functionName, returnType, parameters.ToArray(), type); ShaderFunctionAndBlockSyntax sfab = new ShaderFunctionAndBlockSyntax(sf, node.Body); foreach (LanguageBackend b in _backends) { b.AddFunction(_shaderSet.Name, sfab); } }
public override void VisitMethodDeclaration(MethodDeclarationSyntax node) { string functionName = node.Identifier.ToFullString(); List <ParameterDefinition> parameters = new List <ParameterDefinition>(); foreach (ParameterSyntax ps in node.ParameterList.Parameters) { parameters.Add(ParameterDefinition.GetParameterDefinition(_compilation, ps)); } TypeReference returnType = new TypeReference(GetModel(node).GetFullTypeName(node.ReturnType)); UInt3 computeGroupCounts = new UInt3(); bool isFragmentShader = false, isComputeShader = false; bool isVertexShader = Utilities.GetMethodAttributes(node, "VertexShader").Any(); if (!isVertexShader) { isFragmentShader = Utilities.GetMethodAttributes(node, "FragmentShader").Any(); } if (!isVertexShader && !isFragmentShader) { AttributeSyntax computeShaderAttr = Utilities.GetMethodAttributes(node, "ComputeShader").FirstOrDefault(); if (computeShaderAttr != null) { isComputeShader = true; computeGroupCounts.X = GetAttributeArgumentUIntValue(computeShaderAttr, 0); computeGroupCounts.Y = GetAttributeArgumentUIntValue(computeShaderAttr, 1); computeGroupCounts.Z = GetAttributeArgumentUIntValue(computeShaderAttr, 2); } } ShaderFunctionType type = isVertexShader ? ShaderFunctionType.VertexEntryPoint : isFragmentShader ? ShaderFunctionType.FragmentEntryPoint : isComputeShader ? ShaderFunctionType.ComputeEntryPoint : ShaderFunctionType.Normal; string nestedTypePrefix = Utilities.GetFullNestedTypePrefix(node, out bool nested); ShaderFunction sf = new ShaderFunction( nestedTypePrefix, functionName, returnType, parameters.ToArray(), type, computeGroupCounts); ShaderFunctionAndBlockSyntax sfab = new ShaderFunctionAndBlockSyntax(sf, node.Body); foreach (LanguageBackend b in _backends) { b.AddFunction(_shaderSet.Name, sfab); } }
public ShaderMethodVisitor( Compilation compilation, string setName, ShaderFunction shaderFunction, LanguageBackend backend) { _compilation = compilation; _setName = setName; _shaderFunction = shaderFunction; _backend = backend; }
public ShaderSetProcessorInput( string name, ShaderFunction vertexFunction, ShaderFunction fragmentFunction, ShaderModel model) { SetName = name; VertexFunction = vertexFunction; FragmentFunction = fragmentFunction; Model = model; }
private void GenerateShaders(ShaderSetInfo ss, ShaderGenerationResult result) { TypeAndMethodName vertexFunctionName = ss.VertexShader; TypeAndMethodName fragmentFunctionName = ss.FragmentShader; HashSet <SyntaxTree> treesToVisit = new HashSet <SyntaxTree>(); if (vertexFunctionName != null) { GetTrees(treesToVisit, vertexFunctionName.TypeName); } if (fragmentFunctionName != null) { GetTrees(treesToVisit, fragmentFunctionName.TypeName); } foreach (LanguageBackend language in _languages) { language.InitContext(ss.Name); } ShaderSyntaxWalker walker = new ShaderSyntaxWalker(_compilation, _languages.ToArray(), ss); foreach (SyntaxTree tree in treesToVisit) { walker.Visit(tree.GetRoot()); } foreach (LanguageBackend language in _languages) { ShaderModel model = language.GetShaderModel(ss.Name); ShaderFunction vsFunc = (ss.VertexShader != null) ? model.GetFunction(ss.VertexShader.FullName) : null; ShaderFunction fsFunc = (ss.FragmentShader != null) ? model.GetFunction(ss.FragmentShader.FullName) : null; { string vsCode = null; string fsCode = null; if (vsFunc != null) { vsCode = language.GetCode(ss.Name, vsFunc); } if (fsFunc != null) { fsCode = language.GetCode(ss.Name, fsFunc); } result.AddShaderSet(language, new GeneratedShaderSet(ss.Name, vsCode, fsCode, vsFunc, fsFunc, model)); } } }
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}"); } } } } }
public MethodProcessResult ProcessEntryFunction(string setName, ShaderFunction function) { if (function == null) { throw new ArgumentNullException(nameof(function)); } if (!_processedFunctions.TryGetValue(function, out MethodProcessResult result)) { if (!function.IsEntryPoint) { throw new ShaderGenerationException("Functions listed in a ShaderSet attribute must have either VertexFunction or FragmentFunction attributes."); } result = GenerateFullTextCore(setName, function); _processedFunctions.Add(function, result); } return(result); }
public GeneratedShaderSet( string name, string vsCode, string fsCode, ShaderFunction vertexfunction, ShaderFunction fragmentFunction, ShaderModel model) { if (string.IsNullOrEmpty(vsCode) && string.IsNullOrEmpty(fsCode)) { throw new ShaderGenerationException("At least one of vsCode or fsCode must be non-empty"); } Name = name; VertexShaderCode = vsCode; FragmentShaderCode = fsCode; VertexFunction = vertexfunction; FragmentFunction = fragmentFunction; Model = model; }
internal static ShaderFunctionAndMethodDeclarationSyntax GetShaderFunction( BaseMethodDeclarationSyntax node, Compilation compilation, bool generateOrderedFunctionList) { SemanticModel semanticModel = compilation.GetSemanticModel(node.SyntaxTree); string functionName; TypeReference returnTypeReference; if (node is MethodDeclarationSyntax mds) { functionName = mds.Identifier.ToFullString(); returnTypeReference = new TypeReference(semanticModel.GetFullTypeName(mds.ReturnType), semanticModel.GetTypeInfo(mds.ReturnType).Type); } else if (node is ConstructorDeclarationSyntax cds) { functionName = ".ctor"; ITypeSymbol typeSymbol = semanticModel.GetDeclaredSymbol(cds).ContainingType; returnTypeReference = new TypeReference(GetFullTypeName(typeSymbol, out _), typeSymbol); } else { throw new ArgumentOutOfRangeException(nameof(node), "Unsupported BaseMethodDeclarationSyntax type."); } UInt3 computeGroupCounts = new UInt3(); bool isFragmentShader = false, isComputeShader = false; bool isVertexShader = GetMethodAttributes(node, "VertexShader").Any(); bool isGeometryShader = GetMethodAttributes(node, "GeometryShader").Any(); if (!isVertexShader) { isFragmentShader = GetMethodAttributes(node, "FragmentShader").Any(); } if (!isVertexShader && !isFragmentShader && !isGeometryShader) { AttributeSyntax computeShaderAttr = GetMethodAttributes(node, "ComputeShader").FirstOrDefault(); if (computeShaderAttr != null) { isComputeShader = true; computeGroupCounts.X = GetAttributeArgumentUIntValue(computeShaderAttr, 0); computeGroupCounts.Y = GetAttributeArgumentUIntValue(computeShaderAttr, 1); computeGroupCounts.Z = GetAttributeArgumentUIntValue(computeShaderAttr, 2); } } ShaderFunctionType type = isVertexShader ? ShaderFunctionType.VertexEntryPoint : isFragmentShader ? ShaderFunctionType.FragmentEntryPoint : isComputeShader ? ShaderFunctionType.ComputeEntryPoint : isGeometryShader ? ShaderFunctionType.GeometryEntryPoint : ShaderFunctionType.Normal; string nestedTypePrefix = GetFullNestedTypePrefix(node, out bool nested); List <ParameterDefinition> parameters = new List <ParameterDefinition>(); foreach (ParameterSyntax ps in node.ParameterList.Parameters) { parameters.Add(ParameterDefinition.GetParameterDefinition(compilation, ps)); } ShaderFunction sf = new ShaderFunction( nestedTypePrefix, functionName, returnTypeReference, parameters.ToArray(), type, computeGroupCounts); if (isGeometryShader) { AttributeSyntax geometryShaderAttr = GetMethodAttributes(node, "GeometryShader").FirstOrDefault(); var geometryArgs = geometryShaderAttr.ArgumentList.Arguments; if (geometryArgs.Count == 3) { sf.InputPrimitive = (PrimitiveType)Enum.ToObject(typeof(PrimitiveType), semanticModel.GetConstantValue(geometryArgs[0].Expression).Value); sf.OutputPrimitive = (PrimitiveType)Enum.ToObject(typeof(PrimitiveType), semanticModel.GetConstantValue(geometryArgs[1].Expression).Value); sf.MaxVertices = (int)semanticModel.GetConstantValue(geometryArgs[2].Expression).Value; } } ShaderFunctionAndMethodDeclarationSyntax[] orderedFunctionList; if (type != ShaderFunctionType.Normal && generateOrderedFunctionList) { FunctionCallGraphDiscoverer fcgd = new FunctionCallGraphDiscoverer( compilation, new TypeAndMethodName { TypeName = sf.DeclaringType, MethodName = sf.Name }); fcgd.GenerateFullGraph(); orderedFunctionList = fcgd.GetOrderedCallList(); } else { orderedFunctionList = new ShaderFunctionAndMethodDeclarationSyntax[0]; } return(new ShaderFunctionAndMethodDeclarationSyntax(sf, node, orderedFunctionList)); }
public ShaderFunctionAndMethodDeclarationSyntax(ShaderFunction function, BaseMethodDeclarationSyntax methodDeclaration, ShaderFunctionAndMethodDeclarationSyntax[] orderedFunctionList) { Function = function; MethodDeclaration = methodDeclaration; OrderedFunctionList = orderedFunctionList; }
protected abstract MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function);
protected abstract string GenerateFullTextCore(string setName, ShaderFunction function);
public ShaderFunctionAndBlockSyntax(ShaderFunction function, BlockSyntax block) { Function = function; Block = block; }
protected abstract void WriteVersionHeader(ShaderFunction function, StringBuilder sb);
public ShaderFunctionAndBlockSyntax(ShaderFunction function, BlockSyntax block, ShaderFunctionAndBlockSyntax[] orderedFunctionList) { Function = function; Block = block; OrderedFunctionList = orderedFunctionList; }
public HlslMethodVisitor(Compilation compilation, string setName, ShaderFunction shaderFunction, LanguageBackend backend) : base(compilation, setName, shaderFunction, backend) { }
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[] orderedStructures = StructureDependencyGraph.GetOrderedStructureList(Compilation, setContext.Structures); foreach (StructureDefinition sd in orderedStructures) { 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, uavBinding = function.ColorOutputCount; 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.Texture2DMS: WriteTexture2DMS(sb, rd, textureBinding++); break; case ShaderResourceKind.Sampler: WriteSampler(sb, rd, samplerBinding++); break; case ShaderResourceKind.StructuredBuffer: WriteStructuredBuffer(sb, rd, textureBinding++); break; case ShaderResourceKind.RWStructuredBuffer: WriteRWStructuredBuffer(sb, rd, uavBinding++); 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()); }
public ShaderFunctionAndBlockSyntax WithParameter(int index, TypeReference type) { ShaderFunction sf = Function.WithParameter(index, type); return(new ShaderFunctionAndBlockSyntax(sf, Block)); }
public ShaderFunctionAndBlockSyntax WithReturnType(TypeReference returnType) { ShaderFunction sf = Function.WithReturnType(returnType); return(new ShaderFunctionAndBlockSyntax(sf, Block)); }
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) { 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()); }
internal static ShaderFunctionAndMethodDeclarationSyntax GetShaderFunction( MethodDeclarationSyntax node, Compilation compilation, bool generateOrderedFunctionList) { string functionName = node.Identifier.ToFullString(); List <ParameterDefinition> parameters = new List <ParameterDefinition>(); foreach (ParameterSyntax ps in node.ParameterList.Parameters) { parameters.Add(ParameterDefinition.GetParameterDefinition(compilation, ps)); } SemanticModel semanticModel = compilation.GetSemanticModel(node.SyntaxTree); TypeReference returnType = new TypeReference(semanticModel.GetFullTypeName(node.ReturnType)); UInt3 computeGroupCounts = new UInt3(); bool isFragmentShader = false, isComputeShader = false; bool isVertexShader = GetMethodAttributes(node, "VertexShader").Any(); if (!isVertexShader) { isFragmentShader = GetMethodAttributes(node, "FragmentShader").Any(); } if (!isVertexShader && !isFragmentShader) { AttributeSyntax computeShaderAttr = GetMethodAttributes(node, "ComputeShader").FirstOrDefault(); if (computeShaderAttr != null) { isComputeShader = true; computeGroupCounts.X = GetAttributeArgumentUIntValue(computeShaderAttr, 0); computeGroupCounts.Y = GetAttributeArgumentUIntValue(computeShaderAttr, 1); computeGroupCounts.Z = GetAttributeArgumentUIntValue(computeShaderAttr, 2); } } ShaderFunctionType type = isVertexShader ? ShaderFunctionType.VertexEntryPoint : isFragmentShader ? ShaderFunctionType.FragmentEntryPoint : isComputeShader ? ShaderFunctionType.ComputeEntryPoint : ShaderFunctionType.Normal; string nestedTypePrefix = GetFullNestedTypePrefix(node, out bool nested); ShaderFunction sf = new ShaderFunction( nestedTypePrefix, functionName, returnType, parameters.ToArray(), type, computeGroupCounts); ShaderFunctionAndMethodDeclarationSyntax[] orderedFunctionList; if (type != ShaderFunctionType.Normal && generateOrderedFunctionList) { FunctionCallGraphDiscoverer fcgd = new FunctionCallGraphDiscoverer( compilation, new TypeAndMethodName { TypeName = sf.DeclaringType, MethodName = sf.Name }); fcgd.GenerateFullGraph(); orderedFunctionList = fcgd.GetOrderedCallList(); } else { orderedFunctionList = new ShaderFunctionAndMethodDeclarationSyntax[0]; } return(new ShaderFunctionAndMethodDeclarationSyntax(sf, node, orderedFunctionList)); }
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("}"); }
protected override void WriteVersionHeader(ShaderFunction function, StringBuilder sb) { sb.AppendLine("#version 450"); sb.AppendLine("#extension GL_ARB_separate_shader_objects : enable"); sb.AppendLine("#extension GL_ARB_shading_language_420pack : enable"); }
protected virtual ShaderMethodVisitor VisitShaderMethod(string setName, ShaderFunction func) { return(new ShaderMethodVisitor(Compilation, setName, func, this)); }
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()); }