Quellcode durchsuchen

More groundwork for HLSL generation.

Eric Mellino vor 8 Jahren
Ursprung
Commit
ea1d0956ee

+ 7 - 0
NuGet.Config

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <packageSources>
+    <add key="dotnet-myget dotnet-core" value="https://dotnet.myget.org/F/dotnet-core/api/v3/index.json" />
+    <add key="dotnet-myget dotnet-corefxlab" value="https://dotnet.myget.org/F/dotnet-corefxlab/api/v3/index.json" />
+  </packageSources>
+</configuration>

+ 13 - 10
src/ShaderGen/DuplicateWithSuffixAttribute.cs

@@ -3,16 +3,19 @@ using System;
 using System.Diagnostics;
 using Validation;
 
-[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
-[CodeGenerationAttribute(typeof(DuplicateWithSuffixGenerator))]
-[Conditional("CodeGeneration")]
-public class DuplicateWithSuffixAttribute : Attribute
+namespace ShaderGen
 {
-    public DuplicateWithSuffixAttribute(string suffix)
+    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
+    [CodeGenerationAttribute(typeof(DuplicateWithSuffixGenerator))]
+    [Conditional("CodeGeneration")]
+    public class DuplicateWithSuffixAttribute : Attribute
     {
-        Requires.NotNullOrEmpty(suffix, nameof(suffix));
-        this.Suffix = suffix;
-    }
+        public DuplicateWithSuffixAttribute(string suffix)
+        {
+            Requires.NotNullOrEmpty(suffix, nameof(suffix));
+            this.Suffix = suffix;
+        }
 
-    public string Suffix { get; }
-}
+        public string Suffix { get; }
+    }
+}

+ 23 - 21
src/ShaderGen/DuplicateWithSuffixGenerator.cs

@@ -8,33 +8,35 @@ using System.Threading;
 using System.Threading.Tasks;
 using Validation;
 
-public class DuplicateWithSuffixGenerator : ICodeGenerator
+namespace ShaderGen
 {
-    private readonly string suffix;
-
-    public DuplicateWithSuffixGenerator(AttributeData attributeData)
+    public class DuplicateWithSuffixGenerator : ICodeGenerator
     {
-        Requires.NotNull(attributeData, nameof(attributeData));
-        this.suffix = (string)attributeData.ConstructorArguments[0].Value;
-    }
+        private readonly string suffix;
 
-    public Task<SyntaxList<MemberDeclarationSyntax>> GenerateAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
-    {
-        var results = SyntaxFactory.List<MemberDeclarationSyntax>();
+        public DuplicateWithSuffixGenerator(AttributeData attributeData)
+        {
+            Requires.NotNull(attributeData, nameof(attributeData));
+            this.suffix = (string)attributeData.ConstructorArguments[0].Value;
+        }
 
-        // Our generator is applied to any class that our attribute is applied to.
-        var applyToClass = (ClassDeclarationSyntax)context.ProcessingMember;
+        public Task<SyntaxList<MemberDeclarationSyntax>> GenerateAsync(TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken)
+        {
+            var results = SyntaxFactory.List<MemberDeclarationSyntax>();
 
-        // Apply a suffix to the name of a copy of the class.
-        var copy = applyToClass
-            .WithIdentifier(SyntaxFactory.Identifier(applyToClass.Identifier.ValueText + this.suffix));
+            // Our generator is applied to any class that our attribute is applied to.
+            var applyToClass = (ClassDeclarationSyntax)context.ProcessingMember;
 
-        ShaderSyntaxWalker walker = new ShaderSyntaxWalker();
-        walker.Visit(context.SemanticModel.SyntaxTree.GetRoot());
-        walker.WriteToFile(@"E:\outputtext.txt");
+            // Apply a suffix to the name of a copy of the class.
+            var copy = applyToClass
+                .WithIdentifier(SyntaxFactory.Identifier(applyToClass.Identifier.ValueText + this.suffix));
 
-        // Return our modified copy. It will be added to the user's project for compilation.
-        results = results.Add(copy);
-        return Task.FromResult<SyntaxList<MemberDeclarationSyntax>>(results);
+            ShaderSyntaxWalker walker = new ShaderSyntaxWalker(context);
+            walker.Visit(context.SemanticModel.SyntaxTree.GetRoot());
+            walker.WriteToFile("outputtext.hlsl");
+            // Return our modified copy. It will be added to the user's project for compilation.
+            results = results.Add(copy);
+            return Task.FromResult<SyntaxList<MemberDeclarationSyntax>>(results);
+        }
     }
 }

+ 27 - 0
src/ShaderGen/HlslKnownTypes.cs

@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+namespace ShaderGen
+{
+    public static class HlslKnownTypes
+    {
+        private static readonly Dictionary<string, string> s_knownTypes = new Dictionary<string, string>()
+        {
+            { "System.Numerics.Vector2", "float2" },
+            { "System.Numerics.Vector3", "float3" },
+            { "System.Numerics.Vector4", "float4" },
+            { "System.Numerics.Matrix4x4", "float4x4" },
+        };
+
+        public static string GetMappedName(string name)
+        {
+            if (s_knownTypes.TryGetValue(name, out string mapped))
+            {
+                return mapped;
+            }
+            else
+            {
+                return name;
+            }
+        }
+    }
+}

+ 45 - 0
src/ShaderGen/HlslWriter.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace ShaderGen
+{
+    public class HlslWriter
+    {
+        private readonly List<StructDefinition> _structs;
+        private readonly List<UniformDefinition> _uniforms;
+
+        public HlslWriter(List<StructDefinition> structs, List<UniformDefinition> uniforms)
+        {
+            _structs = structs;
+            _uniforms = uniforms;
+        }
+
+        public string GetHlslText()
+        {
+            StringBuilder sb = new StringBuilder();
+            foreach (UniformDefinition ud in _uniforms)
+            {
+                sb.AppendLine($"cbuffer {ud.Name}Buffer : register(b{ud.Binding})");
+                sb.AppendLine("{");
+                sb.AppendLine($"    {HlslKnownTypes.GetMappedName(ud.Type.Name.Trim())} {ud.Name.Trim()};");
+                sb.AppendLine("}");
+                sb.AppendLine();
+            }
+
+            foreach (StructDefinition sd in _structs)
+            {
+                sb.AppendLine($"struct {sd.Name}");
+                sb.AppendLine("{");
+                foreach (FieldDefinition field in sd.Fields)
+                {
+                    sb.AppendLine($"    {HlslKnownTypes.GetMappedName(field.Type.Name.Trim())} {field.Name.Trim()};");
+                }
+                sb.AppendLine("};");
+                sb.AppendLine();
+            }
+
+            return sb.ToString();
+        }
+    }
+}

+ 119 - 54
src/ShaderGen/ShaderSyntaxWalker.cs

@@ -4,81 +4,146 @@ using System.Text;
 using System.Linq;
 using System;
 using System.IO;
+using ShaderGen;
+using System.Collections.Generic;
+using CodeGeneration.Roslyn;
+using Microsoft.CodeAnalysis;
+using System.Diagnostics;
 
-public class ShaderSyntaxWalker : CSharpSyntaxWalker
+namespace ShaderGen
 {
-    private readonly StringBuilder _sb = new StringBuilder();
-    private readonly ShaderFunctionWalker _functionWalker;
-
-    public ShaderSyntaxWalker() : base(Microsoft.CodeAnalysis.SyntaxWalkerDepth.Token)
+    public class ShaderSyntaxWalker : CSharpSyntaxWalker
     {
-        _functionWalker = new ShaderFunctionWalker(_sb);
-    }
+        private readonly StringBuilder _sb = new StringBuilder();
+        private readonly TransformationContext _context;
+        private readonly ShaderFunctionWalker _functionWalker;
 
-    public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
-    {
-        _sb.AppendLine($"Encountered method declaration: {node.Identifier.Text}");
-        if (node.AttributeLists.Any(als => als.Attributes.Any(attrSyntax => attrSyntax.GetText().ToString().Contains("EntryFunction"))))
+        private readonly List<StructDefinition> _structs = new List<StructDefinition>();
+        private readonly List<UniformDefinition> _uniforms = new List<UniformDefinition>();
+
+        public ShaderSyntaxWalker(TransformationContext context) : base(Microsoft.CodeAnalysis.SyntaxWalkerDepth.Token)
         {
-            _sb.AppendLine($"  - Is a shader method.");
+            _context = context;
+            _functionWalker = new ShaderFunctionWalker(_sb);
         }
 
-        VisitBlock(node.Body);
-    }
+        public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
+        {
+            _sb.AppendLine($"Encountered method declaration: {node.Identifier.Text}");
+            if (node.AttributeLists.Any(als => als.Attributes.Any(attrSyntax => attrSyntax.GetText().ToString().Contains("EntryFunction"))))
+            {
+                _sb.AppendLine($"  - Is a shader method.");
+            }
 
-    public override void VisitStructDeclaration(StructDeclarationSyntax node)
-    {
-        _sb.AppendLine($"Encountered struct declaration: {node.Identifier.Text}");
-        foreach (MemberDeclarationSyntax member in node.Members)
+            VisitBlock(node.Body);
+        }
+
+        public override void VisitStructDeclaration(StructDeclarationSyntax node)
         {
-            _sb.AppendLine($"  * Member: {member.ToFullString()}");
+            string structName = node.Identifier.Text;
+
+            List<FieldDefinition> fields = new List<FieldDefinition>();
+            foreach (MemberDeclarationSyntax member in node.Members)
+            {
+                if (member is FieldDeclarationSyntax fds)
+                {
+                    VariableDeclarationSyntax varDecl = fds.Declaration;
+                    foreach (VariableDeclaratorSyntax vds in varDecl.Variables)
+                    {
+                        string fieldName = vds.Identifier.Text;
+                        TypeReference tr = new TypeReference(GetFullTypeName(varDecl.Type));
+                        fields.Add(new FieldDefinition(fieldName, tr));
+                    }
+                }
+            }
+
+            _structs.Add(new StructDefinition(structName, fields.ToArray()));
         }
-    }
 
-    public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
-    {
-        _sb.AppendLine($"  * Assignment: [[ {node.ToFullString()} ]]");
-    }
+        public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
+        {
+            _sb.AppendLine($"  * Assignment: [[ {node.ToFullString()} ]]");
+        }
 
-    public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
-    {
-        _sb.AppendLine($"  * Member access: [[ {node.ToFullString()} ]]");
-    }
+        public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node)
+        {
+            _sb.AppendLine($"  * Member access: [[ {node.ToFullString()} ]]");
+        }
 
-    public override void VisitInvocationExpression(InvocationExpressionSyntax node)
-    {
-        _sb.AppendLine($"  * Invocation: {node.ToFullString()}");
-    }
+        public override void VisitInvocationExpression(InvocationExpressionSyntax node)
+        {
+            _sb.AppendLine($"  * Invocation: {node.ToFullString()}");
+        }
 
-    public override void VisitVariableDeclaration(VariableDeclarationSyntax node)
-    {
-        _sb.AppendLine($"  * Var decl: [[ {node.ToFullString()} ]] ");
-        if (GetUniformDecl(node, out AttributeSyntax uniformAttr))
+        public override void VisitVariableDeclaration(VariableDeclarationSyntax node)
         {
-            _sb.AppendLine($"    - This is a uniform: {uniformAttr.ToFullString()}");
+            if (GetUniformDecl(node, out AttributeSyntax uniformAttr))
+            {
+                ExpressionSyntax uniformBindingExpr = uniformAttr.ArgumentList.Arguments[0].Expression;
+                if (!(uniformBindingExpr is LiteralExpressionSyntax les))
+                {
+                    throw new InvalidOperationException("Must use a literal parameter in UniformAttribute ctor.");
+                }
+
+                int uniformBinding = int.Parse(les.ToFullString());
+
+                foreach (VariableDeclaratorSyntax vds in node.Variables)
+                {
+                    string uniformName = vds.Identifier.Text;
+                    TypeInfo typeInfo = _context.SemanticModel.GetTypeInfo(node.Type);
+                    string fullTypeName = GetFullTypeName(node.Type);
+                    TypeReference tr = new TypeReference(fullTypeName);
+                    UniformDefinition ud = new UniformDefinition(uniformName, uniformBinding, tr);
+                    _uniforms.Add(ud);
+                }
+            }
         }
 
-    }
+        private string GetFullTypeName(TypeSyntax type)
+        {
+            TypeInfo typeInfo = _context.SemanticModel.GetTypeInfo(type);
+            string ns = GetFullNamespace(typeInfo.Type.ContainingNamespace);
+            return ns + "." + typeInfo.Type.Name;
+        }
 
-    private bool GetUniformDecl(VariableDeclarationSyntax node, out AttributeSyntax attr)
-    {
-        attr = (node.Parent.DescendantNodes().OfType<AttributeSyntax>().FirstOrDefault(
-            attrSyntax => attrSyntax.ToString().Contains("Uniform")));
-        return attr != null;
-    }
+        private string GetFullNamespace(INamespaceSymbol ns)
+        {
+            Debug.Assert(ns != null);
+            string currentNamespace = ns.Name;
+            if (ns.ContainingNamespace != null && !ns.ContainingNamespace.IsGlobalNamespace)
+            {
+                return GetFullNamespace(ns.ContainingNamespace) + "." + currentNamespace;
+            }
+            else
+            {
+                return currentNamespace;
+            }
+        }
 
-    internal void WriteToFile(string file)
-    {
-        File.WriteAllText(file, _sb.ToString());
-    }
-}
+        private bool GetUniformDecl(VariableDeclarationSyntax node, out AttributeSyntax attr)
+        {
+            attr = (node.Parent.DescendantNodes().OfType<AttributeSyntax>().FirstOrDefault(
+                attrSyntax => attrSyntax.ToString().Contains("Uniform")));
+            return attr != null;
+        }
 
-public class ShaderFunctionWalker : CSharpSyntaxWalker
-{
-    private readonly StringBuilder _sb;
+        internal void WriteToFile(string file)
+        {
+            StringBuilder fullText = new StringBuilder();
+            HlslWriter hlslWriter = new HlslWriter(_structs, _uniforms);
+            fullText.Append(hlslWriter.GetHlslText());
+            fullText.Append(_sb);
+            File.WriteAllText(file, fullText.ToString());
+        }
+    }
 
-    public ShaderFunctionWalker(StringBuilder sb)
+    public class ShaderFunctionWalker : CSharpSyntaxWalker
     {
-        _sb = sb;
+        private readonly StringBuilder _sb;
+
+        public ShaderFunctionWalker(StringBuilder sb)
+        {
+            _sb = sb;
+        }
     }
 }

+ 31 - 0
src/TestShaders/outputtext.hlsl

@@ -0,0 +1,31 @@
+cbuffer WorldBuffer : register(b0)
+{
+    float4x4 World;
+}
+
+cbuffer ViewBuffer : register(b1)
+{
+    float4x4 View;
+}
+
+cbuffer ProjectionBuffer : register(b2)
+{
+    float4x4 Projection;
+}
+
+struct VertexOutput
+{
+    float4 Position;
+    float2 TextureCoord;
+};
+
+struct PositionTexture
+{
+    float3 Position;
+    float2 TextureCoord;
+};
+
+Encountered method declaration: VS
+  - Is a shader method.
+  * Assignment: [[             output.Position = Vector4.Transform(viewPosition, Projection) ]]
+  * Assignment: [[             output.TextureCoord = input.TextureCoord ]]