public static ConstantDefinition FromXML(XElement elem) { ConstantDefinition constant = new ConstantDefinition(); constant.Name = elem.Attribute("name").Value; constant.Comment = elem.Attribute("comment")?.Value; constant.Alias = elem.Attribute("alias")?.Value; if (constant.Alias == null) { constant.Value = elem.Attribute("value").Value; constant.Type = ParseType(constant.Value); } return(constant); }
static void Main(string[] args) { string vkFile = "..\\..\\..\\..\\..\\..\\KhronosRegistry\\vk.xml"; string outputPath = "..\\..\\..\\..\\WaveEngine.Bindings.Vulkan\\Generated"; var vulkanSpec = VulkanSpecification.FromFile(vkFile); var vulkanVersion = VulkanVersion.FromSpec(vulkanSpec, "AllVersions", vulkanSpec.Extensions.ToImmutableList()); // Write Constants using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Constants.cs"))) { file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); file.WriteLine("\tpublic static partial class Vulkan"); file.WriteLine("\t{"); foreach (var constant in vulkanVersion.Constants) { if (constant.Alias != null) { var refConstant = vulkanVersion.Constants.FirstOrDefault(c => c.Name == constant.Alias); file.WriteLine($"\t\tpublic const {refConstant.Type.ToCSharp()} {constant.Name} = {refConstant.Name};"); } else { file.WriteLine($"\t\tpublic const {constant.Type.ToCSharp()} {constant.Name} = {ConstantDefinition.NormalizeValue(constant.Value)};"); } } file.WriteLine("\t}"); file.WriteLine("}"); } // Delegates using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Delegates.cs"))) { file.WriteLine("using System;\n"); file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); foreach (var func in vulkanVersion.FuncPointers) { file.Write($"\tpublic unsafe delegate {func.Type} {func.Name}("); if (func.Parameters.Count > 0) { file.Write("\n"); string type, convertedType; for (int p = 0; p < func.Parameters.Count; p++) { if (p > 0) { file.Write(",\n"); } type = func.Parameters[p].Type; var typeDef = vulkanSpec.TypeDefs.Find(t => t.Name == type); if (typeDef != null) { vulkanSpec.BaseTypes.TryGetValue(typeDef.Type, out type); } convertedType = Helpers.ConvertBasicTypes(type); if (convertedType == string.Empty) { convertedType = type; } file.Write($"\t\t{convertedType} {Helpers.ValidatedName(func.Parameters[p].Name)}"); } } file.Write(");\n\n"); } file.WriteLine("}"); } // Enums using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Enums.cs"))) { file.WriteLine("using System;\n"); file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); foreach (var e in vulkanVersion.Enums) { if (e.Type == EnumType.Bitmask) { file.WriteLine("\t[Flags]"); } file.WriteLine($"\tpublic enum {e.Name}"); file.WriteLine("\t{"); if (e.Values.Count == 0) { file.WriteLine("\t\tNone = 0,"); } else { foreach (var member in e.Values) { file.WriteLine($"\t\t{member.Name} = {member.Value},"); } } file.WriteLine("\t}\n"); } file.WriteLine("}"); } // Unions using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Unions.cs"))) { file.WriteLine("using System.Runtime.InteropServices;\n"); file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); foreach (var union in vulkanVersion.Unions) { file.WriteLine("\t[StructLayout(LayoutKind.Explicit)]"); file.WriteLine($"\tpublic unsafe partial struct {union.Name}"); file.WriteLine("\t{"); foreach (var member in union.Members) { string csType = Helpers.ConvertToCSharpType(member.Type, member.PointerLevel, vulkanSpec); file.WriteLine($"\t\t[FieldOffset(0)]"); if (member.ElementCount > 1) { file.WriteLine($"\t\tpublic unsafe fixed {csType} {member.Name}[{member.ElementCount}];"); } else { file.WriteLine($"\t\tpublic {csType} {member.Name};"); } } file.WriteLine("\t}\n"); } file.WriteLine("}\n"); } // structs using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Structs.cs"))) { file.WriteLine("using System;"); file.WriteLine("using System.Runtime.InteropServices;\n"); file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); foreach (var structure in vulkanVersion.Structs) { file.WriteLine("\t[StructLayout(LayoutKind.Sequential)]"); file.WriteLine($"\tpublic unsafe partial struct {structure.Name}"); file.WriteLine("\t{"); foreach (var member in structure.Members) { string csType = Helpers.ConvertToCSharpType(member.Type, member.PointerLevel, vulkanSpec); if (member.ElementCount > 1) { for (int i = 0; i < member.ElementCount; i++) { file.WriteLine($"\t\tpublic {csType} {member.Name}_{i};"); } } else if (member.ConstantValue != null) { var validConstant = vulkanVersion.Constants.FirstOrDefault(c => c.Name == member.ConstantValue); if (Helpers.SupportFixed(csType)) { file.WriteLine($"\t\tpublic fixed {csType} {Helpers.ValidatedName(member.Name)}[(int)Vulkan.{validConstant.Name}];"); } else { int count = int.Parse(validConstant.Value); for (int i = 0; i < count; i++) { file.WriteLine($"\t\tpublic {csType} {member.Name}_{i};"); } } } else { file.WriteLine($"\t\tpublic {csType} {Helpers.ValidatedName(member.Name)};"); } } file.WriteLine("\t}\n"); } file.WriteLine("}\n"); } // Handles using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Handles.cs"))) { file.WriteLine("using System;\n"); file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); foreach (var handle in vulkanVersion.Handles) { file.WriteLine($"\tpublic partial struct {handle.Name} : IEquatable<{handle.Name}>"); file.WriteLine("{"); string handleType = handle.Dispatchable ? "IntPtr" : "ulong"; string nullValue = handle.Dispatchable ? "IntPtr.Zero" : "0"; file.WriteLine($"\t\tpublic readonly {handleType} Handle;"); file.WriteLine($"\t\tpublic {handle.Name}({handleType} existingHandle) {{ Handle = existingHandle; }}"); file.WriteLine($"\t\tpublic static {handle.Name} Null => new {handle.Name}({nullValue});"); file.WriteLine($"\t\tpublic static implicit operator {handle.Name}({handleType} handle) => new {handle.Name}(handle);"); file.WriteLine($"\t\tpublic static bool operator ==({handle.Name} left, {handle.Name} right) => left.Handle == right.Handle;"); file.WriteLine($"\t\tpublic static bool operator !=({handle.Name} left, {handle.Name} right) => left.Handle != right.Handle;"); file.WriteLine($"\t\tpublic static bool operator ==({handle.Name} left, {handleType} right) => left.Handle == right;"); file.WriteLine($"\t\tpublic static bool operator !=({handle.Name} left, {handleType} right) => left.Handle != right;"); file.WriteLine($"\t\tpublic bool Equals({handle.Name} h) => Handle == h.Handle;"); file.WriteLine($"\t\tpublic override bool Equals(object o) => o is {handle.Name} h && Equals(h);"); file.WriteLine($"\t\tpublic override int GetHashCode() => Handle.GetHashCode();"); file.WriteLine("}\n"); } file.WriteLine("}"); } // Commands using (StreamWriter file = File.CreateText(Path.Combine(outputPath, "Commands.cs"))) { file.WriteLine("using System;"); file.WriteLine("using System.Runtime.InteropServices;\n"); file.WriteLine("namespace WaveEngine.Bindings.Vulkan"); file.WriteLine("{"); file.WriteLine("\tpublic static unsafe partial class VulkanNative"); file.WriteLine("\t{"); foreach (var command in vulkanVersion.Commands) { string convertedType = Helpers.ConvertToCSharpType(command.Prototype.Type, 0, vulkanSpec); file.WriteLine("\t\t[UnmanagedFunctionPointer(CallConv)]"); // Delegate file.WriteLine($"\t\tprivate delegate {convertedType} {command.Prototype.Name}Delegate({command.GetParametersSignature(vulkanSpec)});"); // internal function file.WriteLine($"\t\tprivate static {command.Prototype.Name}Delegate {command.Prototype.Name}_ptr;"); // public function file.WriteLine($"\t\tpublic static {convertedType} {command.Prototype.Name}({command.GetParametersSignature(vulkanSpec)})"); file.WriteLine($"\t\t\t=> {command.Prototype.Name}_ptr({command.GetParametersSignature(vulkanSpec, useTypes: false)});\n"); } file.WriteLine($"\t\tprivate static void LoadFuncionPointers()"); file.WriteLine("\t\t{"); foreach (var command in vulkanVersion.Commands) { file.WriteLine($"\t\t\tnativeLib.LoadFunction(\"{command.Prototype.Name}\", out {command.Prototype.Name}_ptr);"); } file.WriteLine("\t\t}"); file.WriteLine("\t}"); file.WriteLine("}"); } }
public static VulkanSpecification FromFile(string xmlFile) { XDocument file = XDocument.Load(xmlFile); VulkanSpecification spec = new VulkanSpecification(); var registry = file.Element("registry"); // Platforms var platforms = registry.Element("platforms").Elements("platform"); foreach (var platform in platforms) { spec.Platforms.Add(PlatformDefinition.FromXML(platform)); } // Tags var tags = registry.Element("tags").Elements("tag"); foreach (var tag in tags) { spec.Tags.Add(TagDefinition.FromXML(tag)); } // Constants var constants = (registry.Elements("enums").Where(e => e.Attribute("name").Value == "API Constants")).Elements("enum"); foreach (var c in constants) { spec.Constants.Add(ConstantDefinition.FromXML(c)); } // Enums var enums = registry.Elements("enums").Where(e => e.Attribute("type")?.Value == "enum" || e.Attribute("type")?.Value == "bitmask"); foreach (var e in enums) { spec.Enums.Add(EnumDefinition.FromXML(e)); } var types = registry.Elements("types"); // FuncPointers var funcPointers = types.Elements("type").Where(f => f.Attribute("category")?.Value == "funcpointer"); foreach (var func in funcPointers) { spec.FuncPointers.Add(FuncpointerDefinition.FromXML(func)); } // Alias spec.Alias = types.Elements("type").Where(a => a.Attribute("alias") != null) .ToDictionary( a => a.Attribute("name").Value, a => a.Attribute("alias").Value); // Command Alias var commandAlias = registry.Element("commands").Elements("command").Where(c => c.Attribute("alias") != null); foreach (var c in commandAlias) { spec.Alias.Add(c.Attribute("name").Value, c.Attribute("alias").Value); } // Structs var structs = types.Elements("type").Where(s => s.Attribute("category")?.Value == "struct" && s.Attribute("alias") == null); foreach (var s in structs) { spec.Structs.Add(StructureDefinition.FromXML(s)); } // Unions var unions = types.Elements("type").Where(u => u.Attribute("category")?.Value == "union"); foreach (var u in unions) { spec.Unions.Add(StructureDefinition.FromXML(u)); } // TypeDef var typeDefs = types.Elements("type").Where(t => t.Value.Contains("typedef") && t.Attribute("category")?.Value == "bitmask"); foreach (var type in typeDefs) { spec.TypeDefs.Add(TypedefDefinition.FromXML(type)); } // BaseTypes spec.BaseTypes = types.Elements("type").Where(bt => bt.Attribute("category")?.Value == "basetype") .ToDictionary( bt => bt.Element("name").Value, bt => bt.Element("type")?.Value); // Handles var handles = types.Elements("type").Where(h => h.Attribute("category")?.Value == "handle"); foreach (var h in handles) { spec.Handles.Add(HandleDefinition.FromXML(h)); } // Commands var commands = registry.Element("commands").Elements("command").Where(c => c.Attribute("alias") == null); foreach (var command in commands) { spec.Commands.Add(CommandDefinition.FromXML(command)); } // Features var features = registry.Elements("feature"); foreach (var feature in features) { spec.Features.Add(FeatureDefinition.FromXML(feature)); } // Extensions var extensions = registry.Element("extensions").Elements("extension"); foreach (var extension in extensions) { spec.Extensions.Add(ExtensionDefinition.FromXML(extension)); } return(spec); }