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}));");
         }
     }
 }
Beispiel #3
0
 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}\");");
             }
         }
     }
 }
Beispiel #4
0
        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);
            }
        }
Beispiel #8
0
        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);
            }
        }
Beispiel #10
0
        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();
            }
        }
Beispiel #11
0
        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);
                    }
Beispiel #12
0
        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;
                                }
                            }
                        }
Beispiel #13
0
        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};");
                    }
                }
            }
        }