GXS.CUDA.FFTPlan.pas 8.6 KB

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