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); } }