public static string ConvertToCSharpType(string type, int pointerlevel, VulkanSpecification spec) { string memberType = type; if (type.StartsWith("PFN") || IsIntPtr(memberType)) { return("IntPtr"); } string result = ConvertBasicTypes(memberType); if (result == string.Empty) { if (spec.Alias.TryGetValue(memberType, out string alias)) { memberType = alias; } spec.BaseTypes.TryGetValue(memberType, out string baseType); if (baseType != null) { result = ConvertBasicTypes(baseType); } else { var typeDef = spec.TypeDefs.Find(t => t.Name == memberType); if (typeDef != null) { if (typeDef.Requires != null) { result = typeDef.Requires; } else { spec.BaseTypes.TryGetValue(typeDef.Type, out baseType); if (baseType != null) { result = ConvertBasicTypes(baseType); } } } else { result = memberType; } } } if (pointerlevel > 0) { for (int i = 0; i < pointerlevel; i++) { result += "*"; } } return(result); }
public string GetParametersSignature(VulkanSpecification spec, bool useTypes = true) { StringBuilder signature = new StringBuilder(); foreach (var p in Parameters) { string convertedType = Helpers.GetPrettyEnumName(Helpers.ConvertToCSharpType(p.Type, p.PointerLevel, spec)); string convertedName = Helpers.ValidatedName(p.Name); if (useTypes) { signature.Append($"{convertedType} "); } signature.Append($"{convertedName}, "); } signature.Length -= 2; return(signature.ToString()); }
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); }
public static VulkanVersion FromSpec(VulkanSpecification spec, string versionName, IEnumerable <ExtensionDefinition> extensions) { VulkanVersion version = new VulkanVersion(); version.Constants = spec.Constants; version.FuncPointers = spec.FuncPointers; version.Handles = spec.Handles; version.Unions = spec.Unions; version.Structs = spec.Structs; version.Enums = spec.Enums; for (int i = 0; i < spec.Features.Count; i++) { FeatureDefinition feature = spec.Features[i]; // Extend Enums foreach (var enumType in feature.Enums) { if (enumType.Extends != null & enumType.Alias == null) { string name = enumType.Extends; var enumDefinition = spec.Enums.Find(c => c.Name == name); EnumValue newValue = new EnumValue(); newValue.Name = enumType.Name; newValue.Value = int.Parse(enumType.Value); enumDefinition.Values.Add(newValue); } } // Add commands foreach (var command in feature.Commands) { string name = command; if (spec.Alias.TryGetValue(name, out string alias)) { name = alias; } var commandDefinition = spec.Commands.Find(c => c.Prototype.Name == name); version.Commands.Add(commandDefinition); } if (feature.Name == versionName) { break; } } foreach (var extension in extensions) { // Extend Enums foreach (var enumType in extension.Enums) { if (enumType.Extends != null & enumType.Alias == null) { string name = enumType.Extends; var enumDefinition = spec.Enums.Find(c => c.Name == name); if (!enumDefinition.Values.Exists(e => e.Name == enumType.Name)) { EnumValue newValue = new EnumValue(); newValue.Name = enumType.Name; newValue.Value = int.Parse(enumType.Value); enumDefinition.Values.Add(newValue); } } } // Add commands foreach (var command in extension.Commands) { string name = command; if (spec.Alias.TryGetValue(name, out string alias)) { name = alias; } var commandDefinition = spec.Commands.Find(c => c.Prototype.Name == name); if (!version.Commands.Exists(c => c.Prototype.Name == name)) { version.Commands.Add(commandDefinition); } } } return(version); }