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.
@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.
@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.
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:
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.
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.
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.
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!
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)?
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.