VulkanCompute - run GPU compute shaders on your waves

Hi all,

I'd like to share an experimental XOP, VulkanCompute, that lets you run a GLSL compute shader on the GPU using Vulkan, with Igor waves as the GPU buffers and Igor scalars as push constants. It's handy when you have a heavy, highly parallel per-element calculation and want to offload it to the GPU.

A demo procedure and full help file are included in the attached zip.

What it does

  • You write a small GLSL compute shader as an Igor string.
  • Input/output waves are bound as std430 storage buffers (SSBOs): /IN waves first, then /OUT waves, all in descriptor set 0.
  • Scalars are passed through a push-constant wave (/PC), marshaled as floats.
  • Results are copied straight back into your output wave.

You don't need to be a GLSL expert. In practice the easiest way to get a shader is to start from one of the provided examples and tweak it, or to ask an AI assistant (ChatGPT, Claude, Copilot, etc.) to generate the GLSL for your calculation - just tell it the binding convention above (/IN waves at bindings 0..N-1, /OUT waves next, scalars in the push-constant block as floats). Paste the result into an Igor string and go.

Two operations

  • VulkanCompute - compile-and-run a GLSL shader on the GPU.
  • VulkanCompileShader - precompile a shader once to a SPIR-V wave, then reuse it via VulkanCompute /SPV=... to skip the per-call compile.

Quick example (waveC = varA*waveA*waveB + varB):

 

The demo .ipf goes further, with a compute-bound example (a per-element transcendental loop) that shows a real GPU speedup, plus a precompile-and-reuse example. To see it in action, just run one of these two functions from the command line:

  • DemoGPUvs1CoreAndMultiCoreCPU() - times the same heavy calculation on the GPU, on a single CPU core, and on all CPU cores via MultiThread, and prints the timings side by side.
  • DemoGPUPrecompiledVsMultiCoreCPU() - same comparison, but the shader is precompiled once with VulkanCompileShader so the GPU timing reflects only the dispatch, not the one-time compile.

A word on performance: the GPU is not a magic "make it faster" button. For simple element-wise math (like the example above), MatrixOp/FastOp on the CPU are typically faster, because the calculation is memory-bandwidth bound and the cost is dominated by moving data to and from the GPU. VulkanCompute pays off when the per-element work is heavy (many operations per value) or when you run many kernels over resident data.

Requirements / installation

  • Igor Pro 10 (64-bit), Windows only. This build targets Igor Pro 10 and is not available for macOS.
  • A Vulkan-capable GPU driver (recent NVIDIA/AMD/Intel drivers already include the Vulkan runtime vulkan-1.dll). No Vulkan SDK is needed.
  • Igor loads only XOPs whose file name ends in 64.xop, so the file must be named VulkanCompute64.xop. Put it (or a shortcut to it) in an Igor Extensions (64-bit) folder and relaunch Igor. Drop the .ihf help file next to it.

Notes / caveats

  • Computation is fp32 by default. Double precision (/DBL) works only if your GPU reports the shaderFloat64 feature.
  • Waves named in /IN and /OUT are resolved in the current data folder.
  • This is an early, main-thread-only build for Igor Pro 10 on Windows - feedback welcome. It is Windows only; a macOS version (via MoltenVK) is not built.

Attached: VulkanCompute.xop, VulkanCompute.ihf, and VulkanCompute_Demo.ipf.

Give it a try and let me know what performance you see on your hardware.

AG

VulkanComputePackage.zip (1.75 MB)
Ben Murphy-Baum

My benchmarks are encouraging, especially when precompiling the shader:

•DemoGPUvs1CoreAndMultiCoreCPU()
  n=200000, iters=2000, threads=32
    GPU        =    366.6 ms
    CPU 1-core =  20815.3 ms  (56.8x slower than GPU)
    CPU N-core =   1074.9 ms  (2.9x slower than GPU, 19.4x faster than 1-core)
    MSE GPU vs CPU = 2.15023e-12,  MSE MT vs 1-core = 0
•DemoGPUPrecompiledVsMultiCoreCPU()
  n=200000, iters=2000, threads=32  (GPU time excludes one-time compile)
    GPU (precompiled) =     12.8 ms
    CPU N-core        =   1030.1 ms  (80.3x slower than GPU)
    MSE GPU vs N-core CPU = 2.15023e-12

This is for an Intel i9-13900K (3.00 GHz) CPU with an RTX 3070 Ti (8 GB) GPU

ggermer

Even though XOP wasn't written for macOS, I wanted to see if Igor 10 could use this XOP on an M4 with Crossover. It seems to be working:

•DemoGPUvs1CoreAndMultiCoreCPU()
  n=200000, iters=2000, threads=10
    GPU        =     88.5 ms
    CPU 1-core =  33312.0 ms  (376.3x slower than GPU)
    CPU N-core =   4766.7 ms  (53.9x slower than GPU, 7.0x faster than 1-core)
    MSE GPU vs CPU = 2.30319e-12,  MSE MT vs 1-core = 0
    
•DemoGPUPrecompiledVsMultiCoreCPU()
 n=200000, iters=2000, threads=10  (GPU time excludes one-time compile)
   GPU (precompiled) =     10.6 ms
   CPU N-core        =   4695.9 ms  (444.0x slower than GPU)
   MSE GPU vs N-core CPU = 2.30319e-12
Igor

On my 4-year-old Windows machine featuring an Intel Core i9-12900K processor and NVIDIA GeForce RTX 3090 graphics card:

•DemoGPUvs1CoreAndMultiCoreCPU()
 n=200000, iters=2000, threads=24
   GPU        =    152.1 ms
   CPU 1-core =  23277.4 ms  (153.1x slower than GPU)
   CPU N-core =   1556.6 ms  (10.2x slower than GPU, 15.0x faster than 1-core)
   MSE GPU vs CPU = 2.15023e-12,  MSE MT vs 1-core = 0


•DemoGPUPrecompiledVsMultiCoreCPU()
 n=200000, iters=2000, threads=24  (GPU time excludes one-time compile)
   GPU (precompiled) =      9.4 ms
   CPU N-core=   1547.1 ms  (164.8x slower than GPU)
   MSE GPU vs N-core CPU = 2.15023e-12

 

Even after leveraging all 24 CPU threads, the GPU is still over 10× faster. Once the GPU kernel is precompiled, the ratio grows to ~165×, while maintaining essentially identical numerical results.   Keep in mind that most CPU computations ran in DP while the GPU ran in SP.

Ben Murphy-Baum

I also have a Windows ARM laptop with this hardware, so it's running Igor 10 under emulation via Prism.

Snapdragon(R) X 12-core X1E80100 @ 3.40 GHz CPU
Qualcomm(R) Adreno(TM) X1-85 GPU

It nearly choked on the single core CPU stress test, with the GPU coming to the rescue:

•DemoGPUvs1CoreAndMultiCoreCPU()
  n=200000, iters=2000, threads=12
    GPU        =    143.2 ms
    CPU 1-core = 110566.6 ms  (771.9x slower than GPU)
    CPU N-core =   7968.1 ms  (55.6x slower than GPU, 13.9x faster than 1-core)
    MSE GPU vs CPU = 2.16207e-12,  MSE MT vs 1-core = 0
•DemoGPUPrecompiledVsMultiCoreCPU()
  n=200000, iters=2000, threads=12  (GPU time excludes one-time compile)
    GPU (precompiled) =     14.6 ms
    CPU N-core        =   7891.9 ms  (540.9x slower than GPU)
    MSE GPU vs N-core CPU = 2.16207e-12