Skip to content

Fix PQ luminance scaling and HLG display conversion - #22516

Merged
TurboGit merged 4 commits into
darktable-org:masterfrom
MaykThewessen:codex/fix-pq-hlg-transfer
Oct 8, 2026
Merged

TurboGit merged 4 commits into
darktable-org:masterfrom
MaykThewessen:codex/fix-pq-hlg-transfer

Conversation

@MaykThewessen

@MaykThewessen MaykThewessen commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

PQ imports use 10000 nit normalization where the pixelpipe expects relative reference white, making 203 nit white approximately 49.26 times too dark. HLG imports omit the display OOTF; exports invert the same incorrect mapping. Apply PQ scaling and the RGB-dependent HLG OOTF at an RGB boundary, with a shared CPU/OpenCL implementation and linear gamut/LittleCMS transforms.

PNG imports retain cICP priority over cached ICC profiles and use libpng's native cICP parser where available. JPEG XL imports prefer structured HDR signaling over a synthesized ICC shaper. Adds independent numeric and CLI tests for Rec.2020 and P3, plus release notes.

Checklist

  • I have read CONTRIBUTING.md and the in-tree coding conventions in AGENTS.md.
  • I have not merged master into the topic branch.
  • The pull request is one logical change. The implementation builds; the second commit adds release notes only.
  • I ran unit tests, the HDR CLI regression matrix and the existing exposure integration test in light-check mode.
  • No new user-visible strings or preferences.
  • A RELEASE_NOTES.md entry was added in a separate commit.

Test instructions

The full macOS arm64 build against upstream cc66615c96 passed. All 14 registered CTest tests passed, including the HDR transfer and DNG hue/saturation tests.

Run the independent file regression with NumPy, ImageMagick and fixtures from hdr-test-images:

python src/tests/test-hdr-transfer-cli.py \
  --cli build/bin/darktable-cli \
  --fixtures /path/to/hdr-test-images/img \
  --output /tmp/darktable-hdr-transfer-test \
  --clipping-opencl

All 36 cases passed: 28 import/export and ICC/cICP reimport cases, plus PQ/HLG Rec.2020/P3 input with sRGB gamut clipping on CPU and actual Apple M5 Pro OpenCL. The new clipping stimuli include highlights above reference white and near-black samples. Their expected values come from independent decoding of the actual input samples. Maximum normalized error was 0.000712, below the 0.003 tolerance. GPU clipping checks require actual colorin OpenCL execution and successful events with zero lost events. Omit --clipping-opencl for the 32 CPU cases.

Separate Apple M5 Pro PQ/HLG import/export comparisons passed. HLG matched CPU exactly; PQ differed by at most one 16-bit code value.

Full CIE 2000 Delta E checks passed on CPU and GPU for 0001-exposure, 0107-colorin-gamma, 0108-colorin-clip, and 0109-colorin-gamma-and-clip, using the companion HLG reference update. The final history entry in 0109 selects HLG P3, so its old reference captures the incorrect decoder. Restoring that decoder reproduces the old reference; it fails both new independent HLG clipping checks at approximately 0.4266 error. PQ still passes the same negative control. The refreshed reference rejects the old decoder at max Delta E 46.857.

The full integration suite, native HDR display rendering, Linux/Wayland runtime, UltraHDR export, and full builds with optional features disabled have not been verified. The colorin/colorout modules compile with OpenCL disabled. CLLI checks were not repeated on this final branch.

The HLG display model remains nominal 1000 nit peak, gamma 1.2 and zero black, with 203 nit reference white. It does not add dynamic adaptation to a physical display.

AI assistance

Implementation, tests and validation were performed with Codex. AI assistance is disclosed here; there are no co-author trailers.

Fixes #20562

@TurboGit TurboGit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works on my side, still I have some comments/changes below.

I found that there is quite some places changed, it seems ok, but if you can by anyway review again on your side and see if some refactoring are possible, please do so.

TIA.

Comment thread data/kernels/basic.cl Outdated
Comment thread data/kernels/basic.cl Outdated
Comment thread data/kernels/color_conversion.h
Comment thread data/kernels/color_conversion.h
Comment thread src/common/colorspaces.h
Comment thread src/imageio/imageio_jpegxl.c
Comment thread src/imageio/imageio_jpegxl.c
Comment thread src/imageio/imageio_jpegxl.c
Comment thread src/iop/colorin.c
@MaykThewessen
MaykThewessen force-pushed the codex/fix-pq-hlg-transfer branch from e7d46cb to 548102f Compare October 6, 2026 16:39
@MaykThewessen

Copy link
Copy Markdown
Contributor Author

Addressed the nine inline review comments in 548102f.

  • Both colorin kernels now choose HDR decoding or ICC shaper lookup before doing the work, avoiding the unused LUT calculations.
  • The OpenCL transfer helpers share one RGB buffer and one return, avoiding extra R/G/B copies. The CPU tone-curve helper uses an explicit if/else.
  • Expanded the profile switch formatting and added braces to the three multi-line JPEG XL conditions.

I reviewed the remaining conversion changes as well. The shared RGB-boundary helpers already remove the duplicated matrix/transfer branches; I kept those rather than adding another abstraction across CPU and OpenCL.

Validation after the refactor: full build passed, all 13 CTest tests passed, and all 28 independent HDR CLI cases passed. Actual Apple M5 Pro OpenCL PQ/HLG Rec.2020 import and export also passed. HLG export matches CPU exactly; PQ differs by at most one 16-bit code value. The PR description has been updated with these final-branch GPU checks.

@TurboGit

TurboGit commented Oct 7, 2026

Copy link
Copy Markdown
Member

@MaykThewessen : This needs a conflict resolution. TIA.

Decode and encode built-in HDR profiles at an RGB boundary with a
shared CPU/OpenCL transfer implementation. Use 203 nit reference
white for PQ and the RGB-dependent HLG OOTF for the nominal
1000 nit display. Keep the gamut matrix and LittleCMS conversion
linear to avoid applying a second transfer.

Preserve structured HDR signaling for PNG and JPEG XL imports, and
add independent transfer and CLI reference tests. Include the shared
header in OpenCL installation and cache invalidation.

Fixes darktable-org#20562
Skip ICC shaper lookups in the HDR colorin kernels and share the RGB
result and return path in the OpenCL transfer helpers. Use explicit
branches in the CPU tone-curve helper and clarify the profile switch
and multi-line JPEG XL conditions.
@MaykThewessen
MaykThewessen force-pushed the codex/fix-pq-hlg-transfer branch from 548102f to 6f95aa9 Compare October 7, 2026 16:33
@TurboGit

TurboGit commented Oct 7, 2026

Copy link
Copy Markdown
Member

On the integration tests there is one important regression due to this change:

The diffs:

Test 0109-colorin-gamma-and-clip
      Image mire1.cr2
      Timing cpu 2.60s
      Timing gpu 2.80s
      CPU & GPU version differ by 73 pixels
      CPU & GPU large difference > 50
      CPU vs. GPU report :
      ----------------------------------
      Max dE                   : 1.48471
      Avg dE                   : 0.00002
      Std dE                   : 0.00352
      ----------------------------------
      Pixels below avg + 0 std : 100.00 %
      Pixels below avg + 1 std : 100.00 %
      Pixels below avg + 3 std : 100.00 %
      Pixels below avg + 6 std : 100.00 %
      Pixels below avg + 9 std : 100.00 %
      ----------------------------------
      Pixels above tolerance   : 0.00 %
 
      Expected CPU vs. current CPU report :
      ----------------------------------
      Max dE                   : 46.85724
      Avg dE                   : 4.03359
      Std dE                   : 3.73803
      ----------------------------------
      Pixels below avg + 0 std : 61.77 %
      Pixels below avg + 1 std : 83.61 %
      Pixels below avg + 3 std : 98.10 %
      Pixels below avg + 6 std : 99.98 %
      Pixels below avg + 9 std : 99.99 %
      ----------------------------------
      Pixels above tolerance   : 56.81 %
 
  FAILS: image visually changed
         see diff.png for visual difference
         (2788521 pixels changed)

The HDR CLI matrix exercised unbound input conversion but not the
separate gamut-clipping path. Add independent PQ and HLG cases for
Rec2020 and P3, using encoded stimuli with highlights above reference
white and near-black samples.

Decode the actual PNG samples with the NumPy reference, clip in linear
sRGB, and compare the rendered output. Optional OpenCL cases require
confirmed GPU execution with no lost events rather than CPU fallback.

The HLG clipping checks reject the legacy input decoder. This provides
numeric coverage for the HLG behavior behind integration test 0109.
@TurboGit

TurboGit commented Oct 8, 2026

Copy link
Copy Markdown
Member

Stupid me, the test 0109 is using P3 HLG, so indeed the expected output change :)

@TurboGit TurboGit added bugfix pull request fixing a bug priority: medium core features are degraded in a way that is still mostly usable, software stutters difficulty: hard big changes across different parts of the code base scope: color management ensuring consistency of colour adaptation through display/output profiles ai:generated labels Oct 8, 2026

@TurboGit TurboGit left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard stuff here (at least to me) but looks good and it works as expected. Thanks!

@TurboGit
TurboGit merged commit 733bd69 into darktable-org:master Oct 8, 2026
5 checks passed
@MaykThewessen

Copy link
Copy Markdown
Contributor Author

ah great

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:generated bugfix pull request fixing a bug difficulty: hard big changes across different parts of the code base priority: medium core features are degraded in a way that is still mostly usable, software stutters scope: color management ensuring consistency of colour adaptation through display/output profiles

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PQ and HLG transfer function problems (too dark import, too bright export)

2 participants