Hello everyone,
For several months now, in my fork Libre DT-Lab, I have been experimenting with various tone mappers. It felt natural to add the reference implementation, an ACES 2.0 Output Transform (April 2025) integrated into the darktable pipeline.
Why ACES 2.0
ACES 2.0 unifies what was split into two stages in ACES 1.x (RRT + ODT) into a single Output Transform, and fundamentally changes the approach: instead of a fixed 3D LUT, the rendering goes through a color appearance model based on CAT16/Hellwig CAM, in a perceptual JMh space (lightness J, colorfulness M, hue h). Concretely, this allows:
- scene-to-display tone mapping (SSTS) that maintains a rolloff characteristic consistent with the target peak luminance
- hue-dependent and luminance-dependent chroma compression, not a uniform RGB treatment
- gamut compression based on the actual display cusp geometry (per hue), bringing out-of-gamut colors back without abrupt transitions or hue shifts
Fidelity to the reference
The core of the module (CAT16 matrices, SSTS, chroma compression, gamut compression) has been compared line by line against the official CTL (aces-core, release v2.0.0, April 4, 2025), constants, formulas, and matrices verified, including the CAT16 matrix specific to ACES 2.0 (derived from CAM16_PRI primaries via XYZtoRGB_f33, different from the published “standard” CAT16 matrix) and the AP1 reach primaries.
Three deliberate deviations from bit-exact reproduction, for robustness and production usability:
- Forward only, no inverse gamut compression. Consistent with standard darktable usage (no proofing/round-trip workflow needed at this stage)
- Uniform hue table spacing (1°)
forward_limit(safety clamp before tone mapping) recalculated for the module’s internal scale rather than copied verbatim from the CTL
Technical features
- OpenCL accelerated, per-pixel computation, no LUT
- Strict parity between CPU and GPU paths (same gamut table, same formulas)
- Adjustable peak luminance (100–4000 nits): standard SDR or HDR headroom
- Optional output clip (disabled by default): the output is not clamped to [0,1] by default, exactly like the official reference, highlights beyond display white remain available for downstream pipeline stages. An optional soft-clip (cubic roll-off, adjustable width) is available for strict SDR workflows.
The module works and produces colour output consistent with my testing.
As you can see, the module has only a few sliders, this is a deliberate choice to stay as faithful as possible to the reference. All other adjustments can be made with the various modules at our disposal, starting with the excellent RGB colour balance module.
Any comments or criticism are welcome, especially regarding gamut compression and highlight rendering, which are the most sensitive areas of this kind of implementation.
The latest version is available on GitHub.
Greetings from a Belgian;
![]()
Christian



