Testers wanted: experimental Slang GPU path for darktable (Metal/Vulkan)

Hi all. I’ve been working on a proof of concept that ports darktable’s OpenCL kernels to Slang. Slang compiles them to Metal on macOS and Vulkan on Linux. This is not part of darktable: the maintainers haven’t adopted it, and it lives on my fork. The discussion is in darktable-org/darktable#22732.

The port now covers a typical scene-referred edit: denoise (profiled), lens correction, exposure, tone equalizer, color calibration, sharpen, color equalizer and AgX. On my M4 Pro, the whole edit runs on the GPU. A full-resolution export takes 179 ms with Slang/Metal, 297 ms with Apple’s OpenCL and 760 ms on the CPU. The output matches OpenCL to normal GPU differences.

So far it has only run on Apple Silicon and on a software Vulkan driver. Results from NVIDIA, AMD and Intel GPUs on Linux would help most.

What you need:

  • a darktable build environment;
  • slangc (from the shader-slang releases);
  • the Vulkan headers and a Vulkan driver on Linux, or Xcode on macOS.

Windows hasn’t been tried yet.

How to run it: build the slang-benchmark branch and run one script. The steps are in tools/slang-bench/README.md. The script exports a test raw on the CPU, OpenCL and Slang, and writes a summary.md with your devices, timings, GPU coverage and image differences.

Reporting: please post your summary.md and GPU driver version here. If it fails, attach fullpipe-results/slang.log. Please don’t file Slang problems as darktable bugs, since it isn’t part of darktable.

Thanks!

4 Likes

Does this run interactively, too? I.e. does it speed up editing, such that sliders give real-time feedback?

For the build on macOS, the Apple Metal toolchain needs to be installed:

xcodebuild -downloadComponent MetalToolchain

full-pipe benchmark, 2026-10-23 19:04

  • os: Darwin 27.0.0 arm64
  • cpu: Apple M5 Pro
  • commit: b6eee8eced
  • slang device: Metal device Apple M5 Pro (unified memory)
  • opencl devices: ‘Apple M5 Pro’
  • export size: full resolution, resourcelevel: default
  • tiled on cpu: none
  • tiled on opencl: none
  • tiled on slang: none

pipe totals in ms, one process per path, 5 exports each

path per export
cpu 471 / 448 / 445 / 453 / 449
opencl 834 / 225 / 221 / 219 / 221
slang 648 / 144 / 146 / 144 / 153

module runs over all 5 exports:

  • opencl: 75 on GPU; on CPU:
  • slang: 75 on GPU; on CPU:
  • slang fallbacks/failures: 0

slang per-module time, last export (ms; GPU work is async, so trust the pipe total):

  • rawprepare (GPU): 1
  • temperature (GPU): 0
  • highlights (GPU): 8
  • demosaic (GPU): 7
  • denoiseprofile (GPU): 58
  • lens (GPU): 19
  • exposure (GPU): 0
  • toneequal (GPU): 0
  • colorin (GPU): 0
  • channelmixerrgb (GPU): 0
  • sharpen (GPU): 1
  • colorequal (GPU): 24
  • agx (GPU): 0
  • colorout (GPU): 0
  • finalscale (GPU): 0

max / avg dE on the first export:

  • cpu vs opencl:
  • cpu vs slang:
  • opencl vs slang:

@bastibe yes, it works in the darkroom too. The same switch moves the preview and the main view onto the Slang kernels, and I’ve edited on it on an M4 Pro: images render correctly, and nothing falls back to the CPU.

To try it, start darktable with darktable --disable-opencl --conf slang_gpu=TRUE. OpenCL has to be off because an OpenCL device still takes precedence; Slang only replaces the CPU path. A module falls back to the CPU while its color picker is on, or when it uses a blend mode that isn’t ported yet.

I haven’t measured slider latency yet, so I can’t promise real-time feedback. The export numbers suggest it should feel at least as fast as OpenCL: the whole edit runs on the GPU and is read back once, rather than per module. There are some known spots that still cost time while editing:

  • the preview’s downscaled demosaic is read back and uploaded again;
  • module previews such as mask display sync back to the CPU;
  • modules without a port (anything outside the list in the first post) also sync back to the CPU.

Measuring that properly is on my list.

@zisoft thank you, that’s exactly what I was hoping for, and the Metal toolchain tip is now in the README.

Here’s your M5 Pro next to my M4 Pro. Times are steady-state per export (exports 2–5), full resolution:

CPU Apple OpenCL Slang → Metal Slang vs OpenCL
M5 Pro 449 ms 221 ms 145 ms 1.52×
M4 Pro 760 ms 297 ms 179 ms 1.66×

All 15 modules ran on the GPU, with no tiling and no fallbacks. Both chips spend most of the Slang time in the same three modules, in the same proportions: denoise, color equalizer and lens.

The empty dE lines were my bug. The comparison tool is normally built by the integration test runner, which you hadn’t run. The script now builds it itself (nicknezis/darktable@b02ffdf3e0). Pulling the branch and running bench.sh again with 1 export would fill them in.

It may be that I need to install some extra packages, but I’m not sure what they would be. I’m running Manjaro Linux on a laptop, plugged-in.

nvidia driver v: 615.71.09

vulkaninfo reports: Vulkan Instance Version: 1.4.363

results.zip (8.1 KB)

Thanks a lot for running it! Good news first: you don’t need any extra packages. The Slang path built and ran fine: all 15 modules of the edit ran on the GPU in every export, with no fallbacks, and its output matches OpenCL (max dE 1.2, average 0.0002).

The catch is that it ran on the wrong GPU. Your summary says slang device: Intel(R) UHD Graphics (TGL GT1), the integrated graphics, while OpenCL used the RTX 3050 Ti. My Vulkan code takes the first GPU the driver lists, and on a hybrid laptop that’s the Intel one. That’s a bug on my side, and I’m fixing it to prefer the discrete GPU.

That explains your numbers. Slang on the Intel iGPU took about 2.18 s per export, barely ahead of the CPU’s 2.29 s, while OpenCL on the RTX took 326 ms.

If you have a few minutes, could you pull the latest from the branch and run it once more on the NVIDIA card? Manjaro’s prime-run (from the nvidia-prime package) hides the Intel GPU from Vulkan, so just prefix the script:

prime-run bash <darktable>/tools/slang-bench/bench.sh <darktable> 5

prime-run vulkaninfo --summary should list only the RTX 3050 Ti. If you don’t have prime-run, this does the same:

__NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only bash <darktable>/tools/slang-bench/bench.sh <darktable> 5

The slang device line in the new summary should then name the RTX 3050 Ti. Your Intel numbers are still useful, by the way: it’s the first Intel Vulkan result I’ve had, and the output was correct there too.

1 Like

@nick_nezis I updated and rebuilt, and then tried the second approach, and I’ve attached the results. Hope it helps!

Archive.zip (8.0 KB)

Thanks for rerunning it! This time Slang picked the RTX 3050 Ti by itself, so the device fix works on a real hybrid laptop. Yours is the first machine with two GPUs it’s run on. Everything still ran on the GPU, nothing fell back to the CPU, and the output matches OpenCL as before.

It’s still well behind OpenCL on your card, though: about 1.36 s per export against 326 ms. Your log shows why. Copying the finished image back from the GPU takes 600 ms on its own, every export. That’s my bug: I read it through a kind of memory that’s very slow for the CPU to read on NVIDIA cards. Fixing that should bring it to about 0.77 s. The rest of the gap is in denoise, lens correction and color equalizer, and I now know where to look in each.

This was really useful, thank you. I’ll post here when there’s a build worth timing again.

1 Like

I’ve fixed the slow copy back from the GPU on NVIDIA. If you have time for one more run, git pull, rebuild and run the script as before. The final “reading … from the device” line in slang.log should drop from about 600 ms.

Yes, Claude, indeed! :joy:

2 Likes

Here’s the latest results…

Archive.zip (18.6 KB)

Thanks again, this run confirmed the fix. Copying the image back from the GPU went from 600 ms to 33 ms, and Slang picked the RTX on its own even though the Intel GPU was listed first this time. A full export with Slang is now about 0.64-0.80 s, down from 1.36 s, against 0.33 s for OpenCL and 2.27 s on the CPU.

So it’s twice as fast as before, but still about twice as slow as OpenCL on your card. Your log shows where the rest goes: denoise, lens correction and color equalizer. Denoise also gets slower with each export, which I want to look into. That’s my homework now, so no need to rerun until I have something new. Your three runs found two real bugs. Much appreciated!

1 Like

Thanks again for the runs on the RTX 3050 Ti. I found why Slang was slower than OpenCL on your laptop: our Vulkan backend waited for the GPU after every kernel and kept its buffers in system memory, which hurts a discrete GPU much more than the Apple ones. A fix is on the slang-vulkan-async branch of GitHub - nicknezis/darktable: darktable is an open source photography workflow application and raw developer · GitHub.

If you have time, could you run the same benchmark once more on that branch?

cd darktable && git fetch https://github.com/nicknezis/darktable slang-vulkan-async && git checkout FETCH_HEAD
cmake --build build -j
mkdir -p /tmp/slang-bench && cd /tmp/slang-bench && bash <darktable>/tools/slang-bench/bench.sh <darktable> 5

and send the fullpipe-results folder as before. The slang.log now has GPU-side times per kernel, which will show what’s still slow.

Sure, here are some results from that branch:

Archive.zip (18.1 KB)

1 Like

Thanks for the run! Your first export was already faster than OpenCL (302 vs 326 ms). The later ones ran out of the 4 GB on your card, which is fixed now. Could you rerun on the usual slang-benchmark branch (git fetch https://github.com/nicknezis/darktable slang-benchmark && git checkout FETCH_HEAD, build, bench.sh as before)?

Sure, here goes…

Archive.zip (17.6 KB)

edited: @nick_nezis I noticed my laptop was behaving oddly, so I rebooted - the results after the reboot are marginally different:

Rebooted.zip (17.6 KB)

Thanks David, that’s the result we were hoping for: on your RTX 3050 Ti, Slang is now slightly faster than OpenCL (about 303 ms vs 325 per export after the reboot), every module stayed on the GPU, and the out-of-memory fallbacks from the last run are gone.

Your logs showed two remaining slow spots, and both are fixed on slang-benchmark now:

  • color equalizer ran out of GPU memory on every export after the first and had to stop and free everything before carrying on
  • lens re-created its 232 MB upload buffer on every export

If you have time for one more run, a fresh pull of slang-benchmark and the same bench.sh command as last time would show how much that saves. No rush.

This is the result of a fresh build on an up-to-date slang-benchmark branch:

Archive.zip (17.9 KB)

Now looking better than OpenCL :tada:

if someone wants to test on an intel mac without building it:
darktable-5.7.x_x86_64_slang.dmg (macOS >= 14.4)

you need to adapt the script in darktable/tools/slang-bench at slang-benchmark · nicknezis/darktable · GitHub and download the raw file
or use this:

mkdir /tmp/slang-bench && cd /tmp/slang-bench
curl -L -O https://github.com/darktable-org/darktable-tests/raw/master/images/mire1.cr2
curl -L -O https://raw.githubusercontent.com/nicknezis/darktable/slang-benchmark/tools/slang-bench/scene-referred.xmp

unzip bench_app.sh.zip (2.8 KB) in /tmp/slang-bench
and run ./bench_app.sh /Volumes/darktable/darktable.app 5

(i had to remove the deltae build and calculation from the script since it’s not part of the darktable package)

1 Like