yum-mirror/VkFFT
git clone https://git.yummers.dev/yum-mirror/VkFFT
d6f7ded
master
1#LyX 2.3 created this file. For more info see http://www.lyx.org/ 2\lyxformat 544 3\begin_document 4\begin_header 5\save_transient_properties true 6\origin unavailable 7\textclass article 8\begin_preamble 9\usepackage{sourcecodepro} 10\usepackage[parfill]{parskip} 11\usepackage{enumitem} 12\setlist[itemize]{leftmargin=*} 13\usepackage{minted} 14\usepackage{mdframed} 15\definecolor{bg}{rgb}{0.95,0.95,0.95} 16\usepackage{hyperref} 17\hypersetup{ 18 colorlinks, 19 citecolor=black, 20 filecolor=black, 21 linkcolor=black, 22 urlcolor=black 23} 24\end_preamble 25\use_default_options true 26\maintain_unincluded_children false 27\language english 28\language_package default 29\inputencoding auto 30\fontencoding global 31\font_roman "default" "default" 32\font_sans "default" "default" 33\font_typewriter "default" "default" 34\font_math "auto" "auto" 35\font_default_family default 36\use_non_tex_fonts true 37\font_sc false 38\font_osf false 39\font_sf_scale 100 100 40\font_tt_scale 100 100 41\use_microtype false 42\use_dash_ligatures true 43\graphics default 44\default_output_format default 45\output_sync 0 46\bibtex_command default 47\index_command default 48\paperfontsize 12 49\spacing single 50\use_hyperref false 51\papersize default 52\use_geometry true 53\use_package amsmath 1 54\use_package amssymb 1 55\use_package cancel 1 56\use_package esint 1 57\use_package mathdots 1 58\use_package mathtools 1 59\use_package mhchem 1 60\use_package stackrel 1 61\use_package stmaryrd 1 62\use_package undertilde 1 63\cite_engine basic 64\cite_engine_type default 65\biblio_style plain 66\use_bibtopic false 67\use_indices false 68\paperorientation portrait 69\suppress_date false 70\justification true 71\use_refstyle 1 72\use_minted 0 73\index Index 74\shortcut idx 75\color #008000 76\end_index 77\leftmargin 2.5cm 78\topmargin 2.5cm 79\rightmargin 2.5cm 80\bottommargin 2.5cm 81\secnumdepth 3 82\tocdepth 3 83\paragraph_separation indent 84\paragraph_indentation default 85\is_math_indent 0 86\math_numbering_side default 87\quotes_style english 88\dynamic_quotes 0 89\papercolumns 1 90\papersides 1 91\paperpagestyle default 92\tracking_changes false 93\output_changes false 94\html_math_output 0 95\html_css_as_file 0 96\html_be_strict false 97\end_header 98 99\begin_body 100 101\begin_layout Standard 102\begin_inset ERT 103status open 104 105\begin_layout Plain Layout 106 107 108\backslash 109UseRawInputEncoding 110\end_layout 111 112\begin_layout Plain Layout 113 114 115\backslash 116begin{titlepage} 117\end_layout 118 119\begin_layout Plain Layout 120 121 122\backslash 123centering 124\end_layout 125 126\begin_layout Plain Layout 127 128 129\backslash 130vspace{1cm} 131\end_layout 132 133\begin_layout Plain Layout 134 135{ 136\backslash 137scshape 138\backslash 139LARGE VkFFT - Vulkan/CUDA/HIP/OpenCL/Level Zero/Metal Fast Fourier Transform 140 library 141\backslash 142par} 143\end_layout 144 145\begin_layout Plain Layout 146 147 148\backslash 149vspace{1.5cm} 150\end_layout 151 152\begin_layout Plain Layout 153 154{ 155\backslash 156huge 157\backslash 158bfseries API guide with examples 159\backslash 160par} 161\end_layout 162 163\begin_layout Plain Layout 164 165 166\backslash 167vspace{2cm} 168\end_layout 169 170\begin_layout Plain Layout 171 172{ 173\backslash 174Large Dmitrii Tolmachev 175\backslash 176par} 177\end_layout 178 179\begin_layout Plain Layout 180 181 182\end_layout 183 184\begin_layout Plain Layout 185 186 187\backslash 188vspace{1cm} 189\end_layout 190 191\begin_layout Plain Layout 192 193{ 194\backslash 195large January 2024, version 1.3.3 196\backslash 197par} 198\end_layout 199 200\begin_layout Plain Layout 201 202 203\backslash 204end{titlepage} 205\end_layout 206 207\end_inset 208 209 210\end_layout 211 212\begin_layout Standard 213\begin_inset Newpage newpage 214\end_inset 215 216 217\end_layout 218 219\begin_layout Standard 220\begin_inset CommandInset toc 221LatexCommand tableofcontents 222 223\end_inset 224 225 226\end_layout 227 228\begin_layout Standard 229\begin_inset Newpage newpage 230\end_inset 231 232 233\end_layout 234 235\begin_layout Section 236Introduction 237\end_layout 238 239\begin_layout Standard 240This document describes VkFFT - Vulkan/CUDA/HIP/OpenCL/Level Zero/Metal 241 Fast Fourier Transform library. 242 It describes the features and current limitations of VkFFT, explains the 243 API and compares it to other FFT libraries (like FFTW and cuFFT) on the 244 set of examples. 245 It is by no means the final version, so if there is something unclear - 246 feel free to contact me (dtolm96@gmail.com), so I can update it. 247 248\end_layout 249 250\begin_layout Standard 251\begin_inset Newpage newpage 252\end_inset 253 254 255\end_layout 256 257\begin_layout Section 258Using the VkFFT API 259\end_layout 260 261\begin_layout Standard 262This chapter will cover the basics of VkFFT. 263 Fourier transform of a sequence is called Discrete Fourier Transform (DFT). 264 It is defined by the following formula: 265\begin_inset Formula 266\begin{equation} 267X_{k}=\stackrel[n=0]{N-1}{\sum}x_{n}e^{-\frac{2\pi i}{N}nk}=\mathrm{DFT}{}_{N}(x_{n},k),\label{eq:dft} 268\end{equation} 269 270\end_inset 271 272 273\end_layout 274 275\begin_layout Standard 276where 277\begin_inset Formula $x_{n}$ 278\end_inset 279 280is the input sequence, 281\begin_inset Formula $N$ 282\end_inset 283 284 is the length of the input sequence and 285\begin_inset Formula $k\in[0,N-1],k\in\mathbb{Z}$ 286\end_inset 287 288is the output index, corresponding to frequency in Fourier space. 289 Corresponding to that, inverse DFT is defined as following: 290\begin_inset Formula 291\begin{equation} 292x_{n}=\stackrel[k=0]{\mathrm{N-1}}{\sum}X_{k}e^{\frac{2\pi i}{N}nk}=\mathrm{IDFT}{}_{N}(X_{k},n) 293\end{equation} 294 295\end_inset 296 297 298\end_layout 299 300\begin_layout Standard 301VkFFT follows the same definitions as FFTW and cuFFT - forward FFT has the 302 exponent sign 303\begin_inset Formula $-1$ 304\end_inset 305 306, while the inverse has the exponent sign 307\begin_inset Formula $1$ 308\end_inset 309 310. 311 Note, that inverse transform by default is unnormalized, so to get the 312 input sequence after FFT + iFFT, the user has to divide the result by 313\begin_inset Formula $N$ 314\end_inset 315 316. 317\end_layout 318 319\begin_layout Subsection 320Installing VkFFT 321\end_layout 322 323\begin_layout Standard 324VkFFT is distributed as a header-only library (strating from the version 325 1.3, it is no longer a single header). 326 The installation process consists of the following steps: 327\end_layout 328 329\begin_layout Enumerate 330\noindent 331\align left 332Copy vkFFT.h file and vkFFT directory into one of the directories included 333 in the user's project. 334\end_layout 335 336\begin_layout Enumerate 337\noindent 338Define VKFFT_BACKEND as a number corresponding to the API used in the user's 339 project: 0 - Vulkan, 1 - CUDA, 2 - HIP, 3 - OpenCL, 4 - Level Zero, 5 - 340 Metal. 341 Definition is done like: 342\begin_inset ERT 343status open 344 345\begin_layout Plain Layout 346 347 348\backslash 349begin{mdframed}[backgroundcolor=bg] 350\end_layout 351 352\begin_layout Plain Layout 353 354 355\backslash 356begin{minted}[tabsize=4,obeytabs,breaklines]{make} 357\end_layout 358 359\begin_layout Plain Layout 360 361-DVKFFT_BACKEND=X 362\end_layout 363 364\begin_layout Plain Layout 365 366 367\backslash 368end{minted} 369\end_layout 370 371\begin_layout Plain Layout 372 373 374\backslash 375end{mdframed} 376\end_layout 377 378\end_inset 379 380 in GCC or as 381\begin_inset ERT 382status open 383 384\begin_layout Plain Layout 385 386 387\backslash 388begin{mdframed}[backgroundcolor=bg] 389\end_layout 390 391\begin_layout Plain Layout 392 393 394\backslash 395begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 396\end_layout 397 398\begin_layout Plain Layout 399 400set(VKFFT_BACKEND 1 CACHE STRING "0 - Vulkan, 1 - CUDA, 2 - HIP, 3 - OpenCL, 401 4 - Level Zero, 5 - Metal") 402\end_layout 403 404\begin_layout Plain Layout 405 406 407\backslash 408end{minted} 409\end_layout 410 411\begin_layout Plain Layout 412 413 414\backslash 415end{mdframed} 416\end_layout 417 418\end_inset 419 420in CMake. 421\end_layout 422 423\begin_layout Enumerate 424Define VKFFT_MAX_FFT_DIMENSIONS as the number of max dimensions to be supported 425 by VkFFT. 426 Default is 4. 427\end_layout 428 429\begin_layout Enumerate 430Depending on the API backend, the project must use additional libraries 431 for run-time compilation: 432\end_layout 433 434\begin_deeper 435\begin_layout Enumerate 436Vulkan API: SPIRV, glslang and Vulkan. 437 Define VK_API_VERSION to the available Vulkan version. 438 Sample CMakeLists can look like this: 439\begin_inset ERT 440status open 441 442\begin_layout Plain Layout 443 444 445\backslash 446begin{mdframed}[backgroundcolor=bg] 447\end_layout 448 449\begin_layout Plain Layout 450 451 452\backslash 453begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 454\end_layout 455 456\begin_layout Plain Layout 457 458find_package(Vulkan REQUIRED) 459\end_layout 460 461\begin_layout Plain Layout 462 463target_compile_definitions(${PROJECT_NAME} PUBLIC -DVK_API_VERSION=11)#10 464 - Vulkan 1.0, 11 - Vulkan 1.1, 12 - Vulkan 1.2 465\end_layout 466 467\begin_layout Plain Layout 468 469target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/gl 470slang-main/glslang/Include/) 471\end_layout 472 473\begin_layout Plain Layout 474 475add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/glslang-main) 476\end_layout 477 478\begin_layout Plain Layout 479 480\end_layout 481 482\begin_layout Plain Layout 483 484target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vk 485FFT/) 486\end_layout 487 488\begin_layout Plain Layout 489 490add_library(VkFFT INTERFACE) 491\end_layout 492 493\begin_layout Plain Layout 494 495target_compile_definitions(VkFFT INTERFACE -DVKFFT_BACKEND=0) 496\end_layout 497 498\begin_layout Plain Layout 499 500\end_layout 501 502\begin_layout Plain Layout 503 504target_link_libraries(${PROJECT_NAME} PUBLIC SPIRV glslang Vulkan::Vulkan 505 VkFFT) 506\end_layout 507 508\begin_layout Plain Layout 509 510 511\backslash 512end{minted} 513\end_layout 514 515\begin_layout Plain Layout 516 517 518\backslash 519end{mdframed} 520\end_layout 521 522\end_inset 523 524 525\end_layout 526 527\begin_layout Enumerate 528CUDA API: CUDA and NVRTC. 529 Sample CMakeLists can look like this: 530\begin_inset ERT 531status open 532 533\begin_layout Plain Layout 534 535 536\backslash 537begin{mdframed}[backgroundcolor=bg] 538\end_layout 539 540\begin_layout Plain Layout 541 542 543\backslash 544begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 545\end_layout 546 547\begin_layout Plain Layout 548 549find_package(CUDA 9.0 REQUIRED) 550\end_layout 551 552\begin_layout Plain Layout 553 554enable_language(CUDA) 555\end_layout 556 557\begin_layout Plain Layout 558 559set_property(TARGET ${PROJECT_NAME} PROPERTY CUDA_ARCHITECTURESs 60 70 75 560 80 86) 561\end_layout 562 563\begin_layout Plain Layout 564 565target_compile_options(${PROJECT_NAME} PUBLIC "$<$<COMPILE_LANGUAGE:CUDA>:SHELL: 566 567\end_layout 568 569\begin_layout Plain Layout 570 571 -DVKFFT_BACKEND=${VKFFT_BACKEND} 572\end_layout 573 574\begin_layout Plain Layout 575 576 -gencode arch=compute_60,code=compute_60 577\end_layout 578 579\begin_layout Plain Layout 580 581 -gencode arch=compute_70,code=compute_70 582\end_layout 583 584\begin_layout Plain Layout 585 586 -gencode arch=compute_75,code=compute_75 587\end_layout 588 589\begin_layout Plain Layout 590 591 -gencode arch=compute_80,code=compute_80 592\end_layout 593 594\begin_layout Plain Layout 595 596 -gencode arch=compute_86,code=compute_86>") 597\end_layout 598 599\begin_layout Plain Layout 600 601set_target_properties(${PROJECT_NAME} PROPERTIES CUDA_SEPARABLE_COMPILATION 602 ON) 603\end_layout 604 605\begin_layout Plain Layout 606 607set_target_properties(${PROJECT_NAME} PROPERTIES CUDA_RESOLVE_DEVICE_SYMBOLS 608 ON) 609\end_layout 610 611\begin_layout Plain Layout 612 613\end_layout 614 615\begin_layout Plain Layout 616 617find_library(CUDA_NVRTC_LIB libnvrtc nvrtc HINTS "${CUDA_TOOLKIT_ROOT_DIR}/lib64 618" "${LIBNVRTC_LIBRARY_DIR}" "${CUDA_TOOLKIT_ROOT_DIR}/lib/x64" /usr/lib64 619 /usr/local/cuda/lib64) 620\end_layout 621 622\begin_layout Plain Layout 623 624add_definitions(-DCUDA_TOOLKIT_ROOT_DIR="${CUDA_TOOLKIT_ROOT_DIR}") 625\end_layout 626 627\begin_layout Plain Layout 628 629\end_layout 630 631\begin_layout Plain Layout 632 633target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vk 634FFT/) 635\end_layout 636 637\begin_layout Plain Layout 638 639add_library(VkFFT INTERFACE) 640\end_layout 641 642\begin_layout Plain Layout 643 644target_compile_definitions(VkFFT INTERFACE -DVKFFT_BACKEND=1) 645\end_layout 646 647\begin_layout Plain Layout 648 649\end_layout 650 651\begin_layout Plain Layout 652 653target_link_libraries(${PROJECT_NAME} PUBLIC ${CUDA_LIBRARIES} cuda ${CUDA_NVRTC 654_LIB} VkFFT) 655\end_layout 656 657\begin_layout Plain Layout 658 659 660\backslash 661end{minted} 662\end_layout 663 664\begin_layout Plain Layout 665 666 667\backslash 668end{mdframed} 669\end_layout 670 671\end_inset 672 673 674\end_layout 675 676\begin_layout Enumerate 677HIP API: HIP and HIPRTC. 678 Sample CMakeLists can look like this: 679\begin_inset ERT 680status open 681 682\begin_layout Plain Layout 683 684 685\backslash 686begin{mdframed}[backgroundcolor=bg] 687\end_layout 688 689\begin_layout Plain Layout 690 691 692\backslash 693begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 694\end_layout 695 696\begin_layout Plain Layout 697 698list(APPEND CMAKE_PREFIX_PATH /opt/rocm/hip /opt/rocm) 699\end_layout 700 701\begin_layout Plain Layout 702 703find_package(hip) 704\end_layout 705 706\begin_layout Plain Layout 707 708\end_layout 709 710\begin_layout Plain Layout 711 712target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vk 713FFT/) 714\end_layout 715 716\begin_layout Plain Layout 717 718add_library(VkFFT INTERFACE) 719\end_layout 720 721\begin_layout Plain Layout 722 723target_compile_definitions(VkFFT INTERFACE -DVKFFT_BACKEND=2) 724\end_layout 725 726\begin_layout Plain Layout 727 728#target_compile_definitions(${PROJECT_NAME} PUBLIC -DVKFFT_OLD_ROCM) #ROCm 729 versions before 4.5 needed kernel include of hiprtc 730\end_layout 731 732\begin_layout Plain Layout 733 734\end_layout 735 736\begin_layout Plain Layout 737 738target_link_libraries(${PROJECT_NAME} PUBLIC hip::host VkFFT) 739\end_layout 740 741\begin_layout Plain Layout 742 743 744\backslash 745end{minted} 746\end_layout 747 748\begin_layout Plain Layout 749 750 751\backslash 752end{mdframed} 753\end_layout 754 755\end_inset 756 757 758\end_layout 759 760\begin_layout Enumerate 761OpenCL API: OpenCL. 762 Sample CMakeLists can look like this: 763\begin_inset ERT 764status open 765 766\begin_layout Plain Layout 767 768 769\backslash 770begin{mdframed}[backgroundcolor=bg] 771\end_layout 772 773\begin_layout Plain Layout 774 775 776\backslash 777begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 778\end_layout 779 780\begin_layout Plain Layout 781 782find_package(OpenCL REQUIRED) 783\end_layout 784 785\begin_layout Plain Layout 786 787\end_layout 788 789\begin_layout Plain Layout 790 791target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vk 792FFT/) 793\end_layout 794 795\begin_layout Plain Layout 796 797add_library(VkFFT INTERFACE) 798\end_layout 799 800\begin_layout Plain Layout 801 802target_compile_definitions(VkFFT INTERFACE -DVKFFT_BACKEND=3) 803\end_layout 804 805\begin_layout Plain Layout 806 807\end_layout 808 809\begin_layout Plain Layout 810 811target_link_libraries(${PROJECT_NAME} PUBLIC OpenCL::OpenCL VkFFT) 812\end_layout 813 814\begin_layout Plain Layout 815 816 817\backslash 818end{minted} 819\end_layout 820 821\begin_layout Plain Layout 822 823 824\backslash 825end{mdframed} 826\end_layout 827 828\end_inset 829 830 831\end_layout 832 833\begin_layout Enumerate 834Level Zero API: Level Zero; Clang and llvm-spirv must be in the system path 835 (for kernel compilation). 836 Sample CMakeLists can look like this: 837\begin_inset ERT 838status open 839 840\begin_layout Plain Layout 841 842 843\backslash 844begin{mdframed}[backgroundcolor=bg] 845\end_layout 846 847\begin_layout Plain Layout 848 849 850\backslash 851begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 852\end_layout 853 854\begin_layout Plain Layout 855 856set(LevelZero_LIBRARY "/usr/lib/x86_64-linux-gnu/") 857\end_layout 858 859\begin_layout Plain Layout 860 861set(LevelZero_INCLUDE_DIR "/usr/include/") 862\end_layout 863 864\begin_layout Plain Layout 865 866find_library( 867\end_layout 868 869\begin_layout Plain Layout 870 871 LevelZero_LIB 872\end_layout 873 874\begin_layout Plain Layout 875 876 NAMES "ze_loader" 877\end_layout 878 879\begin_layout Plain Layout 880 881 PATHS ${LevelZero_LIBRARY} 882\end_layout 883 884\begin_layout Plain Layout 885 886 PATH_SUFFIXES "lib" "lib64" 887\end_layout 888 889\begin_layout Plain Layout 890 891 NO_DEFAULT_PATH 892\end_layout 893 894\begin_layout Plain Layout 895 896 ) 897\end_layout 898 899\begin_layout Plain Layout 900 901find_path( 902\end_layout 903 904\begin_layout Plain Layout 905 906 LevelZero_INCLUDES 907\end_layout 908 909\begin_layout Plain Layout 910 911 NAMES "ze_api.h" 912\end_layout 913 914\begin_layout Plain Layout 915 916 PATHS ${LevelZero_INCLUDE_DIR} 917\end_layout 918 919\begin_layout Plain Layout 920 921 PATH_SUFFIXES "include" 922\begin_inset Quotes eld 923\end_inset 924 925level_zero 926\begin_inset Quotes erd 927\end_inset 928 929 930\end_layout 931 932\begin_layout Plain Layout 933 934 NO_DEFAULT_PATH 935\end_layout 936 937\begin_layout Plain Layout 938 939 ) 940\end_layout 941 942\begin_layout Plain Layout 943 944target_include_directories(${PROJECT_NAME} PUBLIC ${LevelZero_INCLUDES}) 945\end_layout 946 947\begin_layout Plain Layout 948 949add_library(VkFFT INTERFACE) 950\end_layout 951 952\begin_layout Plain Layout 953 954target_compile_definitions(VkFFT INTERFACE -DVKFFT_BACKEND=4) 955\end_layout 956 957\begin_layout Plain Layout 958 959\end_layout 960 961\begin_layout Plain Layout 962 963target_link_libraries(${PROJECT_NAME} PUBLIC LevelZero VkFFT) 964\end_layout 965 966\begin_layout Plain Layout 967 968 969\backslash 970end{minted} 971\end_layout 972 973\begin_layout Plain Layout 974 975 976\backslash 977end{mdframed} 978\end_layout 979 980\end_inset 981 982 983\end_layout 984 985\begin_layout Enumerate 986Metal API: Metal. 987 Sample CMakeLists can look like this: 988\begin_inset ERT 989status open 990 991\begin_layout Plain Layout 992 993 994\backslash 995begin{mdframed}[backgroundcolor=bg] 996\end_layout 997 998\begin_layout Plain Layout 999 1000 1001\backslash 1002begin{minted}[tabsize=4,obeytabs,breaklines]{cmake} 1003\end_layout 1004 1005\begin_layout Plain Layout 1006 1007add_compile_options(-WMTL_IGNORE_WARNINGS) 1008\end_layout 1009 1010\begin_layout Plain Layout 1011 1012find_library(FOUNDATION_LIB Foundation REQUIRED) 1013\end_layout 1014 1015\begin_layout Plain Layout 1016 1017find_library(QUARTZ_CORE_LIB QuartzCore REQUIRED) 1018\end_layout 1019 1020\begin_layout Plain Layout 1021 1022find_library(METAL_LIB Metal REQUIRED) 1023\end_layout 1024 1025\begin_layout Plain Layout 1026 1027target_include_directories(${PROJECT_NAME} PUBLIC "metal-cpp/") 1028\end_layout 1029 1030\begin_layout Plain Layout 1031 1032\end_layout 1033 1034\begin_layout Plain Layout 1035 1036target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/vk 1037FFT/) 1038\end_layout 1039 1040\begin_layout Plain Layout 1041 1042add_library(VkFFT INTERFACE) 1043\end_layout 1044 1045\begin_layout Plain Layout 1046 1047target_compile_definitions(VkFFT INTERFACE -DVKFFT_BACKEND=5) 1048\end_layout 1049 1050\begin_layout Plain Layout 1051 1052\end_layout 1053 1054\begin_layout Plain Layout 1055 1056target_link_libraries(${PROJECT_NAME} PUBLIC ${FOUNDATION_LIB} ${QUARTZ_CORE_LIB 1057} ${METAL_LIB} VkFFT) 1058\end_layout 1059 1060\begin_layout Plain Layout 1061 1062 1063\backslash 1064end{minted} 1065\end_layout 1066 1067\begin_layout Plain Layout 1068 1069 1070\backslash 1071end{mdframed} 1072\end_layout 1073 1074\end_inset 1075 1076 1077\end_layout 1078 1079\end_deeper 1080\begin_layout Subsection 1081Fourier Transform Setup 1082\end_layout 1083 1084\begin_layout Standard 1085VkFFT follows a plan structure like FFTW/cuFFT with a notable difference 1086 - there is a unified interface to all transforms. 1087 This means that there are no separate functions like fftPlan1D/fftPlan2D/fftPla 1088nMany/etc. 1089 The initialization is done through a single configuration struct - VkFFTConfigu 1090ration. 1091 Each parameter of it will be covered in detail in this document. 1092 Plans in VkFFT are called VkFFTApplication and they are created with a 1093 unified initializeVkFFT call. 1094 1095\end_layout 1096 1097\begin_layout Standard 1098As the code is written in C, don't forget to zero-initialize used structs! 1099\end_layout 1100 1101\begin_layout Standard 1102During the initializeVkFFT(VkFFTApplication* app, VkFFTConfiguration inputLaunch 1103Configuration) call VkFFT performs kernel generation and compilation from 1104 scratch (kernel reuse may be added later). 1105 The overall process of initialization looks like this: 1106\end_layout 1107 1108\begin_layout Enumerate 1109Get device parameters, perform default initialization of internal copy of 1110 configuration struct inside the VkFFTApplication, then fill in user-defined 1111 parameters from inputLaunchConfiguration. 1112\begin_inset space ~ 1113\end_inset 1114 1115VkFFTApplication is passed as a pointer, so initializeVkFFT modifies the 1116 user-provided application. 1117\end_layout 1118 1119\begin_layout Enumerate 1120By default, there are two internal FFT plans created - inverse and forward. 1121 Multidimensional FFT is done as a combination of 1D FFTs in each axis direction. 1122 For each axis, the VkFFTPlanAxis function is called. 1123\end_layout 1124 1125\begin_layout Enumerate 1126VkFFTPlanAxis configures parameters for each axis. 1127 It may perform additional memory allocations (see: memory allocated by 1128 VkFFT). 1129\end_layout 1130 1131\begin_layout Enumerate 1132shaderGenVkFFT generates corresponding to the axis code in a char buffer 1133 (each axis may require more than one kernel: see Four-step FFT, Bluestein's 1134 algorithm for FFT). 1135 1136\end_layout 1137 1138\begin_layout Enumerate 1139Code is then compiled with the run-time compiler of the specified backend. 1140\end_layout 1141 1142\begin_layout Standard 1143Once the plan is no longer need, a call to the deleteVkFFT function frees 1144 all the allocated resources. 1145 There are no processes launched that continue to work outside of the VkFFT 1146 related function calls. 1147\end_layout 1148 1149\begin_layout Subsection 1150Fourier Transform types and their definitions 1151\end_layout 1152 1153\begin_layout Standard 1154VkFFT supports commonly used Complex to complex (C2C), real to complex (R2C), 1155 complex to real (C2R) transformations and real to real (R2R) Discrete Cosine/Si 1156ne Transformations of types I, II, III and IV. 1157 VkFFT uses the same definitions as FFTW, except for the multidimensional 1158 FFT axis ordering: in FFTW dimensions are ordered with the decrease in 1159 consecutive elements stride, while VkFFT does the opposite - the first 1160 axis is the non-strided axis (the one that has elements located consecutively 1161 in memory with no gaps, usually named as the X-axis). 1162 So, in FFTW dimensions are specified as ZYX and in VkFFT as XYZ. 1163 This felt more logical to me - no matter if there are 1, 2, 3 or more dimension 1164s, the user can always find the axis with the same stride at the same position. 1165 This choice doesn't require any modification in the user's data management 1166 - just provide the FFT dimensions in the reverse order to VkFFT. 1167 1168\end_layout 1169 1170\begin_layout Standard 1171The 1.3 version of VkFFT supports arbitrary number of dimensions, defined 1172 as VKFFT_MAX_FFT_DIMENSIONS compile constant. 1173 VkFFT also supports two forms of batching: the number of coordinates and 1174 the number of systems. 1175 The choice of two distinct batching ways is made to support matrix-vector 1176 convolutions, where the kernel is presented as a matrix. 1177 Overall, the layout of VkFFT can be described as WHD+CN - width, height, 1178 depth, other dimensions, coordinate and number of systems (in order of 1179 increasing strides, starting with 1 for width). 1180 Often, the coordinate part of the layout is not used, so the main batching 1181 is done by specifying N. 1182\end_layout 1183 1184\begin_layout Standard 1185VkFFT assumes that complex numbers are stored consecutively in memory: RIRIRI... 1186 where R denotes the real part of the complex number and I denotes the imaginary 1187 part. 1188 There is no difference between using a float2/double2/half2 container or 1189 access memory as float/double/half/double-double as long as the byte order 1190 remains the same. 1191\end_layout 1192 1193\begin_layout Standard 1194This section and the next one will cover the basics of VkFFT data layouts 1195 and memory management. 1196 1197\end_layout 1198 1199\begin_layout Subsubsection 1200C2C transforms 1201\end_layout 1202 1203\begin_layout Standard 1204The base FFT algorithm - C2C in VkFFT has the same definition as FFTW. 1205 Forward FFT has the exponent sign 1206\begin_inset Formula $-1$ 1207\end_inset 1208 1209, while the inverse has the exponent sign 1210\begin_inset Formula $1$ 1211\end_inset 1212 1213. 1214 By default, the inverse transform is unnormalized. 1215 1216\begin_inset Formula $N_{x}N_{y}N_{z}$ 1217\end_inset 1218 1219 complex numbers map to 1220\begin_inset Formula $N_{x}N_{y}N_{z}$ 1221\end_inset 1222 1223 complex numbers and no additional padding is required. 1224 The resulting data order will be the same as in FFTW/cuFFT, unless special 1225 parameters are provided in configuration (see: advanced memory management) 1226\end_layout 1227 1228\begin_layout Subsubsection 1229R2C/C2R transforms 1230\end_layout 1231 1232\begin_layout Standard 1233R2C/C2R transforms can be explained as C2C transforms with imaginary part 1234 set to zero. 1235 They exploit Hermitian symmetry of the result: 1236\begin_inset Formula $X_{k}=X_{N-k}^{*}$ 1237\end_inset 1238 1239 on the non-strided axis (the one that has elements located consecutively 1240 in memory with no gaps). 1241 This results in s reduction of required memory to store the complex result 1242 - we may only store 1243\begin_inset Formula $floor(\frac{N_{x}}{2})+1$ 1244\end_inset 1245 1246 complex numbers instead of 1247\begin_inset Formula $N_{x}$ 1248\end_inset 1249 1250. 1251 However, this results in memory requirements mismatch between input and 1252 output in R2C: 1253\begin_inset Formula $floor(\frac{N_{x}}{2})+1$ 1254\end_inset 1255 1256 complex elements will require 1257\begin_inset Formula $N_{x}+2$ 1258\end_inset 1259 1260 real numbers worth of memory for even 1261\begin_inset Formula $N_{x}$ 1262\end_inset 1263 1264 and 1265\begin_inset Formula $N_{x}+1$ 1266\end_inset 1267 1268 real numbers worth of memory for odd 1269\begin_inset Formula $N_{x}$ 1270\end_inset 1271 1272. 1273 For C2R the situation is reversed. 1274 There are two approaches to this problem: pad each sequence of the non-strided 1275 axis with zeros to the required length or use out-of-place mode. 1276 More information on how to do this will be given in the next section. 1277\end_layout 1278 1279\begin_layout Subsubsection 1280R2R (DCT) transforms 1281\end_layout 1282 1283\begin_layout Standard 1284R2R transforms in VkFFT are implemented in the form of Discrete cosine transform 1285s and Discrete sine transforms of types I, II, III and IV. 1286 Their definitions and transforms results match FFTW: 1287\end_layout 1288 1289\begin_layout Enumerate 1290DCT-I: 1291\begin_inset Formula $X_{k}=x_{0}+(-1)^{k}x_{N-1}+2\stackrel[n=1]{N-2}{\sum}x_{n}cos(\frac{\pi}{N-1}nk)$ 1292\end_inset 1293 1294, inverse of DCT-I (itself) 1295\end_layout 1296 1297\begin_layout Enumerate 1298DCT-II: 1299\begin_inset Formula $X_{k}=2\stackrel[n=0]{N-1}{\sum}x_{n}cos(\frac{\pi}{N}(n+\frac{1}{2})k)$ 1300\end_inset 1301 1302, inverse of DCT-III 1303\end_layout 1304 1305\begin_layout Enumerate 1306DCT-III: 1307\begin_inset Formula $X_{k}=x_{0}+2\stackrel[n=1]{N-1}{\sum}x_{n}cos(\frac{\pi}{N}n(k+\frac{1}{2}))$ 1308\end_inset 1309 1310, inverse of DCT-II 1311\end_layout 1312 1313\begin_layout Enumerate 1314DCT-IV: 1315\begin_inset Formula $X_{k}=2\stackrel[n=0]{N-1}{\sum}x_{n}cos(\frac{\pi}{N}(n+\frac{1}{2})(k+\frac{1}{2}))$ 1316\end_inset 1317 1318, inverse of DCT-IV (itself) 1319\end_layout 1320 1321\begin_layout Enumerate 1322DST-I: 1323\begin_inset Formula $X_{k}=2\stackrel[n=0]{N-1}{\sum}x_{n}sin(\frac{\pi}{N+1}(n+1)(k+1))$ 1324\end_inset 1325 1326, inverse of DST-I (itself) 1327\end_layout 1328 1329\begin_layout Enumerate 1330DST-II: 1331\begin_inset Formula $X_{k}=2\stackrel[n=0]{N-1}{\sum}x_{n}sin(\frac{\pi}{N}(n+\frac{1}{2})(k+1))$ 1332\end_inset 1333 1334, inverse of DST-III 1335\end_layout 1336 1337\begin_layout Enumerate 1338DST-III: 1339\begin_inset Formula $X_{k}=(-1)^{k}x_{N-1}+2\stackrel[n=0]{N-2}{\sum}x_{n}sin(\frac{\pi}{N}(n+1)(k+\frac{1}{2}))$ 1340\end_inset 1341 1342, inverse of DST-II 1343\end_layout 1344 1345\begin_layout Enumerate 1346DST-IV: 1347\begin_inset Formula $X_{k}=2\stackrel[n=0]{N-1}{\sum}x_{n}sin(\frac{\pi}{N}(n+\frac{1}{2})(k+\frac{1}{2}))$ 1348\end_inset 1349 1350, inverse of DST-IV (itself) 1351\end_layout 1352 1353\begin_layout Standard 1354R2R transforms are performed by redefinition of them to the C2C transforms 1355 (internal C2C sequence length can be different from the input R2R sequence 1356 length). 1357 R2R transform performs a one-to-one mapping between real numbers, so they 1358 don't require stride management, unlike R2C/C2R. 1359\end_layout 1360 1361\begin_layout Subsection 1362Memory management, data layouts for different transforms 1363\end_layout 1364 1365\begin_layout Subsubsection 1366VkFFT buffers 1367\end_layout 1368 1369\begin_layout Standard 1370VkFFT allows for explicit control over the data flow, which makes both in-place 1371 and out-of-place transforms possible. 1372 Buffers are passed to VkFFT as VkBuffer pointer in Vulkan, as double void 1373 pointers in CUDA/HIP/Level Zero, as cl_mem pointer in OpenCL and as MTL::Buffer 1374 pointer in Metal. 1375 This is done to maintain a uniform data pattern because some of the buffers 1376 can be allocated automatically. 1377 1378\end_layout 1379 1380\begin_layout Standard 1381The main buffer is called buffer and it always has to be provided, either 1382 during the plan creation or when the plan is executed. 1383 All calculations are performed in this buffer and it is always overwritten. 1384 To do calculations out-of-place, VkFFT provides an option to specify inputBuffe 1385r/outputBuffer buffer. 1386 The logic behind their usage is fairly simple - the user specifies inputBuffer 1387 if the input data has to be read from a buffer, different from the main 1388 buffer. 1389 As the data is read only once and nothing is written back to the inputBuffer, 1390 this allows doing truly out-of-place transformations. 1391 The same logic applies to outputBuffer with the difference that it is responsib 1392le for the absolute last write of the VkFFT. 1393 It is possible to use all three buffers to create complex data management 1394 paths. 1395\end_layout 1396 1397\begin_layout Standard 1398It must be noted, that sometimes FFT can not be done inside one buffer (see: 1399 Four-Step FFT algorithm, Bluestein's algorithm). 1400 To compute FFT in these cases, there exists tempBuffer buffer and data 1401 is transferred between the main buffer and tempBuffer during the FFT execution. 1402 The ordering of transfers between the main buffer and tempBuffer is done 1403 in such a way, so the initial data read and final data write are obeying 1404 the configuration from the previous paragraph. 1405 Users can allocate tempBuffer themselves of some memory that does not have 1406 any useful information at the time of FFT execution (the tempBuffer size 1407 can depend on the configuration, so this is a rather advanced operation 1408 - read more in the advanced memory management section) or allow VkFFT to 1409 manage tempBuffer allocation itself (tempBuffer will be freed at the deleteVkFF 1410T call). 1411\end_layout 1412 1413\begin_layout Standard 1414To compute convolutions and cross-correlations, a kernel buffer has to be 1415 specified. 1416 It must have the same layout as the result of the FFT transform. 1417\end_layout 1418 1419\begin_layout Subsubsection 1420VkFFT buffers strides. 1421 A special case of R2C/C2R transforms 1422\end_layout 1423 1424\begin_layout Standard 1425To have better control of memory, the user can specify the strides between 1426 consecutive elements of different axes. 1427 The W (width) stride is fixed to be 1, so to achieve innermost batching, 1428 user needs to initialize an N+1 dimension FFT and omit the innermost dimension 1429 using omitDimension[0] = 1 parameter. 1430 N (number of systems) stride will be consecutive of C in memory if C is 1431 used, otherwise N will propagate the previous non-uniform stride multiplied 1432 by the corresponding axis length). 1433 Strides are specified not in bytes, but in the element type used - similar 1434 to the way how the user would access the corresponding element in the array. 1435 If all elements are consecutive in C2C, stride for H will be equal to the 1436 FFT length of W axis, stride for D will be multiplication of first two 1437 FFT axis lengths and so on, stride for C will be multiplication of all 1438 FFT axes lengths, etc. 1439 These are the default values of C2C and R2R strides if they are not explicitly 1440 specified. 1441\end_layout 1442 1443\begin_layout Standard 1444One of the main use-cases of strides comes to solve the R2C/C2R Hermitian 1445 symmetry H stride mismatch - for real space, it is equal to 1446\begin_inset Formula $N_{x}$ 1447\end_inset 1448 1449 real elements and for the frequency space it is equal to 1450\begin_inset Formula $floor(\frac{N_{x}}{2})+1$ 1451\end_inset 1452 1453 complex numbers. 1454 So, with strides it is possible to use a buffer, padded to 1455\begin_inset Formula $2\cdot(floor(\frac{N_{x}}{2})+1)$ 1456\end_inset 1457 1458 real elements in H stride (all elements between 1459\begin_inset Formula $N_{x}$ 1460\end_inset 1461 1462 and 1463\begin_inset Formula $2\cdot(floor(\frac{N_{x}}{2})+1)$ 1464\end_inset 1465 1466 will not be read so it does not matter what data is there before the write 1467 stage). 1468 All other strides are done as a multiplication between the previous stride 1469 and the number of elements in the previous axis. 1470 These are the default values of R2C/C2R strides if they are not explicitly 1471 specified. 1472\end_layout 1473 1474\begin_layout Standard 1475It is possible to specify separate sets of strides for all user-defined 1476 buffers: bufferStride for the main buffer, inputStride for input buffer, 1477 outputStride for output buffer (kernel stride is assumed to be the same 1478 as bufferStride, tempBuffer strides are configured automatically). 1479 1480\end_layout 1481 1482\begin_layout Standard 1483For an out-of-place R2C FFT, there is no need to pad buffer with real numbers, 1484 but user must specify H stride there (as it differs to default one) - 1485\begin_inset Formula $N_{x}$ 1486\end_inset 1487 1488 real elements for real space and 1489\begin_inset Formula $floor(\frac{N_{x}}{2})+1$ 1490\end_inset 1491 1492 complex numbers for the frequency space. 1493 1494\end_layout 1495 1496\begin_layout Standard 1497An out-of-place C2R FFT is a more tricky transform. 1498 In the multidimensional case, the main buffer will be written to and read 1499 from multiple times. 1500 The intermediate stores have a complex layout, which requires more space 1501 than the output real layout, so in order not to modify the input data, 1502 there exist two options. 1503 First, pad the real data layout has to 1504\begin_inset Formula $2\cdot(floor(\frac{N_{x}}{2})+1)$ 1505\end_inset 1506 1507 real elements in H stride (complex buffer will be used as inputBuffer, 1508 real buffer as buffer). 1509 Second, use the third buffer, so both input and output buffers have their 1510 original layouts (complex buffer will be used as inputBuffer, the main 1511 buffer for calculations is buffer and output real buffer as outputBuffer). 1512 If you use inverseReturnToInputBuffer option, where R2C is configured to 1513 read from input buffer and C2R is configured to write to the input buffer; 1514 C2R will modify the buffer it reads from in some cases (see issue 1515\begin_inset CommandInset href 1516LatexCommand href 1517name "#58" 1518target "https://github.com/DTolm/VkFFT/issues/58#issuecomment-1007205682" 1519literal "false" 1520 1521\end_inset 1522 1523) 1524\end_layout 1525 1526\begin_layout Standard 1527By default, R2C/C2R will assume the complex-padded real strides in the in-place 1528 mode and non-padded real strides in out-of-place mode. 1529\end_layout 1530 1531\begin_layout Subsection 1532VkFFT algorithms 1533\end_layout 1534 1535\begin_layout Standard 1536VkFFT implements a wide range of algorithms to compute different types of 1537 FFTs but all of them can be reduced to a mixed-radix Cooley-Tukey FFT algorithm 1538 in the Stockham autosort form. 1539 The main idea behind it is to decompose the sequence as a set of primes, 1540 for each of which FFT can be written down exactly. 1541 As of now, VkFFT has radix implementations for primes up to 13, so all 1542 C2C sequences decomposable into a multiplication of such primes will be 1543 done purely with the Stockham algorithm. 1544 Below additional algorithms and their use-cases are described. 1545\end_layout 1546 1547\begin_layout Subsubsection 1548Bluestein's algorithm 1549\end_layout 1550 1551\begin_layout Standard 1552A complex algorithm that is used in cases where the sequence is not decomposable 1553 with implemented radix butterflies (currently - primes up to 13). 1554 It is derived by replacing 1555\begin_inset Formula $nk=\left(n^{2}+k^{2}-(n-k)^{2}\right)/2$ 1556\end_inset 1557 1558 in 1559\begin_inset CommandInset ref 1560LatexCommand ref 1561reference "eq:dft" 1562plural "false" 1563caps "false" 1564noprefix "false" 1565 1566\end_inset 1567 1568: 1569\end_layout 1570 1571\begin_layout Standard 1572\begin_inset Formula 1573\begin{align} 1574X_{k} & =\left(e^{-\pi i\frac{k^{2}}{N}}\right)\stackrel[n=0]{N-1}{\sum}\left(x_{n}e^{-\pi i\frac{n^{2}}{N}}\right)\left(e^{\pi i\frac{\left(k-n\right)^{2}}{N}}\right)=b_{k}^{\ast}\stackrel[n=0]{N-1}{\sum}a_{n}b_{k-n}\label{eq:dft-1}\\ 1575a_{n} & =x_{n}b_{n}^{\ast}\\ 1576b_{n} & =e^{\pi i\frac{n^{2}}{N}} 1577\end{align} 1578 1579\end_inset 1580 1581 1582\end_layout 1583 1584\begin_layout Standard 1585Here FFT is represented as a convolution between two sequences: 1586\begin_inset Formula $a_{n}$ 1587\end_inset 1588 1589 and 1590\begin_inset Formula $b_{n}$ 1591\end_inset 1592 1593, which can be performed by the means of convolution theorem: 1594\end_layout 1595 1596\begin_layout Standard 1597\begin_inset Formula 1598\begin{equation} 1599F\{a\ast b\}=F\{a\}\cdot F\{b\} 1600\end{equation} 1601 1602\end_inset 1603 1604 1605\end_layout 1606 1607\begin_layout Standard 1608By padding 1609\begin_inset Formula $a_{n}$ 1610\end_inset 1611 1612 and 1613\begin_inset Formula $b_{n}$ 1614\end_inset 1615 1616 to a sequence length decomposable with implemented radix butterflies with 1617 a size of at least 1618\begin_inset Formula $2N-1$ 1619\end_inset 1620 1621 (because the length of 1622\begin_inset Formula $b_{n}$ 1623\end_inset 1624 1625 is 1626\begin_inset Formula $2N-1$ 1627\end_inset 1628 1629), we can perform FFT of any length. 1630 FFT of 1631\begin_inset Formula $b_{n}$ 1632\end_inset 1633 1634 can be precomputed, so overall this algorithm requires at least 4x the 1635 computations and more memory transfers. 1636 This algorithm can be combined with all other algorithms implemented in 1637 VkFFT. 1638 If an FFT can not be done in a single upload, a tempBuffer has to be allocated 1639 (because the logical FFT buffer size is bigger than the original system). 1640\end_layout 1641 1642\begin_layout Subsubsection 1643The Four-Step FFT algorithm 1644\end_layout 1645 1646\begin_layout Standard 1647GPUs and CPUs have a hierarchical memory model - the closer memory to the 1648 unit that performs the computations, the faster its speed and the lower 1649 the size. 1650 So it is advantageous to split FFTs, not to the lowest primes, but to some 1651 bigger multiplication of those primes, then upload this subsequence to 1652 the closest cache level to the cores and do the final prime split there. 1653 The absolute lowest level is the register file, however, it does not allow 1654 for thread communications outside the warp. 1655 For this purpose, modern GPUs employ shared memory - a fast memory with 1656 a bank structure that is visible to all threads in a thread block. 1657 The usual sizes of it change on a scale from 16KB to 192KB and it is often 1658 beneficial to use it fully. 1659 However, if the full sequence can not fit inside the shared memory, FFT 1660 has to be done in multiple uploads - with the Four Step FFT algorithm. 1661 The main idea behind it is to represent a big 1D sequence as a 2D (or 3D 1662 for the three-upload scheme) FFT - we first do FFT along the columns, then 1663 the rows, then transpose the result and multiply by a special set of phase 1664 vectors. 1665 Similar decomposition idea as the main Cooley-Tukey algorithm. 1666 However, performing transpositions in-place is a complicated task - especially 1667 for a non-trivial ratio between dimensions. 1668 It will also require an additional read/write stage, as it can not be merged 1669 with the last write of the FFT algorithm. 1670 The easiest and the most performant solution is to use a tempBuffer (it 1671 is the main reason for having this functionality, actually) and store intermedi 1672ate FFT results out-of-place. 1673 This way the last transposition step can be merged with the write step, 1674 as we can overwrite the output buffer without losing data. 1675\end_layout 1676 1677\begin_layout Standard 1678To estimate if your sequence size is single upload or not, divide the amount 1679 of available shared memory (48KB - Nvidia GPUs with Vulkan/OpenCL API, 1680 64KB - AMD GPUs, 100KB - Nvidia GPUs in CUDA API) by the complex size used 1681 for calculations (4 byte - half precision, 8 byte - single precision, 16 1682 byte - double precision, 32 byte - double-double). 1683 For 64KB of shared memory, we get 8192 as max single upload single-precision 1684 non-strided FFT, 4096 for double precision. 1685 For strided axes (H and D parts of the layout) these numbers have to be 1686 divided by 4 and 2 respectively to achieve coalescing, resulting in 2048 1687 length for single upload in both precisions. 1688 For more information on coalescing see: coalescing API reference. 1689\end_layout 1690 1691\begin_layout Standard 1692In the case of the Four-Step FFT algorithm, tempBuffer size has to be at 1693 least the same as the default main buffer size. 1694 It does not matter how many uploads are in the Four Step FFT algorithm 1695 - only a single tempBuffer is required. 1696 In this document, all systems that can fit in the shared memory entirely 1697 and be done without the Four Step FFT algorithm (and multiple uploads) 1698 are called single upload systems. 1699\end_layout 1700 1701\begin_layout Standard 1702If the last transposition is not required (the output data is allowed to 1703 be in not unshuffled form) it can be disabled during the configuration 1704 phase. 1705 This way tempBuffer will not be needed and all computations will be done 1706 in-place (unless Bluestein's algorithm is used). 1707 An example use-case of this is convolutions - if the kernel is computed 1708 with the same operation ordering, point-wise multiplication in the frequency 1709 domain is not dependent on the correct data ordering and the inverse FFT 1710 will restore the original layout. 1711\end_layout 1712 1713\begin_layout Subsubsection 1714R2C/C2R FFTs 1715\end_layout 1716 1717\begin_layout Standard 1718A typical approach to a single upload R2C/C2R system is to just set the 1719 imaginary part to zero inside the shared memory and do a simple C2C transform. 1720 This doesn't affect the amount of memory transferred from VRAM and is not 1721 a bad approach as FFT is a memory-bound algorithm, however, this can be 1722 improved in multidimensional (in HDCN part of the layout) case by the compositi 1723on of a single C2C sequence from two real sequences and some write for R2C/read 1724 for C2R post-processing. 1725 Both of these algorithms are implemented in VkFFT. 1726 Note, that R2C/C2R only affects the non-strided axis (W). 1727 All strided axes are still done as C2C. 1728\end_layout 1729 1730\begin_layout Subsubsection 1731R2C/C2R multi-upload FFT algorithm 1732\end_layout 1733 1734\begin_layout Standard 1735For even sequences there exists an easy mapping between R2C/C2R FFTs and 1736 the C2C of half the size. 1737 In this case, all even indices (starting from 0) are read as the real values 1738 of a complex number and all odd indices are read as the imaginary values. 1739 This C2C sequence can be done with the help of the Four-Step FFT algorithm. 1740 When FFT is done, separate post-processing for R2C/pre-processing for C2R 1741 is applied. 1742\end_layout 1743 1744\begin_layout Standard 1745VkFFt also implements a general R2C/C2R algorithm that computes R2C as a 1746 C2C of the same length with imaginary part set to zero. 1747 The memory layout of it is optimized to reduce memory footprint. 1748\end_layout 1749 1750\begin_layout Subsubsection 1751R2R Discrete Cosine/Sine Transforms 1752\end_layout 1753 1754\begin_layout Standard 1755There exist many different mappings between DCT and FFT. 1756 DSTs are reformulated as DCTs inside the VkFFT, so they use the same algorithms. 1757 As of now, VkFFT has the following algorithms implemented (both single 1758 and multiple uploads): 1759\end_layout 1760 1761\begin_layout Itemize 1762DCT-I - mapping between R2R and C2C of the 1763\begin_inset Formula $2N-2$ 1764\end_inset 1765 1766 length. 1767 For non-strided axis can use an optimization similar to the R2C/C2R multidimens 1768ional case (setting the imaginary part to the next FFT sequence). 1769\end_layout 1770 1771\begin_layout Itemize 1772DCT-II/DCT-III - mapping between R2R and C2C of the same length. 1773 For non-strided axis can use an optimization similar to the R2C/C2R multidimens 1774ional case (setting the imaginary part to the next FFT sequence). 1775\end_layout 1776 1777\begin_layout Itemize 1778DCT-IV - for even sizes, mapping between R2R and C2C sequence of half-length. 1779 For odd sizes mapping to the FFT of the same length (for non-strided axis 1780 can use an optimization similar to the R2C/C2R multidimensional case (setting 1781 the imaginary part to the next FFT sequence)). 1782\end_layout 1783 1784\begin_layout Standard 1785The single upload versions (that can fit in shared memory) of these algorithms 1786 have all mappings done in shared memory of the compute unit. 1787 For multiple upload sequence sizes, special callback versions of these 1788 algorithms are created that work similar to callbacks in CUDA (though more 1789 sophisticated as these algorithms can use multiple input values). 1790 The callback functionality has not been yet exposed to the user for general 1791 applications and its design is open to discussion. 1792\end_layout 1793 1794\begin_layout Subsubsection 1795Register overutilization 1796\end_layout 1797 1798\begin_layout Standard 1799Not an FFT algorithm by itself, but an optimization to do bigger sequences 1800 in a single upload instead of switching to the Four Step FFT algorithm. 1801 The main idea behind it is to use a register file (which is often bigger 1802 than the amount of shared memory) to store the sequence and use shared 1803 memory only as a communication buffer. 1804 This is useful in Vulkan and OpenCL APIs on Nvidia GPU, as they are only 1805 allowed to allocate 48KB of shared memory with a register file having the 1806 size of 256KB. 1807\end_layout 1808 1809\begin_layout Subsubsection 1810Zero padding 1811\end_layout 1812 1813\begin_layout Standard 1814Not an FFT algorithm by itself, but a memory management optimization. 1815 If the user's system has parts that are known to be zero - for example, 1816 when an open system is modeled, to avoid a circular part of the FFT system 1817 has to be padded with zeros up to 2x in each direction. 1818 VkFFT can omit sequences full of zeros and don't perform the corresponding 1819 memory transfers and computations, as the output result will be zero. 1820 This way it is possible to get up to two times speed increase in the 2D 1821 case and up to 3x increase in the 3D case. 1822 1823\end_layout 1824 1825\begin_layout Subsubsection 1826Convolution and cross-correlation support 1827\end_layout 1828 1829\begin_layout Standard 1830With the help of the Convolution theorem, which states that the Fourier 1831 transform of a convolution is the pointwise product of signals Fourier 1832 transforms, it is possible to perform convolution with 1833\begin_inset Formula $NlogN$ 1834\end_inset 1835 1836 complexity, compared to 1837\begin_inset Formula $N^{2}$ 1838\end_inset 1839 1840 complexity of the simple multiplication approach. 1841 This is extremely useful for kernels spanning more than 50 elements in 1842 size. 1843 VkFFT can merge the last step FFT, kernel multiplication in the Fourier 1844 domain and the first step of inverse FFT to provide substantial memory 1845 transfer savings. 1846 Moreover, FFTs of big sequences can be performed without data reordering, 1847 which results in a better locality. 1848 1849\end_layout 1850 1851\begin_layout Subsection 1852VkFFT accuracy 1853\end_layout 1854 1855\begin_layout Standard 1856To measure how VkFFT (single/double/half/double-double precision) results 1857 compare to cuFFT/rocFFT (single/double/half precision) and FFTW (double/quad 1858 precision), multiple sets of systems covering full supported C2C/R2C+C2R/R2R 1859 FFT range are filled with random complex data on the scale of [-1,1] and 1860 one transform was performed on each system. 1861 Samples 11(single), 12(double), 13(half), 14(non-power of 2 C2C, single), 1862 15(R2C+C2R, single), 16(DCT-I/II/III/IV, single), 17(DCT-I/II/III/IV, double), 1863 18(non-power of 2 C2C, double), 19(double-double emulation of quad precision, 1864 C2C) are available in VkFFT Benchmark Suite to perform VkFFT verification 1865 on any of the target platforms. 1866 Overall, the Cooley-Tukey algorithm (Stockham autosort) exhibits logarithmic 1867 relative error scaling, similar to those of other GPU FFT libraries. 1868 Typically, the more computationally expensive algorithm is - the worse 1869 its precision is. 1870 So, Bluestein's algorithm has lower accuracy than Stockham autosort algorithm. 1871\end_layout 1872 1873\begin_layout Standard 1874Single precision in VkFFT supports two modes of calculation - by using the 1875 on-chip Special Function Units that can compute sines and cosines on the 1876 go or by using the precomputed on CPU look-up tables. 1877 For Nvidia and AMD GPUs, SFU provide great precision, while Intel iGPUs 1878 and mobile GPUs must use LUT to perform FFTs correctly. 1879\end_layout 1880 1881\begin_layout Standard 1882Double precision in VkFFT also supports two modes of calculation - by using 1883 polynomial sincos approximation and computing them on-chip or by using 1884 precomputed LUT as well. 1885 The second option is the better one, as polynomial sincos approximation 1886 is too compute-heavy for modern GPUs. 1887 It is selected by default on all devices. 1888\end_layout 1889 1890\begin_layout Standard 1891Half precision is supported in all backends. 1892 Half precision is implemented only as a memory trick - all on-chip computations 1893 are done in single precision. 1894 Half precision can use SFU or LUT as well. 1895\end_layout 1896 1897\begin_layout Standard 1898Double-double emulation of quad precision uses precomputed on CPU in quad 1899 precision twiddle factors and implements only additions and multiplications 1900 on GPU (for now). 1901\end_layout 1902 1903\begin_layout Standard 1904VkFFT also supports mixed-precision operations, where memory storing is 1905 done at lower precision, compared to the on-chip calculations. 1906 For example, it is possible to read data in single precision, do calculations 1907 in double and store data back in single precision. 1908 1909\end_layout 1910 1911\begin_layout Subsection 1912VkFFT additional memory allocations 1913\end_layout 1914 1915\begin_layout Standard 1916In this section, all GPU memory allocations that are done by VkFFT are described. 1917 There are up to three situations when VkFFT allocates memory. 1918 All of the VkFFT allocated memory is freed at the deleteVkFFT call. 1919\end_layout 1920 1921\begin_layout Subsubsection 1922LUT allocations 1923\end_layout 1924 1925\begin_layout Standard 1926This memory is used to store precomputed twiddle factors and phase vectors 1927 used during the computation. 1928 This buffer can have: 1929\end_layout 1930 1931\begin_layout Itemize 1932twiddle factors for each radix stage of Stockham FFT calculation 1933\end_layout 1934 1935\begin_layout Itemize 1936phase vectors used in the Four Step FFT algorithm between stages 1937\end_layout 1938 1939\begin_layout Itemize 1940phase vectors used in DCT/DST-II/III/IV to perform a mapping between R2R 1941 and C2C 1942\end_layout 1943 1944\begin_layout Itemize 1945phase vectors used in post-processing for R2C/pre-processing for C2R for 1946 even length sequences as C2C of half size 1947\end_layout 1948 1949\begin_layout Standard 1950VkFFT manages LUT allocations by itself and they are performed during the 1951 initializeVkFFT call. 1952 LUT are allocated per axis, though some of them can be reused if the axes 1953 have the same LUT. 1954 Inverse and forward FFT plans share the same LUT (conjugation is performed 1955 on-chip). 1956\end_layout 1957 1958\begin_layout Subsubsection 1959The Four-Step FFT algorithm - tempBuffer allocation 1960\end_layout 1961 1962\begin_layout Standard 1963To perform the merging of the transposition with the last upload of an axis, 1964 VkFFT requires additional memory to mimic an out-of-place execution. 1965 This memory is located in tempBuffer and has to be of at least the same 1966 size as the main buffer. 1967 It is possible for the users to allocate it themselves, though if this 1968 is not done, VkFFT can do the allocation automatically (the size of the 1969 tempBuffer will be the same as the main buffer, unless the logical dimensions 1970 of FFT are bigger than user-defined - then, it will allocate the system 1971 with the minimal size, that can cover maximal logical system size used 1972 in any of the axes - see next subsection). 1973\end_layout 1974 1975\begin_layout Subsubsection 1976Bluestein's buffers allocation 1977\end_layout 1978 1979\begin_layout Standard 1980To do Bluestein's FFT algorithm, precomputed sequences 1981\begin_inset Formula $b_{n}=e^{\pi i\frac{n^{2}}{N}}$ 1982\end_inset 1983 1984, 1985\begin_inset Formula $FFT(b_{n})$ 1986\end_inset 1987 1988 and 1989\begin_inset Formula $iFFT(b_{n})$ 1990\end_inset 1991 1992 are required. 1993 For each axis, they can be different and are computed separately (unless 1994 VkFFT can determine that they match, then the buffers are allocated only 1995 once). 1996 Notably, as Bluestein's algorithm pads the sequence length to at least 1997 1998\begin_inset Formula $2N-1$ 1999\end_inset 2000 2001, if it can not be done in a single upload and the Four Step algorithm has 2002 to be used, the intermediate storage required will be bigger than the main 2003 buffer size. 2004 In this case, tempBuffer must always be allocated. 2005 As the padded sequence can be different for each of the dimensions, the 2006 required size of the tempBuffer will also vary. 2007 VkFFT determines the biggest size needed among axes and allocated tempBuffer 2008 of this size. 2009\end_layout 2010 2011\begin_layout Subsection 2012VkFFT support for double-double emulation of quad precision 2013\end_layout 2014 2015\begin_layout Standard 2016Since VkFFT 1.3.2 experimental support for double-double emulation of quad 2017 precision has been added. 2018 Double-double number is defined as an unevaluated sum of two double numbers, 2019 second one being on the order of ~1 ULP of the first one (like 1 and 1e-16). 2020 This boosts the significand from 53 to 106 bits and leaves the exponent 2021 the same (11bits). 2022 For example, true quad precision would have 15 bits of exponent and 113 2023 bits significand. 2024 The range of double-double stays the same as in double precision (1e308 2025 vs 1e4932), while precision boosts from ~1e-16 to ~1e-32 (vs ~1e-34 of 2026 true quad precision). 2027 The double-double format of VkFFT is equivalent to __ibm128 type in gcc. 2028 VkFFT uses quadmath library to precompute twiddle factors and initialize 2029 kernels for double-double in the true quad precision. 2030 Currently, conversion between quad and double-double is only possible on 2031 CPU in true quad (GPU can only do operations on data in double-double format). 2032 This will be changed later. 2033\end_layout 2034 2035\begin_layout Standard 2036To enable double-double support, link against quadmath and set VkFFT_use_FP128_d 2037ouble_double compile flag to true. 2038\end_layout 2039 2040\begin_layout Standard 2041The performance impact is rather harsh - the code becomes compute-bound 2042 even on modern HPC clusters. 2043 The simple radix algorithms work well and are usable (~2x impact compared 2044 to double precision), while Bluestein and big primes Rader algorithms incur 2045 a high toll on operations count. 2046 This can be improved in the future, but probably not to the extent of being 2047 VRAM bandwidth-bound on modern accelerators. 2048\end_layout 2049 2050\begin_layout Standard 2051The main usage for the double-double precision should be mixed-precision 2052 calculations, where most of the time is spent in regular FP64 and only 2053 some parts that hit precision boundaries are calculated in double-double. 2054 For example, in VkFFT it is possible to perform a double precision FFT 2055 with all on-chip calculations done in double-double. 2056 This way the final errors should be on the scale of 1 ULP. 2057\end_layout 2058 2059\begin_layout Standard 2060 2061\end_layout 2062 2063\begin_layout Standard 2064\begin_inset Newpage newpage 2065\end_inset 2066 2067 2068\end_layout 2069 2070\begin_layout Section 2071Runtime code optimization platform 2072\begin_inset CommandInset label 2073LatexCommand label 2074name "sec:Modern-GPU-architecture." 2075 2076\end_inset 2077 2078 2079\end_layout 2080 2081\begin_layout Subsection 2082Platform for GPU code generation 2083\end_layout 2084 2085\begin_layout Standard 2086While GPUs show extraordinary performance, they are harder to program for 2087 compared to regular CPUs. 2088 Firstly, the algorithms must be optimized for SIMT (single instruction, 2089 multiple threads) execution, which is the soul of the GPU model. 2090 Secondly, rapid GPU development makes all vendor architectures (Nvidia, 2091 AMD, Intel) largely different. 2092 Below we will list some examples: 2093\end_layout 2094 2095\begin_layout Itemize 2096Shared memory size. 2097 If your code uses the full 64KB of shared memory on AMD MI250X, it won't 2098 be optimal on Nvidia H100 which has 256KB of it. 2099 The same goes for L2/L3 cache size. 2100\end_layout 2101 2102\begin_layout Itemize 2103Warp size. 2104 If your code uses 32 core warps (usual on Nvidia), it will not work or 2105 work inefficiently for 64 core warps of AMD CDNA. 2106\end_layout 2107 2108\begin_layout Itemize 2109Coalesced memory. 2110 For Nvidia and AMD we have to coalesce 32-byte memory requests, for Intel, 2111 it is equal to 64 bytes. 2112 Multiple of these requests are then combined into 128-byte transactions 2113 to the chip. 2114 However, this is a big simplification. 2115 There exist undocumented issues for Nvidia and AMD, when bandwidth drops 2116 when code tries to do distant, but coalesced memory accesses, i.e. 2117 data are still grouped in 32-byte transactions but target addresses with 2118 > 2^18 bytes between them (and the bigger the distance - the bigger the 2119 drop). 2120 The load-store unit (LSU) can not group 32-byte transactions. 2121 It is possible to regain full bandwidth by switching to 128-byte memory 2122 coalescing on Nvidia, while on AMD memory management follows different 2123 rules and these requests just happen to hit the same physical memory pin 2124 and thus be serialized. 2125 All this information is usually never shared by vendors, so programmers 2126 have to find solutions by trial and error. 2127\end_layout 2128 2129\begin_layout Itemize 2130Compute unit composition. 2131 Some compute units have special function units that can evaluate single 2132 precision sines and cosines in one cycle (AMD and Nvidia). 2133 On Intel GPUs, they are often imprecise. 2134 The ratio between FP32 and FP64 units also imposes limitations on the algorithm 2135 - compute units with low FP64 core count will benefit from data precomputation 2136 in the lookup tables more. 2137 Some compute units have tensor cores for accelerated matrix products. 2138\end_layout 2139 2140\begin_layout Itemize 2141There are many other nuanced differences (like the number of supported by 2142 hardware queues/streams, support for CUDA MPS execution model, register 2143 spilling control) which result in some complicated kernels being unpredictable 2144 in performance before you try. 2145 So having an option to tweak some of its parameters loosely related to 2146 hardware is a huge benefit. 2147 2148\end_layout 2149 2150\begin_layout Standard 2151This brings us to a big obstacle: all vendors have their own computing platforms. 2152 CUDA for Nvidia, HIP for AMD, Level Zero for Intel, Metal for Apple. 2153 To facilitate the development of code for all these different in details 2154 but similar in SIMD nature GPUs, I used all the knowledge obtained via 2155 numerous experiments with VkFFT to generalize GPU programming as much as 2156 possible - and create a unified platform for GPU code generation. 2157 2158\end_layout 2159 2160\begin_layout Subsection 2161Platform structure 2162\end_layout 2163 2164\begin_layout Standard 2165The project structure is split into four main parts: 2166\end_layout 2167 2168\begin_layout Itemize 2169Application manager. 2170 We use a container-based model of management - the user fills out the configura 2171tion struct and then initializes the application with only one initializer 2172 function. 2173 So this part of the platform performs initial configuration management, 2174 pass of the parameters to the corresponding to the particular subprogram 2175 plan initializer, binary load/store for future reuse and resources deallocation. 2176 Here we have application dispatch handlers, which abstract the actual applicati 2177on-dependent code dispatch handlers in the same way as we have one function 2178 for initialization. 2179\end_layout 2180 2181\begin_layout Itemize 2182Plan manager. 2183 After configuration propagation, the plan manager performs extensive configurat 2184ion of parameters for a particular task code generation. 2185 It also performs general API-dependent parameter initialization for supported 2186 backends. 2187 The plan manager also performs code compilation using supported by the 2188 target API runtime compiler (NVRTC by Nvidia CUDA, HIPRTC by AMD HIP, glslang 2189 by Vulkan, native OpenCL, clang and llvm-spirv for Intel Level Zero). 2190 It manages additional memory allocations and backend-specific memory management. 2191 Finally, it has plan-specific dispatch routines and a plan resource deallocatio 2192n manager. 2193\end_layout 2194 2195\begin_layout Itemize 2196Code manager. 2197 This part of the platform is solely responsible for GPU code generation. 2198 It takes a special input configuration structure created from user configuratio 2199n and API-derived parameters and produces a char array containing code to 2200 be executed. 2201 The code manager has a block structure that developers can use. 2202 This allows reusing parts of code between kernels. 2203 The block structure has the following designations: 2204\end_layout 2205 2206\begin_deeper 2207\begin_layout Itemize 2208Level 2 kernels: problem-specific kernels and layout configuration. 2209 These functions are called by the plan manager and they are intended to 2210 have a clear description of what is going on in the function. 2211 There is no pure code here - only calls to append lower-level functions 2212 code to the kernel code and additional inlining constants configuration 2213 that can be performed by the propagated from the plan manager information. 2214 This kernel also performs calls to additional kernel configuration routines 2215 like shared memory and register inlining inside a kernel and overall kernel 2216 decoration (like calls to inlining structure definitions, calls to kernel 2217 name inlining) - these routines are defined in lower kernels levels. 2218\end_layout 2219 2220\begin_layout Itemize 2221Level 1 kernels: less abstract simple routine kernels, like matrix-vector 2222 products, copy kernels, radix components of FFT, read/write managers. 2223 All of them must have a specified structure so they can be reused, for 2224 example, considering all input data to be in shared memory with a specific 2225 layout - then level 2 kernels will have a simple job of providing data 2226 to level 1 kernels in a specified manner and get the output in an also 2227 specified manner. 2228\end_layout 2229 2230\begin_layout Itemize 2231Level 0 kernels: memory management kernels. 2232 Here we have the absolute simplest kernel blocks, like memory data transfer 2233 request calls, synchronization, inlining of register/shared memory initializati 2234on code, etc. 2235 Many APIs have their own definitions for particular math operations, so 2236 we can define functions for inlining additions multiplications and other 2237 basic arithmetics here as well. 2238 The target of this level is to provide level 1 and 2 kernels with an easy 2239 way to reuse things that can be generalized between the widest range of 2240 math algorithms. 2241 2242\end_layout 2243 2244\begin_layout Standard 2245All of the different level kernels have full access to the target GPU hardware 2246 parameters - hence (depending on the quality of implemented kernels) it 2247 is possible to autotune the algorithm at run-time and simplify the compiler 2248 job as much as possible. 2249 This involves loop unrolling, constants inlining, etc. 2250 Having an additional level (level 1) dedicated to the simple algorithms 2251 allows for kernel merging. 2252 2253\end_layout 2254 2255\end_deeper 2256\begin_layout Itemize 2257Structs definitions. 2258 Here we define all structs used by the platform. 2259 It also contains some helper structs that can be used to manage GPU with 2260 different APIs and collect generated applications in a library struct for 2261 easier access through a map key (if the user's code uses many applications, 2262 this turns out to be extremely helpful). 2263\end_layout 2264 2265\begin_layout Subsection 2266Container abstractions 2267\end_layout 2268 2269\begin_layout Standard 2270The main design improvement that enables the platform functionality and 2271 greatly expands its usability are container abstractions. 2272 The code generator now operates on special data containers (implemented 2273 as C-unions), that can hold integer/float/complex numbers either as known 2274 during the plan creation values or as strings of variable names - no more 2275 sprintf calls with big chunks of unreadable code. 2276 2277\end_layout 2278 2279\begin_layout Standard 2280An example operation that uses containers is a MUL operation that performs 2281 a multiplication A equals B multiplied by C. 2282 If all containers have known values, A can be precomputed during plan creation. 2283 If A , B and C are, for example, register names, we print to the kernel 2284 an operation of multiplication. 2285 Each operation like MUL has its own representation for all supported APIs 2286 in the vkFFT_MathUtils.h file. 2287 An important distinction is that it is not a full compiler, but a simple 2288 tool that unifies syntaxis of different APIs and supports JIT optimizations. 2289 However, as the code manager outputs code that resembles binary, one of 2290 the future exploration possibilities it may be interesting to try to make 2291 level 0 and 1 kernels output assembly without additional compilation by 2292 the plan manager. 2293 2294\end_layout 2295 2296\begin_layout Standard 2297Usage of container abstractions brings exciting opportunities to code creation. 2298 Behaving as multi-API templates it will be possible to implement double-double 2299 FP128 mathematics support on GPU without modifying any of the already written 2300 algorithm code. 2301 Another big benefit is automatic type casting between precisions and option 2302 to perform precomputation in higher precision than the GPU code executes 2303 in. 2304 2305\end_layout 2306 2307\begin_layout Standard 2308I have also explored other ways to implement these container abstractions 2309 - including switching to C++ from C99 and using templates and operator 2310 overloading, however this turned out to be just a syntactic sugar, as if 2311 it did not reduce number of lines of code and did not increase readibility. 2312 So the code is still C with almost instant compilations as a bonus. 2313 All this is subject to change in the future if people present convincing 2314 arguments. 2315 2316\end_layout 2317 2318\begin_layout Standard 2319VkFFT supports two base number modes (used for all FP calculations on CPU) 2320 - long double or quad (__float128). 2321 The latter is needed to calculate the twiddle factors in double-double 2322 emulation of quad precision. 2323\end_layout 2324 2325\begin_layout Standard 2326\begin_inset Newpage newpage 2327\end_inset 2328 2329 2330\end_layout 2331 2332\begin_layout Section 2333VkFFT API Reference 2334\end_layout 2335 2336\begin_layout Standard 2337This section covers error codes, API functions that can be used by the user 2338 and configuration parameters. 2339\end_layout 2340 2341\begin_layout Subsection 2342Return value VkFFTResult 2343\end_layout 2344 2345\begin_layout Standard 2346All VkFFT Library return values except for VKFFT_SUCCESS are used in case 2347 of a failure and provide information on what has gone wrong. 2348 VkFFTResult is unified among different backends, though some of its values 2349 may not be used in specific backends. 2350 Possible return values of VkFFTResult are defined as following: 2351\end_layout 2352 2353\begin_layout Standard 2354\begin_inset ERT 2355status open 2356 2357\begin_layout Plain Layout 2358 2359 2360\backslash 2361begin{mdframed}[backgroundcolor=bg] 2362\end_layout 2363 2364\begin_layout Plain Layout 2365 2366 2367\backslash 2368begin{minted}[tabsize=4,obeytabs,breaklines]{C} 2369\end_layout 2370 2371\begin_layout Plain Layout 2372 2373typedef enum VkFFTResult { 2374\end_layout 2375 2376\begin_layout Plain Layout 2377 2378VKFFT_SUCCESS = 0, // The VkFFT operation was successful 2379\end_layout 2380 2381\begin_layout Plain Layout 2382 2383VKFFT_ERROR_MALLOC_FAILED = 1, // Some malloc call inside VkFFT has failed. 2384 Report this to the GitHub repo 2385\end_layout 2386 2387\begin_layout Plain Layout 2388 2389VKFFT_ERROR_INSUFFICIENT_CODE_BUFFER = 2, // Generated kernel is bigger 2390 than default kernel array. 2391 Increase it with maxCodeLength parameter of configuration. 2392\end_layout 2393 2394\begin_layout Plain Layout 2395 2396VKFFT_ERROR_INSUFFICIENT_TEMP_BUFFER = 3, // Temporary string used in kernel 2397 generation is bigger than default temporary string array. 2398 Increase it with maxTempLength parameter of configuration. 2399\end_layout 2400 2401\begin_layout Plain Layout 2402 2403VKFFT_ERROR_PLAN_NOT_INITIALIZED = 4, // Code attempts to use uninitialized 2404 plan (it is zero inside VkFFTApplication) 2405\end_layout 2406 2407\begin_layout Plain Layout 2408 2409VKFFT_ERROR_NULL_TEMP_PASSED = 5, // Internal kernel generation error 2410\end_layout 2411 2412\begin_layout Plain Layout 2413 2414VKFFT_ERROR_MATH_FAILED = 6, // Math instruction in code generator failed 2415 2416\end_layout 2417 2418\begin_layout Plain Layout 2419 2420VKFFT_ERROR_FFTdim_GT_MAX_FFT_DIMENSIONS = 7, // User specified a number 2421 of dimensions higher than the code is compiled to handle with VKFFT_MAX_FFT_DIM 2422ENSIONS 2423\end_layout 2424 2425\begin_layout Plain Layout 2426 2427VKFFT_ERROR_NONZERO_APP_INITIALIZATION = 8, // The app pointer is not pointing 2428 to the zero-filled memory block 2429\end_layout 2430 2431\begin_layout Plain Layout 2432 2433VKFFT_ERROR_INVALID_PHYSICAL_DEVICE = 1001, // No physical device is provided 2434 (Vulkan API) 2435\end_layout 2436 2437\begin_layout Plain Layout 2438 2439VKFFT_ERROR_INVALID_DEVICE = 1002, // No device is provided (All APIs) 2440\end_layout 2441 2442\begin_layout Plain Layout 2443 2444VKFFT_ERROR_INVALID_QUEUE = 1003, // No queue is provided (Vulkan API) 2445\end_layout 2446 2447\begin_layout Plain Layout 2448 2449VKFFT_ERROR_INVALID_COMMAND_POOL = 1004, // No command pool is provided 2450 (Vulkan API) 2451\end_layout 2452 2453\begin_layout Plain Layout 2454 2455VKFFT_ERROR_INVALID_FENCE = 1005, // No fence is provided (Vulkan API) 2456\end_layout 2457 2458\begin_layout Plain Layout 2459 2460VKFFT_ERROR_ONLY_FORWARD_FFT_INITIALIZED = 1006, // VkFFT tries to access 2461 inverse FFT plan, when appliction is created with makeForwardPlanOnly flag 2462\end_layout 2463 2464\begin_layout Plain Layout 2465 2466VKFFT_ERROR_ONLY_INVERSE_FFT_INITIALIZED = 1007, // VkFFT tries to access 2467 forward FFT plan, when appliction is created with makeInversePlanOnly flag 2468\end_layout 2469 2470\begin_layout Plain Layout 2471 2472VKFFT_ERROR_INVALID_CONTEXT = 1008, // No context is provided (OpenCL API) 2473\end_layout 2474 2475\begin_layout Plain Layout 2476 2477VKFFT_ERROR_INVALID_PLATFORM = 1009, // No platform is provided (OpenCL 2478 API) 2479\end_layout 2480 2481\begin_layout Plain Layout 2482 2483VKFFT_ERROR_EMPTY_FILE = 1011, 2484\end_layout 2485 2486\begin_layout Plain Layout 2487 2488VKFFT_ERROR_EMPTY_FFTdim = 2001, // Number of dimensions is not provided 2489 in the configuration 2490\end_layout 2491 2492\begin_layout Plain Layout 2493 2494VKFFT_ERROR_EMPTY_size = 2002, // Array of dimensions is not provided in 2495 the configuration 2496\end_layout 2497 2498\begin_layout Plain Layout 2499 2500VKFFT_ERROR_EMPTY_bufferSize = 2003, // Buffer size has to be provided during 2501 the application creation 2502\end_layout 2503 2504\begin_layout Plain Layout 2505 2506VKFFT_ERROR_EMPTY_buffer = 2004, // Buffer has te be specified either at 2507 the application creation stage or during launch through VkFFTLaunchParams 2508 struct 2509\end_layout 2510 2511\begin_layout Plain Layout 2512 2513VKFFT_ERROR_EMPTY_tempBufferSize = 2005, // Same error as VKFFT_ERROR_EMPTY_buff 2514erSize if userTempBuffer is enabled 2515\end_layout 2516 2517\begin_layout Plain Layout 2518 2519VKFFT_ERROR_EMPTY_tempBuffer = 2006, // Same error as VKFFT_ERROR_EMPTY_buffer 2520 if userTempBuffer is enabled 2521\end_layout 2522 2523\begin_layout Plain Layout 2524 2525VKFFT_ERROR_EMPTY_inputBufferSize = 2007, // Same error as VKFFT_ERROR_EMPTY_buf 2526ferSize if isInputFormatted is enabled 2527\end_layout 2528 2529\begin_layout Plain Layout 2530 2531VKFFT_ERROR_EMPTY_inputBuffer = 2008, // Same error as VKFFT_ERROR_EMPTY_buffer 2532 if isInputFormatted is enabled 2533\end_layout 2534 2535\begin_layout Plain Layout 2536 2537VKFFT_ERROR_EMPTY_outputBufferSize = 2009, // Same error as VKFFT_ERROR_EMPTY_bu 2538fferSize if isOutputFormatted is enabled 2539\end_layout 2540 2541\begin_layout Plain Layout 2542 2543VKFFT_ERROR_EMPTY_outputBuffer = 2010, // Same error as VKFFT_ERROR_EMPTY_buffer 2544 if isOutputFormatted is enabled 2545\end_layout 2546 2547\begin_layout Plain Layout 2548 2549VKFFT_ERROR_EMPTY_kernelSize = 2011, // Same error as VKFFT_ERROR_EMPTY_bufferSi 2550ze if performConvolution is enabled 2551\end_layout 2552 2553\begin_layout Plain Layout 2554 2555VKFFT_ERROR_EMPTY_kernel = 2012, // Same error as VKFFT_ERROR_EMPTY_buffer 2556 if performConvolution is enabled 2557\end_layout 2558 2559\begin_layout Plain Layout 2560 2561VKFFT_ERROR_EMPTY_applicationString = 2013, // loadApplicationString is 2562 zero when loadApplicationFromString is enabled 2563\end_layout 2564 2565\begin_layout Plain Layout 2566 2567VKFFT_ERROR_EMPRY_useCustomBluesteinPaddingPattern_arrays = 2014, // pointers 2568 to primeSizes or paddedSizes arrays are zero when useCustomBluesteinPaddingPatt 2569ern is enabled 2570\end_layout 2571 2572\begin_layout Plain Layout 2573 2574VKFFT_ERROR_EMPTY_app = 2015, // app pointer is zero 2575\end_layout 2576 2577\begin_layout Plain Layout 2578 2579VKFFT_ERROR_INVALID_user_tempBuffer_too_small = 2016, // user provided tempBuffe 2580r is not sufficient for VkFFT intermediate calculations 2581\end_layout 2582 2583\begin_layout Plain Layout 2584 2585VKFFT_ERROR_UNSUPPORTED_RADIX = 3001, // VkFFT has encountered unsupported 2586 radix (more than 13) during decomposition and Bluestein's FFT fallback 2587 did not work 2588\end_layout 2589 2590\begin_layout Plain Layout 2591 2592VKFFT_ERROR_UNSUPPORTED_FFT_LENGTH = 3002, // VkFFT can not do this sequence 2593 length currently - it requires mor than three-upload Four step FFT 2594\end_layout 2595 2596\begin_layout Plain Layout 2597 2598VKFFT_ERROR_UNSUPPORTED_FFT_LENGTH_R2C = 3003, // VkFFT can not do this 2599 sequence length currently - should no longer be thrown 2600\end_layout 2601 2602\begin_layout Plain Layout 2603 2604VKFFT_ERROR_UNSUPPORTED_FFT_LENGTH_R2R = 3004, // VkFFT can not do this 2605 sequence length currently - should no longer be thrown 2606\end_layout 2607 2608\begin_layout Plain Layout 2609 2610VKFFT_ERROR_UNSUPPORTED_FFT_OMIT = 3005, // VkFFT can not omit sequences 2611 in convolution calculations and R2C/C2R case 2612\end_layout 2613 2614\begin_layout Plain Layout 2615 2616VKFFT_ERROR_FAILED_TO_ALLOCATE = 4001, // VkFFT failed to allocate GPU memory 2617\end_layout 2618 2619\begin_layout Plain Layout 2620 2621VKFFT_ERROR_FAILED_TO_MAP_MEMORY = 4002, // 4002-4052 are handlers for errors 2622 of used backend APIs. 2623 They may indicate a driver failure. 2624 If they are thrown - report to the GitHub repo 2625\end_layout 2626 2627\begin_layout Plain Layout 2628 2629VKFFT_ERROR_FAILED_TO_ALLOCATE_COMMAND_BUFFERS = 4003, 2630\end_layout 2631 2632\begin_layout Plain Layout 2633 2634VKFFT_ERROR_FAILED_TO_BEGIN_COMMAND_BUFFER = 4004, 2635\end_layout 2636 2637\begin_layout Plain Layout 2638 2639VKFFT_ERROR_FAILED_TO_END_COMMAND_BUFFER = 4005, 2640\end_layout 2641 2642\begin_layout Plain Layout 2643 2644VKFFT_ERROR_FAILED_TO_SUBMIT_QUEUE = 4006, 2645\end_layout 2646 2647\begin_layout Plain Layout 2648 2649VKFFT_ERROR_FAILED_TO_WAIT_FOR_FENCES = 4007, 2650\end_layout 2651 2652\begin_layout Plain Layout 2653 2654VKFFT_ERROR_FAILED_TO_RESET_FENCES = 4008, 2655\end_layout 2656 2657\begin_layout Plain Layout 2658 2659VKFFT_ERROR_FAILED_TO_CREATE_DESCRIPTOR_POOL = 4009, 2660\end_layout 2661 2662\begin_layout Plain Layout 2663 2664VKFFT_ERROR_FAILED_TO_CREATE_DESCRIPTOR_SET_LAYOUT = 4010, 2665\end_layout 2666 2667\begin_layout Plain Layout 2668 2669VKFFT_ERROR_FAILED_TO_ALLOCATE_DESCRIPTOR_SETS = 4011, 2670\end_layout 2671 2672\begin_layout Plain Layout 2673 2674VKFFT_ERROR_FAILED_TO_CREATE_PIPELINE_LAYOUT = 4012, 2675\end_layout 2676 2677\begin_layout Plain Layout 2678 2679VKFFT_ERROR_FAILED_SHADER_PREPROCESS = 4013, 2680\end_layout 2681 2682\begin_layout Plain Layout 2683 2684VKFFT_ERROR_FAILED_SHADER_PARSE = 4014, 2685\end_layout 2686 2687\begin_layout Plain Layout 2688 2689VKFFT_ERROR_FAILED_SHADER_LINK = 4015, 2690\end_layout 2691 2692\begin_layout Plain Layout 2693 2694VKFFT_ERROR_FAILED_SPIRV_GENERATE = 4016, 2695\end_layout 2696 2697\begin_layout Plain Layout 2698 2699VKFFT_ERROR_FAILED_TO_CREATE_SHADER_MODULE = 4017, 2700\end_layout 2701 2702\begin_layout Plain Layout 2703 2704VKFFT_ERROR_FAILED_TO_CREATE_INSTANCE = 4018, 2705\end_layout 2706 2707\begin_layout Plain Layout 2708 2709VKFFT_ERROR_FAILED_TO_SETUP_DEBUG_MESSENGER = 4019, 2710\end_layout 2711 2712\begin_layout Plain Layout 2713 2714VKFFT_ERROR_FAILED_TO_FIND_PHYSICAL_DEVICE = 4020, 2715\end_layout 2716 2717\begin_layout Plain Layout 2718 2719VKFFT_ERROR_FAILED_TO_CREATE_DEVICE = 4021, 2720\end_layout 2721 2722\begin_layout Plain Layout 2723 2724VKFFT_ERROR_FAILED_TO_CREATE_FENCE = 4022, 2725\end_layout 2726 2727\begin_layout Plain Layout 2728 2729VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_POOL = 4023, 2730\end_layout 2731 2732\begin_layout Plain Layout 2733 2734VKFFT_ERROR_FAILED_TO_CREATE_BUFFER = 4024, 2735\end_layout 2736 2737\begin_layout Plain Layout 2738 2739VKFFT_ERROR_FAILED_TO_ALLOCATE_MEMORY = 4025, 2740\end_layout 2741 2742\begin_layout Plain Layout 2743 2744VKFFT_ERROR_FAILED_TO_BIND_BUFFER_MEMORY = 4026, 2745\end_layout 2746 2747\begin_layout Plain Layout 2748 2749VKFFT_ERROR_FAILED_TO_FIND_MEMORY = 4027, 2750\end_layout 2751 2752\begin_layout Plain Layout 2753 2754VKFFT_ERROR_FAILED_TO_SYNCHRONIZE = 4028, 2755\end_layout 2756 2757\begin_layout Plain Layout 2758 2759VKFFT_ERROR_FAILED_TO_COPY = 4029, 2760\end_layout 2761 2762\begin_layout Plain Layout 2763 2764VKFFT_ERROR_FAILED_TO_CREATE_PROGRAM = 4030, 2765\end_layout 2766 2767\begin_layout Plain Layout 2768 2769VKFFT_ERROR_FAILED_TO_COMPILE_PROGRAM = 4031, 2770\end_layout 2771 2772\begin_layout Plain Layout 2773 2774VKFFT_ERROR_FAILED_TO_GET_CODE_SIZE = 4032, 2775\end_layout 2776 2777\begin_layout Plain Layout 2778 2779VKFFT_ERROR_FAILED_TO_GET_CODE = 4033, 2780\end_layout 2781 2782\begin_layout Plain Layout 2783 2784VKFFT_ERROR_FAILED_TO_DESTROY_PROGRAM = 4034, 2785\end_layout 2786 2787\begin_layout Plain Layout 2788 2789VKFFT_ERROR_FAILED_TO_LOAD_MODULE = 4035, 2790\end_layout 2791 2792\begin_layout Plain Layout 2793 2794VKFFT_ERROR_FAILED_TO_GET_FUNCTION = 4036, 2795\end_layout 2796 2797\begin_layout Plain Layout 2798 2799VKFFT_ERROR_FAILED_TO_SET_DYNAMIC_SHARED_MEMORY = 4037, 2800\end_layout 2801 2802\begin_layout Plain Layout 2803 2804VKFFT_ERROR_FAILED_TO_MODULE_GET_GLOBAL = 4038, 2805\end_layout 2806 2807\begin_layout Plain Layout 2808 2809VKFFT_ERROR_FAILED_TO_LAUNCH_KERNEL = 4039, 2810\end_layout 2811 2812\begin_layout Plain Layout 2813 2814VKFFT_ERROR_FAILED_TO_EVENT_RECORD = 4040, 2815\end_layout 2816 2817\begin_layout Plain Layout 2818 2819VKFFT_ERROR_FAILED_TO_ADD_NAME_EXPRESSION = 4041, 2820\end_layout 2821 2822\begin_layout Plain Layout 2823 2824VKFFT_ERROR_FAILED_TO_INITIALIZE = 4042, 2825\end_layout 2826 2827\begin_layout Plain Layout 2828 2829VKFFT_ERROR_FAILED_TO_SET_DEVICE_ID = 4043, 2830\end_layout 2831 2832\begin_layout Plain Layout 2833 2834VKFFT_ERROR_FAILED_TO_GET_DEVICE = 4044, 2835\end_layout 2836 2837\begin_layout Plain Layout 2838 2839VKFFT_ERROR_FAILED_TO_CREATE_CONTEXT = 4045, 2840\end_layout 2841 2842\begin_layout Plain Layout 2843 2844VKFFT_ERROR_FAILED_TO_CREATE_PIPELINE = 4046, 2845\end_layout 2846 2847\begin_layout Plain Layout 2848 2849VKFFT_ERROR_FAILED_TO_SET_KERNEL_ARG = 4047, 2850\end_layout 2851 2852\begin_layout Plain Layout 2853 2854VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_QUEUE = 4048, 2855\end_layout 2856 2857\begin_layout Plain Layout 2858 2859VKFFT_ERROR_FAILED_TO_RELEASE_COMMAND_QUEUE = 4049, 2860\end_layout 2861 2862\begin_layout Plain Layout 2863 2864VKFFT_ERROR_FAILED_TO_ENUMERATE_DEVICES = 4050, 2865\end_layout 2866 2867\begin_layout Plain Layout 2868 2869VKFFT_ERROR_FAILED_TO_GET_ATTRIBUTE = 4051, 2870\end_layout 2871 2872\begin_layout Plain Layout 2873 2874VKFFT_ERROR_FAILED_TO_CREATE_EVENT = 4052, 2875\end_layout 2876 2877\begin_layout Plain Layout 2878 2879VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_LIST = 4053, 2880\end_layout 2881 2882\begin_layout Plain Layout 2883 2884VKFFT_ERROR_FAILED_TO_DESTROY_COMMAND_LIST = 4054, 2885\end_layout 2886 2887\begin_layout Plain Layout 2888 2889VKFFT_ERROR_FAILED_TO_SUBMIT_BARRIER = 4055 2890\end_layout 2891 2892\begin_layout Plain Layout 2893 2894} VkFFTResult; 2895\end_layout 2896 2897\begin_layout Plain Layout 2898 2899 2900\backslash 2901end{minted} 2902\end_layout 2903 2904\begin_layout Plain Layout 2905 2906 2907\backslash 2908end{mdframed} 2909\end_layout 2910 2911\end_inset 2912 2913 2914\end_layout 2915 2916\begin_layout Subsection 2917VkFFT application management functions 2918\end_layout 2919 2920\begin_layout Standard 2921VkFFT has a unified plan management model - all different transform types/ 2922 dimensionalities/ precision use the same calls with configuration done 2923 through VkFFTConfiguration struct. 2924 This section shows how to initialize/use/free VkFFT with this unified model, 2925 while the next one will go into how to configure VkFFTConfiguration correctly. 2926 All of the functions operate on VkFFTApplication and VkFFTConfiguration 2927 assuming they have been zero-initialized before usage, so do not forget 2928 to do this when initializing (otherwise VkFFT will throw an error): 2929\end_layout 2930 2931\begin_layout Standard 2932\begin_inset ERT 2933status open 2934 2935\begin_layout Plain Layout 2936 2937 2938\backslash 2939begin{mdframed}[backgroundcolor=bg] 2940\end_layout 2941 2942\begin_layout Plain Layout 2943 2944 2945\backslash 2946begin{minted}[tabsize=4,obeytabs,breaklines]{C} 2947\end_layout 2948 2949\begin_layout Plain Layout 2950 2951VkFFTConfiguration configuration = {}; 2952\end_layout 2953 2954\begin_layout Plain Layout 2955 2956VkFFTApplication app = {}; 2957\end_layout 2958 2959\begin_layout Plain Layout 2960 2961 2962\backslash 2963end{minted} 2964\end_layout 2965 2966\begin_layout Plain Layout 2967 2968 2969\backslash 2970end{mdframed} 2971\end_layout 2972 2973\end_inset 2974 2975 2976\end_layout 2977 2978\begin_layout Subsubsection 2979Function initializeVkFFT() 2980\end_layout 2981 2982\begin_layout Standard 2983\begin_inset ERT 2984status open 2985 2986\begin_layout Plain Layout 2987 2988 2989\backslash 2990begin{mdframed}[backgroundcolor=bg] 2991\end_layout 2992 2993\begin_layout Plain Layout 2994 2995 2996\backslash 2997begin{minted}[tabsize=4,obeytabs,breaklines]{C} 2998\end_layout 2999 3000\begin_layout Plain Layout 3001 3002VkFFTResult initializeVkFFT(VkFFTApplication* app, VkFFTConfiguration inputLaunc 3003hConfiguration) 3004\end_layout 3005 3006\begin_layout Plain Layout 3007 3008 3009\backslash 3010end{minted} 3011\end_layout 3012 3013\begin_layout Plain Layout 3014 3015 3016\backslash 3017end{mdframed} 3018\end_layout 3019 3020\end_inset 3021 3022 3023\end_layout 3024 3025\begin_layout Standard 3026Creates an FFT application (collection of forward and inverse plans). 3027 As forward and inverse FFTs may have different memory layouts, can have 3028 different normalizations - they are done as separate internal plans inside 3029 VkFFTApplication. 3030 This call assumes the application to be zero-initialized, so can be only 3031 done once on a particular application, until it is deleted. 3032\end_layout 3033 3034\begin_layout Standard 3035If the initializeVkFFT call fails, it frees all allocated by VkFFT CPU/GPU 3036 resources and sets the application to zero. 3037 VkFFTResult is returned with an error code corresponding to what went wrong. 3038\end_layout 3039 3040\begin_layout Standard 3041In case of success, VkFFTApplication will contain initialized plans with 3042 compiled kernels ready for execution with VKFFT_SUCCESS returned. 3043\end_layout 3044 3045\begin_layout Subsubsection 3046Function VkFFTAppend() 3047\end_layout 3048 3049\begin_layout Standard 3050\begin_inset ERT 3051status open 3052 3053\begin_layout Plain Layout 3054 3055 3056\backslash 3057begin{mdframed}[backgroundcolor=bg] 3058\end_layout 3059 3060\begin_layout Plain Layout 3061 3062 3063\backslash 3064begin{minted}[tabsize=4,obeytabs,breaklines]{C} 3065\end_layout 3066 3067\begin_layout Plain Layout 3068 3069VkFFTResult VkFFTAppend(VkFFTApplication* app, int inverse, VkFFTLaunchParams* 3070 launchParams) 3071\end_layout 3072 3073\begin_layout Plain Layout 3074 3075 3076\backslash 3077end{minted} 3078\end_layout 3079 3080\begin_layout Plain Layout 3081 3082 3083\backslash 3084end{mdframed} 3085\end_layout 3086 3087\end_inset 3088 3089 3090\end_layout 3091 3092\begin_layout Standard 3093Performs FFT in the int inverse direction (-1 for forward FFT, 1 for inverse 3094 FFT). 3095 FFT plans are selected from the VkFFTApplication collection automatically. 3096 VkFFTApplication must be initialized with initializeVkFFT call before. 3097 VkFFTLaunchParams struct allows for pre-launch configuration of some parameters 3098, namely: 3099\end_layout 3100 3101\begin_layout Itemize 3102buffer - similar to how FFTW/cuFFT expects input/output data pointers in 3103 *execC2C (and other) function calls, VkFFT allows specifying memory used 3104 for computations at launch. 3105 It must have the same size/layout/strides as defined during the application 3106 creation. 3107\end_layout 3108 3109\begin_layout Itemize 3110inputBuffer/outputBuffer/tempBuffer/kernel - other buffers can also be specified 3111 at launch. 3112 In addition to them having the same size/layout/strides as defined during 3113 the application creation, the application must be created with flags enabling 3114 the corresponding buffer usage: isInputFormatted/isOutputFormatted/userTempBuff 3115er/performConvolution respectively. 3116\end_layout 3117 3118\begin_layout Itemize 3119bufferOffset/tempBufferOffset/inputBufferOffset/outputBufferOffset/kernelOffset 3120 - specify if VkFFT has to offset the first element position inside the 3121 corresponding buffer. 3122 In bytes. 3123 Default 0. 3124 specifyOffsetsAtLaunch parameter must be enabled during the initializeVkFFT 3125 call before. 3126 3127\end_layout 3128 3129\begin_layout Standard 3130Depending on the API, the execution model may vary and require additional 3131 information at launch: 3132\end_layout 3133 3134\begin_layout Itemize 3135Vulkan API: VkFFT appends a sequence of vkCmdDispatch calls to the user-defined 3136 VkCommandBuffer (with respective push constants/descriptor sets/pipelines/memor 3137y barriers bindings). 3138 VkCommandBuffer must be provided as a pointer in VkFFTLaunchParams. 3139 VkCommandBuffer must be in the writing stage, started with vkBeginCommandBuffer 3140 call. 3141 After VkFFTAppend has finished, provided VkCommandBuffer will contain a 3142 sequence of operations performing FFT. 3143 The first call of the sequence has no input memory barrier, the last call 3144 has one, ensuring FFT has finished execution. 3145\end_layout 3146 3147\begin_layout Itemize 3148CUDA/HIP API: if the user wants to use streams, they have to be provided 3149 during the application configuration stage. 3150 VkFFTAppend performs a series of cuLaunchKernel, which are sequential if 3151 appended to one stream and synchronized if appended to multiple streams. 3152\end_layout 3153 3154\begin_layout Itemize 3155OpenCL API: similar to Vulkan, VkFFT appends a sequence of clEnqueueNDRangeKerne 3156l calls to user-defined cl_command_queue. 3157 Currently, they are all assumed to be sequential. 3158 cl_command_queue must be provided as a pointer in VkFFTLaunchParams. 3159 3160\end_layout 3161 3162\begin_layout Itemize 3163Level Zero API: similar to Vulkan, VkFFT appends a sequence of zeCommandListAppe 3164ndLaunchKernel calls to user-defined command list ze_command_list_handle_t. 3165 They have execution barriers between. 3166 ze_command_list_handle_t must be provided as a pointer in VkFFTLaunchParams. 3167 3168\end_layout 3169 3170\begin_layout Itemize 3171Metal API: similar to Vulkan, VkFFT appends a sequence of dispatchThreads 3172 calls to user-defined command encoder MTL::ComputeCommandEncoder. 3173 MTL::ComputeCommandEncoder and its MTL::CommandBuffer must be provided 3174 as a pointer in VkFFTLaunchParams. 3175 3176\end_layout 3177 3178\begin_layout Standard 3179If VkFFT fails during the VkFFTAppend call, it will not free the application 3180 and allocated there resources - use a separate call for that. 3181\end_layout 3182 3183\begin_layout Subsubsection 3184Function deleteVkFFT() 3185\end_layout 3186 3187\begin_layout Standard 3188\begin_inset ERT 3189status open 3190 3191\begin_layout Plain Layout 3192 3193 3194\backslash 3195begin{mdframed}[backgroundcolor=bg] 3196\end_layout 3197 3198\begin_layout Plain Layout 3199 3200 3201\backslash 3202begin{minted}[tabsize=4,obeytabs,breaklines]{C} 3203\end_layout 3204 3205\begin_layout Plain Layout 3206 3207void deleteVkFFT(VkFFTApplication* app) 3208\end_layout 3209 3210\begin_layout Plain Layout 3211 3212 3213\backslash 3214end{minted} 3215\end_layout 3216 3217\begin_layout Plain Layout 3218 3219 3220\backslash 3221end{mdframed} 3222\end_layout 3223 3224\end_inset 3225 3226 3227\end_layout 3228 3229\begin_layout Standard 3230Performs deallocation of resources used in the provided application. 3231 Returns application to the zero-initialized state. 3232\end_layout 3233 3234\begin_layout Subsubsection 3235Function VkFFTGetVersion() 3236\end_layout 3237 3238\begin_layout Standard 3239\begin_inset ERT 3240status open 3241 3242\begin_layout Plain Layout 3243 3244 3245\backslash 3246begin{mdframed}[backgroundcolor=bg] 3247\end_layout 3248 3249\begin_layout Plain Layout 3250 3251 3252\backslash 3253begin{minted}[tabsize=4,obeytabs,breaklines]{C} 3254\end_layout 3255 3256\begin_layout Plain Layout 3257 3258int VkFFTGetVersion() 3259\end_layout 3260 3261\begin_layout Plain Layout 3262 3263 3264\backslash 3265end{minted} 3266\end_layout 3267 3268\begin_layout Plain Layout 3269 3270 3271\backslash 3272end{mdframed} 3273\end_layout 3274 3275\end_inset 3276 3277 3278\end_layout 3279 3280\begin_layout Standard 3281Returns the version of the VkFFT library in the X.XX.XX format (without dots). 3282\end_layout 3283 3284\begin_layout Subsection 3285VkFFT configuration 3286\end_layout 3287 3288\begin_layout Standard 3289This section will cover all the parameters that can be specified in the 3290 VkFFTConfiguration struct. 3291 It will start with a short description of the struct (intended to be used 3292 as a cheat sheet), then go for each field in detail. 3293 Here pfUINT and pfINT are defined as uint64_t and int64_t respectively. 3294\end_layout 3295 3296\begin_layout Standard 3297\begin_inset ERT 3298status open 3299 3300\begin_layout Plain Layout 3301 3302 3303\backslash 3304begin{mdframed}[backgroundcolor=bg] 3305\end_layout 3306 3307\begin_layout Plain Layout 3308 3309 3310\backslash 3311begin{minted}[tabsize=4,obeytabs,breaklines]{C} 3312\end_layout 3313 3314\begin_layout Plain Layout 3315 3316typedef struct { 3317\end_layout 3318 3319\begin_layout Plain Layout 3320 3321// Required parameters: 3322\end_layout 3323 3324\begin_layout Plain Layout 3325 3326pfUINT FFTdim; // FFT dimensionality (1, 2 or 3) 3327\end_layout 3328 3329\begin_layout Plain Layout 3330 3331pfUINT size[VKFFT_MAX_FFT_DIMENSIONS]; // WHD+ - system dimensions 3332\end_layout 3333 3334\begin_layout Plain Layout 3335 3336#if(VKFFT_BACKEND==0) //Vulkan API 3337\end_layout 3338 3339\begin_layout Plain Layout 3340 3341VkPhysicalDevice* physicalDevice; // Pointer to Vulkan physical device, 3342 obtained from vkEnumeratePhysicalDevices 3343\end_layout 3344 3345\begin_layout Plain Layout 3346 3347VkDevice* device; // Pointer to Vulkan device, created with vkCreateDevice 3348\end_layout 3349 3350\begin_layout Plain Layout 3351 3352VkQueue* queue; // Pointer to Vulkan queue, created with vkGetDeviceQueue 3353\end_layout 3354 3355\begin_layout Plain Layout 3356 3357VkCommandPool* commandPool; // Pointer to Vulkan command pool, created with 3358 vkCreateCommandPool 3359\end_layout 3360 3361\begin_layout Plain Layout 3362 3363VkFence* fence; // Pointer to Vulkan fence, created with vkCreateFence 3364\end_layout 3365 3366\begin_layout Plain Layout 3367 3368pfUINT isCompilerInitialized; // Specify if glslang compiler has been intialized 3369 before (0 - off, 1 - on). 3370 Default 0 3371\end_layout 3372 3373\begin_layout Plain Layout 3374 3375#elif(VKFFT_BACKEND==1) //CUDA API 3376\end_layout 3377 3378\begin_layout Plain Layout 3379 3380CUdevice* device; // Pointer to CUDA device, obtained from cuDeviceGet 3381\end_layout 3382 3383\begin_layout Plain Layout 3384 3385cudaStream_t* stream; // Pointer to streams (can be more than 1), where 3386 to execute the kernels. 3387 Deafult 0 3388\end_layout 3389 3390\begin_layout Plain Layout 3391 3392pfUINT num_streams; // Try to submit CUDA kernels in multiple streams for 3393 asynchronous execution. 3394 Default 0, set to >=1 if you pass values in the stream pointer. 3395 3396\end_layout 3397 3398\begin_layout Plain Layout 3399 3400#elif(VKFFT_BACKEND==2) //HIP API 3401\end_layout 3402 3403\begin_layout Plain Layout 3404 3405hipDevice_t* device; // Pointer to HIP device, obtained from hipDeviceGet 3406\end_layout 3407 3408\begin_layout Plain Layout 3409 3410hipStream_t* stream; // Pointer to streams (can be more than 1), where to 3411 execute the kernels. 3412 Deafult 0 3413\end_layout 3414 3415\begin_layout Plain Layout 3416 3417pfUINT num_streams; // Try to submit HIP kernels in multiple streams for 3418 asynchronous execution. 3419 Default 0, set to >=1 if you pass values in the stream pointer. 3420\end_layout 3421 3422\begin_layout Plain Layout 3423 3424#elif(VKFFT_BACKEND==3) //OpenCL API 3425\end_layout 3426 3427\begin_layout Plain Layout 3428 3429cl_platform_id* platform; // NOT REQUIRED 3430\end_layout 3431 3432\begin_layout Plain Layout 3433 3434cl_device_id* device; // Pointer to OpenCL device, obtained from clGetDeviceIDs 3435\end_layout 3436 3437\begin_layout Plain Layout 3438 3439cl_context* context; // Pointer to OpenCL context, obtained from clCreateContext 3440\end_layout 3441 3442\begin_layout Plain Layout 3443 3444#elif(VKFFT_BACKEND==4) //Level Zero API 3445\end_layout 3446 3447\begin_layout Plain Layout 3448 3449ze_device_handle_t* device; // Pointer to Level Zero device, obtained from 3450 zeDeviceGet 3451\end_layout 3452 3453\begin_layout Plain Layout 3454 3455ze_context_handle_t* context; // Pointer to Level Zero context, obtained 3456 from zeContextCreate 3457\end_layout 3458 3459\begin_layout Plain Layout 3460 3461ze_command_queue_handle_t* commandQueue; // Pointer to Level Zero command 3462 queue with compute and copy capabilities, obtained from zeCommandQueueCreate 3463\end_layout 3464 3465\begin_layout Plain Layout 3466 3467uint32_t commandQueueID; // ID of the commandQueue with compute and copy 3468 capabilities 3469\end_layout 3470 3471\begin_layout Plain Layout 3472 3473#elif(VKFFT_BACKEND==5) 3474\end_layout 3475 3476\begin_layout Plain Layout 3477 3478MTL::Device* device; // Pointer to Metal device, obtained from MTL::CopyAllDevic 3479es 3480\end_layout 3481 3482\begin_layout Plain Layout 3483 3484MTL::CommandQueue* queue; // Pointer to Metal queue, obtained from device->newCo 3485mmandQueue() 3486\end_layout 3487 3488\begin_layout Plain Layout 3489 3490#endif 3491\end_layout 3492 3493\begin_layout Plain Layout 3494 3495\end_layout 3496 3497\begin_layout Plain Layout 3498 3499// Data parameters (buffers can be specified at launch): 3500\end_layout 3501 3502\begin_layout Plain Layout 3503 3504pfUINT userTempBuffer; // Buffer allocated by app automatically if needed 3505 to reorder Four step algorithm. 3506 Setting to non zero value enables manual user allocation (0 - off, 1 - 3507 on) 3508\end_layout 3509 3510\begin_layout Plain Layout 3511 3512pfUINT bufferNum; // Multiple buffer sequence storage is Vulkan only. 3513 Default 1 3514\end_layout 3515 3516\begin_layout Plain Layout 3517 3518pfUINT tempBufferNum; // Multiple buffer sequence storage is Vulkan only. 3519 Default 1, buffer allocated by app automatically if needed to reorder Four 3520 step algorithm. 3521 Setting to non zero value enables manual user allocation 3522\end_layout 3523 3524\begin_layout Plain Layout 3525 3526pfUINT inputBufferNum; // Multiple buffer sequence storage is Vulkan only. 3527 Default 1, if isInputFormatted is enabled 3528\end_layout 3529 3530\begin_layout Plain Layout 3531 3532pfUINT outputBufferNum; // Multiple buffer sequence storage is Vulkan only. 3533 Default 1, if isOutputFormatted is enabled 3534\end_layout 3535 3536\begin_layout Plain Layout 3537 3538pfUINT kernelNum; // Multiple buffer sequence storage is Vulkan only. 3539 Default 1, if performConvolution is enabled 3540\end_layout 3541 3542\begin_layout Plain Layout 3543 3544pfUINT* bufferSize; // Array of buffers sizes in bytes 3545\end_layout 3546 3547\begin_layout Plain Layout 3548 3549pfUINT* tempBufferSize; // Array of temp buffers sizes in bytes. 3550 Default set to bufferSize sum, buffer allocated by app automatically if 3551 needed to reorder Four step algorithm. 3552 Setting to non zero value enables manual user allocation 3553\end_layout 3554 3555\begin_layout Plain Layout 3556 3557pfUINT* inputBufferSize; // Array of input buffers sizes in bytes, if isInputFor 3558matted is enabled 3559\end_layout 3560 3561\begin_layout Plain Layout 3562 3563pfUINT* outputBufferSize; // Array of output buffers sizes in bytes, if 3564 isOutputFormatted is enabled 3565\end_layout 3566 3567\begin_layout Plain Layout 3568 3569pfUINT* kernelSize; // Array of kernel buffers sizes in bytes, if performConvolu 3570tion is enabled 3571\end_layout 3572 3573\begin_layout Plain Layout 3574 3575#if(VKFFT_BACKEND==0) //Vulkan API 3576\end_layout 3577 3578\begin_layout Plain Layout 3579 3580VkBuffer* buffer; // Pointer to array of buffers (or one buffer) used for 3581 computations 3582\end_layout 3583 3584\begin_layout Plain Layout 3585 3586VkBuffer* tempBuffer; // Needed if reorderFourStep is enabled to transpose 3587 the array. 3588 Same sum size or bigger as buffer (can be split in multiple). 3589 Default 0. 3590 Setting to non zero value enables manual user allocation 3591\end_layout 3592 3593\begin_layout Plain Layout 3594 3595VkBuffer* inputBuffer; // Pointer to array of input buffers (or one buffer) 3596 used to read data from if isInputFormatted is enabled 3597\end_layout 3598 3599\begin_layout Plain Layout 3600 3601VkBuffer* outputBuffer; // Pointer to array of output buffers (or one buffer) 3602 used to write data to if isOutputFormatted is enabled 3603\end_layout 3604 3605\begin_layout Plain Layout 3606 3607VkBuffer* kernel; // Pointer to array of kernel buffers (or one buffer) 3608 used to read kernel data from if performConvolution is enabled 3609\end_layout 3610 3611\begin_layout Plain Layout 3612 3613#elif(VKFFT_BACKEND==1) //CUDA API 3614\end_layout 3615 3616\begin_layout Plain Layout 3617 3618void** buffer; // Pointer to device buffer used for computations 3619\end_layout 3620 3621\begin_layout Plain Layout 3622 3623void** tempBuffer; // Needed if reorderFourStep is enabled to transpose 3624 the array. 3625 Same size as buffer. 3626 Default 0. 3627 Setting to non zero value enables manual user allocation 3628\end_layout 3629 3630\begin_layout Plain Layout 3631 3632void** inputBuffer; // Pointer to device buffer used to read data from if 3633 isInputFormatted is enabled 3634\end_layout 3635 3636\begin_layout Plain Layout 3637 3638void** outputBuffer; // Pointer to device buffer used to write data to if 3639 isOutputFormatted is enabled 3640\end_layout 3641 3642\begin_layout Plain Layout 3643 3644void** kernel; // Pointer to device buffer used to read kernel data from 3645 if performConvolution is enabled 3646\end_layout 3647 3648\begin_layout Plain Layout 3649 3650#elif(VKFFT_BACKEND==2) //HIP API 3651\end_layout 3652 3653\begin_layout Plain Layout 3654 3655void** buffer; // Pointer to device buffer used for computations 3656\end_layout 3657 3658\begin_layout Plain Layout 3659 3660void** tempBuffer; // Needed if reorderFourStep is enabled to transpose 3661 the array. 3662 Same size as buffer. 3663 Default 0. 3664 Setting to non zero value enables manual user allocation 3665\end_layout 3666 3667\begin_layout Plain Layout 3668 3669void** inputBuffer; // Pointer to device buffer used to read data from if 3670 isInputFormatted is enabled 3671\end_layout 3672 3673\begin_layout Plain Layout 3674 3675void** outputBuffer; // Pointer to device buffer used to write data to if 3676 isOutputFormatted is enabled 3677\end_layout 3678 3679\begin_layout Plain Layout 3680 3681void** kernel; // Pointer to device buffer used to read kernel data from 3682 if performConvolution is enabled 3683\end_layout 3684 3685\begin_layout Plain Layout 3686 3687#elif(VKFFT_BACKEND==3) //OpenCL API 3688\end_layout 3689 3690\begin_layout Plain Layout 3691 3692cl_mem* buffer; // Pointer to device buffer used for computations 3693\end_layout 3694 3695\begin_layout Plain Layout 3696 3697cl_mem* tempBuffer; // Needed if reorderFourStep is enabled to transpose 3698 the array. 3699 Same size as buffer. 3700 Default 0. 3701 Setting to non zero value enables manual user allocation 3702\end_layout 3703 3704\begin_layout Plain Layout 3705 3706cl_mem* inputBuffer; // Pointer to device buffer used to read data from 3707 if isInputFormatted is enabled 3708\end_layout 3709 3710\begin_layout Plain Layout 3711 3712cl_mem* outputBuffer; // Pointer to device buffer used to write data to 3713 if isOutputFormatted is enabled 3714\end_layout 3715 3716\begin_layout Plain Layout 3717 3718cl_mem* kernel; // Pointer to device buffer used to read kernel data from 3719 if performConvolution is enabled 3720\end_layout 3721 3722\begin_layout Plain Layout 3723 3724#elif(VKFFT_BACKEND==4) 3725\end_layout 3726 3727\begin_layout Plain Layout 3728 3729void** buffer; // Pointer to device buffer used for computations 3730\end_layout 3731 3732\begin_layout Plain Layout 3733 3734void** tempBuffer; // Needed if reorderFourStep is enabled to transpose 3735 the array. 3736 Same size as buffer. 3737 Default 0. 3738 Setting to non zero value enables manual user allocation 3739\end_layout 3740 3741\begin_layout Plain Layout 3742 3743void** inputBuffer; // Pointer to device buffer used to read data from if 3744 isInputFormatted is enabled 3745\end_layout 3746 3747\begin_layout Plain Layout 3748 3749void** outputBuffer; // Pointer to device buffer used to read data from 3750 if isOutputFormatted is enabled 3751\end_layout 3752 3753\begin_layout Plain Layout 3754 3755void** kernel; // Pointer to device buffer used to read kernel data from 3756 if performConvolution is enabled 3757\end_layout 3758 3759\begin_layout Plain Layout 3760 3761#elif(VKFFT_BACKEND==5) 3762\end_layout 3763 3764\begin_layout Plain Layout 3765 3766MTL::Buffer** buffer; // Pointer to device buffer used for computations 3767\end_layout 3768 3769\begin_layout Plain Layout 3770 3771MTL::Buffer** tempBuffer; // Needed if reorderFourStep is enabled to transpose 3772 the array. 3773 Same size as buffer. 3774 Default 0. 3775 Setting to non zero value enables manual user allocation 3776\end_layout 3777 3778\begin_layout Plain Layout 3779 3780MTL::Buffer** inputBuffer; // Pointer to device buffer used to read data 3781 from if isInputFormatted is enabled 3782\end_layout 3783 3784\begin_layout Plain Layout 3785 3786MTL::Buffer** outputBuffer; // Pointer to device buffer used to read data 3787 from if isOutputFormatted is enabled 3788\end_layout 3789 3790\begin_layout Plain Layout 3791 3792MTL::Buffer** kernel; // Pointer to device buffer used to read kernel data 3793 from if performConvolution is enabled 3794\end_layout 3795 3796\begin_layout Plain Layout 3797 3798#endif 3799\end_layout 3800 3801\begin_layout Plain Layout 3802 3803pfUINT bufferOffset; // Specify if VkFFT has to offset the first element 3804 position inside the buffer. 3805 In bytes. 3806 Default 0 3807\end_layout 3808 3809\begin_layout Plain Layout 3810 3811pfUINT tempBufferOffset; // Specify if VkFFT has to offset the first element 3812 position inside the temp buffer. 3813 In bytes. 3814 Default 0 3815\end_layout 3816 3817\begin_layout Plain Layout 3818 3819pfUINT inputBufferOffset; // Specify if VkFFT has to offset the first element 3820 position inside the input buffer. 3821 In bytes. 3822 Default 0 3823\end_layout 3824 3825\begin_layout Plain Layout 3826 3827pfUINT outputBufferOffset; // Specify if VkFFT has to offset the first element 3828 position inside the output buffer. 3829 In bytes. 3830 Default 0 3831\end_layout 3832 3833\begin_layout Plain Layout 3834 3835pfUINT kernelOffset; // Specify if VkFFT has to offset the first element 3836 position inside the kernel. 3837 In bytes. 3838 Default 0 3839\end_layout 3840 3841\begin_layout Plain Layout 3842 3843pfUINT specifyOffsetsAtLaunch; // Specify if offsets will be selected with 3844 launch parameters VkFFTLaunchParams (0 - off, 1 - on). 3845 Default 0 3846\end_layout 3847 3848\begin_layout Plain Layout 3849 3850\end_layout 3851 3852\begin_layout Plain Layout 3853 3854// Optional: (default 0 if not stated otherwise) 3855\end_layout 3856 3857\begin_layout Plain Layout 3858 3859pfUINT coalescedMemory; // In bytes, for Nvidia and AMD is equal to 32, 3860 Intel is equal 64, scaled for half precision. 3861 Going to work regardless, but if specified by user correctly, the performance 3862 will be higher. 3863\end_layout 3864 3865\begin_layout Plain Layout 3866 3867pfUINT aimThreads; // Aim at this many threads per block. 3868 Default 128 3869\end_layout 3870 3871\begin_layout Plain Layout 3872 3873pfUINT numSharedBanks; // How many banks shared memory has. 3874 Default 32 3875\end_layout 3876 3877\begin_layout Plain Layout 3878 3879pfUINT inverseReturnToInputBuffer; // return data to the input buffer in 3880 inverse transform (0 - off, 1 - on). 3881 isInputFormatted must be enabled 3882\end_layout 3883 3884\begin_layout Plain Layout 3885 3886pfUINT numberBatches; // N - used to perform multiple batches of initial 3887 data. 3888 Default 1 3889\end_layout 3890 3891\begin_layout Plain Layout 3892 3893pfUINT useUint64; // Use 64-bit addressing mode in generated kernels 3894\end_layout 3895 3896\begin_layout Plain Layout 3897 3898pfUINT omitDimension[VKFFT_MAX_FFT_DIMENSIONS]; // Disable FFT for this 3899 dimension (0 - FFT enabled, 1 - FFT disabled). 3900 Default 0. 3901 Doesn't work for R2C first axis for now. 3902 Doesn't work with convolutions. 3903\end_layout 3904 3905\begin_layout Plain Layout 3906 3907int performBandwidthBoost; // Try to reduce coalsesced number by a factor 3908 of X to get bigger sequence in one upload for strided axes. 3909 Default: -1 for DCT/DST, 2 for Bluestein's algorithm (or -1 if DCT/DST), 3910 0 otherwise 3911\end_layout 3912 3913\begin_layout Plain Layout 3914 3915\end_layout 3916 3917\begin_layout Plain Layout 3918 3919pfUINT doublePrecision; // Perform calculations in double precision (0 - 3920 off, 1 - on). 3921\end_layout 3922 3923\begin_layout Plain Layout 3924 3925pfUINT quadDoubleDoublePrecision; // Perform calculations in double-double 3926 emulation of quad precision (0 - off, 1 - on). 3927\end_layout 3928 3929\begin_layout Plain Layout 3930 3931pfUINT quadDoubleDoublePrecisionDoubleMemory; // Perform calculations in 3932 double-double emulation of quad precision, while all memory storage is 3933 done in FP64. 3934\end_layout 3935 3936\begin_layout Plain Layout 3937 3938pfUINT halfPrecision; // Perform calculations in half precision (0 - off, 3939 1 - on) 3940\end_layout 3941 3942\begin_layout Plain Layout 3943 3944pfUINT halfPrecisionMemoryOnly; // Use half precision only as input/output 3945 buffer. 3946 Input/Output have to be allocated as half, buffer/tempBuffer have to be 3947 allocated as float (out-of-place mode only). 3948 Specify isInputFormatted and isOutputFormatted to use (0 - off, 1 - on) 3949\end_layout 3950 3951\begin_layout Plain Layout 3952 3953pfUINT doublePrecisionFloatMemory; // Use FP64 precision for all calculations, 3954 while all memory storage is done in FP32. 3955\end_layout 3956 3957\begin_layout Plain Layout 3958 3959\end_layout 3960 3961\begin_layout Plain Layout 3962 3963pfUINT performR2C; // Perform R2C/C2R decomposition (0 - off, 1 - on) 3964\end_layout 3965 3966\begin_layout Plain Layout 3967 3968pfUINT performDCT; // Perform DCT transformation (X - DCT type, 1-4) 3969\end_layout 3970 3971\begin_layout Plain Layout 3972 3973pfUINT performDST; // Perform DST transformation (X - DST type, 1-4) 3974\end_layout 3975 3976\begin_layout Plain Layout 3977 3978pfUINT disableMergeSequencesR2C; // Disable merging of two real sequences 3979 to reduce calculations (0 - off, 1 - on) 3980\end_layout 3981 3982\begin_layout Plain Layout 3983 3984pfUINT forceCallbackVersionRealTransforms; // Force callback version of 3985 R2C and R2R algorithms for all usecases (0 - off, 1 - on) 3986\end_layout 3987 3988\begin_layout Plain Layout 3989 3990\end_layout 3991 3992\begin_layout Plain Layout 3993 3994pfUINT normalize; // Normalize inverse transform (0 - off, 1 - on) 3995\end_layout 3996 3997\begin_layout Plain Layout 3998 3999pfUINT disableReorderFourStep; // Disables unshuffling of Four step algorithm. 4000 Requires tempbuffer allocation (0 - off, 1 - on) 4001\end_layout 4002 4003\begin_layout Plain Layout 4004 4005pfINT useLUT; // Switches from calculating sincos to using precomputed LUT 4006 tables (0 - off, 1 - on). 4007 Configured by initialization routine 4008\end_layout 4009 4010\begin_layout Plain Layout 4011 4012pfINT useLUT_4step; // Switches from calculating sincos to using precomputed 4013 LUT tables for intermediate roots of 1 in the Four-step FFT algorithm. 4014 (-1 - off, 0 - auto, 1 - on). 4015 Configured by initialization routine 4016\end_layout 4017 4018\begin_layout Plain Layout 4019 4020pfUINT makeForwardPlanOnly; // Generate code only for forward FFT (0 - off, 4021 1 - on) 4022\end_layout 4023 4024\begin_layout Plain Layout 4025 4026pfUINT makeInversePlanOnly; // Generate code only for inverse FFT (0 - off, 4027 1 - on) 4028\end_layout 4029 4030\begin_layout Plain Layout 4031 4032pfUINT bufferStride[VKFFT_MAX_FFT_DIMENSIONS]; // Buffer strides - default 4033 set to x - x*y - x*y*z values 4034\end_layout 4035 4036\begin_layout Plain Layout 4037 4038pfUINT isInputFormatted; // Specify if input buffer is padded - 0 - padded, 4039 1 - not padded. 4040 For example if it is not padded for R2C if out-of-place mode is selected 4041 (only if numberBatches==1 and numberKernels==1) 4042\end_layout 4043 4044\begin_layout Plain Layout 4045 4046pfUINT isOutputFormatted; // Specify if output buffer is padded - 0 - padded, 4047 1 - not padded. 4048 For example if it is not padded for R2C if out-of-place mode is selected 4049 (only if numberBatches==1 and numberKernels==1) 4050\end_layout 4051 4052\begin_layout Plain Layout 4053 4054pfUINT inputBufferStride[VKFFT_MAX_FFT_DIMENSIONS]; // Input buffer strides. 4055 Used if isInputFormatted is enabled. 4056 Default set to bufferStride values 4057\end_layout 4058 4059\begin_layout Plain Layout 4060 4061pfUINT outputBufferStride[VKFFT_MAX_FFT_DIMENSIONS]; // Output buffer strides. 4062 Used if isInputFormatted is enabled. 4063 Default set to bufferStride values 4064\end_layout 4065 4066\begin_layout Plain Layout 4067 4068pfUINT swapTo2Stage4Step; // Specify at which number to switch from 1 upload 4069 to 2 upload 4-step FFT, in case if making max sequence size lower than 4070 coalesced sequence helps to combat TLB misses. 4071 Default 0 - disabled. 4072 4073\end_layout 4074 4075\begin_layout Plain Layout 4076 4077pfUINT swapTo3Stage4Step; // Specify at which power of 2 to switch from 4078 2 upload to 3 upload 4-step FFT, in case if making max sequence size lower 4079 than coalesced sequence helps to combat TLB misses. 4080 Default 0 - disabled. 4081 Must be at least 17 4082\end_layout 4083 4084\begin_layout Plain Layout 4085 4086pfUINT considerAllAxesStrided; // Will create plan for non-strided axis 4087 similar as a strided axis - used with disableReorderFourStep to get the 4088 same layout for Bluestein kernel (0 - off, 1 - on) 4089\end_layout 4090 4091\begin_layout Plain Layout 4092 4093\end_layout 4094 4095\begin_layout Plain Layout 4096 4097pfUINT keepShaderCode; // Will keep shader code and print all executed shaders 4098 during the plan execution in order (0 - off, 1 - on) 4099\end_layout 4100 4101\begin_layout Plain Layout 4102 4103pfUINT printMemoryLayout; // Will print order of buffers used in shaders 4104 (0 - off, 1 - on) 4105\end_layout 4106 4107\begin_layout Plain Layout 4108 4109\end_layout 4110 4111\begin_layout Plain Layout 4112 4113pfUINT saveApplicationToString; // Will save all compiled binaries to VkFFTAppli 4114cation.saveApplicationString (will be allocated by VkFFT, deallocated with 4115 deleteVkFFT call). 4116 VkFFTApplication.applicationStringSize will contain size of binary in bytes. 4117 Currently disabled in Metal backend. 4118 (0 - off, 1 - on) 4119\end_layout 4120 4121\begin_layout Plain Layout 4122 4123pfUINT loadApplicationFromString; // Will load all binaries from loadApplication 4124String instead of recompiling them (must be allocated by user, must contain 4125 what saveApplicationToString call generated previously in VkFFTApplication.saveA 4126pplicationString). 4127 Currently disabled in Metal backend. 4128 (0 - off, 1 - on). 4129 Mutually exclusive with saveApplicationToString 4130\end_layout 4131 4132\begin_layout Plain Layout 4133 4134void* loadApplicationString; // Memory binary array through which user can 4135 load VkFFT binaries, must be provided by user if loadApplicationFromString 4136 = 1. 4137 Use rb/wb flags to load/save. 4138\end_layout 4139 4140\begin_layout Plain Layout 4141 4142\end_layout 4143 4144\begin_layout Plain Layout 4145 4146pfUINT disableSetLocale; // disables all VkFFT attempts to set locale to 4147 C - user must ensure that VkFFT has C locale during the plan initialization. 4148 This option is needed for multithreading. 4149 Default 0. 4150 4151\end_layout 4152 4153\begin_layout Plain Layout 4154 4155\end_layout 4156 4157\begin_layout Plain Layout 4158 4159// Optional Bluestein optimizations: (default 0 if not stated otherwise) 4160\end_layout 4161 4162\begin_layout Plain Layout 4163 4164pfUINT fixMaxRadixBluestein; // controls the padding of sequences in Bluestein 4165 convolution. 4166 If specified, padded sequence will be made of up to fixMaxRadixBluestein 4167 primes. 4168 Default: 2 for CUDA and Vulkan/OpenCL/HIP up to 1048576 combined dimension 4169 FFT system, 7 for Vulkan/OpenCL/HIP past after. 4170 Min = 2, Max = 13. 4171\end_layout 4172 4173\begin_layout Plain Layout 4174 4175pfUINT forceBluesteinSequenceSize; // force the sequence size to pad to 4176 in Bluestein's algorithm. 4177 Must be at least 2*N-1 and decomposable with primes 2-13. 4178\end_layout 4179 4180\begin_layout Plain Layout 4181 4182pfUINT useCustomBluesteinPaddingPattern; // force the sequence sizes to 4183 pad to in Bluestein's algorithm, but on a range. 4184 This number specifies the number of elements in primeSizes and in paddedSizes 4185 arrays. 4186 primeSizes - array of non-decomposable as radix scheme sizes - 17, 23, 4187 31 etc. 4188 paddedSizes - array of lengths to pad to. 4189 paddedSizes[i] will be the padding size for all non-decomposable sequences 4190 from primeSizes[i] to primeSizes[i+1] (will use default scheme after last 4191 one) - 42, 60, 64 for primeSizes before and 37+ will use default scheme 4192 (for example). 4193 Default is vendor and API-based specified in autoCustomBluesteinPaddingPattern. 4194\end_layout 4195 4196\begin_layout Plain Layout 4197 4198pfUINT* primeSizes; // described in useCustomBluesteinPaddingPattern 4199\end_layout 4200 4201\begin_layout Plain Layout 4202 4203pfUINT* paddedSizes; // described in useCustomBluesteinPaddingPattern 4204\end_layout 4205 4206\begin_layout Plain Layout 4207 4208\end_layout 4209 4210\begin_layout Plain Layout 4211 4212pfUINT fixMinRaderPrimeMult; // start direct multiplication Rader's algorithm 4213 for radix primes from this number. 4214 This means that VkFFT will inline custom Rader kernels if sequence is divisible 4215 by these primes. 4216 Default is 17, as VkFFT has kernels for 2-13. 4217 If you make it less than 13, VkFFT will switch from these kernels to Rader. 4218\end_layout 4219 4220\begin_layout Plain Layout 4221 4222pfUINT fixMaxRaderPrimeMult; // switch from Mult Rader's algorithm for radix 4223 primes from this number. 4224 Current limitation for Rader is maxThreadNum/2+1, realistically you would 4225 want to switch somewhere on 30-100 range. 4226 Default is vendor-specific (currently ~40) 4227\end_layout 4228 4229\begin_layout Plain Layout 4230 4231\end_layout 4232 4233\begin_layout Plain Layout 4234 4235pfUINT fixMinRaderPrimeFFT; // start FFT convolution version of Rader for 4236 radix primes from this number. 4237 Better than direct multiplication version for almost all primes (except 4238 small ones, like 17-23 on some GPUs). 4239 Must be bigger or equal to fixMinRaderPrimeMult. 4240 Deafult 29 on AMD and 17 on other GPUs. 4241 4242\end_layout 4243 4244\begin_layout Plain Layout 4245 4246pfUINT fixMaxRaderPrimeFFT; // switch to Bluestein's algorithm for radix 4247 primes from this number. 4248 Switch may happen earlier if prime can't fit in shared memory. 4249 Default is 16384, which is bigger than most current GPU's shared memory. 4250\end_layout 4251 4252\begin_layout Plain Layout 4253 4254\end_layout 4255 4256\begin_layout Plain Layout 4257 4258// Optional zero padding control parameters: (default 0 if not stated otherwise) 4259\end_layout 4260 4261\begin_layout Plain Layout 4262 4263pfUINT performZeropadding[VKFFT_MAX_FFT_DIMENSIONS]; // Don't read some 4264 data/perform computations if some input sequences are zeropadded for each 4265 axis (0 - off, 1 - on) 4266\end_layout 4267 4268\begin_layout Plain Layout 4269 4270pfUINT fft_zeropad_left[VKFFT_MAX_FFT_DIMENSIONS]; // Specify start boundary 4271 of zero block in the system for each axis 4272\end_layout 4273 4274\begin_layout Plain Layout 4275 4276pfUINT fft_zeropad_right[VKFFT_MAX_FFT_DIMENSIONS]; // Specify end boundary 4277 of zero block in the system for each axis 4278\end_layout 4279 4280\begin_layout Plain Layout 4281 4282pfUINT frequencyZeroPadding; // Set to 1 if zeropadding of frequency domain, 4283 default 0 - spatial zeropadding 4284\end_layout 4285 4286\begin_layout Plain Layout 4287 4288\end_layout 4289 4290\begin_layout Plain Layout 4291 4292// Optional convolution control parameters: (default 0 if not stated otherwise) 4293\end_layout 4294 4295\begin_layout Plain Layout 4296 4297pfUINT performConvolution; // Perform convolution in this application (0 4298 - off, 1 - on). 4299 Disables reorderFourStep parameter 4300\end_layout 4301 4302\begin_layout Plain Layout 4303 4304pfUINT coordinateFeatures; // C - coordinate, or dimension of features vector. 4305 In matrix convolution - size of a vector 4306\end_layout 4307 4308\begin_layout Plain Layout 4309 4310pfUINT matrixConvolution; // If equal to 2 perform 2x2, if equal to 3 perform 4311 3x3 matrix-vector convolution. 4312 Overrides coordinateFeatures 4313\end_layout 4314 4315\begin_layout Plain Layout 4316 4317pfUINT symmetricKernel; // Specify if kernel in 2x2 or 3x3 matrix convolution 4318 is symmetric 4319\end_layout 4320 4321\begin_layout Plain Layout 4322 4323pfUINT numberKernels; // N - only used in convolution step - specify how 4324 many kernels were initialized before. 4325 Expands one input to multiple (batched) output 4326\end_layout 4327 4328\begin_layout Plain Layout 4329 4330pfUINT kernelConvolution; // Specify if this application is used to create 4331 kernel for convolution, so it has the same properties. 4332 performConvolution has to be set to 0 for kernel creation 4333\end_layout 4334 4335\begin_layout Plain Layout 4336 4337\end_layout 4338 4339\begin_layout Plain Layout 4340 4341// Register overutilization (experimental): (default 0 if not stated otherwise) 4342\end_layout 4343 4344\begin_layout Plain Layout 4345 4346pfUINT registerBoost; // Specify if register file size is bigger than shared 4347 memory and can be used to extend it X times (on Nvidia 256KB register file 4348 can be used instead of 32KB of shared memory, set this constant to 4 to 4349 emulate 128KB of shared memory). 4350 Defaults: Nvidia - 4 in Vulkan/OpenCL, 1 in CUDA backend; AMD - 2 if shared 4351 memory >= 64KB, else 4 in Vulkan/OpenCL backend, 1 in HIP backend; Intel 4352 - 1 if shared memory >= 64KB, else 2 in Vulkan/OpenCL/Level Zero backends, 4353 1 in Metal; Default 1 4354\end_layout 4355 4356\begin_layout Plain Layout 4357 4358pfUINT registerBoostNonPow2; // Specify if register overutilization should 4359 be used on non power of 2 sequences (0 - off, 1 - on) 4360\end_layout 4361 4362\begin_layout Plain Layout 4363 4364pfUINT registerBoost4Step; // Specify if register file overutilization should 4365 be used in big sequences (>2^14), same definition as registerBoost. 4366 Default 1 4367\end_layout 4368 4369\begin_layout Plain Layout 4370 4371\end_layout 4372 4373\begin_layout Plain Layout 4374 4375//not used techniques: 4376\end_layout 4377 4378\begin_layout Plain Layout 4379 4380pfUINT devicePageSize; // In KB, the size of a page on the GPU. 4381 Setting to 0 disables local buffer split in pages 4382\end_layout 4383 4384\begin_layout Plain Layout 4385 4386pfUINT localPageSize; // In KB, the size to split page into if sequence 4387 spans multiple devicePageSize pages 4388\end_layout 4389 4390\begin_layout Plain Layout 4391 4392\end_layout 4393 4394\begin_layout Plain Layout 4395 4396// Automatically filled based on device info (still can be reconfigured 4397 by user): 4398\end_layout 4399 4400\begin_layout Plain Layout 4401 4402pfUINT computeCapabilityMajor; // CUDA/HIP compute capability of the device 4403\end_layout 4404 4405\begin_layout Plain Layout 4406 4407pfUINT computeCapabilityMinor; // CUDA/HIP compute capability of the device 4408 4409\end_layout 4410 4411\begin_layout Plain Layout 4412 4413pfUINT maxComputeWorkGroupCount[VKFFT_MAX_FFT_DIMENSIONS]; // maxComputeWorkGrou 4414pCount from VkPhysicalDeviceLimits 4415\end_layout 4416 4417\begin_layout Plain Layout 4418 4419pfUINT maxComputeWorkGroupSize[VKFFT_MAX_FFT_DIMENSIONS]; // maxComputeWorkGroup 4420Count from VkPhysicalDeviceLimits 4421\end_layout 4422 4423\begin_layout Plain Layout 4424 4425pfUINT maxThreadsNum; // Max number of threads from VkPhysicalDeviceLimits 4426\end_layout 4427 4428\begin_layout Plain Layout 4429 4430pfUINT sharedMemorySizeStatic; // Available for static allocation shared 4431 memory size, in bytes 4432\end_layout 4433 4434\begin_layout Plain Layout 4435 4436pfUINT sharedMemorySize; // Available for allocation shared memory size, 4437 in bytes 4438\end_layout 4439 4440\begin_layout Plain Layout 4441 4442pfUINT sharedMemorySizePow2; // Power of 2 which is less or equal to sharedMemor 4443ySize, in bytes 4444\end_layout 4445 4446\begin_layout Plain Layout 4447 4448pfUINT warpSize; // Number of threads per warp/wavefront. 4449\end_layout 4450 4451\begin_layout Plain Layout 4452 4453pfUINT halfThreads; // Intel fix 4454\end_layout 4455 4456\begin_layout Plain Layout 4457 4458pfUINT allocateTempBuffer; // Buffer allocated by app automatically if needed 4459 to reorder Four step algorithm. 4460 Parameter to check if it has been allocated 4461\end_layout 4462 4463\begin_layout Plain Layout 4464 4465pfUINT reorderFourStep; // Unshuffle Four step algorithm. 4466 Requires tempbuffer allocation (0 - off, 1 - on). 4467 Default 1. 4468\end_layout 4469 4470\begin_layout Plain Layout 4471 4472pfINT maxCodeLength; // Specify how big can be buffer used for code generation 4473 (in char). 4474 Default 1000000 chars. 4475 4476\end_layout 4477 4478\begin_layout Plain Layout 4479 4480pfINT maxTempLength; // Specify how big can be buffer used for intermediate 4481 string sprintfs be (in char). 4482 Default 5000 chars. 4483 If code segfaults for some reason - try increasing this number. 4484\end_layout 4485 4486\begin_layout Plain Layout 4487 4488pfUINT autoCustomBluesteinPaddingPattern; // default value for useCustomBluestei 4489nPaddingPattern 4490\end_layout 4491 4492\begin_layout Plain Layout 4493 4494pfUINT useRaderUintLUT; // allocate additional LUT to store g_pow 4495\end_layout 4496 4497\begin_layout Plain Layout 4498 4499pfUINT vendorID; // vendorID 0x10DE - NVIDIA, 0x8086 - Intel, 0x1002 - AMD, 4500 etc 4501\end_layout 4502 4503\begin_layout Plain Layout 4504 4505#if(VKFFT_BACKEND==0) //Vulkan API 4506\end_layout 4507 4508\begin_layout Plain Layout 4509 4510VkDeviceMemory tempBufferDeviceMemory; // Filled at app creation 4511\end_layout 4512 4513\begin_layout Plain Layout 4514 4515VkCommandBuffer* commandBuffer; // Filled at app execution 4516\end_layout 4517 4518\begin_layout Plain Layout 4519 4520VkMemoryBarrier* memory_barrier; // Filled at app creation 4521\end_layout 4522 4523\begin_layout Plain Layout 4524 4525#elif(VKFFT_BACKEND==1) //CUDA API 4526\end_layout 4527 4528\begin_layout Plain Layout 4529 4530cudaEvent_t* stream_event; // Filled at app creation 4531\end_layout 4532 4533\begin_layout Plain Layout 4534 4535pfUINT streamCounter; // Filled at app creation 4536\end_layout 4537 4538\begin_layout Plain Layout 4539 4540pfUINT streamID; // Filled at app creation 4541\end_layout 4542 4543\begin_layout Plain Layout 4544 4545#elif(VKFFT_BACKEND==2) //HIP API 4546\end_layout 4547 4548\begin_layout Plain Layout 4549 4550hipEvent_t* stream_event; // Filled at app creation 4551\end_layout 4552 4553\begin_layout Plain Layout 4554 4555pfUINT streamCounter; // Filled at app creation 4556\end_layout 4557 4558\begin_layout Plain Layout 4559 4560pfUINT streamID; // Filled at app creation 4561\end_layout 4562 4563\begin_layout Plain Layout 4564 4565#elif(VKFFT_BACKEND==3) //OpenCL API 4566\end_layout 4567 4568\begin_layout Plain Layout 4569 4570cl_command_queue* commandQueue; // Filled at app creation 4571\end_layout 4572 4573\begin_layout Plain Layout 4574 4575#elif(VKFFT_BACKEND==4) 4576\end_layout 4577 4578\begin_layout Plain Layout 4579 4580ze_command_list_handle_t* commandList; // Filled at app creation 4581\end_layout 4582 4583\begin_layout Plain Layout 4584 4585#elif(VKFFT_BACKEND==5) 4586\end_layout 4587 4588\begin_layout Plain Layout 4589 4590MTL::CommandBuffer* commandBuffer; // Filled at app execution 4591\end_layout 4592 4593\begin_layout Plain Layout 4594 4595MTL::ComputeCommandEncoder* commandEncoder; // Filled at app execution 4596\end_layout 4597 4598\begin_layout Plain Layout 4599 4600#endif 4601\end_layout 4602 4603\begin_layout Plain Layout 4604 4605} VkFFTConfiguration; 4606\end_layout 4607 4608\begin_layout Plain Layout 4609 4610 4611\backslash 4612end{minted} 4613\end_layout 4614 4615\begin_layout Plain Layout 4616 4617 4618\backslash 4619end{mdframed} 4620\end_layout 4621 4622\end_inset 4623 4624 4625\end_layout 4626 4627\begin_layout Subsubsection 4628Driver API parameters 4629\end_layout 4630 4631\begin_layout Standard 4632In order to work, VkFFT needs some structures that are provided by the driver. 4633 They are backend API-dependent. 4634 VkFFT will return corresponding VkFFTResult if one of these structures 4635 are not provided (value equal to zero) unless it is stated that there is 4636 a default value assigned. 4637 VkFFT will not modify provided values directly. 4638\end_layout 4639 4640\begin_layout Standard 4641Vulkan API will need the following information: 4642\end_layout 4643 4644\begin_layout Itemize 4645VkPhysicalDevice* physicalDevice - Pointer to Vulkan physical device, obtained 4646 from vkEnumeratePhysicalDevices() 4647\end_layout 4648 4649\begin_layout Itemize 4650VkDevice* device - Pointer to Vulkan device, created with vkCreateDevice() 4651\end_layout 4652 4653\begin_layout Itemize 4654VkQueue* queue - Pointer to Vulkan queue, created with vkGetDeviceQueue() 4655\end_layout 4656 4657\begin_layout Itemize 4658VkCommandPool* commandPool - Pointer to Vulkan command pool, created with 4659 vkCreateCommandPool() 4660\end_layout 4661 4662\begin_layout Itemize 4663VkFence* fence - Pointer to Vulkan fence, created with vkCreateFence() 4664\end_layout 4665 4666\begin_layout Itemize 4667uint64_t isCompilerInitialized - Specify if glslang compiler has been intialized 4668 before (0 - off, 1 - on). 4669 Default 0 - VkFFT will call glslang_initialize_process() at initializeVkFFT() 4670 and glslang_finialize_process() at deleteVkFFT() calls. 4671\end_layout 4672 4673\begin_layout Standard 4674CUDA API will need the following information: 4675\end_layout 4676 4677\begin_layout Itemize 4678CUdevice* device - Pointer to CUDA device, obtained from cuDeviceGet() 4679\end_layout 4680 4681\begin_layout Itemize 4682cudaStream_t* stream - Pointer to streams (can be more than 1), where to 4683 execute the kernels. 4684 Default 0. 4685 Streams must be associated with the provided device. 4686 There is no real benefit in having more than one, however. 4687 4688\end_layout 4689 4690\begin_layout Itemize 4691uint64_t num_streams - Try to submit CUDA kernels in multiple streams for 4692 asynchronous execution. 4693 Default 0, set to >=1 if you pass values in the stream pointer. 4694 4695\end_layout 4696 4697\begin_layout Standard 4698HIP API will need the following information: 4699\end_layout 4700 4701\begin_layout Itemize 4702hipDevice_t* device - Pointer to HIP device, obtained from hipDeviceGet() 4703\end_layout 4704 4705\begin_layout Itemize 4706hipStream_t* stream - Pointer to streams (can be more than 1), where to 4707 execute the kernels. 4708 Default 0. 4709 Streams must be associated with the provided device. 4710 There is no real benefit in having more than one, however. 4711 4712\end_layout 4713 4714\begin_layout Itemize 4715uint64_t num_streams - Try to submit HIP kernels in multiple streams for 4716 asynchronous execution. 4717 Default 0, set to >=1 if you pass values in the stream pointer. 4718 4719\end_layout 4720 4721\begin_layout Standard 4722OpenCL API will need the following information: 4723\end_layout 4724 4725\begin_layout Itemize 4726cl_device_id* device - Pointer to OpenCL device, obtained from clGetDeviceIDs() 4727\end_layout 4728 4729\begin_layout Itemize 4730cl_context* context - Pointer to OpenCL context, obtained from clCreateContext() 4731\end_layout 4732 4733\begin_layout Standard 4734Level Zero API will need the following information: 4735\end_layout 4736 4737\begin_layout Itemize 4738ze_device_handle_t* device - Pointer to Level Zero device, obtained from 4739 zeDeviceGet() 4740\end_layout 4741 4742\begin_layout Itemize 4743ze_context_handle_t* context - Pointer to Level Zero context, obtained from 4744 zeContextGet() 4745\end_layout 4746 4747\begin_layout Itemize 4748ze_command_queue_handle_t* commandQueue - Pointer to Level Zero command 4749 queuewith compute and copy capabilities, obtained from zeCommandQueueCreate() 4750\end_layout 4751 4752\begin_layout Itemize 4753uint32_t commandQueueID - ID of the commandQueue with compute and copy capabilit 4754ies 4755\end_layout 4756 4757\begin_layout Standard 4758Metal API will need the following information: 4759\end_layout 4760 4761\begin_layout Itemize 4762MTL::Device* device - Pointer to Metal device, obtained from MTL::CopyAllDevices 4763\end_layout 4764 4765\begin_layout Itemize 4766MTL::CommandQueue* queue - Pointer to Metal queue, obtained from device->newComm 4767andQueue() 4768\end_layout 4769 4770\begin_layout Subsubsection 4771Memory management parameters 4772\end_layout 4773 4774\begin_layout Standard 4775There are five buffer types user can provide to VkFFT: 4776\end_layout 4777 4778\begin_layout Itemize 4779the main buffer (buffer) 4780\end_layout 4781 4782\begin_layout Itemize 4783temporary buffer used for calculations requiring out-of-place writes (tempBuffer 4784) 4785\end_layout 4786 4787\begin_layout Itemize 4788separate input buffer, from which initial read is performed (inputBuffer) 4789\end_layout 4790 4791\begin_layout Itemize 4792separate output buffer, to which final write is performed (outputBuffer) 4793\end_layout 4794 4795\begin_layout Itemize 4796kernel buffer, used for calculation of convolutions and cross-correlations 4797 (kernel) 4798\end_layout 4799 4800\begin_layout Standard 4801These buffers must be passed by a pointer: in Vulkan API they are provided 4802 as VkBuffer*, in CUDA, HIP and Level Zero they are provided as void**, 4803 in OpenCL they are provided as cl_mem*, in Metal they are provided as MTL::Buff 4804er*. 4805 Even though the underlying structure (VkBuffer, void*, cl_mem, MTL::Buffer*) 4806 is not a memory but just a number that the driver can use to access correspondi 4807ng allocated memory on the GPU, passing them by a pointer allows for the 4808 user to query multiple GPU allocated buffers for VkFFT to use. 4809 Currently, it is only supported in Vulkan API - each of five buffer types 4810 can be made out of multiple separate memory allocations. 4811 For example, it is possible to combine multiple small unused at the point 4812 of FFT calculation buffers to form a tempBuffer. 4813 This option also allows Vulkan API to overcome the limit of 4GB for a single 4814 memory allocation - due to the fact that Vulkan can only use 32-bit numbers 4815 for addressing (other APIs support 64-bit addressing). 4816 4817\end_layout 4818 4819\begin_layout Standard 4820To use the buffers other than the main buffer, the user has to specify this 4821 in configuration at the application creation stage (set to zero by default, 4822 optional parameters): 4823\end_layout 4824 4825\begin_layout Itemize 4826uint64_t userTempBuffer - enables manual temporary buffer allocation (otherwise 4827 it is managed by VkFFT) 4828\end_layout 4829 4830\begin_layout Itemize 4831uint64_t isInputFormatted - specifies that initial read is performed from 4832 a separate buffer (inputBuffer) 4833\end_layout 4834 4835\begin_layout Itemize 4836uint64_t isOutputFormatted - specifies that final write is performed to 4837 a separate buffer (outputBuffer) 4838\end_layout 4839 4840\begin_layout Itemize 4841uint64_t performConvolution - enables convolution calculations, which requires 4842 precomputed kernel (kernel) 4843\end_layout 4844 4845\begin_layout Standard 4846Buffer sizes (bufferSize/tempBufferSize/inputBufferSize/outputBufferSize/kernelS 4847ize) are provided as a uint64_t pointer to an array, where each element 4848 corresponds to the buffer size of the buffer with the same placement in 4849 the buffer array. 4850 Buffer sizes have to be provided in Vulkan API (due to the stricter memory 4851 management model and multiple buffer support) and are optional in other 4852 backends (they can be useful to determine when to switch for 64-bit addressing). 4853\end_layout 4854 4855\begin_layout Standard 4856Buffer number (bufferNum/tempBufferNum/inputBufferNum/outputBufferNum/kernelNum) 4857 corresponds to how many elements are in the buffer and buffer size array. 4858 By default it is set to 1 and is not required to be provided by the user. 4859 Non-Vulkan backends currently don't support values other than default. 4860 Optional parameter. 4861\end_layout 4862 4863\begin_layout Standard 4864Buffer offset (bufferOffset/ tempBufferOffset/ inputBufferOffset/ outputBufferOf 4865fset/ kernelOffset) specifies offset from the start of the buffer sequence. 4866 It must be specified in bytes and must be divisible by the number type 4867 size used in the corresponding array (otherwise, the offset will be truncated). 4868 It is provided as a single uint64_t value. 4869 Can be provided at launch time, if specifyOffsetsAtLaunch parameter is 4870 enabled during initialization call. 4871 Optional parameters. 4872\end_layout 4873 4874\begin_layout Standard 4875User can provide custom dimension strides for buffer/inputBuffer/outputBuffer 4876 buffers - uint64_t[VKFFT_MAX_FFT_DIMENSIONS] array. 4877 Strides are specified in elements used in the array (not bytes). 4878 The first element corresponds to the stride between elements in the H direction 4879, the second corresponds to the D direction and the third to C (or N, if 4880 the number of elements in C is 1). 4881 The first axis is assumed to be non-strided. 4882 Must be at least of the same size as default strides, otherwise the behavior 4883 is undefined. 4884 Optional parameters. 4885\end_layout 4886 4887\begin_layout Standard 4888uint64_t inverseReturnToInputBuffer - an option that allows setting the 4889 final output buffer of the inverse transform to the same buffer, initial 4890 read of forward transform is performed from (inputBuffer, if isInputFormatted 4891 enabled). 4892 Optional parameter. 4893\end_layout 4894 4895\begin_layout Subsubsection 4896General FFT parameters 4897\end_layout 4898 4899\begin_layout Standard 4900This section describes part of the configuration structure responsible for 4901 FFT specification. 4902 4903\end_layout 4904 4905\begin_layout Standard 4906uint64_t FFTdim - dimensionality of the transform (up to VKFFT_MAX_FFT_DIMENSION 4907S). 4908 Required parameter. 4909\end_layout 4910 4911\begin_layout Standard 4912uint64_t size[VKFFT_MAX_FFT_DIMENSIONS] - WHD+ dimensions of the transform. 4913 Required parameter. 4914\end_layout 4915 4916\begin_layout Standard 4917uint64_t numberBatches - N parameter of the transform. 4918 By default, it is set to 1. 4919 Optional parameter. 4920\end_layout 4921 4922\begin_layout Standard 4923uint64_t performR2C - perform R2C/C2R decomposition. 4924 performDCT and performDST must be set to 0. 4925 Default 0, set to 1 to enable. 4926 Optional parameter. 4927\end_layout 4928 4929\begin_layout Standard 4930uint64_t performDCT - perform DCT transformation. 4931 performR2C and performDST must be set to 0. 4932 Default 0, set to X for DCT-X (currently supported X: 1, 2, 3 and 4). 4933 Optional parameter. 4934\end_layout 4935 4936\begin_layout Standard 4937uint64_t performDST - perform DST transformation. 4938 performR2C and performDCT must be set to 0. 4939 Default 0, set to X for DST-X (currently supported X: 1, 2, 3 and 4). 4940 Optional parameter. 4941\end_layout 4942 4943\begin_layout Standard 4944uint64_t normalize - enabling this parameter will make the inverse transform 4945 divide the result by the FFT length. 4946 Default 0, set to 1 to enable. 4947 Optional parameter. 4948\end_layout 4949 4950\begin_layout Subsubsection 4951Precision parameters (and some things that can affect it): 4952\end_layout 4953 4954\begin_layout Standard 4955uint64_t doublePrecision - perform calculations in double precision. 4956 Default 0, set to 1 to enable. 4957 In Vulkan/OpenCL/Level Zero your device must support double precision functiona 4958lity. 4959 Metal API does not support double precision. 4960 Optional parameter. 4961\end_layout 4962 4963\begin_layout Standard 4964uint64_t doublePrecisionFloatMemory - perform calculations in double precision, 4965 but all intermediate and final storage in float. 4966 Input/Output/main buffers must have single-precision layout. 4967 doublePrecision must be set to 0. 4968 This option increases precision, but not that much to be recommended for 4969 actual use. 4970 Default 0, set to 1 to enable. 4971 In Vulkan/OpenCL/Level Zero your device must support double precision functiona 4972lity. 4973 Metal API does not support double precision. 4974 Optional parameter. 4975\end_layout 4976 4977\begin_layout Standard 4978uint64_t quadDoubleDoublePrecision - perform calculations in double-double 4979 emulation of quad precision (0 - off, 1 - on). 4980 Optional parameter. 4981 Requires quadmath library (for now). 4982\end_layout 4983 4984\begin_layout Standard 4985uint64_t quadDoubleDoublePrecisionDoubleMemory - perform calculations in 4986 double-double emulation of quad precision, while all memory storage is 4987 done in FP64. 4988 Optional parameter. 4989 Requires quadmath library (for now). 4990\end_layout 4991 4992\begin_layout Standard 4993uint64_t halfPrecision - half-precision in VkFFT is implemented only as 4994 memory optimization. 4995 All calculations are done in single precision (similar way as doublePrecisionFl 4996oatMemory works for double and single precision). 4997 Default 0, set to 1 to enable. 4998 Optional parameter. 4999\end_layout 5000 5001\begin_layout Standard 5002uint64_t halfPrecisionMemoryOnly - another way of performing half-precision 5003 in VkFFT, it will use half-precision only for initial and final memory 5004 storage in input/output buffer. 5005 Input/Output have to be allocated as half, buffer/tempBuffer have to be 5006 allocated as float (out-of-place mode only). 5007 Specify isInputFormatted and isOutputFormatted to use. 5008 So, for example, intermediate storage between axes FFTs in the multidimensional 5009 case will be done in single precision, as opposed to half-precision in 5010 the base halfPrecision case. 5011 halfPrecision must be set to 1. 5012 Default 0, set to 1 to enable. 5013 Optional parameter. 5014\end_layout 5015 5016\begin_layout Standard 5017int64_t useLUT - switches from calculating sines and cosines (via special 5018 function units in single precision or as a polynomial approximation in 5019 double precision) to using precomputed Look-Up Tables. 5020 -1 - off, 0 - auto, 1 - on. 5021 Default 0 in single precision, 1 in double precision. 5022 Set to 1 by default for Intel GPUs. 5023 If you have issues with single-precision accuracy on your GPU, try enabling 5024 this parameter (mobile GPUs may be affected). 5025 Optional parameter. 5026\end_layout 5027 5028\begin_layout Standard 5029int64_t useLUT_4step - switches from calculating sincos to using precomputed 5030 LUT tables for intermediate roots of 1 in the Four-step FFT algorithm. 5031 (-1 - off, 0 - auto, 1 - on). 5032 Configured by initialization routine. 5033 Optional parameter. 5034 5035\end_layout 5036 5037\begin_layout Subsubsection 5038Advanced parameters (code will work fine without using them) 5039\end_layout 5040 5041\begin_layout Standard 5042uint64_t omitDimension[VKFFT_MAX_FFT_DIMENSIONS] - parameter, that disables 5043 the FFT calculation for a particular axis (WHD). 5044 Note, that omitted dimensions still need to be included in FFTdim and size. 5045 This parameter simply works as a switch during execution - by not executing 5046 the particular dimension code. 5047 It doesn't work with the non-strided axis (W) of R2C/C2R mode. 5048 It doesn't work with convolution calculations. 5049 Default 0, set to 1 to enable. 5050 Optional parameter. 5051\end_layout 5052 5053\begin_layout Standard 5054uint64_t useUint64 - forces VkFFT to use 64-bit addressing in generated 5055 kernels. 5056 It is automatically enabled if the estimated buffer size is more than 4GB. 5057 Doesn't work with the Vulkan backend. 5058 By default, it is set to 0. 5059 Optional parameter. 5060\end_layout 5061 5062\begin_layout Standard 5063uint64_t coalescedMemory - number of bytes to coalesce per one transaction. 5064 For Nvidia and AMD is equal to 32, Intel is equal to 64. 5065 Going to work regardless, but if specified by the user correctly, the performan 5066ce will be higher. 5067 Default 64 for other GPUs. 5068 For half-precision should be multiplied by two. 5069 Should be a power of two. 5070 Optional parameter. 5071\end_layout 5072 5073\begin_layout Standard 5074uint64_t numSharedBanks - configure the number of shared banks on the target 5075 GPU. 5076 Default 32. 5077 Minor performance boost as it solves shared memory conflicts for the power 5078 of two systems. 5079 Optional parameter. 5080\end_layout 5081 5082\begin_layout Standard 5083uint64_t aimThreads - try to aim all kernels at this amount of threads. 5084 Gains/losses are not predictable, just a parameter to play with (it is 5085 not guaranteed that the target kernel will use that many threads). 5086 Default 128. 5087 Optional parameter. 5088\end_layout 5089 5090\begin_layout Standard 5091uint64_t useUint64 - forces 64-bit addressing in generated kernels. 5092 Should be enabled automatically for systems spanning more than 4GB, but 5093 it is better to have an option to force it as a failsafe. 5094 Doesn't work in Vulkan API (use multiple buffer binding). 5095 Default 0, set to 1 to enable. 5096 Optional parameter. 5097\end_layout 5098 5099\begin_layout Standard 5100int performBandwidthBoost - try to reduce coalsesced number by a factor 5101 of X to get bigger sequence in one upload for strided axes. 5102 Default: -1(inf) for DCT and DST, 2 for Bluestein's algorithm (or -1 if 5103 DCT and DST), 0 otherwise 5104\end_layout 5105 5106\begin_layout Standard 5107uint64_t disableMergeSequencesR2C - disable the optimization that performs 5108 merging of two real sequences to reduce calculations (in R2C/C2R and R2R). 5109 If enabled, calculations will be performed by simply setting the imaginary 5110 component to zero. 5111 Default 0, set to 1 to enable. 5112 Optional parameter. 5113\end_layout 5114 5115\begin_layout Standard 5116uint64_t forceCallbackVersionRealTransforms - force callback version of 5117 R2C and R2R algorithms for all usecases (0 - off, 1 - on) 5118\end_layout 5119 5120\begin_layout Standard 5121uint64_t disableReorderFourStep - disables unshuffling of the Four Step 5122 FFT algorithm (last transposition of data). 5123 With this option enabled, tempBuffer will not be needed (unless it is required 5124 by Bluestein's multi-upload FFT algorithm). 5125 Default 0, set to 1 to enable. 5126 Automatically enabled for convolution calculations and Bluestein's algorithm. 5127 Optional parameter. 5128\end_layout 5129 5130\begin_layout Standard 5131uint64_t makeForwardPlanOnly - generate code only for forward FFT. 5132 Default 0, set to 1 to enable. 5133 Mutually exclusive with makeInversePlanOnly. 5134 Optional parameter. 5135\end_layout 5136 5137\begin_layout Standard 5138uint64_t makeInversePlanOnly - generate code only for inverse FFT. 5139 Default 0, set to 1 to enable. 5140 Mutually exclusive with makeForwardPlan. 5141 Optional parameter. 5142\end_layout 5143 5144\begin_layout Standard 5145uint64_t considerAllAxesStrided - will create a plan for a non-strided axis 5146 similar to a strided axis (used with disableReorderFourStep to get the 5147 same layout for Bluestein kernel). 5148 Default 0, set to 1 to enable. 5149 Optional parameter. 5150\end_layout 5151 5152\begin_layout Standard 5153uint64_t keepShaderCode - debugging option, will keep shader code and print 5154 all executed shaders during the plan execution in order. 5155 Default 0, set to 1 to enable. 5156 Optional parameter. 5157\end_layout 5158 5159\begin_layout Standard 5160uint64_t printMemoryLayout - debugging option, will print order of buffers 5161 used in kernels. 5162 Default 0, set to 1 to enable. 5163 Optional parameter. 5164 5165\end_layout 5166 5167\begin_layout Standard 5168uint64_t saveApplicationToString - will save all compiled binaries to VkFFTAppli 5169cation.saveApplicationString (will be allocated by VkFFT, deallocated with 5170 deleteVkFFT call). 5171 VkFFTApplication.applicationStringSize will contain size of binary in bytes. 5172 Currently disabled in Metal backend. 5173 Default 0, set to 1 to enable. 5174 Optional parameter. 5175\end_layout 5176 5177\begin_layout Standard 5178uint64_t loadApplicationFromString - will load all binaries from loadApplication 5179String instead of recompiling them (loadApplicationString must be allocated 5180 by user, must contain what saveApplicationToString call generated previously 5181 in VkFFTApplication.saveApplicationString). 5182 Currently disabled in Metal backend. 5183 Default 0, set to 1 to enable. 5184 Optional parameter. 5185 Mutually exclusive with saveApplicationToString 5186\end_layout 5187 5188\begin_layout Standard 5189void* loadApplicationString - memory binary array through which user can 5190 load VkFFT binaries, must be provided by user if loadApplicationFromString 5191 = 1. 5192 Use rb/wb flags to load/save. 5193\end_layout 5194 5195\begin_layout Standard 5196uint64_t disableSetLocale - disables all VkFFT attempts to set locale to 5197 C - user must ensure that VkFFT has C locale during the plan initialization. 5198 This option is needed for multithreading. 5199 Default 0. 5200\end_layout 5201 5202\begin_layout Standard 5203uint64_t groupedBatch[VKFFT_MAX_FFT_DIMENSIONS] - try to force this many 5204 FFTs to be perfromed by one threadblock for each dimension. 5205 Optional parameter. 5206 5207\end_layout 5208 5209\begin_layout Subsubsection 5210Rader control parameters 5211\end_layout 5212 5213\begin_layout Standard 5214uint64_t fixMinRaderPrimeMult - start direct multiplication Rader's algorithm 5215 for radix primes from this number. 5216 This means that VkFFT will inline custom Rader kernels if sequence is divisible 5217 by these primes. 5218 Default is 17, as VkFFT has kernels for 2-13. 5219 If you make it less than 13, VkFFT will switch from these kernels to Rader. 5220\end_layout 5221 5222\begin_layout Standard 5223uint64_t fixMaxRaderPrimeMult - switch from Mult Rader's algorithm for radix 5224 primes from this number. 5225 Current limitation for Rader is maxThreadNum/2+1, realistically you would 5226 want to switch somewhere on 30-100 range. 5227 Default is vendor-specific (currently ~40) 5228\end_layout 5229 5230\begin_layout Standard 5231uint64_t fixMinRaderPrimeFFT - start FFT convolution version of Rader for 5232 radix primes from this number. 5233 Better than direct multiplication version for almost all primes (except 5234 small ones, like 17-23 on some GPUs). 5235 Must be bigger or equal to fixMinRaderPrimeMult. 5236 Deafult 29 on AMD and 17 on other GPUs. 5237 5238\end_layout 5239 5240\begin_layout Standard 5241uint64_t fixMaxRaderPrimeFFT - switch to Bluestein's algorithm for radix 5242 primes from this number. 5243 Switch may happen earlier if prime can't fit in shared memory. 5244 Default is 16384, which is bigger than most current GPU's shared memory. 5245\end_layout 5246 5247\begin_layout Subsubsection 5248Bluestein control parameters 5249\end_layout 5250 5251\begin_layout Standard 5252If the sequence can not be decomposed as a multiplication of primes up to 5253 13, FFT is performed as a convolution. 5254 The sequence to pad to with the best performance is usually device-dependent. 5255 VkFFT uses parameters manually tuned for all sequences between 2 and 4096 5256 for both double and single precision on Nvidia A100 (Nvidia profile) and 5257 AMD MI250 (default profile). 5258 To control this process, VkFFT allows for the following parameters specificatio 5259n: 5260\end_layout 5261 5262\begin_layout Standard 5263uint64_t fixMaxRadixBluestein - controls the padding of sequences in Bluestein 5264 convolution. 5265 If specified, padded sequence will be made of up to fixMaxRadixBluestein 5266 primes. 5267 Default: 2 for CUDA and Vulkan/OpenCL/HIP up to 1048576 combined dimension 5268 FFT system, 7 for Vulkan/OpenCL/HIP past after. 5269 Min = 2, Max = 13. 5270\end_layout 5271 5272\begin_layout Standard 5273uint64_t forceBluesteinSequenceSize - force the sequence size to pad to 5274 in Bluestein's algorithm. 5275 Must be at least 2*N-1 and decomposable with primes 2-13. 5276\end_layout 5277 5278\begin_layout Standard 5279uint64_t useCustomBluesteinPaddingPattern - force the sequence sizes to 5280 pad to in Bluestein's algorithm, but on a range. 5281 This number specifies the number of elements in primeSizes and in paddedSizes 5282 arrays. 5283 primeSizes - array of non-decomposable as radix scheme sizes - 17, 23, 5284 31 etc. 5285 paddedSizes - array of lengths to pad to. 5286 paddedSizes[i] will be the padding size for all non-decomposable sequences 5287 from primeSizes[i] to primeSizes[i+1] (will use default scheme after last 5288 one) - 42, 60, 64 for primeSizes before and 37+ will use default scheme 5289 (for example). 5290 Default is vendor and API-based specified in autoCustomBluesteinPaddingPattern. 5291\end_layout 5292 5293\begin_layout Standard 5294uint64_t* primeSizes - described in useCustomBluesteinPaddingPattern 5295\end_layout 5296 5297\begin_layout Standard 5298uint64_t* paddedSizes - described in useCustomBluesteinPaddingPattern 5299\end_layout 5300 5301\begin_layout Subsubsection 5302Zero padding parameters 5303\end_layout 5304 5305\begin_layout Standard 5306uint64_t performZeropadding[VKFFT_MAX_FFT_DIMENSIONS] - do not read/write 5307 some data/perform computations if some part of the sequence is known to 5308 have zeros. 5309 Set separately for each axis (WHD). 5310 If enabled, all 1D sequences in this direction will be considered padded 5311 (independent of other zero-padded axes). 5312 Default 0, set to 1 to enable. 5313 Optional parameter. 5314 5315\end_layout 5316 5317\begin_layout Standard 5318uint64_t fft_zeropad_left[VKFFT_MAX_FFT_DIMENSIONS] - specify start boundary 5319 of zero block in the system for each axis. 5320 Default 0, set to the value between 0 and size[X]-1. 5321 Optional parameter. 5322\end_layout 5323 5324\begin_layout Standard 5325uint64_t fft_zeropad_right[VKFFT_MAX_FFT_DIMENSIONS] - specify end boundary 5326 of zero block in the system for each axis. 5327 Default 0, set to the value between fft_zeropad_left[X] and size[X]-1. 5328 Optional parameter. 5329\end_layout 5330 5331\begin_layout Standard 5332uint64_t frequencyZeroPadding - enables zero padding of the frequency domain, 5333 so the first read of inverse FFT will consider the parts of the system 5334 from fft_zeropad_left to fft_zeropad_right as zero. 5335 Default 0 - spatial zero padding, set to 1 to enable. 5336 Optional parameter. 5337 5338\end_layout 5339 5340\begin_layout Subsubsection 5341Convolution parameters 5342\end_layout 5343 5344\begin_layout Standard 5345uint64_t performConvolution - main parameter that enables convolutions in 5346 the application. 5347 If enabled, you must specify kernel buffer, number of kernel buffers and 5348 kernel sizes (in Vulkan API). 5349 Disables reordering of the Four Step FFT algorithm. 5350 Default 0, set to 1 to enable. 5351 Optional parameter. 5352 5353\end_layout 5354 5355\begin_layout Standard 5356uint64_t conjugateConvolution - default 0, set to 1 to enable enables conjugatio 5357n of the sequence FFT is currently done on, 2 to enable conjugation of the 5358 convolution kernel. 5359 Optional parameter. 5360 5361\end_layout 5362 5363\begin_layout Standard 5364uint64_t crossPowerSpectrumNormalization - normalize the FFT * kernel multiplica 5365tion in frequency domain. 5366 Default 0, set to 1 to enable. 5367 Optional parameter. 5368 5369\end_layout 5370 5371\begin_layout Standard 5372uint64_t coordinateFeatures - max coordinate (C), or dimension of the features 5373 vector. 5374 In matrix convolution - the size of the vector. 5375 The main purpose is to support Matrix-Vector convolutions. 5376 Use numberBatches parameter in tasks, not requiring two separate coordinate-lik 5377e enumerations of data. 5378 Default 1. 5379 Optional parameter. 5380\end_layout 5381 5382\begin_layout Standard 5383uint64_t matrixConvolution - set to 2 to perform 2x2, set to 3 to perform 5384 3x3 matrix-vector convolution. 5385 Matrix-vector convolution is a form of point-wise multiplication in the 5386 Fourier space, used by the convolution theorem, where multiplication takes 5387 the form of Matrix-vector multiplication. 5388 Overrides coordinateFeatures during execution. 5389 Default 0. 5390 Optional parameter. 5391 5392\end_layout 5393 5394\begin_layout Standard 5395uint64_t symmetricKernel - specify if kernel in 2x2 or 3x3 matrix convolution 5396 is symmetric. 5397 You need to store data as xx, xy, yy (upper-triangular) if enabled and 5398 as xx, xy, yx, yy (along rows then along columns, from left to right) if 5399 disabled. 5400 Default 0, set to 1 to enable. 5401 Optional parameter. 5402 5403\end_layout 5404 5405\begin_layout Standard 5406uint64_t numberKernels - specify how many kernels were initialized before 5407 performing one input/multiple output convolutions. 5408 Overwrites numberBatches (N). 5409 Only used in convolution step and the following inverse transforms. 5410 Default 1. 5411 Optional parameter. 5412 5413\end_layout 5414 5415\begin_layout Standard 5416uint64_t kernelConvolution - specify if this application is used to create 5417 kernel for convolution, so it has the same properties/memory layout. 5418 performConvolution has to be set to 0 for the kernel creation. 5419 Default 0, set to 1 to enable. 5420 Optional parameter, but it is a required parameter for kernel generation. 5421\end_layout 5422 5423\begin_layout Subsubsection 5424Register overutilization 5425\end_layout 5426 5427\begin_layout Standard 5428Only works in C2C mode, without convolution support. 5429 Enabled in Vulkan, OpenCL and Level Zero APIs only (it works in other APIs, 5430 but worse, does not work in Metal). 5431 Experimental feature. 5432\end_layout 5433 5434\begin_layout Standard 5435uint64_t registerBoost - specify if the register file size is bigger than 5436 shared memory and can be used to extend it X times (on Nvidia 256KB register 5437 file can be used instead of 32KB of shared memory, set this constant to 5438 4 to emulate 128KB of shared memory). 5439 Default 1 - no overutilization. 5440 In Vulkan, OpenCL and Level Zero it is set to 4 on Nvidia GPUs, to 2 if 5441 the driver shows 64KB or more of shared memory on AMD, to 2 if the driver 5442 shows less than 64KB of shared memory on AMD, to 1 if the driver shows 5443 64KB or more of shared memory on Intel, to 2 if the driver shows less than 5444 64KB of shared memory on Intel. 5445 Optional parameter. 5446\end_layout 5447 5448\begin_layout Standard 5449uint64_t registerBoostNonPow2 - specify if register overutilization should 5450 be used on non-power of 2 sequences. 5451 Default 0, set to 1 to enable. 5452 Optional parameter. 5453\end_layout 5454 5455\begin_layout Standard 5456uint64_t registerBoost4Step - specify if register file overutilization should 5457 be used in big sequences (>2^14), same definition as registerBoost. 5458 Default 1. 5459 Optional parameter. 5460\end_layout 5461 5462\begin_layout Subsubsection 5463Extra advanced parameters (filled automatically) 5464\end_layout 5465 5466\begin_layout Standard 5467uint64_t computeCapabilityMajor - CUDA/HIP compute capability of the device 5468\end_layout 5469 5470\begin_layout Standard 5471uint64_t computeCapabilityMinor - CUDA/HIP compute capability of the device 5472 5473\end_layout 5474 5475\begin_layout Standard 5476uint64_t maxComputeWorkGroupCount[3] - how many workgroups can be launched 5477 at one dispatch. 5478 Automatically derived from the driver, can be artificially lowered. 5479 Then VkFFT will perform a logical split and extension of the number of 5480 workgroups to cover the required range. 5481\end_layout 5482 5483\begin_layout Standard 5484uint64_t maxComputeWorkGroupSize[3] - max dimensions of the workgroup. 5485 Automatically derived from the driver. 5486 Can be modified if there are some issues with the driver (as there were 5487 with ROCm 4.0, when it returned 1024 for maxComputeWorkGroupSize and actually 5488 supported only up to 256 threads). 5489\end_layout 5490 5491\begin_layout Standard 5492uint64_t maxThreadsNum - max number of threads per block. 5493 Similar to maxComputeWorkGroupSize, but aggregated. 5494 Automatically derived from the driver. 5495\end_layout 5496 5497\begin_layout Standard 5498uint64_t sharedMemorySizeStatic - available for static allocation shared 5499 memory size, in bytes. 5500 Automatically derived from the driver. 5501 Can be controlled by the user, if desired. 5502\end_layout 5503 5504\begin_layout Standard 5505uint64_t sharedMemorySize - available for allocation shared memory size, 5506 in bytes. 5507 VkFFT uses dynamic shared memory in CUDA/HIP as it allows for bigger allocation 5508s. 5509 Automatically derived from the driver. 5510 Can be controlled by the user, if desired. 5511\end_layout 5512 5513\begin_layout Standard 5514uint64_t sharedMemorySizePow2 - the power of 2 which is less or equal to 5515 sharedMemorySize, in bytes. 5516 Automatically computed. 5517\end_layout 5518 5519\begin_layout Standard 5520uint64_t warpSize - number of threads per warp/wavefront. 5521 Automatically derived from the driver, but can be modified (can increase 5522 performance, though unpredictable as defaults have good values). 5523 Must be a power of two. 5524\end_layout 5525 5526\begin_layout Standard 5527uint64_t halfThreads - Intel GPU fix, tries to reduce the amount of dispatched 5528 threads in half to solve performance degradation in the Four Step FFT algorithm. 5529 Default 0 for other GPUs, try enabling it if performance degrades in the 5530 Four Step FFT algorithm for your GPU as well. 5531 5532\end_layout 5533 5534\begin_layout Standard 5535int64_t maxCodeLength - specify how big can the buffer used for code generation 5536 be (in char). 5537 Default 1000000 chars. 5538 5539\end_layout 5540 5541\begin_layout Standard 5542int64_t maxTempLength - specify how big can the buffer used for intermediate 5543 string sprintf's be (in char). 5544 Default 5000 chars. 5545 If code segfaults for some reason - try increasing this number. 5546\end_layout 5547 5548\begin_layout Standard 5549uint64_t autoCustomBluesteinPaddingPattern - default value for useCustomBluestei 5550nPaddingPattern 5551\end_layout 5552 5553\begin_layout Standard 5554uint64_t useRaderUintLUT - allocate additional LUT to store g_pow 5555\end_layout 5556 5557\begin_layout Standard 5558uint64_t vendorID - vendorID 0x10DE - NVIDIA, 0x8086 - Intel, 0x1002 - AMD, 5559 etc. 5560\end_layout 5561 5562\begin_layout Standard 5563\begin_inset Newpage newpage 5564\end_inset 5565 5566 5567\end_layout 5568 5569\begin_layout Section 5570VkFFT Benchmark/Precision Suite and utils_VkFFT helper routines 5571\end_layout 5572 5573\begin_layout Standard 5574The only licensed (MIT) part of the VkFFT repository is the VkFFT header 5575 file - core library. 5576 Other files are either external helper libraries (half, glslang, with their 5577 respective licenses) or unlicensed code that is intended for simple copy-pastin 5578g (benchmark_scripts, utils_VkFFT.h). 5579 It is the easiest way to understand how to use VkFFT by taking the provided 5580 scripts and tinker them to the particular task. 5581 The current version of the benchmark and precision verification suite has 5582 the following codes available: 5583\end_layout 5584 5585\begin_layout Itemize 5586user_benchmark_VkFFT - generalization of the main configuration parameters 5587 that can be used to launch simplest in-place transforms for the most important 5588 supported functionality 5589\end_layout 5590 5591\begin_layout Itemize 5592Sample 0 - FFT + iFFT C2C benchmark 1D batched in single precision 5593\end_layout 5594 5595\begin_layout Itemize 5596Sample 1 - FFT + iFFT C2C benchmark 1D batched in double precision 5597\end_layout 5598 5599\begin_layout Itemize 5600Sample 2 - FFT + iFFT C2C benchmark 1D batched in half precision 5601\end_layout 5602 5603\begin_layout Itemize 5604Sample 3 - FFT + iFFT C2C multidimensional benchmark in single precision 5605\end_layout 5606 5607\begin_layout Itemize 5608Sample 4 - FFT + iFFT C2C multidimensional benchmark in single precision, 5609 native zeropadding 5610\end_layout 5611 5612\begin_layout Itemize 5613Sample 5 - FFT + iFFT C2C benchmark 1D batched in single precision, no reshuffli 5614ng 5615\end_layout 5616 5617\begin_layout Itemize 5618Sample 6 - FFT + iFFT R2C / C2R benchmark, in-place. 5619\end_layout 5620 5621\begin_layout Itemize 5622Sample 7 - FFT + iFFT C2C Bluestein benchmark in single precision 5623\end_layout 5624 5625\begin_layout Itemize 5626Sample 8 - FFT + iFFT C2C Bluestein benchmark in double precision 5627\end_layout 5628 5629\begin_layout Itemize 5630Sample 9 - FFT + iFFT C2C benchmark 1D batched in double-double emulation 5631 of quad precision 5632\end_layout 5633 5634\begin_layout Itemize 5635Sample 10 - multiple buffers (4 by default) split version of benchmark 0 5636\end_layout 5637 5638\begin_layout Itemize 5639Sample 11 - VkFFT / xFFT / FFTW C2C precision test in single precision (xFFT 5640 can be cuFFT or rocFFT) 5641\end_layout 5642 5643\begin_layout Itemize 5644Sample 12 - VkFFT / xFFT / FFTW C2C precision test in double precision (xFFT 5645 can be cuFFT or rocFFT) 5646\end_layout 5647 5648\begin_layout Itemize 5649Sample 13 - VkFFT / cuFFT / FFTW C2C precision test in half precision 5650\end_layout 5651 5652\begin_layout Itemize 5653Sample 14 - VkFFT / FFTW C2C radix 3 / 5 / 7 / 11 / 13 / Bluestein precision 5654 test in single precision 5655\end_layout 5656 5657\begin_layout Itemize 5658Sample 15 - VkFFT / xFFT / FFTW R2C+C2R precision test in single precision, 5659 out-of-place. 5660 (xFFT can be cuFFT or rocFFT) 5661\end_layout 5662 5663\begin_layout Itemize 5664Sample 16 - VkFFT / FFTW R2R DCT-I, II, III and IV precision test in single 5665 precision 5666\end_layout 5667 5668\begin_layout Itemize 5669Sample 17 - VkFFT / FFTW R2R DCT-I, II, III and IV precision test in double 5670 precision 5671\end_layout 5672 5673\begin_layout Itemize 5674Sample 18 - VkFFT / FFTW C2C radix 3 / 5 / 7 / 11 / 13 / Bluestein precision 5675 test in double precision 5676\end_layout 5677 5678\begin_layout Itemize 5679Sample 19 - VkFFT / FFTW C2C precision test in double-double emulation of 5680 quad precision 5681\end_layout 5682 5683\begin_layout Itemize 5684Sample 50 - convolution example with identity kernel 5685\end_layout 5686 5687\begin_layout Itemize 5688Sample 51 - zero padding convolution example with identity kernel 5689\end_layout 5690 5691\begin_layout Itemize 5692Sample 52 - batched convolution example with identity kernel 5693\end_layout 5694 5695\begin_layout Itemize 5696Sample 100 - VkFFT FFT + iFFT R2R DCT multidimensional benchmark in single 5697 precision 5698\end_layout 5699 5700\begin_layout Itemize 5701Sample 101 - VkFFT FFT + iFFT R2R DCT multidimensional benchmark in double 5702 precision 5703\end_layout 5704 5705\begin_layout Itemize 5706Sample 1000 - FFT + iFFT C2C benchmark 1D batched in single precision: all 5707 supported systems from 2 to 4096 5708\end_layout 5709 5710\begin_layout Itemize 5711Sample 1001 - FFT + iFFT C2C benchmark 1D batched in double precision: all 5712 supported systems from 2 to 4096 5713\end_layout 5714 5715\begin_layout Itemize 5716Sample 1002 - FFT + iFFT C2C benchmark 1D batched in half precision: all 5717 supported systems from 2 to 4096 5718\end_layout 5719 5720\begin_layout Itemize 5721Sample 1003 - FFT + iFFT C2C benchmark 1D batched in single precision: all 5722 supported systems from 2 to 4096 5723\end_layout 5724 5725\begin_layout Itemize 5726Sample 1004 - FFT + iFFT C2C benchmark 1D batched in double-double emulation 5727 of quad precision: all supported systems from 2 to 4096 5728\end_layout 5729 5730\begin_layout Subsection 5731utils_VkFFT helper routines 5732\end_layout 5733 5734\begin_layout Standard 5735Launching even the simplest Vulkan application can be a non-trivial task. 5736 To help with this, utils_VkFFT contains the routines that can help to create 5737 the simplest Vulkan application, allocate memory, record command buffers 5738 and launch them. 5739 Code has some comments explaining what is going on at each step. 5740 It also has some useful struct defines (like vkGPU) that keep the most 5741 important handles used in Vulkan Compute. 5742 This section may be expanded in the future to the proper step-by-step guide 5743 on Vulkan Compute simple application creation. 5744 I also encourage to check https://github.com/DTolm/VulkanComputeSamples-Transpos 5745ition repository for another example of a compute algorithm (matrix transpositio 5746n) implemented with Vulkan API. 5747\end_layout 5748 5749\begin_layout Standard 5750utils_VkFFT also has a routine that prints the list of available devices. 5751\end_layout 5752 5753\begin_layout Standard 5754vkGPU struct has the following definition: 5755\end_layout 5756 5757\begin_layout Standard 5758\begin_inset ERT 5759status open 5760 5761\begin_layout Plain Layout 5762 5763 5764\backslash 5765begin{mdframed}[backgroundcolor=bg] 5766\end_layout 5767 5768\begin_layout Plain Layout 5769 5770 5771\backslash 5772begin{minted}[tabsize=4,obeytabs,breaklines]{C} 5773\end_layout 5774 5775\begin_layout Plain Layout 5776 5777typedef struct { 5778\end_layout 5779 5780\begin_layout Plain Layout 5781 5782#if(VKFFT_BACKEND==0) //Vulkan API 5783\end_layout 5784 5785\begin_layout Plain Layout 5786 5787VkInstance instance; //a connection between the application and the Vulkan 5788 library 5789\end_layout 5790 5791\begin_layout Plain Layout 5792 5793VkPhysicalDevice physicalDevice; //a handle for the graphics card used in 5794 the application 5795\end_layout 5796 5797\begin_layout Plain Layout 5798 5799VkPhysicalDeviceProperties physicalDeviceProperties; //bastic device properties 5800\end_layout 5801 5802\begin_layout Plain Layout 5803 5804VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; //basic 5805 memory properties of the device 5806\end_layout 5807 5808\begin_layout Plain Layout 5809 5810VkDevice device; //a logical device, interacting with physical device 5811\end_layout 5812 5813\begin_layout Plain Layout 5814 5815VkDebugUtilsMessengerEXT debugMessenger; //extension for debugging 5816\end_layout 5817 5818\begin_layout Plain Layout 5819 5820uint64_t queueFamilyIndex; //if multiple queues are available, specify the 5821 used one 5822\end_layout 5823 5824\begin_layout Plain Layout 5825 5826VkQueue queue; //a place, where all operations are submitted 5827\end_layout 5828 5829\begin_layout Plain Layout 5830 5831VkCommandPool commandPool; //an opaque objects that command buffer memory 5832 is allocated from 5833\end_layout 5834 5835\begin_layout Plain Layout 5836 5837VkFence fence; //a vkGPU->fence used to synchronize dispatches 5838\end_layout 5839 5840\begin_layout Plain Layout 5841 5842std::vector<const char*> enabledDeviceExtensions; 5843\end_layout 5844 5845\begin_layout Plain Layout 5846 5847uint64_t enableValidationLayers; 5848\end_layout 5849 5850\begin_layout Plain Layout 5851 5852#elif(VKFFT_BACKEND==1) //CUDA API 5853\end_layout 5854 5855\begin_layout Plain Layout 5856 5857CUdevice device; 5858\end_layout 5859 5860\begin_layout Plain Layout 5861 5862CUcontext context; 5863\end_layout 5864 5865\begin_layout Plain Layout 5866 5867#elif(VKFFT_BACKEND==2) //HIP API 5868\end_layout 5869 5870\begin_layout Plain Layout 5871 5872hipDevice_t device; 5873\end_layout 5874 5875\begin_layout Plain Layout 5876 5877hipCtx_t context; 5878\end_layout 5879 5880\begin_layout Plain Layout 5881 5882#elif(VKFFT_BACKEND==3) //OpenCL API 5883\end_layout 5884 5885\begin_layout Plain Layout 5886 5887cl_platform_id platform; 5888\end_layout 5889 5890\begin_layout Plain Layout 5891 5892cl_device_id device; 5893\end_layout 5894 5895\begin_layout Plain Layout 5896 5897cl_context context; 5898\end_layout 5899 5900\begin_layout Plain Layout 5901 5902cl_command_queue commandQueue; 5903\end_layout 5904 5905\begin_layout Plain Layout 5906 5907#elif(VKFFT_BACKEND==4) //Level Zero API 5908\end_layout 5909 5910\begin_layout Plain Layout 5911 5912ze_driver_handle_t driver; 5913\end_layout 5914 5915\begin_layout Plain Layout 5916 5917ze_device_handle_t device; 5918\end_layout 5919 5920\begin_layout Plain Layout 5921 5922ze_context_handle_t context; 5923\end_layout 5924 5925\begin_layout Plain Layout 5926 5927ze_command_queue_handle_t commandQueue; 5928\end_layout 5929 5930\begin_layout Plain Layout 5931 5932uint32_t commandQueueID; 5933\end_layout 5934 5935\begin_layout Plain Layout 5936 5937#elif(VKFFT_BACKEND==5) //Metal API 5938\end_layout 5939 5940\begin_layout Plain Layout 5941 5942MTL::Device* device; 5943\end_layout 5944 5945\begin_layout Plain Layout 5946 5947MTL::CommandQueue* queue; 5948\end_layout 5949 5950\begin_layout Plain Layout 5951 5952#endif 5953\end_layout 5954 5955\begin_layout Plain Layout 5956 5957uint64_t device_id; //an id of a device, reported by devices_list call 5958\end_layout 5959 5960\begin_layout Plain Layout 5961 5962} VkGPU; 5963\end_layout 5964 5965\begin_layout Plain Layout 5966 5967 5968\backslash 5969end{minted} 5970\end_layout 5971 5972\begin_layout Plain Layout 5973 5974 5975\backslash 5976end{mdframed} 5977\end_layout 5978 5979\end_inset 5980 5981 5982\begin_inset Newpage newpage 5983\end_inset 5984 5985 5986\end_layout 5987 5988\begin_layout Section 5989VkFFT Code Examples 5990\end_layout 5991 5992\begin_layout Standard 5993This section will provide some simple pseudocode for VkFFT usage, which 5994 will once again outline important steps required to launch FFT with VkFFT. 5995 More information (and fully working code) can be found in this folder of 5996 the VkFFT repository: 5997\end_layout 5998 5999\begin_layout Standard 6000/benchmark_samples/vkFFT_scripts/src/ 6001\end_layout 6002 6003\begin_layout Subsection 6004Driver initializations 6005\end_layout 6006 6007\begin_layout Standard 6008Before launching VkFFT, do not forget to do all necessary driver initializations. 6009 The following code specifies them for all the supported backends, though 6010 the final implementation may be different depending on the particular user's 6011 configuration. 6012\end_layout 6013 6014\begin_layout Standard 6015\begin_inset ERT 6016status open 6017 6018\begin_layout Plain Layout 6019 6020 6021\backslash 6022begin{mdframed}[backgroundcolor=bg] 6023\end_layout 6024 6025\begin_layout Plain Layout 6026 6027 6028\backslash 6029begin{minted}[tabsize=4,obeytabs,breaklines]{C} 6030\end_layout 6031 6032\begin_layout Plain Layout 6033 6034#if(VKFFT_BACKEND==0) //Vulkan API 6035\end_layout 6036 6037\begin_layout Plain Layout 6038 6039VkResult res = VK_SUCCESS; 6040\end_layout 6041 6042\begin_layout Plain Layout 6043 6044//create instance - a connection between the application and the Vulkan 6045 library 6046\end_layout 6047 6048\begin_layout Plain Layout 6049 6050res = createInstance(vkGPU, sample_id); 6051\end_layout 6052 6053\begin_layout Plain Layout 6054 6055if (res != 0) { 6056\end_layout 6057 6058\begin_layout Plain Layout 6059 6060 //printf("Instance creation failed, error code: %" PRIu64 " 6061\backslash 6062n", res); 6063\end_layout 6064 6065\begin_layout Plain Layout 6066 6067 return VKFFT_ERROR_FAILED_TO_CREATE_INSTANCE; 6068\end_layout 6069 6070\begin_layout Plain Layout 6071 6072} 6073\end_layout 6074 6075\begin_layout Plain Layout 6076 6077//set up the debugging messenger 6078\end_layout 6079 6080\begin_layout Plain Layout 6081 6082res = setupDebugMessenger(vkGPU); 6083\end_layout 6084 6085\begin_layout Plain Layout 6086 6087if (res != 0) { 6088\end_layout 6089 6090\begin_layout Plain Layout 6091 6092//printf("Debug messenger creation failed, error code: %" PRIu64 " 6093\backslash 6094n", res); 6095\end_layout 6096 6097\begin_layout Plain Layout 6098 6099 return VKFFT_ERROR_FAILED_TO_SETUP_DEBUG_MESSENGER; 6100\end_layout 6101 6102\begin_layout Plain Layout 6103 6104} 6105\end_layout 6106 6107\begin_layout Plain Layout 6108 6109//check if there are GPUs that support Vulkan and select one 6110\end_layout 6111 6112\begin_layout Plain Layout 6113 6114res = findPhysicalDevice(vkGPU); 6115\end_layout 6116 6117\begin_layout Plain Layout 6118 6119if (res != 0) { 6120\end_layout 6121 6122\begin_layout Plain Layout 6123 6124//printf("Physical device not found, error code: %" PRIu64 " 6125\backslash 6126n", res); 6127\end_layout 6128 6129\begin_layout Plain Layout 6130 6131 return VKFFT_ERROR_FAILED_TO_FIND_PHYSICAL_DEVICE; 6132\end_layout 6133 6134\begin_layout Plain Layout 6135 6136} 6137\end_layout 6138 6139\begin_layout Plain Layout 6140 6141//create logical device representation 6142\end_layout 6143 6144\begin_layout Plain Layout 6145 6146res = createDevice(vkGPU, sample_id); 6147\end_layout 6148 6149\begin_layout Plain Layout 6150 6151if (res != 0) { 6152\end_layout 6153 6154\begin_layout Plain Layout 6155 6156//printf("Device creation failed, error code: %" PRIu64 " 6157\backslash 6158n", res); 6159\end_layout 6160 6161\begin_layout Plain Layout 6162 6163 return VKFFT_ERROR_FAILED_TO_CREATE_DEVICE; 6164\end_layout 6165 6166\begin_layout Plain Layout 6167 6168} 6169\end_layout 6170 6171\begin_layout Plain Layout 6172 6173//create fence for synchronization 6174\end_layout 6175 6176\begin_layout Plain Layout 6177 6178res = createFence(vkGPU); 6179\end_layout 6180 6181\begin_layout Plain Layout 6182 6183if (res != 0) { 6184\end_layout 6185 6186\begin_layout Plain Layout 6187 6188//printf("Fence creation failed, error code: %" PRIu64 " 6189\backslash 6190n", res); 6191\end_layout 6192 6193\begin_layout Plain Layout 6194 6195 return VKFFT_ERROR_FAILED_TO_CREATE_FENCE; 6196\end_layout 6197 6198\begin_layout Plain Layout 6199 6200} 6201\end_layout 6202 6203\begin_layout Plain Layout 6204 6205//create a place, command buffer memory is allocated from 6206\end_layout 6207 6208\begin_layout Plain Layout 6209 6210res = createCommandPool(vkGPU); 6211\end_layout 6212 6213\begin_layout Plain Layout 6214 6215if (res != 0) { 6216\end_layout 6217 6218\begin_layout Plain Layout 6219 6220 //printf("Fence creation failed, error code: %" PRIu64 " 6221\backslash 6222n", res); 6223\end_layout 6224 6225\begin_layout Plain Layout 6226 6227 return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_POOL; 6228\end_layout 6229 6230\begin_layout Plain Layout 6231 6232} 6233\end_layout 6234 6235\begin_layout Plain Layout 6236 6237vkGetPhysicalDeviceProperties(vkGPU->physicalDevice, &vkGPU->physicalDevicePrope 6238rties); 6239\end_layout 6240 6241\begin_layout Plain Layout 6242 6243vkGetPhysicalDeviceMemoryProperties(vkGPU->physicalDevice, &vkGPU->physicalDevic 6244eMemoryProperties); 6245\end_layout 6246 6247\begin_layout Plain Layout 6248 6249glslang_initialize_process(); 6250\end_layout 6251 6252\begin_layout Plain Layout 6253 6254//compiler can be initialized before VkFFT 6255\end_layout 6256 6257\begin_layout Plain Layout 6258 6259\end_layout 6260 6261\begin_layout Plain Layout 6262 6263#elif(VKFFT_BACKEND==1) //CUDA API 6264\end_layout 6265 6266\begin_layout Plain Layout 6267 6268CUresult res = CUDA_SUCCESS; 6269\end_layout 6270 6271\begin_layout Plain Layout 6272 6273cudaError_t res2 = cudaSuccess; 6274\end_layout 6275 6276\begin_layout Plain Layout 6277 6278res = cuInit(0); 6279\end_layout 6280 6281\begin_layout Plain Layout 6282 6283if (res != CUDA_SUCCESS) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6284\end_layout 6285 6286\begin_layout Plain Layout 6287 6288res2 = cudaSetDevice((int)vkGPU->device_id); 6289\end_layout 6290 6291\begin_layout Plain Layout 6292 6293if (res2 != cudaSuccess) return VKFFT_ERROR_FAILED_TO_SET_DEVICE_ID; 6294\end_layout 6295 6296\begin_layout Plain Layout 6297 6298res = cuDeviceGet(&vkGPU->device, (int)vkGPU->device_id); 6299\end_layout 6300 6301\begin_layout Plain Layout 6302 6303if (res != CUDA_SUCCESS) return VKFFT_ERROR_FAILED_TO_GET_DEVICE; 6304\end_layout 6305 6306\begin_layout Plain Layout 6307 6308res = cuCtxCreate(&vkGPU->context, 0, (int)vkGPU->device); 6309\end_layout 6310 6311\begin_layout Plain Layout 6312 6313if (res != CUDA_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_CONTEXT; 6314\end_layout 6315 6316\begin_layout Plain Layout 6317 6318#elif(VKFFT_BACKEND==2) //HIP API 6319\end_layout 6320 6321\begin_layout Plain Layout 6322 6323hipError_t res = hipSuccess; 6324\end_layout 6325 6326\begin_layout Plain Layout 6327 6328res = hipInit(0); 6329\end_layout 6330 6331\begin_layout Plain Layout 6332 6333if (res != hipSuccess) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6334\end_layout 6335 6336\begin_layout Plain Layout 6337 6338res = hipSetDevice((int)vkGPU->device_id); 6339\end_layout 6340 6341\begin_layout Plain Layout 6342 6343if (res != hipSuccess) return VKFFT_ERROR_FAILED_TO_SET_DEVICE_ID; 6344\end_layout 6345 6346\begin_layout Plain Layout 6347 6348res = hipDeviceGet(&vkGPU->device, (int)vkGPU->device_id); 6349\end_layout 6350 6351\begin_layout Plain Layout 6352 6353if (res != hipSuccess) return VKFFT_ERROR_FAILED_TO_GET_DEVICE; 6354\end_layout 6355 6356\begin_layout Plain Layout 6357 6358res = hipCtxCreate(&vkGPU->context, 0, (int)vkGPU->device); 6359\end_layout 6360 6361\begin_layout Plain Layout 6362 6363if (res != hipSuccess) return VKFFT_ERROR_FAILED_TO_CREATE_CONTEXT; 6364\end_layout 6365 6366\begin_layout Plain Layout 6367 6368#elif(VKFFT_BACKEND==3) //OpenCL API 6369\end_layout 6370 6371\begin_layout Plain Layout 6372 6373cl_int res = CL_SUCCESS; 6374\end_layout 6375 6376\begin_layout Plain Layout 6377 6378cl_uint numPlatforms; 6379\end_layout 6380 6381\begin_layout Plain Layout 6382 6383res = clGetPlatformIDs(0, 0, &numPlatforms); 6384\end_layout 6385 6386\begin_layout Plain Layout 6387 6388if (res != CL_SUCCESS) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6389\end_layout 6390 6391\begin_layout Plain Layout 6392 6393cl_platform_id* platforms = (cl_platform_id*)malloc(sizeof(cl_platform_id) 6394 * numPlatforms); 6395\end_layout 6396 6397\begin_layout Plain Layout 6398 6399if (!platforms) return VKFFT_ERROR_MALLOC_FAILED; 6400\end_layout 6401 6402\begin_layout Plain Layout 6403 6404res = clGetPlatformIDs(numPlatforms, platforms, 0); 6405\end_layout 6406 6407\begin_layout Plain Layout 6408 6409if (res != CL_SUCCESS) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6410\end_layout 6411 6412\begin_layout Plain Layout 6413 6414uint64_t k = 0; 6415\end_layout 6416 6417\begin_layout Plain Layout 6418 6419for (uint64_t j = 0; j < numPlatforms; j++) { 6420\end_layout 6421 6422\begin_layout Plain Layout 6423 6424 cl_uint numDevices; 6425\end_layout 6426 6427\begin_layout Plain Layout 6428 6429 res = clGetDeviceIDs(platforms[j], CL_DEVICE_TYPE_ALL, 0, 0, &numDevices); 6430\end_layout 6431 6432\begin_layout Plain Layout 6433 6434 cl_device_id* deviceList = (cl_device_id*)malloc(sizeof(cl_device_id) * 6435 numDevices); 6436\end_layout 6437 6438\begin_layout Plain Layout 6439 6440 if (!deviceList) return VKFFT_ERROR_MALLOC_FAILED; 6441\end_layout 6442 6443\begin_layout Plain Layout 6444 6445 res = clGetDeviceIDs(platforms[j], CL_DEVICE_TYPE_ALL, numDevices, deviceList, 6446 0); 6447\end_layout 6448 6449\begin_layout Plain Layout 6450 6451 if (res != CL_SUCCESS) return VKFFT_ERROR_FAILED_TO_GET_DEVICE; 6452\end_layout 6453 6454\begin_layout Plain Layout 6455 6456 for (uint64_t i = 0; i < numDevices; i++) { 6457\end_layout 6458 6459\begin_layout Plain Layout 6460 6461 if (k == vkGPU->device_id) { 6462\end_layout 6463 6464\begin_layout Plain Layout 6465 6466 vkGPU->platform = platforms[j]; 6467\end_layout 6468 6469\begin_layout Plain Layout 6470 6471 vkGPU->device = deviceList[i]; 6472\end_layout 6473 6474\begin_layout Plain Layout 6475 6476 vkGPU->context = clCreateContext(NULL, 1, &vkGPU->device, NULL, NULL, 6477 &res); 6478\end_layout 6479 6480\begin_layout Plain Layout 6481 6482 if (res != CL_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_CONTEXT; 6483\end_layout 6484 6485\begin_layout Plain Layout 6486 6487 cl_command_queue commandQueue = clCreateCommandQueue(vkGPU->context, 6488 vkGPU->device, 0, &res); 6489\end_layout 6490 6491\begin_layout Plain Layout 6492 6493 if (res != CL_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_QUEUE; 6494\end_layout 6495 6496\begin_layout Plain Layout 6497 6498 vkGPU->commandQueue = commandQueue; 6499\end_layout 6500 6501\begin_layout Plain Layout 6502 6503 i=numDevices; 6504\end_layout 6505 6506\begin_layout Plain Layout 6507 6508 j=numPlatforms; 6509\end_layout 6510 6511\begin_layout Plain Layout 6512 6513 } 6514\end_layout 6515 6516\begin_layout Plain Layout 6517 6518 else { 6519\end_layout 6520 6521\begin_layout Plain Layout 6522 6523 k++; 6524\end_layout 6525 6526\begin_layout Plain Layout 6527 6528 } 6529\end_layout 6530 6531\begin_layout Plain Layout 6532 6533 } 6534\end_layout 6535 6536\begin_layout Plain Layout 6537 6538 free(deviceList); 6539\end_layout 6540 6541\begin_layout Plain Layout 6542 6543} 6544\end_layout 6545 6546\begin_layout Plain Layout 6547 6548free(platforms); 6549\end_layout 6550 6551\begin_layout Plain Layout 6552 6553#elif(VKFFT_BACKEND==4) 6554\end_layout 6555 6556\begin_layout Plain Layout 6557 6558 ze_result_t res = ZE_RESULT_SUCCESS; 6559\end_layout 6560 6561\begin_layout Plain Layout 6562 6563 res = zeInit(0); 6564\end_layout 6565 6566\begin_layout Plain Layout 6567 6568 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6569\end_layout 6570 6571\begin_layout Plain Layout 6572 6573 uint32_t numDrivers = 0; 6574\end_layout 6575 6576\begin_layout Plain Layout 6577 6578 res = zeDriverGet(&numDrivers, 0); 6579\end_layout 6580 6581\begin_layout Plain Layout 6582 6583 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6584\end_layout 6585 6586\begin_layout Plain Layout 6587 6588 ze_driver_handle_t* drivers = (ze_driver_handle_t*)malloc(numDrivers * 6589 sizeof(ze_driver_handle_t)); 6590\end_layout 6591 6592\begin_layout Plain Layout 6593 6594 if (!drivers) return VKFFT_ERROR_MALLOC_FAILED; 6595\end_layout 6596 6597\begin_layout Plain Layout 6598 6599 res = zeDriverGet(&numDrivers, drivers); 6600\end_layout 6601 6602\begin_layout Plain Layout 6603 6604 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_INITIALIZE; 6605\end_layout 6606 6607\begin_layout Plain Layout 6608 6609 uint64_t k = 0; 6610\end_layout 6611 6612\begin_layout Plain Layout 6613 6614 for (uint64_t j = 0; j < numDrivers; j++) { 6615\end_layout 6616 6617\begin_layout Plain Layout 6618 6619 uint32_t numDevices = 0; 6620\end_layout 6621 6622\begin_layout Plain Layout 6623 6624 res = zeDeviceGet(drivers[j], &numDevices, nullptr); 6625\end_layout 6626 6627\begin_layout Plain Layout 6628 6629 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_GET_DEVICE; 6630\end_layout 6631 6632\begin_layout Plain Layout 6633 6634 ze_device_handle_t* deviceList = (ze_device_handle_t*)malloc(numDevices 6635 * sizeof(ze_device_handle_t)); 6636\end_layout 6637 6638\begin_layout Plain Layout 6639 6640 if (!deviceList) return VKFFT_ERROR_MALLOC_FAILED; 6641\end_layout 6642 6643\begin_layout Plain Layout 6644 6645 res = zeDeviceGet(drivers[j], &numDevices, deviceList); 6646\end_layout 6647 6648\begin_layout Plain Layout 6649 6650 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_GET_DEVICE; 6651\end_layout 6652 6653\begin_layout Plain Layout 6654 6655 for (uint64_t i = 0; i < numDevices; i++) { 6656\end_layout 6657 6658\begin_layout Plain Layout 6659 6660 if (k == vkGPU->device_id) { 6661\end_layout 6662 6663\begin_layout Plain Layout 6664 6665 vkGPU->driver = drivers[j]; 6666\end_layout 6667 6668\begin_layout Plain Layout 6669 6670 vkGPU->device = deviceList[i]; 6671\end_layout 6672 6673\begin_layout Plain Layout 6674 6675 ze_context_desc_t contextDescription = {}; 6676\end_layout 6677 6678\begin_layout Plain Layout 6679 6680 contextDescription.stype = ZE_STRUCTURE_TYPE_CONTEXT_DESC; 6681\end_layout 6682 6683\begin_layout Plain Layout 6684 6685 res = zeContextCreate(vkGPU->driver, &contextDescription, &vkGPU->context); 6686\end_layout 6687 6688\begin_layout Plain Layout 6689 6690 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_CONTEXT; 6691\end_layout 6692 6693\begin_layout Plain Layout 6694 6695\end_layout 6696 6697\begin_layout Plain Layout 6698 6699 uint32_t queueGroupCount = 0; 6700\end_layout 6701 6702\begin_layout Plain Layout 6703 6704 res = zeDeviceGetCommandQueueGroupProperties(vkGPU->device, &queueGroupCount 6705, 0); 6706\end_layout 6707 6708\begin_layout Plain Layout 6709 6710 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_QU 6711EUE; 6712\end_layout 6713 6714\begin_layout Plain Layout 6715 6716\end_layout 6717 6718\begin_layout Plain Layout 6719 6720 ze_command_queue_group_properties_t* cmdqueueGroupProperties = (ze_command_q 6721ueue_group_properties_t*) malloc(queueGroupCount * sizeof(ze_command_queue_group 6722_properties_t)); 6723\end_layout 6724 6725\begin_layout Plain Layout 6726 6727 if (!cmdqueueGroupProperties) return VKFFT_ERROR_MALLOC_FAILED; 6728\end_layout 6729 6730\begin_layout Plain Layout 6731 6732 res = zeDeviceGetCommandQueueGroupProperties(vkGPU->device, &queueGroupCount 6733, cmdqueueGroupProperties); 6734\end_layout 6735 6736\begin_layout Plain Layout 6737 6738 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_QU 6739EUE; 6740\end_layout 6741 6742\begin_layout Plain Layout 6743 6744\end_layout 6745 6746\begin_layout Plain Layout 6747 6748 uint32_t commandQueueID = -1; 6749\end_layout 6750 6751\begin_layout Plain Layout 6752 6753 for (uint32_t i = 0; i < queueGroupCount; ++i) { 6754\end_layout 6755 6756\begin_layout Plain Layout 6757 6758 if ((cmdqueueGroupProperties[i].flags && ZE_COMMAND_QUEUE_GROUP_PROPERTY_FLA 6759G_COMPUTE) && (cmdqueueGroupProperties[i].flags && ZE_COMMAND_QUEUE_GROUP_PROPERT 6760Y_FLAG_COPY)) { 6761\end_layout 6762 6763\begin_layout Plain Layout 6764 6765 commandQueueID = i; 6766\end_layout 6767 6768\begin_layout Plain Layout 6769 6770 break; 6771\end_layout 6772 6773\begin_layout Plain Layout 6774 6775 } 6776\end_layout 6777 6778\begin_layout Plain Layout 6779 6780 } 6781\end_layout 6782 6783\begin_layout Plain Layout 6784 6785 if (commandQueueID == -1) return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_QUEUE; 6786\end_layout 6787 6788\begin_layout Plain Layout 6789 6790 vkGPU->commandQueueID = commandQueueID; 6791\end_layout 6792 6793\begin_layout Plain Layout 6794 6795 ze_command_queue_desc_t commandQueueDescription = {}; 6796\end_layout 6797 6798\begin_layout Plain Layout 6799 6800 commandQueueDescription.stype = ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC; 6801\end_layout 6802 6803\begin_layout Plain Layout 6804 6805 commandQueueDescription.ordinal = commandQueueID; 6806\end_layout 6807 6808\begin_layout Plain Layout 6809 6810 commandQueueDescription.priority = ZE_COMMAND_QUEUE_PRIORITY_NORMAL; 6811\end_layout 6812 6813\begin_layout Plain Layout 6814 6815 commandQueueDescription.mode = ZE_COMMAND_QUEUE_MODE_DEFAULT; 6816\end_layout 6817 6818\begin_layout Plain Layout 6819 6820 res = zeCommandQueueCreate(vkGPU->context, vkGPU->device, &commandQueueDescr 6821iption, &vkGPU->commandQueue); 6822\end_layout 6823 6824\begin_layout Plain Layout 6825 6826 if (res != ZE_RESULT_SUCCESS) return VKFFT_ERROR_FAILED_TO_CREATE_COMMAND_QU 6827EUE; 6828\end_layout 6829 6830\begin_layout Plain Layout 6831 6832 free(cmdqueueGroupProperties); 6833\end_layout 6834 6835\begin_layout Plain Layout 6836 6837 i=numDevices; 6838\end_layout 6839 6840\begin_layout Plain Layout 6841 6842 j=numPlatforms; 6843\end_layout 6844 6845\begin_layout Plain Layout 6846 6847 } 6848\end_layout 6849 6850\begin_layout Plain Layout 6851 6852 else { 6853\end_layout 6854 6855\begin_layout Plain Layout 6856 6857 k++; 6858\end_layout 6859 6860\begin_layout Plain Layout 6861 6862 } 6863\end_layout 6864 6865\begin_layout Plain Layout 6866 6867 } 6868\end_layout 6869 6870\begin_layout Plain Layout 6871 6872\end_layout 6873 6874\begin_layout Plain Layout 6875 6876 free(deviceList); 6877\end_layout 6878 6879\begin_layout Plain Layout 6880 6881 } 6882\end_layout 6883 6884\begin_layout Plain Layout 6885 6886 free(drivers); 6887\end_layout 6888 6889\begin_layout Plain Layout 6890 6891#elif(VKFFT_BACKEND==5) 6892\end_layout 6893 6894\begin_layout Plain Layout 6895 6896 NS::Array* devices = MTL::CopyAllDevices(); 6897\end_layout 6898 6899\begin_layout Plain Layout 6900 6901 MTL::Device* device = (MTL::Device*)devices->object(vkGPU->device_id); 6902\end_layout 6903 6904\begin_layout Plain Layout 6905 6906 vkGPU->device = device; 6907\end_layout 6908 6909\begin_layout Plain Layout 6910 6911 MTL::CommandQueue* queue = device->newCommandQueue(); 6912\end_layout 6913 6914\begin_layout Plain Layout 6915 6916 vkGPU->queue = queue; 6917\end_layout 6918 6919\begin_layout Plain Layout 6920 6921#endif 6922\end_layout 6923 6924\begin_layout Plain Layout 6925 6926 6927\backslash 6928end{minted} 6929\end_layout 6930 6931\begin_layout Plain Layout 6932 6933 6934\backslash 6935end{mdframed} 6936\end_layout 6937 6938\end_inset 6939 6940 6941\end_layout 6942 6943\begin_layout Subsection 6944Simple FFT application example: 1D (one dimensional) C2C (complex to complex) 6945 FP32 (single precision) FFT 6946\end_layout 6947 6948\begin_layout Standard 6949This example performs the simplest case of FFT. 6950 It shows all the necessary fields that the user must fill during the configurat 6951ion and the submission process. 6952 Other samples will build on this one, as driver parameters initialization 6953 and code execution commands are the same for all configurations (except 6954 for the launch parameters that can be configured after application creation). 6955\end_layout 6956 6957\begin_layout Standard 6958\begin_inset ERT 6959status open 6960 6961\begin_layout Plain Layout 6962 6963 6964\backslash 6965begin{mdframed}[backgroundcolor=bg] 6966\end_layout 6967 6968\begin_layout Plain Layout 6969 6970 6971\backslash 6972begin{minted}[tabsize=4,obeytabs,breaklines]{C} 6973\end_layout 6974 6975\begin_layout Plain Layout 6976 6977//zero-initialize configuration + FFT application 6978\end_layout 6979 6980\begin_layout Plain Layout 6981 6982VkFFTConfiguration configuration = {}; 6983\end_layout 6984 6985\begin_layout Plain Layout 6986 6987VkFFTApplication app = {}; 6988\end_layout 6989 6990\begin_layout Plain Layout 6991 6992\end_layout 6993 6994\begin_layout Plain Layout 6995 6996configuration.FFTdim = 1; //FFT dimension 6997\end_layout 6998 6999\begin_layout Plain Layout 7000 7001configuration.size[0] = Nx; //FFT size 7002\end_layout 7003 7004\begin_layout Plain Layout 7005 7006uint64_t bufferSize = (uint64_t)sizeof(float) * 2 * configuration.size[0]; 7007\end_layout 7008 7009\begin_layout Plain Layout 7010 7011\end_layout 7012 7013\begin_layout Plain Layout 7014 7015//Device management + code submission 7016\end_layout 7017 7018\begin_layout Plain Layout 7019 7020#if(VKFFT_BACKEND==5) 7021\end_layout 7022 7023\begin_layout Plain Layout 7024 7025configuration.device = vkGPU->device; 7026\end_layout 7027 7028\begin_layout Plain Layout 7029 7030#else 7031\end_layout 7032 7033\begin_layout Plain Layout 7034 7035configuration.device = &vkGPU->device; 7036\end_layout 7037 7038\begin_layout Plain Layout 7039 7040#endif 7041\end_layout 7042 7043\begin_layout Plain Layout 7044 7045\end_layout 7046 7047\begin_layout Plain Layout 7048 7049#if(VKFFT_BACKEND==0) //Vulkan API 7050\end_layout 7051 7052\begin_layout Plain Layout 7053 7054configuration.queue = &vkGPU->queue; 7055\end_layout 7056 7057\begin_layout Plain Layout 7058 7059configuration.fence = &vkGPU->fence; 7060\end_layout 7061 7062\begin_layout Plain Layout 7063 7064configuration.commandPool = &vkGPU->commandPool; 7065\end_layout 7066 7067\begin_layout Plain Layout 7068 7069configuration.physicalDevice = &vkGPU->physicalDevice; 7070\end_layout 7071 7072\begin_layout Plain Layout 7073 7074configuration.isCompilerInitialized = isCompilerInitialized; //glslang compiler 7075 can be initialized before VkFFT plan creation. 7076 if not, VkFFT will create and destroy one after initialization 7077\end_layout 7078 7079\begin_layout Plain Layout 7080 7081#elif(VKFFT_BACKEND==3) //OpenCL API 7082\end_layout 7083 7084\begin_layout Plain Layout 7085 7086configuration.context = &vkGPU->context; 7087\end_layout 7088 7089\begin_layout Plain Layout 7090 7091#elif(VKFFT_BACKEND==4) 7092\end_layout 7093 7094\begin_layout Plain Layout 7095 7096configuration.context = &vkGPU->context; 7097\end_layout 7098 7099\begin_layout Plain Layout 7100 7101configuration.commandQueue = &vkGPU->commandQueue; 7102\end_layout 7103 7104\begin_layout Plain Layout 7105 7106configuration.commandQueueID = vkGPU->commandQueueID; 7107\end_layout 7108 7109\begin_layout Plain Layout 7110 7111#elif(VKFFT_BACKEND==5) 7112\end_layout 7113 7114\begin_layout Plain Layout 7115 7116configuration.queue = vkGPU->queue; 7117\end_layout 7118 7119\begin_layout Plain Layout 7120 7121#endif 7122\end_layout 7123 7124\begin_layout Plain Layout 7125 7126\end_layout 7127 7128\begin_layout Plain Layout 7129 7130allocateBuffer(buffer, bufferSize); //Pseudocode for buffer allocation, 7131 differs between APIs 7132\end_layout 7133 7134\begin_layout Plain Layout 7135 7136transferDataFromCPU(buffer, cpu_buffer); //Pseudocode for data transfer 7137 from CPU to GPU, differs between APIs 7138\end_layout 7139 7140\begin_layout Plain Layout 7141 7142\end_layout 7143 7144\begin_layout Plain Layout 7145 7146#if(VKFFT_BACKEND==0) //Vulkan API needs bufferSize at initialization 7147\end_layout 7148 7149\begin_layout Plain Layout 7150 7151configuration.bufferSize = &bufferSize; 7152\end_layout 7153 7154\begin_layout Plain Layout 7155 7156#endif 7157\end_layout 7158 7159\begin_layout Plain Layout 7160 7161\end_layout 7162 7163\begin_layout Plain Layout 7164 7165VkFFTResult resFFT = initializeVkFFT(&app, configuration); 7166\end_layout 7167 7168\begin_layout Plain Layout 7169 7170\end_layout 7171 7172\begin_layout Plain Layout 7173 7174VkFFTLaunchParams launchParams = {}; 7175\end_layout 7176 7177\begin_layout Plain Layout 7178 7179launchParams.buffer = &buffer; 7180\end_layout 7181 7182\begin_layout Plain Layout 7183 7184#if(VKFFT_BACKEND==0) //Vulkan API 7185\end_layout 7186 7187\begin_layout Plain Layout 7188 7189launchParams.commandBuffer = &commandBuffer; 7190\end_layout 7191 7192\begin_layout Plain Layout 7193 7194#elif(VKFFT_BACKEND==3) //OpenCL API 7195\end_layout 7196 7197\begin_layout Plain Layout 7198 7199launchParams.commandQueue = &commandQueue; 7200\end_layout 7201 7202\begin_layout Plain Layout 7203 7204#elif(VKFFT_BACKEND==4) //Level Zero API 7205\end_layout 7206 7207\begin_layout Plain Layout 7208 7209launchParams->commandList = &commandList; 7210\end_layout 7211 7212\begin_layout Plain Layout 7213 7214#elif(VKFFT_BACKEND==5) //Metal API 7215\end_layout 7216 7217\begin_layout Plain Layout 7218 7219launchParams->commandBuffer = commandBuffer; 7220\end_layout 7221 7222\begin_layout Plain Layout 7223 7224launchParams->commandEncoder = commandEncoder; 7225\end_layout 7226 7227\begin_layout Plain Layout 7228 7229#endif 7230\end_layout 7231 7232\begin_layout Plain Layout 7233 7234resFFT = VkFFTAppend(app, -1, &launchParams); 7235\end_layout 7236 7237\begin_layout Plain Layout 7238 7239\end_layout 7240 7241\begin_layout Plain Layout 7242 7243//add synchronization relevant to your API - vkWaitForFences/cudaDeviceSynchroni 7244ze/hipDeviceSynchronize/clFinish 7245\end_layout 7246 7247\begin_layout Plain Layout 7248 7249transferDataToCPU(cpu_buffer, buffer); //Pseudocode for data transfer from 7250 GPU to CPU, differs between APIs 7251\end_layout 7252 7253\begin_layout Plain Layout 7254 7255\end_layout 7256 7257\begin_layout Plain Layout 7258 7259freeBuffer(buffer, bufferSize); //Pseudocode for buffer deallocation, differs 7260 between APIs 7261\end_layout 7262 7263\begin_layout Plain Layout 7264 7265\end_layout 7266 7267\begin_layout Plain Layout 7268 7269deleteVkFFT(&app); 7270\end_layout 7271 7272\begin_layout Plain Layout 7273 7274 7275\backslash 7276end{minted} 7277\end_layout 7278 7279\begin_layout Plain Layout 7280 7281 7282\backslash 7283end{mdframed} 7284\end_layout 7285 7286\end_inset 7287 7288 7289\end_layout 7290 7291\begin_layout Subsection 7292Advanced FFT application example: ND, C2C/R2C/R2R, different precisions, 7293 batched FFT 7294\end_layout 7295 7296\begin_layout Standard 7297This example shows how to configure the main parameters of interest in the 7298 VkFFT library: multidimensional case, different types of transforms, different 7299 precision, perform batched transforms. 7300\end_layout 7301 7302\begin_layout Standard 7303In the code below X, Y and Z are the dimensions of FFT, B - number of batches, 7304 R2C - real to complex mode 0 or 1 (on/off), DCT - 0, 1, 2, 3 or 4 (off/DCT 7305 type), P - precision (0 - single, 1 - double, 2 - half). 7306\end_layout 7307 7308\begin_layout Standard 7309\begin_inset ERT 7310status open 7311 7312\begin_layout Plain Layout 7313 7314 7315\backslash 7316begin{mdframed}[backgroundcolor=bg] 7317\end_layout 7318 7319\begin_layout Plain Layout 7320 7321 7322\backslash 7323begin{minted}[tabsize=4,obeytabs,breaklines]{C} 7324\end_layout 7325 7326\begin_layout Plain Layout 7327 7328//zero-initialize configuration + FFT application 7329\end_layout 7330 7331\begin_layout Plain Layout 7332 7333VkFFTConfiguration configuration = {}; 7334\end_layout 7335 7336\begin_layout Plain Layout 7337 7338VkFFTApplication app = {}; 7339\end_layout 7340 7341\begin_layout Plain Layout 7342 7343\end_layout 7344 7345\begin_layout Plain Layout 7346 7347configuration.FFTdim = 1; //FFT dimension 7348\end_layout 7349 7350\begin_layout Plain Layout 7351 7352configuration.size[0] = X; 7353\end_layout 7354 7355\begin_layout Plain Layout 7356 7357configuration.size[1] = Y; 7358\end_layout 7359 7360\begin_layout Plain Layout 7361 7362configuration.size[2] = Z; 7363\end_layout 7364 7365\begin_layout Plain Layout 7366 7367if (Y > 1) configuration.FFTdim++; 7368\end_layout 7369 7370\begin_layout Plain Layout 7371 7372if (Z > 1) configuration.FFTdim++; 7373\end_layout 7374 7375\begin_layout Plain Layout 7376 7377configuration.numberBatches = B; 7378\end_layout 7379 7380\begin_layout Plain Layout 7381 7382configuration.performR2C = R2C; 7383\end_layout 7384 7385\begin_layout Plain Layout 7386 7387configuration.performDCT = DCT; 7388\end_layout 7389 7390\begin_layout Plain Layout 7391 7392if (P == 1) configuration.doublePrecision = 1; 7393\end_layout 7394 7395\begin_layout Plain Layout 7396 7397if (P == 2) configuration.halfPrecision = 1; 7398\end_layout 7399 7400\begin_layout Plain Layout 7401 7402if (P == 3) configuration.quadDoubleDoublePrecision = 1; 7403\end_layout 7404 7405\begin_layout Plain Layout 7406 7407\end_layout 7408 7409\begin_layout Plain Layout 7410 7411uint64_t bufferSize = 0; 7412\end_layout 7413 7414\begin_layout Plain Layout 7415 7416\end_layout 7417 7418\begin_layout Plain Layout 7419 7420if (R2C) { 7421\end_layout 7422 7423\begin_layout Plain Layout 7424 7425 bufferSize = (uint64_t)(storageComplexSize / 2) * (configuration.size[0] 7426 + 2) * configuration.size[1] * configuration.size[2] * configuration.numberBatches 7427; 7428\end_layout 7429 7430\begin_layout Plain Layout 7431 7432} 7433\end_layout 7434 7435\begin_layout Plain Layout 7436 7437else { 7438\end_layout 7439 7440\begin_layout Plain Layout 7441 7442 if (DCT) { 7443\end_layout 7444 7445\begin_layout Plain Layout 7446 7447 bufferSize = (uint64_t)(storageComplexSize / 2) * configuration.size[0] 7448 * configuration.size[1] * configuration.size[2] * configuration.numberBatches; 7449\end_layout 7450 7451\begin_layout Plain Layout 7452 7453 } 7454\end_layout 7455 7456\begin_layout Plain Layout 7457 7458 else { 7459\end_layout 7460 7461\begin_layout Plain Layout 7462 7463 bufferSize = (uint64_t)storageComplexSize * configuration.size[0] * configurati 7464on.size[1] * configuration.size[2] * configuration.numberBatches; 7465\end_layout 7466 7467\begin_layout Plain Layout 7468 7469 } 7470\end_layout 7471 7472\begin_layout Plain Layout 7473 7474} // storageComplexSize - 4/8/16 for FP16/FP32/FP64 respectively. 7475\end_layout 7476 7477\begin_layout Plain Layout 7478 7479\end_layout 7480 7481\begin_layout Plain Layout 7482 7483//Device management + code submission - code is identical to the previous 7484 example 7485\end_layout 7486 7487\begin_layout Plain Layout 7488 7489 7490\backslash 7491end{minted} 7492\end_layout 7493 7494\begin_layout Plain Layout 7495 7496 7497\backslash 7498end{mdframed} 7499\end_layout 7500 7501\end_inset 7502 7503 7504\end_layout 7505 7506\begin_layout Subsection 7507Advanced FFT application example: out-of-place R2C FFT with custom strides 7508\end_layout 7509 7510\begin_layout Standard 7511In this example, VkFFT is configured to calculate a 3D out-of-place R2C 7512 FFT of a system with custom strides. 7513 VkFFT reads data from the inputBuffer and produces the result in the buffer. 7514 7515\end_layout 7516 7517\begin_layout Standard 7518\begin_inset ERT 7519status open 7520 7521\begin_layout Plain Layout 7522 7523 7524\backslash 7525begin{mdframed}[backgroundcolor=bg] 7526\end_layout 7527 7528\begin_layout Plain Layout 7529 7530 7531\backslash 7532begin{minted}[tabsize=4,obeytabs,breaklines]{C} 7533\end_layout 7534 7535\begin_layout Plain Layout 7536 7537//zero-initialize configuration + FFT application 7538\end_layout 7539 7540\begin_layout Plain Layout 7541 7542VkFFTConfiguration configuration = {}; 7543\end_layout 7544 7545\begin_layout Plain Layout 7546 7547VkFFTApplication app = {}; 7548\end_layout 7549 7550\begin_layout Plain Layout 7551 7552\end_layout 7553 7554\begin_layout Plain Layout 7555 7556configuration.FFTdim = 3; //FFT dimension 7557\end_layout 7558 7559\begin_layout Plain Layout 7560 7561configuration.size[0] = Nx; 7562\end_layout 7563 7564\begin_layout Plain Layout 7565 7566configuration.size[1] = Ny; 7567\end_layout 7568 7569\begin_layout Plain Layout 7570 7571configuration.size[2] = Nz; 7572\end_layout 7573 7574\begin_layout Plain Layout 7575 7576\end_layout 7577 7578\begin_layout Plain Layout 7579 7580configuration.performR2C = 1; 7581\end_layout 7582 7583\begin_layout Plain Layout 7584 7585\end_layout 7586 7587\begin_layout Plain Layout 7588 7589//out-of-place - we need to specify that input buffer is separate from the 7590 main buffer 7591\end_layout 7592 7593\begin_layout Plain Layout 7594 7595configuration.isInputFormatted = 1; 7596\end_layout 7597 7598\begin_layout Plain Layout 7599 7600configuration.inputBufferStride[0] = configuration.size[0]; 7601\end_layout 7602 7603\begin_layout Plain Layout 7604 7605configuration.inputBufferStride[1] = configuration.inputBufferStride[0] * 7606 configuration.size[1]; 7607\end_layout 7608 7609\begin_layout Plain Layout 7610 7611configuration.inputBufferStride[2] = configuration.inputBufferStride[1] * 7612 configuration.size[2]; 7613\end_layout 7614 7615\begin_layout Plain Layout 7616 7617 7618\end_layout 7619 7620\begin_layout Plain Layout 7621 7622configuration.bufferStride[0] = (uint64_t) (configuration.size[0] / 2) + 1; 7623\end_layout 7624 7625\begin_layout Plain Layout 7626 7627configuration.bufferStride[1] = configuration.bufferStride[0] * configuration.size[ 76281]; 7629\end_layout 7630 7631\begin_layout Plain Layout 7632 7633configuration.bufferStride[2] = configuration.bufferStride[1]* configuration.size[2 7634]; 7635\end_layout 7636 7637\begin_layout Plain Layout 7638 7639\end_layout 7640 7641\begin_layout Plain Layout 7642 7643uint64_t inputBufferSize = (uint64_t)sizeof(float) * configuration.size[0] 7644 * configuration.size[1] * configuration.size[2]; 7645\end_layout 7646 7647\begin_layout Plain Layout 7648 7649\end_layout 7650 7651\begin_layout Plain Layout 7652 7653uint64_t bufferSize = (uint64_t)sizeof(float) * 2 * (configuration.size[0]/2+1) 7654 * configuration.size[1] * configuration.size[2]; 7655\end_layout 7656 7657\begin_layout Plain Layout 7658 7659\end_layout 7660 7661\begin_layout Plain Layout 7662 7663//Device management + code submission - code is identical to the first example, 7664 except that you need to allocate two buffers (and provide them in the launch 7665 configuration). 7666\end_layout 7667 7668\begin_layout Plain Layout 7669 7670\end_layout 7671 7672\begin_layout Plain Layout 7673 7674 7675\backslash 7676end{minted} 7677\end_layout 7678 7679\begin_layout Plain Layout 7680 7681 7682\backslash 7683end{mdframed} 7684\end_layout 7685 7686\end_inset 7687 7688 7689\end_layout 7690 7691\begin_layout Subsection 7692Advanced FFT application example: 3D FFT with innermost batching 7693\end_layout 7694 7695\begin_layout Standard 7696In this example, VkFFT is configured to calculate a 3D in-place C2C FFT 7697 of a system with innermost (fast axis) batching. 7698 7699\end_layout 7700 7701\begin_layout Standard 7702\begin_inset ERT 7703status open 7704 7705\begin_layout Plain Layout 7706 7707 7708\backslash 7709begin{mdframed}[backgroundcolor=bg] 7710\end_layout 7711 7712\begin_layout Plain Layout 7713 7714 7715\backslash 7716begin{minted}[tabsize=4,obeytabs,breaklines]{C} 7717\end_layout 7718 7719\begin_layout Plain Layout 7720 7721//zero-initialize configuration + FFT application 7722\end_layout 7723 7724\begin_layout Plain Layout 7725 7726VkFFTConfiguration configuration = {}; 7727\end_layout 7728 7729\begin_layout Plain Layout 7730 7731VkFFTApplication app = {}; 7732\end_layout 7733 7734\begin_layout Plain Layout 7735 7736\end_layout 7737 7738\begin_layout Plain Layout 7739 7740configuration.FFTdim = 4; //FFT dimension, 3+1 7741\end_layout 7742 7743\begin_layout Plain Layout 7744 7745configuration.size[0] = Nbatch; 7746\end_layout 7747 7748\begin_layout Plain Layout 7749 7750configuration.size[1] = Nx; 7751\end_layout 7752 7753\begin_layout Plain Layout 7754 7755configuration.size[2] = Ny; 7756\end_layout 7757 7758\begin_layout Plain Layout 7759 7760configuration.size[3] = Nz; 7761\end_layout 7762 7763\begin_layout Plain Layout 7764 7765\end_layout 7766 7767\begin_layout Plain Layout 7768 7769configuration.omitDimension[0] = 1; // disable FFT over the batching dimension 7770\end_layout 7771 7772\begin_layout Plain Layout 7773 7774\end_layout 7775 7776\begin_layout Plain Layout 7777 7778uint64_t bufferSize = (uint64_t)sizeof(float) * configuration.size[0] * configura 7779tion.size[1] * configuration.size[2] * configuration.size[3]; 7780\end_layout 7781 7782\begin_layout Plain Layout 7783 7784\end_layout 7785 7786\begin_layout Plain Layout 7787 7788//Device management + code submission - code is identical to the first example, 7789 except that you need to allocate two buffers (and provide them in the launch 7790 configuration). 7791\end_layout 7792 7793\begin_layout Plain Layout 7794 7795\end_layout 7796 7797\begin_layout Plain Layout 7798 7799 7800\backslash 7801end{minted} 7802\end_layout 7803 7804\begin_layout Plain Layout 7805 7806 7807\backslash 7808end{mdframed} 7809\end_layout 7810 7811\end_inset 7812 7813 7814\end_layout 7815 7816\begin_layout Subsection 7817Advanced FFT application example: 3D zero-padded FFT 7818\end_layout 7819 7820\begin_layout Standard 7821In this example, VkFFT is configured to calculate a 3D FFT of a system. 7822 The meaningful data is located in the first octant of the buffer, the rest 7823 is padded with zeros. 7824 This configuration removes the circular part of the convolution and allows 7825 modelling of open systems. 7826\end_layout 7827 7828\begin_layout Standard 7829\begin_inset ERT 7830status open 7831 7832\begin_layout Plain Layout 7833 7834 7835\backslash 7836begin{mdframed}[backgroundcolor=bg] 7837\end_layout 7838 7839\begin_layout Plain Layout 7840 7841 7842\backslash 7843begin{minted}[tabsize=4,obeytabs,breaklines]{C} 7844\end_layout 7845 7846\begin_layout Plain Layout 7847 7848//zero-initialize configuration + FFT application 7849\end_layout 7850 7851\begin_layout Plain Layout 7852 7853VkFFTConfiguration configuration = {}; 7854\end_layout 7855 7856\begin_layout Plain Layout 7857 7858VkFFTApplication app = {}; 7859\end_layout 7860 7861\begin_layout Plain Layout 7862 7863\end_layout 7864 7865\begin_layout Plain Layout 7866 7867configuration.FFTdim = 3; //FFT dimension 7868\end_layout 7869 7870\begin_layout Plain Layout 7871 7872configuration.size[0] = Nx; 7873\end_layout 7874 7875\begin_layout Plain Layout 7876 7877configuration.size[1] = Ny; 7878\end_layout 7879 7880\begin_layout Plain Layout 7881 7882configuration.size[2] = Nz; 7883\end_layout 7884 7885\begin_layout Plain Layout 7886 7887\end_layout 7888 7889\begin_layout Plain Layout 7890 7891configuration.performZeropadding[0] = 1; //Perform padding with zeros on 7892 GPU. 7893 Still need to properly align input data (no need to fill padding area with 7894 meaningful data) but this will increase performance due to the lower amount 7895 of the memory reads/writes and omitting sequences only consisting of zeros. 7896\end_layout 7897 7898\begin_layout Plain Layout 7899 7900configuration.performZeropadding[1] = 1; 7901\end_layout 7902 7903\begin_layout Plain Layout 7904 7905configuration.performZeropadding[2] = 1; 7906\end_layout 7907 7908\begin_layout Plain Layout 7909 7910configuration.fft_zeropad_left[0] = (uint64_t)ceil(configuration.size[0] / 7911 2.0); 7912\end_layout 7913 7914\begin_layout Plain Layout 7915 7916configuration.fft_zeropad_right[0] = configuration.size[0]; 7917\end_layout 7918 7919\begin_layout Plain Layout 7920 7921configuration.fft_zeropad_left[1] = (uint64_t)ceil(configuration.size[1] / 7922 2.0); 7923\end_layout 7924 7925\begin_layout Plain Layout 7926 7927configuration.fft_zeropad_right[1] = configuration.size[1]; 7928\end_layout 7929 7930\begin_layout Plain Layout 7931 7932configuration.fft_zeropad_left[2] = (uint64_t)ceil(configuration.size[2] / 7933 2.0); 7934\end_layout 7935 7936\begin_layout Plain Layout 7937 7938configuration.fft_zeropad_right[2] = configuration.size[2]; 7939\end_layout 7940 7941\begin_layout Plain Layout 7942 7943\end_layout 7944 7945\begin_layout Plain Layout 7946 7947uint64_t bufferSize = (uint64_t)storageComplexSize * configuration.size[0] 7948 * configuration.size[1] * configuration.size[2]; 7949\end_layout 7950 7951\begin_layout Plain Layout 7952 7953\end_layout 7954 7955\begin_layout Plain Layout 7956 7957\end_layout 7958 7959\begin_layout Plain Layout 7960 7961//Device management + code submission - code is identical to the first example 7962\end_layout 7963 7964\begin_layout Plain Layout 7965 7966\end_layout 7967 7968\begin_layout Plain Layout 7969 7970 7971\backslash 7972end{minted} 7973\end_layout 7974 7975\begin_layout Plain Layout 7976 7977 7978\backslash 7979end{mdframed} 7980\end_layout 7981 7982\end_inset 7983 7984 7985\end_layout 7986 7987\begin_layout Subsection 7988Convolution application example: 3x3 matrix-vector convolution in 1D 7989\end_layout 7990 7991\begin_layout Standard 7992In this example, VkFFT is configured to calculate a kernel, represented 7993 by a 3x3 matrix and a system, represented by a 3D vector. 7994 Their convolution is a matrix-vector multiplication in the frequency domain. 7995\end_layout 7996 7997\begin_layout Standard 7998\begin_inset ERT 7999status open 8000 8001\begin_layout Plain Layout 8002 8003 8004\backslash 8005begin{mdframed}[backgroundcolor=bg] 8006\end_layout 8007 8008\begin_layout Plain Layout 8009 8010 8011\backslash 8012begin{minted}[tabsize=4,obeytabs,breaklines]{C} 8013\end_layout 8014 8015\begin_layout Plain Layout 8016 8017//zero-initialize configuration + FFT application, we need two - one for 8018 kernel calculation 8019\end_layout 8020 8021\begin_layout Plain Layout 8022 8023VkFFTConfiguration kernel_configuration = {}; 8024\end_layout 8025 8026\begin_layout Plain Layout 8027 8028VkFFTConfiguration convolution_configuration = {}; 8029\end_layout 8030 8031\begin_layout Plain Layout 8032 8033VkFFTApplication app_kernel = {}; 8034\end_layout 8035 8036\begin_layout Plain Layout 8037 8038VkFFTApplication app_convolution = {}; 8039\end_layout 8040 8041\begin_layout Plain Layout 8042 8043\end_layout 8044 8045\begin_layout Plain Layout 8046 8047\end_layout 8048 8049\begin_layout Plain Layout 8050 8051kernel_configuration.FFTdim = 1; //FFT dimension 8052\end_layout 8053 8054\begin_layout Plain Layout 8055 8056kernel_configuration.size[0] = Nx; //FFT size 8057\end_layout 8058 8059\begin_layout Plain Layout 8060 8061\end_layout 8062 8063\begin_layout Plain Layout 8064 8065uint64_t bufferSize = (uint64_t)sizeof(float) * 2 * kernel_configuration.size[0]; 8066\end_layout 8067 8068\begin_layout Plain Layout 8069 8070\end_layout 8071 8072\begin_layout Plain Layout 8073 8074//configure kernel 8075\end_layout 8076 8077\begin_layout Plain Layout 8078 8079kernel_configuration.kernelConvolution = 1; //specify if this plan is used 8080 to create kernel for convolution 8081\end_layout 8082 8083\begin_layout Plain Layout 8084 8085kernel_configuration.coordinateFeatures = 9; //Specify dimensionality of 8086 the input feature vector (default 1). 8087 Each component is stored not as a vector, but as a separate system and 8088 padded on it's own according to other options (i.e. 8089 for x*y system of 3-vector, first x*y elements correspond to the first 8090 dimension, then goes x*y for the second, etc). 8091\end_layout 8092 8093\begin_layout Plain Layout 8094 8095//coordinateFeatures number is an important constant for convolution. 8096 If we perform 1x1 convolution, it is equal to number of features, but matrixCon 8097volution should be equal to 1. 8098 For matrix convolution, it must be equal to matrixConvolution parameter. 8099 If we perform 2x2 convolution, it is equal to 3 for symmetric kernel (stored 8100 as xx, xy, yy) and 4 for nonsymmetric (stored as xx, xy, yx, yy). 8101 Similarly, 6 (stored as xx, xy, xz, yy, yz, zz) and 9 (stored as xx, xy, 8102 xz, yx, yy, yz, zx, zy, zz) for 3x3 convolutions. 8103 8104\end_layout 8105 8106\begin_layout Plain Layout 8107 8108kernel_configuration.normalize = 1; 8109\end_layout 8110 8111\begin_layout Plain Layout 8112 8113\end_layout 8114 8115\begin_layout Plain Layout 8116 8117//Initialize app_kernel and perform a single forward FFT like in examples 8118 before. 8119 You pass kernel as a buffer for the preparation stage. 8120\end_layout 8121 8122\begin_layout Plain Layout 8123 8124\end_layout 8125 8126\begin_layout Plain Layout 8127 8128convolution_configuration = kernel_configuration; 8129\end_layout 8130 8131\begin_layout Plain Layout 8132 8133convolution_configuration.kernelConvolution = 0; 8134\end_layout 8135 8136\begin_layout Plain Layout 8137 8138convolution_configuration.performConvolution = 1; 8139\end_layout 8140 8141\begin_layout Plain Layout 8142 8143convolution_configuration.symmetricKernel = 0;//Specify if convolution kernel 8144 is symmetric. 8145 In this case we only pass upper triangle part of it in the form of: (xx, 8146 xy, yy) for 2d and (xx, xy, xz, yy, yz, zz) for 3d. 8147\end_layout 8148 8149\begin_layout Plain Layout 8150 8151convolution_configuration.matrixConvolution = 3;//we do matrix convolution, 8152 so kernel is 9 numbers (3x3), but vector dimension is 3 8153\end_layout 8154 8155\begin_layout Plain Layout 8156 8157convolution_configuration.coordinateFeatures = 3;//equal to matrixConvolution 8158 size 8159\end_layout 8160 8161\begin_layout Plain Layout 8162 8163\end_layout 8164 8165\begin_layout Plain Layout 8166 8167//Initialize app_convolution and perform a single forward FFT like in examples 8168 before. 8169 You pass kernel as kernel and system to be convolved with it as buffer 8170\end_layout 8171 8172\begin_layout Plain Layout 8173 8174\end_layout 8175 8176\begin_layout Plain Layout 8177 8178 8179\backslash 8180end{minted} 8181\end_layout 8182 8183\begin_layout Plain Layout 8184 8185 8186\backslash 8187end{mdframed} 8188\end_layout 8189 8190\end_inset 8191 8192 8193\end_layout 8194 8195\begin_layout Subsection 8196Convolution application example: R2C cross-correlation between two sets 8197 of N images 8198\end_layout 8199 8200\begin_layout Standard 8201In this example, VkFFT is configured to calculate a kernel, represented 8202 by three 2D vectors (RGB values of a pixel) and a system, also represented 8203 by three 2D vectors. 8204 There are N kernels and N systems. 8205 Their cross-correlation is a conjugate convolution in the frequency domain. 8206 Images are usually stored as real, not complex numbers, so code uses R2C 8207 optimization as well. 8208\end_layout 8209 8210\begin_layout Standard 8211\begin_inset ERT 8212status open 8213 8214\begin_layout Plain Layout 8215 8216 8217\backslash 8218begin{mdframed}[backgroundcolor=bg] 8219\end_layout 8220 8221\begin_layout Plain Layout 8222 8223 8224\backslash 8225begin{minted}[tabsize=4,obeytabs,breaklines]{C} 8226\end_layout 8227 8228\begin_layout Plain Layout 8229 8230//zero-initialize configuration + FFT application, we need two - one for 8231 kernel calculation 8232\end_layout 8233 8234\begin_layout Plain Layout 8235 8236VkFFTConfiguration kernel_configuration = {}; 8237\end_layout 8238 8239\begin_layout Plain Layout 8240 8241VkFFTConfiguration convolution_configuration = {}; 8242\end_layout 8243 8244\begin_layout Plain Layout 8245 8246VkFFTApplication app_kernel = {}; 8247\end_layout 8248 8249\begin_layout Plain Layout 8250 8251VkFFTApplication app_convolution = {}; 8252\end_layout 8253 8254\begin_layout Plain Layout 8255 8256\end_layout 8257 8258\begin_layout Plain Layout 8259 8260\end_layout 8261 8262\begin_layout Plain Layout 8263 8264kernel_configuration.FFTdim = 2; //FFT dimension 8265\end_layout 8266 8267\begin_layout Plain Layout 8268 8269kernel_configuration.size[0] = Nx; 8270\end_layout 8271 8272\begin_layout Plain Layout 8273 8274kernel_configuration.size[1] = Ny; 8275\end_layout 8276 8277\begin_layout Plain Layout 8278 8279kernel_configuration.coordinateFeatures = 3; 8280\end_layout 8281 8282\begin_layout Plain Layout 8283 8284kernel_configuration.numberBatches = N; 8285\end_layout 8286 8287\begin_layout Plain Layout 8288 8289kernel_configuration.performR2C = 1; 8290\end_layout 8291 8292\begin_layout Plain Layout 8293 8294kernel_configuration.normalize = 1; 8295\end_layout 8296 8297\begin_layout Plain Layout 8298 8299\end_layout 8300 8301\begin_layout Plain Layout 8302 8303uint64_t bufferSize = (uint64_t)sizeof(float) * 2 * (kernel_configuration.size[0] 8304/2+1) * kernel_configuration.size[1] * kernel_configuration.coordinateFeatures 8305 * kernel_configuration.numberBatches; 8306\end_layout 8307 8308\begin_layout Plain Layout 8309 8310 8311\end_layout 8312 8313\begin_layout Plain Layout 8314 8315kernel_configuration.kernelConvolution = 1; //specify if this plan is used 8316 to create kernel for convolution 8317\end_layout 8318 8319\begin_layout Plain Layout 8320 8321\end_layout 8322 8323\begin_layout Plain Layout 8324 8325//Initialize app_kernel and perform a single forward FFT like in examples 8326 before. 8327 Pad in-place R2C system like this: 8328\end_layout 8329 8330\begin_layout Plain Layout 8331 8332\end_layout 8333 8334\begin_layout Plain Layout 8335 8336for (uint64_t n = 0; n < kernel_configuration.numberBatches; n++) { 8337\end_layout 8338 8339\begin_layout Plain Layout 8340 8341 for (uint64_t c = 0; c < kernel_configuration.coordinateFeatures; c++) { 8342\end_layout 8343 8344\begin_layout Plain Layout 8345 8346 for (uint64_t j = 0; j < kernel_configuration.size[1]; j++) { 8347\end_layout 8348 8349\begin_layout Plain Layout 8350 8351 for (uint64_t i = 0; i < kernel_configuration.size[0]; i++) { 8352\end_layout 8353 8354\begin_layout Plain Layout 8355 8356 kernel_padded_GPU[i + j * 2 * (kernel_configuration.size[0]/2 + 1) + 8357 c * 2 * (kernel_configuration.size[0]/2 + 1) * kernel_configuration.size[1] 8358 + n * 2 * (kernel_configuration.size[0]/2 + 1) * kernel_configuration.size[1] 8359 * kernel_configuration.coordinateFeatures] = kernel_input[i + j * kernel_configu 8360ration.size[0] + c * kernel_configuration.size[0] * kernel_configuration.size[1] 8361 + n * kernel_configuration.size[0] * kernel_configuration.size[1] * kernel_config 8362uration.coordinateFeatures]; 8363\end_layout 8364 8365\begin_layout Plain Layout 8366 8367 } 8368\end_layout 8369 8370\begin_layout Plain Layout 8371 8372 } 8373\end_layout 8374 8375\begin_layout Plain Layout 8376 8377 } 8378\end_layout 8379 8380\begin_layout Plain Layout 8381 8382} 8383\end_layout 8384 8385\begin_layout Plain Layout 8386 8387convolution_configuration = kernel_configuration; 8388\end_layout 8389 8390\begin_layout Plain Layout 8391 8392convolution_configuration.kernelConvolution = 0; 8393\end_layout 8394 8395\begin_layout Plain Layout 8396 8397convolution_configuration.performConvolution = 1; 8398\end_layout 8399 8400\begin_layout Plain Layout 8401 8402convolution_configuration.conjugateConvolution = 1; 8403\end_layout 8404 8405\begin_layout Plain Layout 8406 8407\end_layout 8408 8409\begin_layout Plain Layout 8410 8411//Initialize app_convolution and perform a single forward FFT like in examples 8412 before. 8413 Pad the system in the same way as the kernel 8414\end_layout 8415 8416\begin_layout Plain Layout 8417 8418\end_layout 8419 8420\begin_layout Plain Layout 8421 8422 8423\backslash 8424end{minted} 8425\end_layout 8426 8427\begin_layout Plain Layout 8428 8429 8430\backslash 8431end{mdframed} 8432\end_layout 8433 8434\end_inset 8435 8436 8437\end_layout 8438 8439\begin_layout Subsection 8440Simple FFT application binary reuse application 8441\end_layout 8442 8443\begin_layout Standard 8444This example shows how to save/load binaries generated by VkFFT. 8445 This can reduce time taken by initializeVkFFT call by removing RTC components 8446 from it. 8447 Be sure that rest of the configuration stays the same to reuse the binary. 8448 Use rb/wb flags to load/save. 8449 This does not currently work in Metal backend. 8450\end_layout 8451 8452\begin_layout Standard 8453\begin_inset ERT 8454status open 8455 8456\begin_layout Plain Layout 8457 8458 8459\backslash 8460begin{mdframed}[backgroundcolor=bg] 8461\end_layout 8462 8463\begin_layout Plain Layout 8464 8465 8466\backslash 8467begin{minted}[tabsize=4,obeytabs,breaklines]{C} 8468\end_layout 8469 8470\begin_layout Plain Layout 8471 8472VkFFTConfiguration configuration = {}; 8473\end_layout 8474 8475\begin_layout Plain Layout 8476 8477VkFFTApplication app = {}; 8478\end_layout 8479 8480\begin_layout Plain Layout 8481 8482\end_layout 8483 8484\begin_layout Plain Layout 8485 8486//configuration is initialized like in other examples 8487\end_layout 8488 8489\begin_layout Plain Layout 8490 8491configuration.saveApplicationToString = 1; 8492\end_layout 8493 8494\begin_layout Plain Layout 8495 8496//configuration.loadApplicationFromString = 1; //choose one to save/load 8497 binary file 8498\end_layout 8499 8500\begin_layout Plain Layout 8501 8502\end_layout 8503 8504\begin_layout Plain Layout 8505 8506if (configuration.loadApplicationFromString) { 8507\end_layout 8508 8509\begin_layout Plain Layout 8510 8511 FILE* kernelCache; 8512\end_layout 8513 8514\begin_layout Plain Layout 8515 8516 uint64_t str_len; 8517\end_layout 8518 8519\begin_layout Plain Layout 8520 8521 kernelCache = fopen("VkFFT_binary", "rb"); 8522\end_layout 8523 8524\begin_layout Plain Layout 8525 8526 fseek(kernelCache, 0, SEEK_END); 8527\end_layout 8528 8529\begin_layout Plain Layout 8530 8531 str_len = ftell(kernelCache); 8532\end_layout 8533 8534\begin_layout Plain Layout 8535 8536 fseek(kernelCache, 0, SEEK_SET); 8537\end_layout 8538 8539\begin_layout Plain Layout 8540 8541 configuration.loadApplicationString = malloc(str_len); 8542\end_layout 8543 8544\begin_layout Plain Layout 8545 8546 fread(configuration.loadApplicationString, str_len, 1, kernelCache); 8547\end_layout 8548 8549\begin_layout Plain Layout 8550 8551 fclose(kernelCache); 8552\end_layout 8553 8554\begin_layout Plain Layout 8555 8556} 8557\end_layout 8558 8559\begin_layout Plain Layout 8560 8561\end_layout 8562 8563\begin_layout Plain Layout 8564 8565resFFT = initializeVkFFT(&app, configuration); 8566\end_layout 8567 8568\begin_layout Plain Layout 8569 8570if (resFFT != VKFFT_SUCCESS) return resFFT; 8571\end_layout 8572 8573\begin_layout Plain Layout 8574 8575\end_layout 8576 8577\begin_layout Plain Layout 8578 8579if (configuration.loadApplicationFromString) 8580\end_layout 8581 8582\begin_layout Plain Layout 8583 8584 free(configuration.loadApplicationString); 8585\end_layout 8586 8587\begin_layout Plain Layout 8588 8589\end_layout 8590 8591\begin_layout Plain Layout 8592 8593if (configuration.saveApplicationToString) { 8594\end_layout 8595 8596\begin_layout Plain Layout 8597 8598 FILE* kernelCache; 8599\end_layout 8600 8601\begin_layout Plain Layout 8602 8603 kernelCache = fopen("VkFFT_binary", "wb"); 8604\end_layout 8605 8606\begin_layout Plain Layout 8607 8608 fwrite(app.saveApplicationString, app.applicationStringSize, 1, kernelCache); 8609\end_layout 8610 8611\begin_layout Plain Layout 8612 8613 fclose(kernelCache); 8614\end_layout 8615 8616\begin_layout Plain Layout 8617 8618} 8619\end_layout 8620 8621\begin_layout Plain Layout 8622 8623\end_layout 8624 8625\begin_layout Plain Layout 8626 8627//application is launched like in other examples 8628\end_layout 8629 8630\begin_layout Plain Layout 8631 8632 8633\backslash 8634end{minted} 8635\end_layout 8636 8637\begin_layout Plain Layout 8638 8639 8640\backslash 8641end{mdframed} 8642\end_layout 8643 8644\end_inset 8645 8646 8647\end_layout 8648 8649\end_body 8650\end_document