Beispiel #1
0
 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();
        }
Beispiel #3
0
        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;
 }
Beispiel #7
0
        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));
                }
            }
        }
Beispiel #8
0
        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}");
                        }
                    }
                }
            }
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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;
        }
Beispiel #11
0
        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));
        }
Beispiel #12
0
 public ShaderFunctionAndMethodDeclarationSyntax(ShaderFunction function, BaseMethodDeclarationSyntax methodDeclaration, ShaderFunctionAndMethodDeclarationSyntax[] orderedFunctionList)
 {
     Function            = function;
     MethodDeclaration   = methodDeclaration;
     OrderedFunctionList = orderedFunctionList;
 }
Beispiel #13
0
 protected abstract MethodProcessResult GenerateFullTextCore(string setName, ShaderFunction function);
 protected abstract string GenerateFullTextCore(string setName, ShaderFunction function);
Beispiel #15
0
 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());
        }
Beispiel #20
0
        public ShaderFunctionAndBlockSyntax WithParameter(int index, TypeReference type)
        {
            ShaderFunction sf = Function.WithParameter(index, type);

            return(new ShaderFunctionAndBlockSyntax(sf, Block));
        }
Beispiel #21
0
        public ShaderFunctionAndBlockSyntax WithReturnType(TypeReference returnType)
        {
            ShaderFunction sf = Function.WithReturnType(returnType);

            return(new ShaderFunctionAndBlockSyntax(sf, Block));
        }
Beispiel #22
0
        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("}");
        }
Beispiel #23
0
        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());
        }
Beispiel #24
0
        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));
        }
Beispiel #25
0
        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");
 }
Beispiel #27
0
 protected virtual ShaderMethodVisitor VisitShaderMethod(string setName, ShaderFunction func)
 {
     return(new ShaderMethodVisitor(Compilation, setName, func, this));
 }
Beispiel #28
0
        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());
        }