示例#1
0
 public StructureDefinition(string name, FieldDefinition[] fields, AlignmentInfo size)
 {
     Name      = name;
     Fields    = fields;
     Alignment = size;
     CSharpMatchesShaderAlignment = GetCSharpMatchesShaderAlignment();
 }
        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);
        }
示例#3
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);
        }
示例#4
0
        private static AlignmentInfo Analyze(ITypeSymbol typeSymbol)
        {
            // Check if we already know this type
            if (s_cachedSizes.TryGetValue(typeSymbol, out AlignmentInfo alignmentInfo))
            {
                return(alignmentInfo);
            }

            string symbolFullName = typeSymbol.GetFullMetadataName();

            // Get any specific shader alignment
            int?specificShaderAlignment = s_shaderAlignments.TryGetValue(symbolFullName, out int sa)
                ? (int?)sa
                : null;

            // Check if this in our list of known sizes
            if (s_knownSizes.TryGetValue(symbolFullName, out int knownSize))
            {
                alignmentInfo = new AlignmentInfo(knownSize, knownSize, knownSize, specificShaderAlignment ?? knownSize);
                s_cachedSizes.TryAdd(typeSymbol, alignmentInfo);
                return(alignmentInfo);
            }

            // Check if enum
            if (typeSymbol.TypeKind == TypeKind.Enum)
            {
                string enumBaseType = ((INamedTypeSymbol)typeSymbol).EnumUnderlyingType.GetFullMetadataName();
                if (!s_knownSizes.TryGetValue(enumBaseType, out int enumSize))
                {
                    throw new ShaderGenerationException($"Unknown enum base type: {enumBaseType}");
                }

                alignmentInfo = new AlignmentInfo(enumSize, enumSize, enumSize, specificShaderAlignment ?? enumSize);
                s_cachedSizes.TryAdd(typeSymbol, alignmentInfo);
                return(alignmentInfo);
            }

            // NOTE This check only works for known types accessible to ShaderGen, but it will pick up most non-blittable types.
            if (BlittableHelper.IsBlittable(symbolFullName) == false)
            {
                throw new ShaderGenerationException($"Cannot use the {symbolFullName} type in a shader as it is not a blittable type.");
            }

            // Unknown type, get the instance fields.
            var fields = typeSymbol.GetMembers()
                         .Where(symb => symb.Kind == SymbolKind.Field && !symb.IsStatic)
                         .Select(symb => (IFieldSymbol)symb)
                         .ToArray();

            if (fields.Length == 0)
            {
                throw new ShaderGenerationException($"No fields on type {symbolFullName}, cannot assess size of structure.");
            }

            int csharpSize      = 0;
            int shaderSize      = 0;
            int csharpAlignment = 0;
            int shaderAlignment = 0;

            // Calculate size of struct from its fields alignment infos
            foreach (IFieldSymbol field in fields)
            {
                // Determine if type is blittable
                if (field.Type is IArrayTypeSymbol arrayType)
                {
                    // We can only analyze array size as fields since the field has the attribute, not the type
                    var elementSizeAndAlignment = Get(arrayType.ElementType);
                    var arraySizeAttribute      = field.GetAttributes().Single(a => a.AttributeClass.Name == nameof(ArraySizeAttribute));
                    var arraySize   = (int)arraySizeAttribute.ConstructorArguments[0].Value;
                    var shaderAlign = Align(elementSizeAndAlignment.ShaderAlignment, 16);
                    alignmentInfo = new AlignmentInfo(
                        elementSizeAndAlignment.CSharpSize * arraySize,
                        Align(elementSizeAndAlignment.ShaderSize * arraySize, shaderAlign),
                        elementSizeAndAlignment.CSharpAlignment,
                        shaderAlign);
                }
                else
                {
                    alignmentInfo = Analyze(field.Type);
                }

                // If specified, the field offset dictates the size of the csharp structure at the point where the field starts
                csharpAlignment = Math.Max(csharpAlignment, alignmentInfo.CSharpAlignment);
                var offset = GetOffset(field);
                if (offset > 0)
                {
                    csharpSize = offset;
                }
                else
                {
                    csharpSize = Align(csharpSize, alignmentInfo.CSharpAlignment);
                }
                csharpSize += alignmentInfo.CSharpSize;

                shaderAlignment = Math.Max(shaderAlignment, alignmentInfo.ShaderAlignment);
                shaderSize      = Align(shaderSize, alignmentInfo.ShaderAlignment);
                shaderSize     += alignmentInfo.ShaderSize;
            }

            // Structures always align to a multiple of 16
            if (typeSymbol.TypeKind == TypeKind.Struct)
            {
                shaderAlignment = Align(specificShaderAlignment ?? shaderAlignment, 16);
            }
            else
            {
                shaderAlignment = specificShaderAlignment ?? shaderAlignment;
            }

            // The overall shader object size is always a multiple of its alignment
            shaderSize = Align(shaderSize, shaderAlignment);

            // If specified, the overall csharp object size is fixed
            var sizeOf = GetSize(typeSymbol);

            if (sizeOf > 0)
            {
                csharpSize = sizeOf;
            }

            // Return new alignment info after adding into cache.
            alignmentInfo = new AlignmentInfo(csharpSize, shaderSize, csharpAlignment, shaderAlignment);
            s_cachedSizes.TryAdd(typeSymbol, alignmentInfo);
            return(alignmentInfo);
        }
示例#5
0
        private static AlignmentInfo Analyze(ITypeSymbol typeSymbol)
        {
            // Check if we already know this type
            if (s_cachedSizes.TryGetValue(typeSymbol, out AlignmentInfo alignmentInfo))
            {
                return(alignmentInfo);
            }

            string symbolFullName = typeSymbol.GetFullMetadataName();

            // Get any specific shader alignment
            int?specificShaderAlignment = s_shaderAlignments.TryGetValue(symbolFullName, out int sa)
                ? (int?)sa
                : null;

            // Check if this in our list of known sizes
            if (s_knownSizes.TryGetValue(symbolFullName, out int knownSize))
            {
                alignmentInfo = new AlignmentInfo(knownSize, knownSize, knownSize, specificShaderAlignment ?? knownSize);
                s_cachedSizes.TryAdd(typeSymbol, alignmentInfo);
                return(alignmentInfo);
            }

            // Check if enum
            if (typeSymbol.TypeKind == TypeKind.Enum)
            {
                string enumBaseType = ((INamedTypeSymbol)typeSymbol).EnumUnderlyingType.GetFullMetadataName();
                if (!s_knownSizes.TryGetValue(enumBaseType, out int enumSize))
                {
                    throw new ShaderGenerationException($"Unknown enum base type: {enumBaseType}");
                }

                alignmentInfo = new AlignmentInfo(enumSize, enumSize, enumSize, specificShaderAlignment ?? enumSize);
                s_cachedSizes.TryAdd(typeSymbol, alignmentInfo);
                return(alignmentInfo);
            }

            // NOTE This check only works for known types accessible to ShaderGen, but it will pick up most non-blittable types.
            if (BlittableHelper.IsBlittable(symbolFullName) == false)
            {
                throw new ShaderGenerationException($"Cannot use the {symbolFullName} type in a shader as it is not a blittable type.");
            }

            // Unknown type, get the instance fields.
            ITypeSymbol[] fields = typeSymbol.GetMembers()
                                   .Where(symb => symb.Kind == SymbolKind.Field && !symb.IsStatic)
                                   .Select(symb => ((IFieldSymbol)symb).Type)
                                   .ToArray();

            if (fields.Length == 0)
            {
                throw new ShaderGenerationException($"No fields on type {symbolFullName}, cannot assess size of structure.");
            }

            int csharpSize      = 0;
            int shaderSize      = 0;
            int csharpAlignment = 0;
            int shaderAlignment = 0;

            // Calculate size of struct from its fields alignment infos
            foreach (ITypeSymbol fieldType in fields)
            {
                // Determine if type is blittable
                alignmentInfo   = Analyze(fieldType);
                csharpAlignment = Math.Max(csharpAlignment, alignmentInfo.CSharpAlignment);
                csharpSize     += alignmentInfo.CSharpSize + csharpSize % alignmentInfo.CSharpAlignment;
                shaderAlignment = Math.Max(shaderAlignment, alignmentInfo.ShaderAlignment);
                shaderSize     += alignmentInfo.ShaderSize + shaderSize % alignmentInfo.ShaderAlignment;
            }

            // Return new alignment info after adding into cache.
            alignmentInfo = new AlignmentInfo(csharpSize, shaderSize, csharpAlignment, specificShaderAlignment ?? shaderAlignment);
            s_cachedSizes.TryAdd(typeSymbol, alignmentInfo);
            return(alignmentInfo);
        }
示例#6
0
        private FieldDefinition ReflectField(IFieldSymbol field)
        {
            int           fixedSize;
            AlignmentInfo fieldSizeAndAlignment;

            if (field.Type is IArrayTypeSymbol arrayType)
            {
                var elementSizeAndAlignment = TypeSizeCache.Get(arrayType.ElementType);
                var arraySizeAttribute      = field.GetAttributes().Single(a => a.AttributeClass.Name == nameof(ArraySizeAttribute));
                fixedSize             = (int)arraySizeAttribute.ConstructorArguments[0].Value;
                fieldSizeAndAlignment = new AlignmentInfo(
                    elementSizeAndAlignment.CSharpSize * fixedSize,
                    elementSizeAndAlignment.ShaderSize * fixedSize,
                    elementSizeAndAlignment.CSharpAlignment,
                    elementSizeAndAlignment.ShaderAlignment);
            }
            else
            {
                fixedSize             = 0;
                fieldSizeAndAlignment = TypeSizeCache.Get(field.Type);
            }

            SemanticType semantic          = SemanticType.None;
            var          semanticAttribute = field.GetAttributes().SingleOrDefault(a => a.AttributeClass.Name.Contains("Semantic"));

            if (semanticAttribute != null)
            {
                switch (semanticAttribute.AttributeClass.Name)
                {
                case nameof(PositionSemanticAttribute):
                    semantic = SemanticType.Position;
                    break;

                case nameof(SystemPositionSemanticAttribute):
                    semantic = SemanticType.SystemPosition;
                    break;

                case nameof(ColorSemanticAttribute):
                    semantic = SemanticType.Color;
                    break;

                case nameof(ColorTargetSemanticAttribute):
                    semantic = SemanticType.ColorTarget;
                    break;

                case nameof(NormalSemanticAttribute):
                    semantic = SemanticType.Normal;
                    break;

                case nameof(TangentSemanticAttribute):
                    semantic = SemanticType.Tangent;
                    break;

                case nameof(TextureCoordinateSemanticAttribute):
                    semantic = SemanticType.TextureCoordinate;
                    break;

                case nameof(GeometrySemanticAttribute):
                    var geometrySemantic = semanticAttribute.ConstructorArguments.First();
                    return(new FieldDefinition(field.Name,
                                               new TypeReference(field.Type.GetFullMetadataName(), field.Type, fixedSize),
                                               (GeometrySemantic)Enum.ToObject(typeof(GeometrySemantic), geometrySemantic.Value),
                                               fixedSize, fieldSizeAndAlignment));

                default:
                    throw new NotSupportedException();
                }
            }

            return(new FieldDefinition(field.Name,
                                       new TypeReference(field.Type.GetFullMetadataName(), field.Type, fixedSize),
                                       semantic, fixedSize, fieldSizeAndAlignment));
        }