FftwInterop.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #region Copyright and License
  2. /*
  3. This file is part of FFTW.NET, a wrapper around the FFTW library
  4. for the .NET framework.
  5. Copyright (C) 2017 Tobias Meyer
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. */
  15. #endregion
  16. using System;
  17. using System.Diagnostics.CodeAnalysis;
  18. using System.Runtime.InteropServices;
  19. using System.Text;
  20. using NativeLibraryLoader;
  21. namespace FFTW.NET
  22. {
  23. public enum DftDirection : int
  24. {
  25. Forwards = -1,
  26. Backwards = 1
  27. }
  28. [Flags]
  29. public enum PlannerFlags : uint
  30. {
  31. Default = Measure,
  32. /// <summary>
  33. /// <see cref="Measure"/> tells FFTW to find an optimized plan by actually
  34. /// computing several FFTs and measuring their execution time.
  35. /// Depending on your machine, this can take some time (often a few seconds).
  36. /// </summary>
  37. Measure = (0U),
  38. /// <summary>
  39. /// <see cref="Exhaustive"/> is like <see cref="Patient"/>,
  40. /// but considers an even wider range of algorithms,
  41. /// including many that we think are unlikely to be fast,
  42. /// to produce the most optimal plan but with a substantially increased planning time.
  43. /// </summary>
  44. Exhaustive = (1U << 3),
  45. /// <summary>
  46. /// <see cref="Patient"/> is like <see cref="Measure"/>,
  47. /// but considers a wider range of algorithms and often produces
  48. /// a “more optimal” plan (especially for large transforms),
  49. /// but at the expense of several times longer planning time
  50. /// (especially for large transforms).
  51. /// </summary>
  52. Patient = (1U << 5),
  53. /// <summary>
  54. /// <see cref="Estimate"/> specifies that,
  55. /// instead of actual measurements of different algorithms,
  56. /// a simple heuristic is used to pick a (probably sub-optimal) plan quickly.
  57. /// With this flag, the input/output arrays are not overwritten during planning.
  58. /// </summary>
  59. Estimate = (1U << 6),
  60. /// <summary>
  61. /// <see cref="WisdomOnly"/> is a special planning mode in which
  62. /// the plan is only created if wisdom is available for the given problem,
  63. /// and otherwise a <c>null</c> plan is returned. This can be combined
  64. /// with other flags, e.g. '<see cref="WisdomOnly"/> | <see cref="Patient"/>'
  65. /// creates a plan only if wisdom is available that was created in
  66. /// <see cref="Patient"/> or <see cref="Exhaustive"/> mode.
  67. /// The <see cref="WisdomOnly"/> flag is intended for users who need to
  68. /// detect whether wisdom is available; for example, if wisdom is not
  69. /// available one may wish to allocate new arrays for planning so that
  70. /// user data is not overwritten.
  71. /// </summary>
  72. WisdomOnly = (1U << 21)
  73. }
  74. public static class FftwInterop
  75. {
  76. public delegate bool fftw_init_threads();
  77. private static readonly string windowsdllname = "libfftw3";
  78. private static readonly string linuxdllname = "libfftw3.so";
  79. static FftwInterop()
  80. {
  81. }
  82. public static void Initialize()
  83. {
  84. if (_NativeLoader != null) return;
  85. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) _NativeLoader = new NativeLibraryLoader.NativeLoader(windowsdllname);
  86. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  87. {
  88. _NativeLoader = new NativeLibraryLoader.NativeLoader(linuxdllname);
  89. }
  90. else
  91. {
  92. throw new PlatformNotSupportedException();
  93. }
  94. _NativeLoader.SearchDirectories.Add(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "libs"));
  95. _NativeLoader.Init();
  96. _version = GetVersionAndInitialize();
  97. }
  98. [AllowNull]
  99. private static NativeLibraryLoader.NativeLoader _NativeLoader;
  100. private static Version _version = new Version();
  101. public static Version Version => _version;
  102. public static bool IsAvailable => _version != null;
  103. public static T GetDelegate<T>() where T : Delegate
  104. {
  105. return _NativeLoader.LoadFunction<T>(typeof(T).Name);
  106. }
  107. internal static object Lock
  108. {
  109. get
  110. {
  111. if (!IsAvailable)
  112. throw new InvalidOperationException($"{nameof(FftwInterop.IsAvailable)} is false.");
  113. return _version;
  114. }
  115. }
  116. public delegate void WriteCharHandler(byte c, IntPtr ptr);
  117. static Version GetVersionAndInitialize()
  118. {
  119. try
  120. {
  121. //GetDelegate<fftw_init_threads>()();
  122. }
  123. catch (DllNotFoundException) { return new Version(); }
  124. string version = GetVersion();
  125. return new Version(version);
  126. }
  127. public delegate int fftw_alignment_of(IntPtr ptr);
  128. public delegate void fftw_free(IntPtr ptr);
  129. public delegate void fftw_plan_with_nthreads(int nthreads);
  130. public delegate IntPtr fftw_plan_dft_r2c(int rank, [MarshalAs(UnmanagedType.LPArray)] int[] n, IntPtr arrIn, IntPtr arrOut, PlannerFlags flags);
  131. public delegate void fftw_forget_wisdom();
  132. public delegate IntPtr fftw_malloc(IntPtr size);
  133. public delegate bool fftw_export_wisdom_to_filename([MarshalAs(UnmanagedType.LPStr)] string filename);
  134. public delegate IntPtr fftw_plan_dft(int rank, [MarshalAs(UnmanagedType.LPArray)] int[] n, IntPtr arrIn, IntPtr arrOut, DftDirection direction, PlannerFlags flags);
  135. public delegate void fftw_execute(IntPtr plan);
  136. public delegate IntPtr fftw_plan_dft_c2r(int rank, [MarshalAs(UnmanagedType.LPArray)] int[] n, IntPtr arrIn, IntPtr arrOut, PlannerFlags flags);
  137. public delegate void fftw_destroy_plan(IntPtr plan);
  138. public delegate bool fftw_import_wisdom_from_string([MarshalAs(UnmanagedType.LPStr)] string wisdom);
  139. public delegate bool fftw_import_wisdom_from_filename([MarshalAs(UnmanagedType.LPStr)] string filename);
  140. public delegate void fftw_export_wisdom([MarshalAs(UnmanagedType.FunctionPtr)] WriteCharHandler writeChar, IntPtr data);
  141. public static string fftw_export_wisdom_to_string()
  142. {
  143. // We cannot use the fftw_export_wisdom_to_string function here
  144. // because we have no way of releasing the returned memory.
  145. StringBuilder sb = new StringBuilder();
  146. FftwInterop.WriteCharHandler writeChar = (c, ptr) => sb.Append((char)c);
  147. GetDelegate<fftw_export_wisdom>()(writeChar, IntPtr.Zero);
  148. return sb.ToString();
  149. }
  150. static string GetVersion()
  151. {
  152. const string VersionPrefix = "fftw-";
  153. const byte WhiteSpace = (byte)' ';
  154. byte[] prefix = Encoding.ASCII.GetBytes(VersionPrefix);
  155. int i = 0;
  156. StringBuilder sb = new StringBuilder();
  157. FftwInterop.WriteCharHandler writeChar = (c, ptr) =>
  158. {
  159. if (i < 0)
  160. return;
  161. if (i == VersionPrefix.Length)
  162. {
  163. if (c == WhiteSpace)
  164. i = -1;
  165. else
  166. sb.Append((char)c);
  167. }
  168. else if (c == prefix[i])
  169. i++;
  170. else
  171. i = 0;
  172. };
  173. // This is only called on initialization, so no synchronization/lock is required
  174. GetDelegate<fftw_export_wisdom>()(writeChar, IntPtr.Zero);
  175. return sb.ToString();
  176. }
  177. }
  178. }