123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- //
- // The graphics engine GLScene
- //
- unit CUDA.FourierTransform;
- (* CUDA Fourier Transform *)
- /// *
- // * Copyright 1993-2009 NVIDIA Corporation. All rights reserved.
- // *
- // * NOTICE TO USER:
- // *
- // * This source code is subject to NVIDIA ownership rights under U.S. and
- // * international Copyright laws. Users and possessors of this source code
- // * are hereby granted a nonexclusive, royalty-free license to use this code
- // * in individual and commercial software.
- // *
- // * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
- // * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
- // * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH
- // * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
- // * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
- // * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
- // * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- // * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
- // * OR PERFORMANCE OF THIS SOURCE CODE.
- // *
- // * U.S. Government End Users. This source code is a "commercial item" as
- // * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of
- // * "commercial computer software" and "commercial computer software
- // * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995)
- // * and is provided to the U.S. Government only as a commercial end item.
- // * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
- // * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
- // * source code with only those rights set forth herein.
- // *
- // * Any use of this source code in individual and commercial software must
- // * include, in the user documentation and internal comments to the code,
- // * the above Disclaimer and U.S. Government End Users Notice.
- // */
- interface
- uses
- {$IFDEF MSWINDOWS}
- Winapi.Windows,
- {$ELSE}
- Windows,
- {$ENDIF}
- CUDA.Import,
- CUDA.RunTime;
- const
- {$IFDEF WIN32}
- CUFFTDLLNAMES: array [0 .. 9] of string = (
- 'cufft32_42_9', 'cufft32_41_28',
- 'cufft32_40_10', 'cufft32_32_16', 'cufft32_31_4', 'cufft32_30_14',
- 'cufft32_30_9', 'cufft32_30_8', 'cufft32', 'cufft');
- {$ENDIF}
- {$IFDEF WIN64}
- CUFFTDLLNAMES: array [0 .. 7] of string = (
- 'cufft64_42_9', 'cufft64_41_28',
- 'cufft64_40_10', 'cufft64_32_16', 'cufft64_31_4', 'cufft64_30_14',
- 'cufft64_30_9', 'cufft64_30_8');
- {$ENDIF}
- /// CUFFT API function return values
- type
- /// CUFFT defines and supports the following data types
- /// cufftHandle is a handle type used to store and access CUFFT plans.
- TcufftHandle = type Cardinal;
- TcufftReal = Single;
- PcufftReal = ^TcufftReal;
- TcufftRealfloat = Single;
- PcufftDoubleReal = ^TcufftDoubleReal;
- TcufftDoubleReal = Double;
- PcufftDoubleComplex = ^TcufftDoubleComplex;
- TcufftDoubleComplex = record
- case Integer of
- 0 : (V: array[0..1] of Double);
- 1 : (X: Double;
- Y: Double);
- end;
- PcufftComplex = ^TcufftComplex;
- TcufftComplex = record
- case Integer of
- 0 : (V: array[0..1] of Single);
- 1 : (X,Y: Single);
- end;
- TcufftResult = type Byte;
- const
- INVALID_CUFFT_HANDLE = $FFFFFFFF;
- CUFFT_SUCCESS: TcufftResult = $00;
- CUFFT_INVALID_PLAN: TcufftResult = $01;
- CUFFT_ALLOC_FAILED: TcufftResult = $02;
- CUFFT_INVALID_TYPE: TcufftResult = $03;
- CUFFT_INVALID_VALUE: TcufftResult = $04;
- CUFFT_INTERNAL_ERROR: TcufftResult = $05;
- CUFFT_EXEC_FAILED: TcufftResult = $06;
- CUFFT_SETUP_FAILED: TcufftResult = $07;
- CUFFT_INVALID_SIZE: TcufftResult = $08;
- type
- TcufftType = type Cardinal;
- TcudaRoundMode = (cudaRoundNearest, cudaRoundZero, cudaRoundPosInf,
- cudaRoundMinInf);
- /// CUFFT transform directions
- const
- CUFFT_FORWARD = -1; // Forward FFT
- CUFFT_INVERSE = 1; // Inverse FFT
- /// CUFFT supports the following transform types
- CUFFT_R2C: TcufftType = $2A; // Real to Complex (interleaved)
- CUFFT_C2R: TcufftType = $2C; // Complex (interleaved) to Real
- CUFFT_C2C: TcufftType = $29; // Complex to Complex, interleaved
- CUFFT_D2Z: TcufftType = $6A; // Double to Double-Complex
- CUFFT_Z2D: TcufftType = $6C; // Double-Complex to Double
- CUFFT_Z2Z: TcufftType = $69; // Double-Complex to Double-Complex
- (*
- Certain R2C and C2R transforms go much more slowly when FFTW memory
- layout and behaviour is required. The default is "best performance",
- which means not-compatible-with-fftw. Use the cufftSetCompatibilityMode
- API to enable exact FFTW-like behaviour.
- These flags can be ORed together to select precise FFTW compatibility
- behaviour. The two levels presently supported are:
- CUFFT_COMPATIBILITY_FFTW_PADDING
- Inserts extra padding between packed in-place transforms for
- batched transforms with power-of-2 size.
- CUFFT_COMPATIBILITY_FFTW_C2R_ASYMMETRIC
- Guarantees FFTW-compatible output for non-symmetric complex inputs
- for transforms with power-of-2 size. This is only useful for
- artificial (i.e. random) datasets as actual data will always be
- symmetric if it has come from the real plane. If you don't
- understand what this means, you probably don't have to use it.
- CUFFT_COMPATIBILITY_FFTW
- For convenience, enables all FFTW compatibility modes at once.
- *)
- type
- TcufftCompatibility = type Cardinal;
- const
- CUFFT_COMPATIBILITY_NORMAL: TcufftCompatibility = $00; // The default value
- CUFFT_COMPATIBILITY_FFTW_PADDING: TcufftCompatibility = $01;
- CUFFT_COMPATIBILITY_FFTW_C2R_ASYMMETRIC: TcufftCompatibility = $02;
- CUFFT_COMPATIBILITY_FFTW: TcufftCompatibility = $03;
- type
- TcufftPlan1d = function(out plan: TcufftHandle; nx: Integer;
- atype: TcufftType; batch: Integer): TcufftResult;stdcall;
- TcufftPlan2d = function(out plan: TcufftHandle; nx: Integer; ny: Integer;
- atype: TcufftType): TcufftResult;stdcall;
- TcufftPlan3d = function(out plan: TcufftHandle; nx: Integer; ny: Integer;
- nz: Integer; atype: TcufftType): TcufftResult;stdcall;
- TcufftDestroy = function(plan: TcufftHandle): TcufftResult;stdcall;
- TcufftPlanMany = function(out plan: TcufftHandle; rank: Integer;
- var n: Integer; var inembed: Integer; istride, idist: Integer;
- var onembed: Integer; ostride, odist: Integer; ctype: TcufftType;
- batch: Integer): TcufftResult;stdcall;
- TcufftExecC2C = function(plan: TcufftHandle; idata: PcufftComplex;
- odata: PcufftComplex; direction: Integer): TcufftResult;stdcall;
- TcufftExecR2C = function(plan: TcufftHandle; idata: PcufftReal;
- odata: PcufftComplex): TcufftResult;stdcall;
- TcufftExecC2R = function(plan: TcufftHandle; idata: PcufftComplex;
- odata: PcufftReal): TcufftResult;stdcall;
- TcufftExecZ2Z = function(plan: TcufftHandle; idata: PcufftDoubleComplex;
- odata: PcufftDoubleComplex; direction: Integer): TcufftResult;stdcall;
- TcufftExecD2Z = function(plan: TcufftHandle; idata: PcufftDoubleReal;
- odata: PcufftDoubleComplex): TcufftResult;stdcall;
- TcufftExecZ2D = function(plan: TcufftHandle; idata: PcufftDoubleComplex;
- odata: PcufftDoubleReal): TcufftResult;stdcall;
- TcufftSetStream = function(p: TcufftHandle; stream: Integer): TcufftResult;stdcall;
- TcufftSetCompatibilityMode = function(plan: TcufftHandle;
- mode: TcufftCompatibility): TcufftResult;stdcall;
- var
- cufftPlan1d: TcufftPlan1d;
- cufftPlan2d: TcufftPlan2d;
- cufftPlan3d: TcufftPlan3d;
- cufftDestroy: TcufftDestroy;
- cufftPlanMany: TcufftPlanMany;
- cufftExecC2C: TcufftExecC2C;
- cufftExecR2C: TcufftExecR2C;
- cufftExecC2R: TcufftExecC2R;
- cufftExecZ2Z: TcufftExecZ2Z;
- cufftExecD2Z: TcufftExecD2Z;
- cufftExecZ2D: TcufftExecZ2D;
- cufftSetStream: TcufftSetStream;
- cufftSetCompatibilityMode: TcufftSetCompatibilityMode;
- function InitCUFFT: Boolean;
- procedure CloseCUFFT;
- function InitCUFFTFromLibrary(const LibName: WideString): Boolean;
- function IsCUFFTInitialized: Boolean;
- function Get_CUDA_FFT_Error_String(AError: TcufftResult): string;
- implementation //---------------------------------------------------------
- const
- cufftPlan1dName = 'cufftPlan1d';
- cufftPlan2dName = 'cufftPlan2d';
- cufftPlan3dName = 'cufftPlan3d';
- cufftDestroyName = 'cufftDestroy';
- cufftPlanManyName = 'cufftPlanMany';
- cufftExecC2CName = 'cufftExecC2C';
- cufftExecR2CName = 'cufftExecR2C';
- cufftExecC2RName = 'cufftExecC2R';
- cufftExecZ2ZName = 'cufftExecZ2Z';
- cufftExecD2ZName = 'cufftExecD2Z';
- cufftExecZ2DName = 'cufftExecZ2D';
- cufftSetStreamName = 'cufftSetStream';
- cufftSetCompatibilityModeName = 'cufftSetCompatibilityMode';
- const
- INVALID_MODULEHANDLE = 0;
- var
- {$IFDEF MSWINDOWS}
- CUFFTHandle: HINST = INVALID_MODULEHANDLE;
- {$ENDIF}{$IFDEF LINUX}
- CUFFTHandle: TLibHandle = INVALID_MODULEHANDLE;
- {$ENDIF}
- {$IFDEF USE_CUDA_DEBUG_MODE}
- var
- cufftPlan1d_: TcufftPlan1d;
- cufftPlan2d_: TcufftPlan2d;
- cufftPlan3d_: TcufftPlan3d;
- cufftDestroy_: TcufftDestroy;
- cufftPlanMany_: TcufftPlanMany;
- cufftExecC2C_: TcufftExecC2C;
- cufftExecR2C_: TcufftExecR2C;
- cufftExecC2R_: TcufftExecC2R;
- cufftExecZ2Z_: TcufftExecZ2Z;
- cufftExecD2Z_: TcufftExecD2Z;
- cufftExecZ2D_: TcufftExecZ2D;
- cufftSetStream_: TcufftSetStream;
- cufftSetCompatibilityMode_: TcufftSetCompatibilityMode;
- function cufftPlan1dShell(out plan: TcufftHandle; nx: Integer;
- atype: TcufftType; batch: Integer): TcufftResult;stdcall;
- begin
- Result := cufftPlan1d_(plan, nx, atype, batch);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftPlan1dName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftPlan2dShell(out plan: TcufftHandle; nx: Integer; ny: Integer;
- atype: TcufftType): TcufftResult;stdcall;
- begin
- Result := cufftPlan2d_(plan, nx, ny, atype);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftPlan2dName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftPlan3dShell(out plan: TcufftHandle; nx: Integer; ny: Integer;
- nz: Integer; atype: TcufftType): TcufftResult;stdcall;
- begin
- Result := cufftPlan3d_(plan, nx, ny, nz, atype);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftPlan3dName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftDestroyShell(plan: TcufftHandle): TcufftResult;stdcall;
- begin
- Result := cufftDestroy_(plan);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftDestroyName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftPlanManyShell(out plan: TcufftHandle; rank: Integer;
- var n: Integer; var inembed: Integer; istride, idist: Integer;
- var onembed: Integer; ostride, odist: Integer; ctype: TcufftType;
- batch: Integer): TcufftResult;stdcall;
- begin
- Result := cufftPlanMany_(plan, rank, n, inembed, istride, idist, onembed,
- ostride, odist, ctype, batch);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftPlanManyName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftExecC2CShell(plan: TcufftHandle; idata: PcufftComplex;
- odata: PcufftComplex; direction: Integer): TcufftResult;stdcall;
- begin
- Result := cufftExecC2C_(plan, idata, odata, direction);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftExecC2CName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftExecR2CShell(plan: TcufftHandle; idata: PcufftReal;
- odata: PcufftComplex): TcufftResult;stdcall;
- begin
- Result := cufftExecR2C_(plan, idata, odata);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftExecR2CName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftExecC2RShell(plan: TcufftHandle; idata: PcufftComplex;
- odata: PcufftReal): TcufftResult;stdcall;
- begin
- Result := cufftExecC2R_(plan, idata, odata);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftExecC2RName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftExecZ2ZShell(plan: TcufftHandle; idata: PcufftDoubleComplex;
- odata: PcufftDoubleComplex; direction: Integer): TcufftResult;stdcall;
- begin
- Result := cufftExecZ2Z_(plan, idata, odata, direction);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftExecZ2ZName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftExecD2ZShell(plan: TcufftHandle; idata: PcufftDoubleReal;
- odata: PcufftDoubleComplex): TcufftResult;stdcall;
- begin
- Result := cufftExecD2Z_(plan, idata, odata);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftExecD2ZName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftExecZ2DShell(plan: TcufftHandle; idata: PcufftDoubleComplex;
- odata: PcufftDoubleReal): TcufftResult;stdcall;
- begin
- Result := cufftExecZ2D_(plan, idata, odata);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftExecZ2DName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftSetStreamShell(p: TcufftHandle; stream: Integer): TcufftResult;stdcall;
- begin
- Result := cufftSetStream_(p, stream);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftSetStreamName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- function cufftSetCompatibilityModeShell(plan: TcufftHandle;
- mode: TcufftCompatibility): TcufftResult;stdcall;
- begin
- Result := cufftSetCompatibilityMode_(plan, mode);
- if Result <> CUFFT_SUCCESS then
- GLSLogger.LogErrorFmt(strFFTFuncRetErr, [cufftSetCompatibilityModeName,
- Get_CUDA_FFT_Error_String(Result)]);
- end;
- {$ENDIF GLS_CUDA_DEBUG_MODE}
- function CUFFTGetProcAddress(ProcName: PAnsiChar): Pointer;
- begin
- result := GetProcAddress(CUFFTHandle, ProcName);
- end;
- function InitCUFFT: Boolean;
- var
- I: Integer;
- begin
- Result := True;
- if CUFFTHandle = INVALID_MODULEHANDLE then
- begin
- for I := 0 to High(CUFFTDLLNAMES) do
- begin
- if InitCUFFTFromLibrary(CUFFTDLLNAMES[I] + '.dll') then
- Exit;
- end;
- Result := False;
- end;
- end;
- procedure CloseCUFFT;
- begin
- if CUFFTHandle <> INVALID_MODULEHANDLE then
- begin
- FreeLibrary(Cardinal(CUFFTHandle));
- CUFFTHandle := INVALID_MODULEHANDLE;
- end;
- end;
- function InitCUFFTFromLibrary(const LibName: WideString): Boolean;
- begin
- CloseCUFFT;
- CUFFTHandle := GetModuleHandleW(PWideChar(LibName));
- if CUFFTHandle = INVALID_MODULEHANDLE then
- CUFFTHandle := LoadLibraryW(PWideChar(LibName));
- if CUFFTHandle = INVALID_MODULEHANDLE then
- Exit(False);
- {$IFNDEF USE_CUDA_DEBUG_MODE}
- cufftPlan1d := CUFFTGetProcAddress(cufftPlan1dName);
- cufftPlan2d := CUFFTGetProcAddress(cufftPlan2dName);
- cufftPlan3d := CUFFTGetProcAddress(cufftPlan3dName);
- cufftDestroy := CUFFTGetProcAddress(cufftDestroyName);
- cufftPlanMany := CUFFTGetProcAddress(cufftPlanManyName);
- cufftExecC2C := CUFFTGetProcAddress(cufftExecC2CName);
- cufftExecR2C := CUFFTGetProcAddress(cufftExecR2CName);
- cufftExecC2R := CUFFTGetProcAddress(cufftExecC2RName);
- cufftExecZ2Z := CUFFTGetProcAddress(cufftExecZ2ZName);
- cufftExecD2Z := CUFFTGetProcAddress(cufftExecD2ZName);
- cufftExecZ2D := CUFFTGetProcAddress(cufftExecZ2DName);
- cufftSetStream := CUFFTGetProcAddress(cufftSetStreamName);
- cufftSetCompatibilityMode := CUFFTGetProcAddress(cufftSetCompatibilityModeName);
- {$ELSE}
- cufftPlan1d_ := CUFFTGetProcAddress(cufftPlan1dName);
- cufftPlan1d := cufftPlan1dShell;
- cufftPlan2d_ := CUFFTGetProcAddress(cufftPlan2dName);
- cufftPlan2d := cufftPlan2dShell;
- cufftPlan3d_ := CUFFTGetProcAddress(cufftPlan3dName);
- cufftPlan3d := cufftPlan3dShell;
- cufftDestroy_ := CUFFTGetProcAddress(cufftDestroyName);
- cufftDestroy := cufftDestroyShell;
- cufftPlanMany_ := CUFFTGetProcAddress(cufftPlanManyName);
- cufftPlanMany := cufftPlanManyShell;
- cufftExecC2C_ := CUFFTGetProcAddress(cufftExecC2CName);
- cufftExecC2C := cufftExecC2CShell;
- cufftExecR2C_ := CUFFTGetProcAddress(cufftExecR2CName);
- cufftExecR2C := cufftExecR2CShell;
- cufftExecC2R_ := CUFFTGetProcAddress(cufftExecC2RName);
- cufftExecC2R := cufftExecC2RShell;
- cufftExecZ2Z_ := CUFFTGetProcAddress(cufftExecZ2ZName);
- cufftExecZ2Z := cufftExecZ2ZShell;
- cufftExecD2Z_ := CUFFTGetProcAddress(cufftExecD2ZName);
- cufftExecD2Z := cufftExecD2ZShell;
- cufftExecZ2D_ := CUFFTGetProcAddress(cufftExecZ2DName);
- cufftExecZ2D := cufftExecZ2DShell;
- cufftSetStream_ := CUFFTGetProcAddress(cufftSetStreamName);
- cufftSetStream := cufftSetStreamShell;
- cufftSetCompatibilityMode_ := CUFFTGetProcAddress(cufftSetCompatibilityModeName);
- cufftSetCompatibilityMode := cufftSetCompatibilityModeShell;
- {$ENDIF}
- {$IFDEF USE_LOGGING}
- LogInfoFmt('%s loaded...', [LibName]);
- {$ENDIF}
- Result := True;
- end;
- function IsCUFFTInitialized: Boolean;
- begin
- result := (CUFFTHandle <> INVALID_MODULEHANDLE);
- end;
- function Get_CUDA_FFT_Error_String(AError: TcufftResult): string;
- begin
- if AError = CUFFT_SUCCESS then
- result := 'CUFFT operation is successful.'
- else if AError = CUFFT_INVALID_PLAN then
- result := 'CUFFT is passed an invalid plan handle.'
- else if AError = CUFFT_ALLOC_FAILED then
- result := 'CUFFT failed to allocate GPU memory.'
- else if AError = CUFFT_INVALID_TYPE then
- result := 'The user requests an unsupported type.'
- else if AError = CUFFT_INVALID_VALUE then
- result := 'The user specifies a bad memory pointer.'
- else if AError = CUFFT_INTERNAL_ERROR then
- result := 'Used for all internal driver errors.'
- else if AError = CUFFT_EXEC_FAILED then
- result := 'CUFFT failed to execute an FFT on the GPU.'
- else if AError = CUFFT_SETUP_FAILED then
- result := 'The CUFFT library failed to initialize.'
- else if AError = CUFFT_INVALID_SIZE then
- result := 'The user specifies an unsupported FFT size.'
- else
- result := 'Unknown error.'
- end;
- end.
|