private static void GenerateHandles(CppCompilation compilation, string outputPath) { // Generate Functions using var writer = new CodeWriter(Path.Combine(outputPath, "Handles.cs"), "System", "System.Diagnostics" ); foreach (var typedef in compilation.Typedefs) { if (typedef.Name.StartsWith("PFN_")) { continue; } if (!(typedef.ElementType is CppPointerType)) { continue; } var isDispatchable = typedef.Name == "VkInstance" || typedef.Name == "VkPhysicalDevice" || typedef.Name == "VkDevice" || typedef.Name == "VkQueue" || typedef.Name == "VkCommandBuffer"; var csName = typedef.Name; writer.WriteLine($"/// <summary>"); writer.WriteLine($"/// A {(isDispatchable ? "dispatchable" : "non-dispatchable")} handle."); writer.WriteLine("/// </summary>"); writer.WriteLine($"[DebuggerDisplay(\"{{DebuggerDisplay,nq}}\")]"); using (writer.PushBlock($"public partial struct {csName} : IEquatable<{csName}>")) { string handleType = isDispatchable ? "IntPtr" : "ulong"; string nullValue = isDispatchable ? "IntPtr.Zero" : "0"; writer.WriteLine($"public readonly {handleType} Handle;"); writer.WriteLine($"public {csName}({handleType} handle) {{ Handle = handle; }}"); writer.WriteLine($"public static {csName} Null => new {csName}(({handleType}){nullValue});"); writer.WriteLine($"public static implicit operator {csName}({handleType} handle) => new {csName}(({handleType})handle);"); writer.WriteLine($"public static implicit operator bool({csName} handle) => handle.Handle != {nullValue};"); writer.WriteLine($"public static bool operator ==({csName} left, {csName} right) => left.Handle == right.Handle;"); writer.WriteLine($"public static bool operator !=({csName} left, {csName} right) => left.Handle != right.Handle;"); writer.WriteLine($"public static bool operator ==({csName} left, {handleType} right) => left.Handle == right;"); writer.WriteLine($"public static bool operator !=({csName} left, {handleType} right) => left.Handle != right;"); writer.WriteLine($"public bool Equals(ref {csName} other) => Handle == other.Handle;"); writer.WriteLine($"public bool Equals({csName} other) => Handle == other.Handle;"); writer.WriteLine($"public override bool Equals(object obj) => obj is {csName} handle && Equals(ref handle);"); writer.WriteLine($"public override int GetHashCode() => Handle.GetHashCode();"); writer.WriteLine($"private string DebuggerDisplay => string.Format(\"{csName} [0x{{0}}]\", Handle.ToString(\"X\"));"); } writer.WriteLine(); } }
private static void WriteCommands(CodeWriter writer, string name, Dictionary <string, CppFunction> commands) { using (writer.PushBlock($"private static void {name}(IntPtr context, LoadFunction load)")) { foreach (var instanceCommand in commands) { var commandName = instanceCommand.Key; writer.WriteLine($"{commandName}_ptr = load(context, nameof({commandName}));"); } } }
private static void WriteCommands(CodeWriter writer, string name, Dictionary <string, CppFunction> commands) { using (writer.PushBlock($"private static void {name}(IntPtr context, LoadFunction load)")) { foreach (var instanceCommand in commands) { var commandName = instanceCommand.Key; if (calliFunction) { } else { writer.WriteLine($"{commandName}_ptr = LoadCallback<{commandName}Delegate>(context, load, \"{commandName}\");"); } } } }
private static void GenerateConstants(CppCompilation compilation, string outputPath) { using var writer = new CodeWriter(Path.Combine(outputPath, "Constants.cs")); writer.WriteLine("/// <summary>"); writer.WriteLine("/// Provides Vulkan specific constants for special values, layer names and extension names."); writer.WriteLine("/// </summary>"); using (writer.PushBlock("public static partial class Vulkan")) { foreach (var cppMacro in compilation.Macros) { if (string.IsNullOrEmpty(cppMacro.Value) || cppMacro.Name.EndsWith("_H_", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VKAPI_CALL", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VKAPI_PTR", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VULKAN_CORE_H_", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VK_TRUE", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VK_FALSE", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VK_MAKE_VERSION", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.StartsWith("VK_ENABLE_BETA_EXTENSIONS", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.StartsWith("VK_VERSION_", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.StartsWith("VK_API_VERSION_", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VK_NULL_HANDLE", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VK_DEFINE_HANDLE", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.Equals("VK_DEFINE_NON_DISPATCHABLE_HANDLE", StringComparison.OrdinalIgnoreCase) || cppMacro.Name.StartsWith("VK_USE_PLATFORM_", StringComparison.OrdinalIgnoreCase) ) { continue; } string csName = GetPrettyEnumName(cppMacro.Name, "VK_"); string modifier = "const"; string csDataType = "string"; var macroValue = NormalizeEnumValue(cppMacro.Value); if (macroValue.EndsWith("F", StringComparison.OrdinalIgnoreCase)) { csDataType = "float"; } else if (macroValue.EndsWith("UL", StringComparison.OrdinalIgnoreCase)) { csDataType = "ulong"; } else if (macroValue.EndsWith("U", StringComparison.OrdinalIgnoreCase)) { csDataType = "uint"; } else if (uint.TryParse(macroValue, out _)) { csDataType = "uint"; } if (cppMacro.Name == "VK_QUEUE_FAMILY_EXTERNAL" || cppMacro.Name == "VK_QUEUE_FAMILY_FOREIGN_EXT") { csDataType = "uint"; } else if (cppMacro.Name == "VK_LUID_SIZE_KHR" || cppMacro.Name == "VK_SHADER_UNUSED_NV" || cppMacro.Name == "VK_QUEUE_FAMILY_EXTERNAL_KHR" || cppMacro.Name == "VK_MAX_DRIVER_NAME_SIZE_KHR" || cppMacro.Name == "VK_MAX_DRIVER_INFO_SIZE_KHR" || cppMacro.Name == "VK_MAX_DEVICE_GROUP_SIZE_KHR" ) { csDataType = "uint"; macroValue = GetCsCleanName(cppMacro.Value); } AddCsMapping(cppMacro.Name, csName); writer.WriteLine("/// <summary>"); if (cppMacro.Name == "VK_HEADER_VERSION_COMPLETE") { modifier = "static readonly"; csDataType = "VkVersion"; } writer.WriteLine($"/// {cppMacro.Name} = {cppMacro.Value}"); writer.WriteLine("/// </summary>"); if (cppMacro.Name == "VK_HEADER_VERSION_COMPLETE") { writer.WriteLine($"public {modifier} {csDataType} {csName} = new VkVersion({cppMacro.Tokens[2]}, {cppMacro.Tokens[4]}, HeaderVersion);"); } else { writer.WriteLine($"public {modifier} {csDataType} {csName} = {macroValue};"); } } } }
public static void GenerateEnums(CppCompilation compilation, string outputPath) { using var writer = new CodeWriter(Path.Combine(outputPath, "Enumerations.cs"), "System"); var createdEnums = new Dictionary <string, string>(); foreach (var cppEnum in compilation.Enums) { var isBitmask = cppEnum.Name.EndsWith("FlagBits") || cppEnum.Name.EndsWith("FlagBitsEXT") || cppEnum.Name.EndsWith("FlagBitsKHR") || cppEnum.Name.EndsWith("FlagBitsNV") || cppEnum.Name.EndsWith("FlagBitsAMD") || cppEnum.Name.EndsWith("FlagBitsMVK") || cppEnum.Name.EndsWith("FlagBitsNN"); if (isBitmask) { writer.WriteLine("[Flags]"); } string csName = GetCsCleanName(cppEnum.Name); string enumNamePrefix = GetEnumNamePrefix(cppEnum.Name); // Rename FlagBits in Flags. if (isBitmask) { csName = csName.Replace("FlagBits", "Flags"); AddCsMapping(cppEnum.Name, csName); } // Remove extension suffix from enum item values string extensionPrefix = ""; if (csName.EndsWith("EXT")) { extensionPrefix = "EXT"; } else if (csName.EndsWith("NV")) { extensionPrefix = "NV"; } else if (csName.EndsWith("KHR")) { extensionPrefix = "KHR"; } createdEnums.Add(csName, cppEnum.Name); using (writer.PushBlock($"public enum {csName}")) { if (isBitmask && !cppEnum.Items.Any(item => GetPrettyEnumName(item.Name, enumNamePrefix) == "None")) { writer.WriteLine("None = 0,"); } foreach (var enumItem in cppEnum.Items) { if (enumItem.Name.EndsWith("_BEGIN_RANGE") || enumItem.Name.EndsWith("_END_RANGE") || enumItem.Name.EndsWith("_RANGE_SIZE") || enumItem.Name.EndsWith("_BEGIN_RANGE_EXT") || enumItem.Name.EndsWith("_BEGIN_RANGE_KHR") || enumItem.Name.EndsWith("_BEGIN_RANGE_NV") || enumItem.Name.EndsWith("_BEGIN_RANGE_AMD") || enumItem.Name.EndsWith("_END_RANGE_EXT") || enumItem.Name.EndsWith("_END_RANGE_KHR") || enumItem.Name.EndsWith("_END_RANGE_NV") || enumItem.Name.EndsWith("_END_RANGE_AMD") || enumItem.Name.EndsWith("_RANGE_SIZE_EXT") || enumItem.Name.EndsWith("_RANGE_SIZE_KHR") || enumItem.Name.EndsWith("_RANGE_SIZE_NV") || enumItem.Name.EndsWith("_RANGE_SIZE_AMD") || enumItem.Name.EndsWith("_MAX_ENUM") || enumItem.Name.EndsWith("_MAX_ENUM_EXT") || enumItem.Name.EndsWith("_MAX_ENUM_KHR") || enumItem.Name.EndsWith("_MAX_ENUM_NV") || enumItem.Name.EndsWith("_MAX_ENUM_AMD") || enumItem.Name.EndsWith("_MAX_ENUM_INTEL") || enumItem.Name == "VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT" || enumItem.Name == "VK_STENCIL_FRONT_AND_BACK" || enumItem.Name == "VK_PIPELINE_CREATE_DISPATCH_BASE") { continue; } var enumItemName = GetEnumItemName(cppEnum, enumItem.Name, enumNamePrefix); if (!string.IsNullOrEmpty(extensionPrefix) && enumItemName.EndsWith(extensionPrefix)) { enumItemName = enumItemName.Remove(enumItemName.Length - extensionPrefix.Length); } //writer.WriteLine("/// <summary>"); //writer.WriteLine($"/// {enumItem.Name}"); //writer.WriteLine("/// </summary>"); if (enumItem.ValueExpression is CppRawExpression rawExpression) { var enumValueName = GetEnumItemName(cppEnum, rawExpression.Text, enumNamePrefix); if (enumItemName == "SurfaceCapabilities2EXT") { continue; } if (!string.IsNullOrEmpty(extensionPrefix) && enumValueName.EndsWith(extensionPrefix)) { enumValueName = enumValueName.Remove(enumValueName.Length - extensionPrefix.Length); if (enumItemName == enumValueName) { continue; } } writer.WriteLine($"{enumItemName} = {enumValueName},"); } else { writer.WriteLine($"{enumItemName} = {enumItem.Value},"); } } if (csName == "VkColorComponentFlags") { writer.WriteLine($"All = R | G | B | A"); } } writer.WriteLine(); } // Map missing flags with typedefs to VkFlags foreach (var typedef in compilation.Typedefs) { if (typedef.Name.StartsWith("PFN_") || typedef.Name.Equals("VkBool32", StringComparison.OrdinalIgnoreCase) || typedef.Name.Equals("VkFlags", StringComparison.OrdinalIgnoreCase)) { continue; } if (typedef.ElementType is CppPointerType) { continue; } if (createdEnums.ContainsKey(typedef.Name)) { continue; } if (typedef.Name.EndsWith("Flags", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagsKHR", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagsEXT", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagsNV", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagsAMD", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagsMVK", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagsNN", StringComparison.OrdinalIgnoreCase)) { writer.WriteLine("[Flags]"); using (writer.PushBlock($"public enum {typedef.Name}")) { writer.WriteLine("None = 0,"); } writer.WriteLine(); } } }
private static void GenerateHelperCommands(CppCompilation compilation, string outputPath) { // Generate Functions using var writer = new CodeWriter(Path.Combine(outputPath, "VkHelpers.cs"), "System", "System.Diagnostics", "System.Runtime.InteropServices", "Vortice.Mathematics"); using (writer.PushBlock($"unsafe partial class Vulkan")) { // Generate methods with array calls foreach (var function in compilation.Functions) { if (!s_outArrayReturnFunctions.Contains(function.Name)) { continue; } if (function.Name == "vkGetPhysicalDeviceSurfacePresentModesKHR") { } // Find count and array return type. var countParameterName = string.Empty; var returnArrayTypeName = string.Empty; var returnVariableName = string.Empty; var newParameters = new List <CppParameter>(); var hasArrayReturn = false; var countArgumentArrayIndex = 0; foreach (var parameter in function.Parameters) { if (parameter.Name.EndsWith("count", StringComparison.OrdinalIgnoreCase)) { countParameterName = GetParameterName(parameter.Name); continue; } if (CanBeUsedAsOutput(parameter.Type, out var cppTypeDeclaration)) { returnVariableName = GetParameterName(parameter.Name); returnArrayTypeName = GetCsTypeName(cppTypeDeclaration); hasArrayReturn = true; countArgumentArrayIndex = function.Parameters.IndexOf(parameter) - 1; continue; } if (parameter.Type is CppPointerType pointerType && pointerType.ElementType is CppQualifiedType qualifiedType && !string.IsNullOrEmpty(countParameterName)) { returnVariableName = GetParameterName(parameter.Name); returnArrayTypeName = GetCsTypeName(qualifiedType); hasArrayReturn = false; countArgumentArrayIndex = function.Parameters.IndexOf(parameter) - 1; continue; } newParameters.Add(parameter); } var csCountParameterType = "uint"; if (!hasArrayReturn) { // Calls without return array. var returnType = GetCsTypeName(function.ReturnType); var argumentsSingleElementBuilder = new StringBuilder(); var argumentsReadOnlySpanBuilder = new StringBuilder(); var index = 0; var invokeSingleElementParameters = new List <string>(); var invokeElementsParameters = new List <string>(); foreach (var cppParameter in newParameters) { var paramCsTypeName = GetCsTypeName(cppParameter.Type, false); var paramCsName = GetParameterName(cppParameter.Name); var argumentSignature = $"{paramCsTypeName} {paramCsName}"; if (index == countArgumentArrayIndex) { AppendCountParameter(false, argumentsSingleElementBuilder, argumentsReadOnlySpanBuilder, invokeSingleElementParameters, invokeElementsParameters, returnArrayTypeName, returnVariableName, csCountParameterType); } argumentsSingleElementBuilder.Append(argumentSignature); argumentsReadOnlySpanBuilder.Append(argumentSignature); if (index < newParameters.Count - 1) { argumentsSingleElementBuilder.Append(", "); argumentsReadOnlySpanBuilder.Append(", "); } invokeSingleElementParameters.Add(paramCsName); invokeElementsParameters.Add(paramCsName); index++; } // Functions like vkFlushMappedMemoryRanges if (newParameters.Count == countArgumentArrayIndex) { AppendCountParameter(true, argumentsSingleElementBuilder, argumentsReadOnlySpanBuilder, invokeSingleElementParameters, invokeElementsParameters, returnArrayTypeName, returnVariableName, csCountParameterType); } // Single element function. var argumentsSingleElementString = argumentsSingleElementBuilder.ToString(); using (writer.PushBlock($"public static {returnType} {function.Name}({argumentsSingleElementString})")) { if (returnType != "void") { writer.Write("return "); } EmitInvoke(writer, function, invokeSingleElementParameters, false); } writer.WriteLine(); // ReadOnlySpan var argumentsReadOnlySpanString = argumentsReadOnlySpanBuilder.ToString(); using (writer.PushBlock($"public static {returnType} {function.Name}({argumentsReadOnlySpanString})")) { using (writer.PushBlock($"fixed ({returnArrayTypeName}* {returnVariableName}Ptr = {returnVariableName})")) { if (returnType != "void") { writer.Write("return "); } EmitInvoke(writer, function, invokeElementsParameters, false); } } } else { var argumentsString = GetParameterSignature(newParameters, false); var returnType = $"ReadOnlySpan<{returnArrayTypeName}>"; using (writer.PushBlock($"public static {returnType} {function.Name}({argumentsString})")) { //var csCountParameterType = GetCsTypeName(countParameterType); writer.WriteLine($"{csCountParameterType} {countParameterName} = 0;"); var invokeParameters = new List <string>(newParameters.Select(item => GetParameterName(item.Name))) { $"&{countParameterName}", "null" }; EmitInvoke(writer, function, invokeParameters); writer.WriteLine(); // Alloc array. writer.WriteLine($"{returnType} {returnVariableName} = new {returnArrayTypeName}[{countParameterName}];"); // Write fixed access using (writer.PushBlock($"fixed ({returnArrayTypeName}* {returnVariableName}Ptr = {returnVariableName})")) { invokeParameters[invokeParameters.Count - 1] = $"{returnVariableName}Ptr"; EmitInvoke(writer, function, invokeParameters); } writer.WriteLine($"return {returnVariableName};"); } } writer.WriteLine(); } } }
private static void GenerateCommands(CppCompilation compilation, string outputPath) { // Generate Functions using var writer = new CodeWriter(Path.Combine(outputPath, "Commands.cs"), "System", "System.Diagnostics", "System.Runtime.InteropServices", "Vortice.Mathematics"); var commands = new Dictionary <string, CppFunction>(); var instanceCommands = new Dictionary <string, CppFunction>(); var deviceCommands = new Dictionary <string, CppFunction>(); foreach (var cppFunction in compilation.Functions) { var returnType = GetCsTypeName(cppFunction.ReturnType, false); bool canUseOut = s_outReturnFunctions.Contains(cppFunction.Name); var csName = cppFunction.Name; var argumentsString = GetParameterSignature(cppFunction, canUseOut); if (disableCalliFunction) { writer.WriteLine("[UnmanagedFunctionPointer(CallingConvention.StdCall)]"); writer.WriteLine($"public unsafe delegate {returnType} {csName}Delegate({argumentsString});"); writer.WriteLine(); } commands.Add(csName, cppFunction); if (cppFunction.Parameters.Count > 0) { var firstParameter = cppFunction.Parameters[0]; if (firstParameter.Type is CppTypedef typedef) { if (typedef.Name == "VkInstance" || typedef.Name == "VkPhysicalDevice" || IsInstanceFunction(cppFunction.Name)) { instanceCommands.Add(csName, cppFunction); } else { deviceCommands.Add(csName, cppFunction); } } } } using (writer.PushBlock($"unsafe partial class Vulkan")) { foreach (var command in commands) { var cppFunction = command.Value; if (disableCalliFunction) { writer.WriteLine($"private static {command.Key}Delegate {command.Key}_ptr;"); } else { writer.WriteLine($"private static IntPtr {command.Key}_ptr;"); writer.WriteLine($"[Calli]"); } var returnType = GetCsTypeName(cppFunction.ReturnType, false); bool canUseOut = s_outReturnFunctions.Contains(cppFunction.Name); var argumentsString = GetParameterSignature(cppFunction, canUseOut); using (writer.PushBlock($"public static {returnType} {cppFunction.Name}({argumentsString})")) { if (disableCalliFunction) { if (returnType != "void") { writer.Write("return "); } writer.Write($"{command.Key}_ptr("); var index = 0; foreach (var cppParameter in cppFunction.Parameters) { var paramCsName = GetParameterName(cppParameter.Name); if (canUseOut && CanBeUsedAsOutput(cppParameter.Type, out var cppTypeDeclaration)) { writer.Write("out "); } writer.Write($"{paramCsName}"); if (index < cppFunction.Parameters.Count - 1) { writer.Write(", "); } index++; } writer.WriteLine($");"); } else { writer.WriteLine("throw new NotImplementedException();"); } } writer.WriteLine(); } WriteCommands(writer, "GenLoadInstance", instanceCommands); WriteCommands(writer, "GenLoadDevice", deviceCommands); } }
public static void GenerateEnums(CppCompilation compilation, string outputPath) { using var writer = new CodeWriter(Path.Combine(outputPath, "Enumerations.cs"), "System"); var createdEnums = new Dictionary <string, string>(); foreach (var cppEnum in compilation.Enums) { var isBitmask = cppEnum.Name.EndsWith("FlagBits") || cppEnum.Name.EndsWith("Flags") || cppEnum.Name.EndsWith("Flags_"); if (isBitmask) { writer.WriteLine("[Flags]"); } string csName = GetCsCleanName(cppEnum.Name); if (csName.EndsWith("_")) { csName = csName.Substring(0, csName.Length - 1); AddCsMapping(cppEnum.Name, csName); } string enumNamePrefix = GetEnumNamePrefix(cppEnum.Name); // Rename FlagBits in Flags. if (isBitmask) { csName = csName.Replace("FlagBits", "Flags"); AddCsMapping(cppEnum.Name, csName); } // Remove extension suffix from enum item values string extensionPrefix = ""; createdEnums.Add(csName, cppEnum.Name); using (writer.PushBlock($"public enum {csName}")) { if (isBitmask && !cppEnum.Items.Any(item => GetPrettyEnumName(item.Name, enumNamePrefix) == "None")) { writer.WriteLine("None = 0,"); } foreach (var enumItem in cppEnum.Items) { var enumItemName = GetEnumItemName(cppEnum, enumItem.Name, enumNamePrefix); if (!string.IsNullOrEmpty(extensionPrefix) && enumItemName.EndsWith(extensionPrefix)) { enumItemName = enumItemName.Remove(enumItemName.Length - extensionPrefix.Length); } //writer.WriteLine("/// <summary>"); //writer.WriteLine($"/// {enumItem.Name}"); //writer.WriteLine("/// </summary>"); if (enumItem.ValueExpression is CppRawExpression rawExpression) { var enumValueName = GetEnumItemName(cppEnum, rawExpression.Text, enumNamePrefix); if (enumItemName == "SurfaceCapabilities2EXT") { continue; } if (!string.IsNullOrEmpty(extensionPrefix) && enumValueName.EndsWith(extensionPrefix)) { enumValueName = enumValueName.Remove(enumValueName.Length - extensionPrefix.Length); if (enumItemName == enumValueName) { continue; } } writer.WriteLine($"{enumItemName} = {enumValueName},"); } else { writer.WriteLine($"{enumItemName} = {enumItem.Value},"); } } } writer.WriteLine(); } // Map missing flags with typedefs to VkFlags foreach (var typedef in compilation.Typedefs) { if (typedef.ElementType is CppPointerType) { continue; } if (createdEnums.ContainsKey(typedef.Name)) { continue; } if (typedef.Name.EndsWith("Flags", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("Flags_", StringComparison.OrdinalIgnoreCase) || typedef.Name.EndsWith("FlagBits", StringComparison.OrdinalIgnoreCase)) { writer.WriteLine("[Flags]"); using (writer.PushBlock($"public enum {typedef.Name}")) { writer.WriteLine("None = 0,"); } writer.WriteLine(); } } }
private static void GenerateCommands(CppCompilation compilation, string outputPath) { // Generate Functions using var writer = new CodeWriter(Path.Combine(outputPath, "Commands.cs"), "System", "Vortice.Mathematics" ); var commands = new Dictionary <string, CppFunction>(); var instanceCommands = new Dictionary <string, CppFunction>(); var deviceCommands = new Dictionary <string, CppFunction>(); foreach (CppFunction?cppFunction in compilation.Functions) { string?returnType = GetCsTypeName(cppFunction.ReturnType, false); bool canUseOut = s_outReturnFunctions.Contains(cppFunction.Name); string?csName = cppFunction.Name; string?argumentsString = GetParameterSignature(cppFunction, canUseOut); commands.Add(csName, cppFunction); if (cppFunction.Parameters.Count > 0) { var firstParameter = cppFunction.Parameters[0]; if (firstParameter.Type is CppTypedef typedef) { if (typedef.Name == "VkInstance" || typedef.Name == "VkPhysicalDevice" || IsInstanceFunction(cppFunction.Name)) { instanceCommands.Add(csName, cppFunction); } else { deviceCommands.Add(csName, cppFunction); } } } } using (writer.PushBlock($"unsafe partial class Vulkan")) { foreach (KeyValuePair <string, CppFunction> command in commands) { CppFunction cppFunction = command.Value; if (cppFunction.Name == "vkCmdSetBlendConstants") { } writer.WriteLine($"private static IntPtr {command.Key}_ptr;"); writer.WriteLine($"[Calli]"); var returnType = GetCsTypeName(cppFunction.ReturnType, false); bool canUseOut = s_outReturnFunctions.Contains(cppFunction.Name); var argumentsString = GetParameterSignature(cppFunction, canUseOut); using (writer.PushBlock($"public static {returnType} {cppFunction.Name}({argumentsString})")) { writer.WriteLine("throw new NotImplementedException();"); } writer.WriteLine(); } WriteCommands(writer, "GenLoadInstance", instanceCommands); WriteCommands(writer, "GenLoadDevice", deviceCommands); } }
private static void GenerateStructAndUnions(CppCompilation compilation, string outputPath) { // Generate Structures using var writer = new CodeWriter(Path.Combine(outputPath, "Structures.cs"), "System", "System.Runtime.InteropServices" ); // Print All classes, structs foreach (var cppClass in compilation.Classes) { if (cppClass.ClassKind == CppClassKind.Class || cppClass.SizeOf == 0 || cppClass.Name.EndsWith("_T")) { continue; } // Mapped to Vortice.Mathematics if (cppClass.Name == "VkTransformMatrixKHR" || cppClass.Name == "VkAccelerationStructureInstanceKHR") { continue; } bool isUnion = cppClass.ClassKind == CppClassKind.Union; Console.WriteLine($"Generating struct {cppClass.Name}"); string csName = cppClass.Name; if (isUnion) { writer.WriteLine("[StructLayout(LayoutKind.Explicit)]"); } else { writer.WriteLine("[StructLayout(LayoutKind.Sequential)]"); } bool isReadOnly = false; string modifier = "partial"; if (csName == "VkOffset2D" || csName == "VkOffset3D" || csName == "VkExtent2D" || csName == "VkExtent3D" || csName == "VkRect2D" || csName == "VkViewport" || csName == "VkClearDepthStencilValue") { modifier = "readonly partial"; isReadOnly = true; } using (writer.PushBlock($"public {modifier} struct {csName}")) { if (generateSizeOfStructs && cppClass.SizeOf > 0) { writer.WriteLine("/// <summary>"); writer.WriteLine($"/// The size of the <see cref=\"{csName}\"/> type, in bytes."); writer.WriteLine("/// </summary>"); writer.WriteLine($"public static readonly int SizeInBytes = {cppClass.SizeOf};"); writer.WriteLine(); } foreach (CppField cppField in cppClass.Fields) { string csFieldName = NormalizeFieldName(cppField.Name); if (isUnion) { writer.WriteLine("[FieldOffset(0)]"); } if (cppField.Type is CppArrayType arrayType) { bool canUseFixed = false; if (arrayType.ElementType is CppPrimitiveType) { canUseFixed = true; } else if (arrayType.ElementType is CppTypedef typedef && typedef.ElementType is CppPrimitiveType) { canUseFixed = true; } if (canUseFixed) { var csFieldType = GetCsTypeName(arrayType.ElementType, false); writer.WriteLine($"public unsafe fixed {csFieldType} {csFieldName}[{arrayType.Size}];"); } else { var unsafePrefix = string.Empty; var csFieldType = GetCsTypeName(arrayType.ElementType, false); if (csFieldType.EndsWith('*')) { unsafePrefix = "unsafe "; } for (var i = 0; i < arrayType.Size; i++) { writer.WriteLine($"public {unsafePrefix}{csFieldType} {csFieldName}_{i};"); } } } else { string csFieldType = GetCsTypeName(cppField.Type, false); if (csFieldName.Equals("specVersion", StringComparison.OrdinalIgnoreCase) || csFieldName.Equals("applicationVersion", StringComparison.OrdinalIgnoreCase) || csFieldName.Equals("engineVersion", StringComparison.OrdinalIgnoreCase) || csFieldName.Equals("apiVersion", StringComparison.OrdinalIgnoreCase)) { csFieldType = "VkVersion"; } string fieldPrefix = isReadOnly ? "readonly " : string.Empty; if (csFieldType.EndsWith('*')) { fieldPrefix += "unsafe "; } writer.WriteLine($"public {fieldPrefix}{csFieldType} {csFieldName};"); } } } writer.WriteLine(); } }
private static void GenerateCommands(CppCompilation compilation, string outputPath) { // Generate Functions using var writer = new CodeWriter(Path.Combine(outputPath, "Commands.cs"), "System", "System.Runtime.InteropServices", "ImGuiID = System.UInt32", "ImTextureID = System.IntPtr", "ImDrawIdx = System.UInt16", "ImFileHandle = System.IntPtr", "ImVec1 = System.Single", "ImVec2 = System.Numerics.Vector2", "ImVec3 = System.Numerics.Vector3", "ImVec4 = System.Numerics.Vector4", "ImColor = System.Numerics.Vector4" ); var commands = new Dictionary <string, CppFunction>(); foreach (var cppFunction in compilation.Functions) { var csName = cppFunction.Name; bool skip = false; foreach (var str in s_knowntructs) { if (csName.StartsWith(str)) { skip = true; break; } } if (skip) { continue; } foreach (var param in cppFunction.Parameters) { var paramType = GetCsTypeName(param.Type, false); if (paramType.Equals("va_list")) { skip = true; } } if (skip) { continue; } commands.Add(cppFunction.Name, cppFunction); } using (writer.PushBlock($"unsafe partial class ImGui")) { foreach (var command in commands) { var cppFunction = command.Value; var funName = cppFunction.Name; if (funName.StartsWith("ig")) { funName = funName.Substring(2); } var signature = GetFunctionPointer(cppFunction); writer.WriteLine($"static {signature} {funName}_ptr;"); var returnType = GetCsTypeName(cppFunction.ReturnType, false); if (s_handleMappings.TryGetValue(returnType, out var handleName)) { returnType = handleName; } var argumentsString = ""; bool voidRet = returnType == "void"; bool outToReturn = false; string declStr = ""; string retStr = ""; if (voidRet && GetOutParameterToReturn(cppFunction, out var retType, out declStr, out retStr)) { outToReturn = true; returnType = retType; argumentsString = GetParameterSignature(cppFunction, 1); }
private static void GenerateHandles(CppCompilation compilation, List <CppClass> handleClasses, string outputPath) { using var writer = new CodeWriter(Path.Combine(outputPath, "Handles.cs"), "System", "System.Runtime.InteropServices", "ImGuiID = System.UInt32", "ImTextureID = System.IntPtr", "ImDrawIdx = System.UInt16", "ImGuiCol = System.Int32", "ImGuiCond = System.Int32", "ImGuiDir = System.Int32", "ImGuiKey = System.Int32", "ImGuiStyleVar = System.Int32", "ImGuiSortDirection = System.Int32", "ImGuiDataAuthority = System.Int32", "ImGuiLayoutType = System.Int32", "ImGuiMouseCursor = System.Int32", "ImPoolIdx = System.Int32", "ImGuiTableColumnIdx = System.SByte", "ImGuiTableDrawChannelIdx = System.Byte", "ImFileHandle = System.IntPtr", "ImVec1 = System.Single", "ImVec2 = System.Numerics.Vector2", "ImVec3 = System.Numerics.Vector3", "ImVec4 = System.Numerics.Vector4", "ImColor = System.Numerics.Vector4", "System.Runtime.CompilerServices" ); foreach (var cppClass in handleClasses) { var csName = cppClass.Name; var handleName = s_handleMappings[csName + "*"]; Console.WriteLine($"Generating Handle {cppClass.Name}Ptr"); using (writer.PushBlock($"public unsafe partial struct {handleName}")) { writer.WriteLine($"private unsafe {csName}* self;"); writer.WriteLine($"public {handleName}({csName}* native) => self = native;"); writer.WriteLine($"public static implicit operator bool({handleName} handle) => handle.self != null;"); writer.WriteLine($"public static implicit operator {handleName}({csName}* native) => new {handleName}(native);"); writer.WriteLine($"public static implicit operator {csName}*({handleName} handle) => handle.self;"); foreach (CppField cppField in cppClass.Fields) { string csFieldName = NormalizeFieldName(cppField.Name); if (!s_csNameMappings.TryGetValue(cppField.Type.GetDisplayName(), out var csFieldType)) { csFieldType = GetCsTypeName(cppField.Type, false); } if (cppField.Type is CppArrayType arrayType) { bool canUseFixed = false; if (arrayType.ElementType is CppPrimitiveType) { canUseFixed = true; } else if (arrayType.ElementType is CppTypedef typedef && typedef.ElementType is CppPrimitiveType) { canUseFixed = true; } var elementTypeName = GetCsTypeName(arrayType.ElementType, false); string wrap = "RangeAccessor"; if (canUseFixed) { writer.WriteLine($"public {wrap}<{elementTypeName}> {csFieldName} => ({elementTypeName}*)Unsafe.AsPointer(ref self->{csFieldName}[0]);"); } else { writer.WriteLine($"public {wrap}<{elementTypeName}> {csFieldName} => ({elementTypeName}*)Unsafe.AsPointer(ref self->{csFieldName}_0);"); } continue; } if (cppField.Type is CppPointerType pointerType) { if (s_handleMappings.TryGetValue(csFieldType, out var p_HandleName)) { writer.WriteLine($"public {p_HandleName} {csFieldName} => self->{csFieldName};"); continue; } } writer.WriteLine($"public ref {csFieldType} {csFieldName} => ref self->{csFieldName};"); } foreach (var cppFunction in compilation.Functions) { if (!cppFunction.Name.StartsWith(csName + "_")) { continue; } if (cppFunction.Name.StartsWith(csName + "__")) { continue; } var returnType = GetCsTypeName(cppFunction.ReturnType, false); if (s_handleMappings.TryGetValue(returnType, out var p_handleName)) { returnType = p_handleName; } var argumentsString = ""; bool isStatic = false; if (cppFunction.Parameters.Count == 0) { isStatic = true; } bool voidRet = returnType == "void"; bool outToReturn = false; string declStr = ""; string retStr = ""; if (voidRet && GetOutParameterToReturn(cppFunction, out var retType, out declStr, out retStr)) { outToReturn = true; returnType = retType; if (cppFunction.Parameters.Count > 1) { if (cppFunction.Parameters[1].Name != "self") { isStatic = true; } } }
private static void GenerateStructures(CodeWriter writer, CppClass cppClass, bool isUnion, string csName, bool isReadOnly, string modifier) { if (isUnion) { writer.WriteLine("[StructLayout(LayoutKind.Explicit)]"); } else { writer.WriteLine("[StructLayout(LayoutKind.Sequential)]"); } using (writer.PushBlock($"{modifier} struct {csName}")) { if (generateSizeOfStructs && cppClass.SizeOf > 0) { writer.WriteLine($"public static readonly int SizeInBytes = {cppClass.SizeOf};"); writer.WriteLine(); } foreach (CppField cppField in cppClass.Fields) { string csFieldName = NormalizeFieldName(cppField.Name); if (isUnion) { writer.WriteLine("[FieldOffset(0)]"); } if (cppField.Type is CppArrayType arrayType) { bool canUseFixed = false; if (arrayType.ElementType is CppPrimitiveType) { canUseFixed = true; } else if (arrayType.ElementType is CppTypedef typedef && typedef.ElementType is CppPrimitiveType) { canUseFixed = true; } if (canUseFixed) { var csFieldType = GetCsTypeName(arrayType.ElementType, false); if (string.IsNullOrEmpty(csFieldType)) { Console.WriteLine(""); } writer.WriteLine($"public unsafe fixed {csFieldType} {csFieldName}[{arrayType.Size}];"); } else { var unsafePrefix = string.Empty; var csFieldType = GetCsTypeName(arrayType.ElementType, false); if (csFieldType.EndsWith('*')) { unsafePrefix = "unsafe "; } for (var i = 0; i < arrayType.Size; i++) { writer.WriteLine($"public {unsafePrefix}{csFieldType} {csFieldName}_{i};"); } } } else { if (!s_csNameMappings.TryGetValue(cppField.Type.GetDisplayName(), out var csFieldType)) { csFieldType = GetCsTypeName(cppField.Type, false); } else { Console.Write(""); } // if (csFieldType.Equals("ImGuiDockNodeSettings*") || // csFieldType.Equals("ImGuiDockRequest*")) // { // csFieldType = "IntPtr"; // } string fieldPrefix = isReadOnly ? "readonly " : string.Empty; if (csFieldType.EndsWith('*')) { fieldPrefix += "unsafe "; } writer.WriteLine($"public {fieldPrefix}{csFieldType} {csFieldName};"); } } } }