private Dictionary <string, Function> ConvertFunctions(VulkanSpecification spec, ProfileConverterOptions opts) { var ret = new Dictionary <string, Function>(); foreach (var function in spec.Commands) { ret.Add ( function.Name, new Function { Name = Naming.Translate(NameTrimmer.Trim(TrimName(function.Name, opts), opts.Prefix), opts.Prefix), Parameters = function.Parameters.Select ( x => new Parameter { Count = x.IsNullTerminated ? null : x.ElementCountSymbolic != null ? new Count(x.ElementCountSymbolic.Split(',')) : new Count(x.ElementCount), Flow = ConvertFlow(x.Modifier), Name = x.Name, Type = ConvertType(x.Type) } ) .ToList(), NativeName = function.Name, ReturnType = ConvertType(function.ReturnType) } ); } return(ret); }
/********* ** Public Methods *********/ /// <summary>The application entry point.</summary> public static void Main() { // ensure vk.xml exists var vkXmlPath = Path.Combine(Environment.CurrentDirectory, "vk.xml"); if (!File.Exists(vkXmlPath)) { throw new FileNotFoundException($"{vkXmlPath} doesn't exist"); } // parse xml file to specification object VulkanSpecification specification; using (var fileStream = File.OpenRead(vkXmlPath)) { try { specification = new VulkanSpecification(XDocument.Load(fileStream)); } catch (Exception ex) { Console.WriteLine($"Failed to parse XML file to VulkanSpecification {ex}"); return; } } // generate code CodeGenerator.GenerateCode(specification); }
/********* ** Public Methods *********/ /// <summary>Geenrates the C# files for a specification.</summary> /// <param name="specification">The specification to generate the code from.</param> public static void GenerateCode(VulkanSpecification specification) { var outputPath = "./Generated/"; if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } GenerateVKFile(specification.Constants, specification.Commands, Path.Combine(outputPath, "VK.gen.cs")); GenerateEnumsFile(specification.Enums, Path.Combine(outputPath, "Enums.gen.cs")); GenerateDelegatesFile(specification.Delegates, Path.Combine(outputPath, "Delegates.gen.cs")); GenerateHandlesFile(specification.Handles, Path.Combine(outputPath, "Handles.gen.cs")); GenerateStructuresFile(specification.Structures, specification.Constants, Path.Combine(outputPath, "Structures.gen.cs")); }
private Dictionary <string, Function> ConvertFunctions(VulkanSpecification spec, BindTask task) { var ret = new Dictionary <string, Function>(); foreach (var function in spec.Commands) { ret.Add ( function.Name, new Function { Name = Naming.Translate(NameTrimmer.Trim(TrimName(function.Name, task), task.FunctionPrefix), task.FunctionPrefix), Parameters = function.Parameters.Select ( x => new Parameter { Count = x.IsNullTerminated ? null : x.ElementCountSymbolic != null ? function.Parameters.Any(y => y.Name == x.ElementCountSymbolic) ? new(x.ElementCountSymbolic) : new(x.ElementCountSymbolic.Split(',')) : new(x.ElementCount), Flow = ConvertFlow(x.Modifier), Name = x.Name, Type = ConvertType(x.Type) }
private Dictionary <string, Struct> ConvertStructs(VulkanSpecification spec, BindTask task) { var prefix = task.FunctionPrefix; var ret = new Dictionary <string, Struct>(); // Gets all aliases of a struct, no matter where in an alias chain we start // Note this could be simpler if we just assume we only need to check $VKALIASES, but this // version is bombproof. IReadOnlyList <Struct> GetAllAliasesFromName(string structName) { var todo = new Queue <string>(); todo.Enqueue(structName); var result = new Dictionary <string, Struct>(); while (todo.Any()) { structName = todo.Dequeue(); if (!ret.TryGetValue(structName, out var s)) { result[structName] = null; continue; } result[structName] = s; // Get any aliases var aliasOf = s.Attributes .FirstOrDefault ( a => a.Arguments.Count > 1 && a.Name == "BuildToolsIntrinsic" && a.Arguments[0] == "$VKALIASOF" ) ?.Arguments[1]; if (!string.IsNullOrWhiteSpace(aliasOf) && !result.ContainsKey(aliasOf)) { todo.Enqueue(aliasOf); } // Check other way as well foreach (var a in s.Attributes .FirstOrDefault ( a => a.Arguments.Count > 1 && a.Name == "BuildToolsIntrinsic" && a.Arguments[0] == "$VKALIASES" ) ?.Arguments .Skip(1) .Where(a => !string.IsNullOrWhiteSpace(a) && !result.ContainsKey(a)) .ToArray() ?? Array.Empty <string>()) { todo.Enqueue(a); } } return(result.Values.Where(s => s is not null).ToList()); } // Opposite way round lookup of what aliases exist for this key-struct // i.e. if VkB is an alias of VkA, and VkC is an alias of VkA, then aliases has [VkA]={VkB,VkC} var aliases = new Dictionary <string, List <string> >(); // Holds any chain starts for chains we haven't seen yet (should rarely be needed). var chainExtensions = new List <(Struct, IReadOnlyList <string>)>(); foreach (var s in spec.Structures) { // Build aliases dictionary if (!string.IsNullOrWhiteSpace(s.Alias)) { if (!aliases.TryGetValue(s.Alias, out var aList)) { aList = new(); aliases[s.Alias] = aList; } aList.Add(s.Name); continue; } var @struct = new Struct { Fields = s.Members.Select ( x => new Field { Count = string.IsNullOrEmpty(x.ElementCountSymbolic) ? x.ElementCount != 1 ? new Count(x.ElementCount) : null : new Count(x.ElementCountSymbolic, false), Name = Naming.Translate(TrimName(x.Name, task), prefix), Doc = $"/// <summary>{x.Comment}</summary>", NativeName = x.Name, NativeType = x.Type.ToString(), Type = ConvertType(x.Type), DefaultAssignment = (x.Type.Name == "VkStructureType" || x.Type.Name == "XrStructureType") && !string.IsNullOrWhiteSpace(x.LegalValues) ? "StructureType." + TryTrim ( Naming.Translate ( TrimName(x.LegalValues.Split(',').FirstOrDefault(), task), task.FunctionPrefix ), Naming.TranslateLite(TrimName("VkStructureType", task), task.FunctionPrefix) ) : null, NumBits = x.NumBits }.WithFixedFieldFixup09072020() ) .ToList(), Name = Naming.TranslateLite(TrimName(s.Name, task), prefix), NativeName = s.Name }; // Find the STYpe field (and it's position, which is required for IChainable var(sTypeField, sTypeFieldIndex) = @struct.Fields.Select((f, i) => (Field: f, Index: i)) .FirstOrDefault(f => f.Field.Name == "SType" && f.Field.Type.Name == "VkStructureType"); if (sTypeField is not null) { @struct.Attributes.Add ( new() { Name = "BuildToolsIntrinsic", Arguments = new() { "$VKSTRUCTUREDTYPE", sTypeField.DefaultAssignment ?? string.Empty } } ); // Ensure SType was in position 0, and we have a pointer called PNext in position 1. Field pNextField; if (sTypeFieldIndex == 0 && @struct.Fields.Count > 1 && (pNextField = @struct.Fields[1]).Name == "PNext" && pNextField.Type.IsPointer) { // The type is at least chainable. @struct.Attributes.Add ( new() { Name = "BuildToolsIntrinsic", Arguments = new() { "$VKCHAINABLE" } } ); if (s.Extends.Any()) { chainExtensions.Add((@struct, s.Extends)); } } } ret.Add(s.Name, @struct); } // Create Aliases foreach (var(structName, aList) in aliases) { if (!ret.TryGetValue(structName, out var @struct)) { continue; } foreach (var alias in aList) { var aliasStruct = @struct.Clone(Naming.TranslateLite(TrimName(alias, task), prefix), alias); aliasStruct.Attributes.Add ( new() { Name = "BuildToolsIntrinsic", Arguments = new() { "$VKALIASOF", @struct.NativeName } } ); // Create a clone for the alias ret.Add(alias, aliasStruct); } // Now that we've finished cloning we can add the build intrinsic to the root struct. @struct.Attributes.Add ( new() { Name = "BuildToolsIntrinsic", Arguments = new[] { "$VKALIASES" }.Concat(aList).ToList() } ); } // Add chain extensions, we have to do this now to account for aliases, we if (chainExtensions.Any()) { foreach (var(@struct, chainNames) in chainExtensions) { // Get all the aliases of this struct (including this one) var allStructs = GetAllAliasesFromName(@struct.NativeName); // Get all the chains this struct extends (including their aliases) var chains = chainNames.SelectMany(n => GetAllAliasesFromName(n)).ToArray(); // Add $VKEXTENDSCHAIN build tools intrinsic attribute to all versions of this struct Attribute attribute = null; foreach (var s in allStructs) { if (attribute is null) { // Create $VKEXTENDSCHAIN build tools intrinsic attribute attribute = new() { Name = "BuildToolsIntrinsic", Arguments = new[] { "$VKEXTENDSCHAIN" }.Concat(chains.Select(c => c.Name)).ToList() }; } else { // Clone existing attribute. attribute = attribute.Clone(); } s.Attributes.Add(attribute); } // Add chain starts to all chains and their aliases attribute = null; foreach (var c in chains) { if (attribute is null) { // Create $VKEXTENDSCHAIN build tools intrinsic attribute attribute = new() { Name = "BuildToolsIntrinsic", Arguments = new[] { "$VKCHAINSTART" }.Concat(allStructs.Select(s => s.Name)).ToList() }; } else { // Clone existing attribute. attribute = attribute.Clone(); } c.Attributes.Add(attribute); } } } foreach (var h in spec.Handles) { ret.Add ( h.Name, new Struct { Fields = new List <Field> { new Field { Name = "Handle", Type = new Type { Name = h.CanBeDispatched ? "nint" : "ulong" } } }, Name = Naming.TranslateLite(TrimName(h.Name, task), prefix), NativeName = h.Name } ); } foreach (var u in spec.Unions) { ret.Add ( u.Name, new Struct { Attributes = new List <Attribute> { new Attribute { Name = "StructLayout", Arguments = new List <string> { "LayoutKind.Explicit" } } }, Fields = GetFields(u, task).ToList(), Name = Naming.TranslateLite(TrimName(u.Name, task), prefix), NativeName = u.Name } ); } return(ret); }
/// <inheritdoc /> public object Load(Stream stream) { return(VulkanSpecification.LoadFromXmlStream(stream)); }
private Dictionary <string, Struct> ConvertStructs(VulkanSpecification spec, ProfileConverterOptions opts) { var prefix = opts.Prefix; var ret = new Dictionary <string, Struct>(); foreach (var s in spec.Structures) { ret.Add ( s.Name, new Struct { Fields = s.Members.Select ( x => new Field { Count = string.IsNullOrEmpty(x.ElementCountSymbolic) ? x.ElementCount != 1 ? new Count(x.ElementCount) : null : new Count(x.ElementCountSymbolic, false), Name = Naming.Translate(TrimName(x.Name, opts), prefix), Doc = $"/// <summary>{x.Comment}</summary>", NativeName = x.Name, NativeType = x.Type.ToString(), Type = ConvertType(x.Type), DefaultAssignment = x.Type.Name == "VkStructureType" && !string.IsNullOrWhiteSpace(x.LegalValues) ? "StructureType." + TryTrim ( Naming.Translate ( TrimName(x.LegalValues.Split(',').FirstOrDefault(), opts), opts.Prefix ), Naming.TranslateLite(TrimName("VkStructureType", opts), opts.Prefix) ) : null } ) .ToList(), Name = Naming.TranslateLite(TrimName(s.Name, opts), prefix), NativeName = s.Name } ); } foreach (var h in spec.Handles) { ret.Add ( h.Name, new Struct { Fields = new List <Field> { new Field { Name = "Handle", Type = new Type { Name = h.CanBeDispatched ? "IntPtr" : "ulong" } } }, Name = Naming.TranslateLite(TrimName(h.Name, opts), prefix), NativeName = h.Name } ); } foreach (var u in spec.Unions) { ret.Add(u.Name, new Struct { Attributes = new List <Attribute> { new Attribute { Name = "StructLayout", Arguments = new List <string> { "LayoutKind.Explicit" } } }, Fields = GetFields(u, opts).ToList(), Name = Naming.TranslateLite(TrimName(u.Name, opts), prefix), NativeName = u.Name }); } return(ret); }