VkFFT Documentation

repository·master·Indexed 23 days ago

https://github.com/dtolm/vkfft

An efficient, open-source, GPU-accelerated multidimensional Fast Fourier Transform library. It provides a high-performance alternative to cuFFT with support for multiple backends, including Vulkan, CUDA, HIP, OpenCL, Level Zero, and Metal. The library is header-only and designed to append FFT, iFFT, or convolution calculations to user-defined command buffers using compute shaders.

Tokens
2.3K
Snippets
5
Records
11
Agent score
33%

What's inside VkFFT

  1. Manage object lifetimes with AutoreleasePools

    master

    Methods that do not begin with alloc, new, copy, or mutableCopy typically add the created object to an AutoreleasePool. These objects are released when the pool is drained.

    • Main Thread: The pool is typically drained when the thread returns control to the RunLoop (e.g., at the end of a frame).
    • Additional Threads: You must create and manage an AutoreleasePool for any additional threads you create to prevent memory leaks.
    • Extending Lifetime: If you need an autoreleased object to live longer than the current pool's scope, call retain() on it before the pool is drained. You then become responsible for calling release() later.

    Debugging Leaks

    • Environment Variable: Set OBJC_DEBUG_MISSING_POOLS=YES to print a runtime warning when an autoreleased object is leaked due to a missing enclosing AutoreleasePool on its thread.
    • macOS Tooling: Use leaks --autoreleasePools <process_id> to view a listing of your program's AutoreleasePools and their contents.
  2. Understand metal-cpp memory management and ownership

    master

    metal-cpp follows Cocoa/Cocoa Touch object allocation policies. Because C++ objects are not eligible for Automatic Reference Counting (ARC), you must manually manage lifecycles using reference counting:

    1. Ownership via alloc, new, copy, or mutableCopy: You own any object returned by methods starting with these prefixes. The retainCount is 1.
    2. Taking ownership: Use the retain() method to take ownership of an existing object or to prevent it from being deallocated by other operations.
    3. Relinquishing ownership: When you no longer need an object you own, you must call release() or autorelease().
    4. Do not relinquish what you do not own: Only call release/autorelease on objects you have explicitly retained or obtained via alloc/new/copy.

    Note: When retainCount reaches 0, the object is immediately deallocated. Calling methods on a deallocated object will cause a crash.

  3. How to use VkFFT in your application

    master

    VkFFT is designed to append FFT, iFFT, or convolution calculations to your existing user-defined command buffer.

    Key Integration Concepts:

    • Memory Management: VkFFT operates on storage buffers allocated by the user. It does not require additional memory by itself, except for Lookup Tables (LUT) if they are enabled.
    • Execution: All computations are performed using Vulkan compute shaders with no CPU usage except during the FFT planning stage.
    • Optimization: The library automatically creates and optimizes the memory layout and selects the best parameters for the FFT.
    • Striding: Instead of using transpositions, VkFFT achieves striding by grouping nearby FFTs.

    For a complete implementation guide, refer to the VkFFT_TestSuite.cpp file in the repository, which contains comments explaining the configuration process.

  4. Install VkFFT for different backends

    master

    VkFFT is a header-only library that requires specific backend definitions and dependencies depending on the target API. You must provide the correct VKFFT_BACKEND definition during compilation.

    Vulkan

    • Requirements: vkFFT.h and glslang compiler.
    • Backend Definition: VKFFT_BACKEND=0.
    • Note: Vulkan 1.0 is required for single/double precision; Vulkan 1.1 is required for half precision.

    CUDA/HIP

    • Requirements: vkFFT.h and a system with NVRTC (for CUDA) or HIPRTC (for HIP) built.
    • Backend Definitions:
      • CUDA: VKFFT_BACKEND=1
      • HIP: VKFFT_BACKEND=2

    OpenCL

    • Requirements: vkFFT.h.
    • Backend Definition: VKFFT_BACKEND=3

    Level Zero

    • Requirements: vkFFT.h, Clang, and llvm-spirv must be valid system calls.
    • Backend Definition: VKFFT_BACKEND=4

    Metal

    • Requirements: vkFFT.h and metal-cpp (for C++ bindings to Apple's Foundation, QuartzCore, and Metal libraries).
    • Backend Definition: VKFFT_BACKEND=5
  5. Add metal-cpp to a Project

    master

    To use metal-cpp, include the appropriate header files. To ensure that selector and class symbols are linked, you must define the private implementation macros in exactly one .cpp file before including the headers.

    For standard Metal functionality, include Metal/Metal.hpp with NS_PRIVATE_IMPLEMENTATION and MTL_PRIVATE_IMPLEMENTATION. If you require QuartzCore (e.g., for CAMetalLayer), also define CA_PRIVATE_IMPLEMENTATION and include QuartzCore/QuartzCore.hpp.

    #define NS_PRIVATE_IMPLEMENTATION
    #define MTL_PRIVATE_IMPLEMENTATION
    #include "Metal/Metal.hpp"
    
    // If using QuartzCore:
    #define CA_PRIVATE_IMPLEMENTATION
    #include "QuartzCore/QuartzCore.hpp"
  6. Generate a single header file for metal-cpp

    master

    You can optionally generate a single header file containing all metal-cpp headers using the provided Python script. By default, the output is written to ./SingleHeader/Metal.hpp.

    ./SingleHeader/MakeSingleHeader.py Foundation/Foundation.hpp QuartzCore/QuartzCore.hpp Metal/Metal.hpp
  7. Create a Metal device in C++

    master

    Use MTL::CreateSystemDefaultDevice() to obtain a pointer to the default MTL::Device. Remember to call release() when finished to manage the reference count.

    MTL::Device* pDevice = MTL::CreateSystemDefaultDevice();
    
    // ...
    
    pDevice->release();
  8. Run VkFFT benchmarks via CLI

    master

    To run a benchmark comparing VkFFT and cuFFT on a specific device and save the results to a file, use the following pattern:

    Single Precision Benchmark (Device 0):

    .
    VkFFT_TestSuite.exe -d 0 -o output.txt -vkfft 0 -cufft 0

    Double Precision Benchmark: Replace the sample IDs with 1:

    .
    VkFFT_TestSuite.exe -d 0 -o output.txt -vkfft 1 -cufft 1

    Half Precision Benchmark: Replace the sample IDs with 2:

    .
    VkFFT_TestSuite.exe -d 0 -o output.txt -vkfft 2 -cufft 2
    .
    VkFFT_TestSuite.exe -d 0 -o output.txt -vkfft 0 -cufft 0
  9. Interoperate with CoreFoundation and QuartzCore

    master

    You can bridge between metal-cpp objects and CoreFoundation or Objective-C types using C++ casts.

    CoreFoundation Example:

    MTL::AccelerationStructureTriangleGeometryDescriptor* pGeoDescriptor  = MTL::AccelerationStructureTriangleGeometryDescriptor::alloc()->init();
    CFTypeRef                                             descriptors[]   = { ( CFTypeRef )( pGeoDescriptor ) };
    NS::Array*                                            pGeoDescriptors = ( NS::Array* )( CFArrayCreate( kCFAllocatorDefault, descriptors, SIZEOF_ARRAY( descriptors), &kCFTypeArrayCallBacks ) );
    
    // ...
    
    pGeoDescriptors->release();

    QuartzCore (CAMetalLayer) Example: When working with Objective-C layers, use a bridge cast to access the CA::MetalDrawable.

    CAMetalLayer*         metalLayer         = /* get your layer from your view */;
    id< CAMetalDrawable > metalDrawable      = [metalLayer nextDrawable];
    CA::MetalDrawable*    pMetalCppDrawable  = ( __bridge CA::MetalDrawable* ) metalDrawable;
  10. Use Metal sampler descriptors and states in C++

    master

    Metal function calls map directly to the MTL:: namespace. For example, creating a sampler involves allocating a descriptor, configuring it, and then creating the sampler state from the device.

    MTL::SamplerDescriptor* pSamplerDescriptor = MTL::SamplerDescriptor::alloc()->init();
    
    pSamplerDescriptor->setSAddressMode( MTL::SamplerAddressModeRepeat );
    pSamplerDescriptor->setTAddressMode( MTL::SamplerAddressModeRepeat );
    pSamplerDescriptor->setRAddressMode( MTL::SamplerAddressModeRepeat );
    pSamplerDescriptor->setMagFilter( MTL::SamplerMinMagFilterLinear );
    pSamplerDescriptor->setMinFilter( MTL::SamplerMinMagFilterLinear );
    pSamplerDescriptor->setMipFilter( MTL::SamplerMipFilterLinear );
    pSamplerDescriptor->setSupportArgumentBuffers( true );
    
    MTL::SamplerState* pSamplerState = pDevice->newSamplerState( pSamplerDescriptor );
    
    pSamplerDescriptor->release();
    
    // ...
    
    pSamplerState->release();
  11. VkFFT Command-line Interface Reference

    master

    The VkFFT test suite provides a command-line interface to run benchmarks and samples. Use these flags to control device selection, output, and specific sample execution.

    Note: Some commands like -vkfft, -cufft, and -rocfft require FFTW to be enabled in CMakeLists.txt during the build process.