GLS.CUDA.FFTPlan.pas 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.CUDA.FFTPlan;
  5. (* Fast Fourier Transform for CUDA *)
  6. interface
  7. uses
  8. System.Classes,
  9. System.SysUtils,
  10. GLS.CUDA.Context,
  11. GLS.CUDA.APIComps,
  12. CUDA.Import,
  13. CUDA.FourierTransform;
  14. type
  15. TCUDAFFTransform =
  16. (
  17. fftRealToComplex,
  18. fftComplexToReal,
  19. fftComplexToComplex,
  20. fftDoubleToDoubleComplex,
  21. fftDoubleComplexToDouble,
  22. fftDoubleComplexToDoubleComplex
  23. );
  24. TCUDAFFTdir = (fftdForward, fftdInverse);
  25. TCUDAFFTPlan = class(TCUDAComponent)
  26. private
  27. FHandle: TcufftHandle;
  28. FWidth: Integer;
  29. FHeight: Integer;
  30. FDepth: Integer;
  31. FBatch: Integer;
  32. FSize: Integer;
  33. FPaddedSize: Integer;
  34. FTransform: TCUDAFFTransform;
  35. FStatus: TcufftResult;
  36. procedure SetWidth(Value: Integer);
  37. procedure SetHeight(Value: Integer);
  38. procedure SetDepth(Value: Integer);
  39. procedure SetBatch(Value: Integer);
  40. procedure SetTransform(Value: TCUDAFFTransform);
  41. protected
  42. procedure AllocateHandles; override;
  43. procedure DestroyHandles; override;
  44. class procedure CheckLib;
  45. public
  46. constructor Create(AOwner: TComponent); override;
  47. destructor Destroy; override;
  48. procedure Assign(Source: TPersistent); override;
  49. procedure Execute(ASrc: TCUDAMemData; ADst: TCUDAMemData;
  50. const ADir: TCUDAFFTdir = fftdForward);
  51. published
  52. property Width: Integer read fWidth write SetWidth default 256;
  53. property Height: Integer read FHeight write SetHeight default 0;
  54. property Depth: Integer read FDepth write SetDepth default 0;
  55. property Batch: Integer read FBatch write SetBatch default 1;
  56. property Transform: TCUDAFFTransform read FTransform write SetTransform
  57. default fftRealToComplex;
  58. end;
  59. implementation //-------------------------------------------------------------
  60. constructor TCUDAFFTPlan.Create(AOwner: TComponent);
  61. begin
  62. inherited Create(AOwner);
  63. FHandle := INVALID_CUFFT_HANDLE;
  64. fWidth := 256;
  65. FHeight := 0;
  66. FDepth := 0;
  67. FBatch := 1;
  68. FTransform := fftRealToComplex;
  69. end;
  70. destructor TCUDAFFTPlan.Destroy;
  71. begin
  72. DestroyHandles;
  73. inherited;
  74. end;
  75. class procedure TCUDAFFTPlan.CheckLib;
  76. begin
  77. if not IsCUFFTInitialized then
  78. if not InitCUFFT then
  79. begin
  80. // ('Can not initialize CUFFT library');
  81. Abort;
  82. end;
  83. end;
  84. procedure TCUDAFFTPlan.Assign(Source: TPersistent);
  85. var
  86. plan: TCUDAFFTPlan;
  87. begin
  88. if Source is TCUDAFFTPlan then
  89. begin
  90. DestroyHandles;
  91. plan := TCUDAFFTPlan(Source);
  92. Width := plan.fWidth;
  93. Height := plan.FHeight;
  94. Depth := plan.FDepth;
  95. Transform := plan.FTransform;
  96. end;
  97. inherited Assign(Source);
  98. end;
  99. procedure TCUDAFFTPlan.AllocateHandles;
  100. var
  101. LType: TcufftType;
  102. begin
  103. DestroyHandles;
  104. case FTransform of
  105. fftRealToComplex:
  106. LType := CUFFT_R2C;
  107. fftComplexToReal:
  108. LType := CUFFT_C2R;
  109. fftComplexToComplex:
  110. LType := CUFFT_C2C;
  111. fftDoubleToDoubleComplex:
  112. LType := CUFFT_D2Z;
  113. fftDoubleComplexToDouble:
  114. LType := CUFFT_Z2D;
  115. fftDoubleComplexToDoubleComplex:
  116. LType := CUFFT_Z2Z;
  117. else
  118. begin
  119. Assert(False, 'Error: Unknown Type');
  120. LType := CUFFT_R2C;
  121. end;
  122. end;
  123. Context.Requires;
  124. if (FHeight = 0) and (FDepth = 0) then
  125. begin
  126. FStatus := cufftPlan1d(FHandle, fWidth, LType, FBatch);
  127. FSize := FWidth;
  128. FPaddedSize := FWidth div 2 + 1;
  129. if FBatch > 0 then
  130. begin
  131. FSize := FSize * FBatch;
  132. FPaddedSize := FPaddedSize * FBatch;
  133. end;
  134. end
  135. else if FDepth = 0 then
  136. begin
  137. FStatus := cufftPlan2d(FHandle, fWidth, FHeight, LType);
  138. FSize := FWidth * FHeight;
  139. FPaddedSize := FWidth * (FHeight div 2 + 1);
  140. end
  141. else
  142. begin
  143. FStatus := cufftPlan3d(FHandle, fWidth, FHeight, FDepth, LType);
  144. FSize := FWidth * FHeight * FDepth;
  145. FPaddedSize := FWidth * FHeight * (FDepth div 2 + 1);
  146. end;
  147. Context.Release;
  148. if FStatus <> CUFFT_SUCCESS then
  149. begin
  150. FHandle := INVALID_CUFFT_HANDLE;
  151. Abort;
  152. end;
  153. Context.Requires;
  154. FStatus := cufftSetCompatibilityMode(FHandle, CUFFT_COMPATIBILITY_FFTW_PADDING);
  155. Context.Release;
  156. fChanges := [];
  157. inherited;
  158. end;
  159. procedure TCUDAFFTPlan.DestroyHandles;
  160. begin
  161. inherited;
  162. CheckLib;
  163. if FHandle <> INVALID_CUFFT_HANDLE then
  164. begin
  165. Context.Requires;
  166. FStatus := cufftDestroy(FHandle);
  167. Context.Release;
  168. if FStatus <> CUFFT_SUCCESS then
  169. Abort;
  170. FHandle := 0;
  171. FPaddedSize := 0;
  172. end;
  173. end;
  174. procedure TCUDAFFTPlan.SetWidth(Value: Integer);
  175. begin
  176. if Value < 1 then
  177. Value := 1;
  178. if Value <> fWidth then
  179. begin
  180. fWidth := Value;
  181. CuNotifyChange(cuchSize);
  182. end;
  183. end;
  184. procedure TCUDAFFTPlan.SetHeight(Value: Integer);
  185. begin
  186. if Value < 0 then
  187. Value := 0;
  188. if Value <> FHeight then
  189. begin
  190. FHeight := Value;
  191. if FHeight > 0 then
  192. FBatch := 1;
  193. CuNotifyChange(cuchSize);
  194. end;
  195. end;
  196. procedure TCUDAFFTPlan.SetDepth(Value: Integer);
  197. begin
  198. if Value < 0 then
  199. Value := 0;
  200. if Value <> FDepth then
  201. begin
  202. FDepth := Value;
  203. if FDepth > 0 then
  204. FBatch := 1;
  205. CuNotifyChange(cuchSize);
  206. end;
  207. end;
  208. procedure TCUDAFFTPlan.SetBatch(Value: Integer);
  209. begin
  210. if Value < 1 then
  211. Value := 1;
  212. if Value <> FBatch then
  213. begin
  214. FBatch := Value;
  215. if FBatch > 1 then
  216. begin
  217. FHeight := 0;
  218. FDepth := 0;
  219. end;
  220. CuNotifyChange(cuchSize);
  221. end;
  222. end;
  223. procedure TCUDAFFTPlan.SetTransform(Value: TCUDAFFTransform);
  224. begin
  225. if Value <> FTransform then
  226. begin
  227. FTransform := Value;
  228. CuNotifyChange(cuchSize);
  229. end;
  230. end;
  231. procedure TCUDAFFTPlan.Execute(ASrc: TCUDAMemData; ADst: TCUDAMemData;
  232. const ADir: TCUDAFFTdir);
  233. const
  234. sFFTdir: array [TCUDAFFTdir] of Integer = (CUFFT_FORWARD, CUFFT_INVERSE);
  235. cSourceTypeSize: array[TCUDAFFTransform] of Byte = (
  236. SizeOf(TcufftReal),
  237. SizeOf(TcufftComplex),
  238. SizeOf(TcufftComplex),
  239. SizeOf(TcufftDoubleReal),
  240. SizeOf(TcufftDoubleComplex),
  241. SizeOf(TcufftDoubleComplex));
  242. cDestinationTypeSize: array[TCUDAFFTransform] of Byte = (
  243. SizeOf(TcufftComplex),
  244. SizeOf(TcufftReal),
  245. SizeOf(TcufftComplex),
  246. SizeOf(TcufftDoubleComplex),
  247. SizeOf(TcufftDoubleReal),
  248. SizeOf(TcufftDoubleComplex));
  249. var
  250. SrcPtr, DstPtr: Pointer;
  251. LSrcSize, LDstSize: Integer;
  252. procedure ForwardCheck;
  253. begin
  254. if (LSrcSize * FSize > ASrc.DataSize)
  255. or (LDstSize * FPaddedSize > ADst.DataSize) then
  256. begin
  257. // Bad Plan Size);
  258. Abort;
  259. end;
  260. end;
  261. procedure InverseCheck;
  262. begin
  263. if (LSrcSize * FPaddedSize > ASrc.DataSize)
  264. or (LDstSize * FSize > ADst.DataSize) then
  265. begin
  266. // Bad Plan Size);
  267. Abort;
  268. end;
  269. end;
  270. begin
  271. if (FHandle = INVALID_CUFFT_HANDLE) or (fChanges <> []) then
  272. AllocateHandles;
  273. if CUDAContextManager.GetCurrentThreadContext <> nil then
  274. begin
  275. Abort;
  276. end;
  277. SrcPtr := ASrc.RawData;
  278. DstPtr := ADst.RawData;
  279. LSrcSize := cSourceTypeSize[FTransform];
  280. LDstSize := cDestinationTypeSize[FTransform];
  281. Context.Requires;
  282. try
  283. case FTransform of
  284. fftRealToComplex:
  285. begin
  286. ForwardCheck;
  287. FStatus := cufftExecR2C(FHandle, SrcPtr, DstPtr);
  288. end;
  289. fftComplexToReal:
  290. begin
  291. InverseCheck;
  292. FStatus := cufftExecC2R(FHandle, SrcPtr, DstPtr);
  293. end;
  294. fftComplexToComplex:
  295. begin
  296. case ADir of
  297. fftdForward: ForwardCheck;
  298. fftdInverse: InverseCheck;
  299. end;
  300. FStatus := cufftExecC2C(FHandle, SrcPtr, DstPtr, sFFTdir[ADir]);
  301. end;
  302. fftDoubleToDoubleComplex:
  303. begin
  304. ForwardCheck;
  305. FStatus := cufftExecD2Z(FHandle, SrcPtr, DstPtr);
  306. end;
  307. fftDoubleComplexToDouble:
  308. begin
  309. InverseCheck;
  310. FStatus := cufftExecZ2D(FHandle, SrcPtr, DstPtr);
  311. end;
  312. fftDoubleComplexToDoubleComplex:
  313. begin
  314. case ADir of
  315. fftdForward: ForwardCheck;
  316. fftdInverse: InverseCheck;
  317. end;
  318. FStatus := cufftExecZ2Z(FHandle, SrcPtr, DstPtr, sFFTdir[ADir]);
  319. end
  320. else
  321. FStatus := CUFFT_INVALID_VALUE;
  322. end;
  323. finally
  324. Context.Release;
  325. end;
  326. if FStatus <> CUFFT_SUCCESS then
  327. Abort;
  328. end;
  329. initialization // ------------------------------------------------------------
  330. RegisterClasses([TCUDAFFTPlan]);
  331. finalization
  332. CloseCUFFT;
  333. end.