Пример #1
0
        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);
        }
Пример #2
0
        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}");
                 }
             }
         }
     }
 }
Пример #4
0
        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);
            }
        }
Пример #5
0
 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);
 }
Пример #6
0
 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));
     }
 }
Пример #7
0
        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);
            }
        }
Пример #8
0
        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);
                }
            }
        }
Пример #10
0
        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);
                }
            }
        }
Пример #11
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}");
                        }
                    }
                }
            }
        }
Пример #12
0
        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);
            }
        }
Пример #13
0
        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);
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
            }
        }
Пример #16
0
        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();
        }
Пример #17
0
        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);
        }
Пример #18
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());
        }
Пример #19
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("}");
        }
Пример #20
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());
        }
Пример #21
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("}");
        }
        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);
        }