CUDA.FFTPlan.pas 8.4 KB

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