Skip to content

macOS: add HDR/EDR preview pipeline tap for external viewer (fixes #17710)#20566

Draft
MaykThewessen wants to merge 4 commits intodarktable-org:masterfrom
MaykThewessen:feature/macos-hdr-edr-viewer
Draft

macOS: add HDR/EDR preview pipeline tap for external viewer (fixes #17710)#20566
MaykThewessen wants to merge 4 commits intodarktable-org:masterfrom
MaykThewessen:feature/macos-hdr-edr-viewer

Conversation

@MaykThewessen
Copy link

@MaykThewessen MaykThewessen commented Mar 18, 2026

Problem

Closes #17710. When editing HDR images in darktable on macOS, the viewer appears very dark because GTK3 has no way to communicate HDR colorspace information to macOS color management. All pixel values are clipped to 8-bit SDR at the gamma module, discarding any HDR signal above 1.0.

Solution

A lightweight, opt-in pipeline tap that forwards float pixel data to an external HDR viewer over a Unix domain socket. The Swift Metal viewer app lives in a separate repository to keep the darktable tree lean.

What this PR adds to darktable (~250 lines total)

1. src/common/hdr_viewer.c/.h — POSIX C client (no dependencies)

int fd = dt_hdr_viewer_connect();   // non-blocking, 200ms timeout, -1 if viewer absent
dt_hdr_viewer_send_frame(fd, w, h, rgb_float32);
dt_hdr_viewer_disconnect(fd);

Returns -1 immediately when the viewer is not running — darktable never stalls.

2. src/develop/pixelpipe_hb.c — pipeline tap (~30 lines)

Taps the float RGBA buffer that is the input to the gamma module — the last step before uint8 downconversion. At this point all HDR values above 1.0 are still intact. Guarded by a conf key (default OFF):

darktable --conf plugins/darkroom/hdr_viewer_enabled=true

External viewer (separate repo)

The standalone macOS Metal viewer app is at: https://github.com/MaykThewessen/darktable-hdr-viewer

It uses CAMetalLayer with wantsExtendedDynamicRangeContent and rgba16Float to display linear BT.2020 data with Extended Dynamic Range on XDR displays (up to ~1600 nits on M1 MacBook Pro).

Notes

  • Zero overhead when viewer is off: connect() returns -1 immediately, guarded by conf key (default OFF)
  • No new dependencies: the C client is pure POSIX (compiles on Linux too, just returns -1)
  • No Swift/Metal in the darktable tree: viewer app is a separate project
  • The tap reuses the same float buffer the colorpicker already reads — no extra pipeline pass
  • A proper solution requires GTK4 color management support; this is an explicit workaround for the interim

Testing

Tested on M1 MacBook Pro (14", XDR display) with darktable master built via Homebrew toolchain. HDR AVIF images with PQ BT.2020 output profile show correct highlight rendering above SDR white in the preview window.

MaykThewessen and others added 2 commits March 17, 2026 22:13
…g#17710)

Adds a standalone Swift Metal HDR preview window that displays darktable's
float pixel data with Extended Dynamic Range on Apple M1/M2 displays (up to
~1600 nits on XDR), working around the GTK3 limitation that clips all output
to 8-bit SDR.

## Architecture

Two components wired together via a Unix domain socket:

**tools/hdr-viewer/** — standalone macOS app (Swift Package, macOS 12+)
- CAMetalLayer with wantsExtendedDynamicRangeContent=YES and rgba16Float
- Fragment shader converts linear BT.2020 → Display-P3 with soft gamut
  compression and a Reinhard knee tone map that preserves HDR signal
- IPCServer listens on /tmp/dt_hdr_viewer.sock for frames from darktable
- Reads EDR headroom from NSScreen to adapt to ambient light conditions

**src/common/hdr_viewer.c/.h** — POSIX C client (no dependencies)
- dt_hdr_viewer_connect(): non-blocking connect with 200ms timeout
- dt_hdr_viewer_send_frame(): sends width/height header + RGB float32 pixels
- Returns -1 immediately when viewer is not running (no darktable stall)

**src/develop/pixelpipe_hb.c** — pipeline tap
- Taps the float RGBA input to the gamma module (last step before uint8
  downconversion), preserving HDR values above 1.0 that GTK would clip
- Guarded by dt_conf bool "plugins/darkroom/hdr_viewer_enabled"
- Strips alpha, sends RGB to viewer on each pipeline redraw

## Usage

  # terminal 1
  cd tools/hdr-viewer && swift build -c release
  .build/release/HDRViewer

  # terminal 2
  darktable --conf plugins/darkroom/hdr_viewer_enabled=true

The HDR Preview window updates live with each darkroom pipeline redraw.
HDR highlight values above diffuse white render with true EDR brightness.

Closes darktable-org#17710

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- hdr_viewer.c: set SO_NOSIGPIPE on the socket so darktable does not
  get killed by SIGPIPE if the HDR viewer crashes while we are writing
  a frame
- IPCServer.swift: set SO_RCVTIMEO (5s) on accepted client sockets so
  the viewer does not block forever if darktable dies mid-frame

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@zisoft
Copy link
Collaborator

zisoft commented Mar 18, 2026

cd tools/hdr-viewer
swift build -c release
.build/release/HDRViewer

Does that mean the user is required to build and run this on their target machine?
What about bundling into the macOS packages?
CI / nightly / release build?

@kmilos
Copy link
Contributor

kmilos commented Mar 18, 2026

What about bundling

What about

  1. Make macOS viewer an independent project outside of dt (could live in darktable-org though)
  2. Make client and tap build optional (start OFF by default, turn ON in macOS nightlies)

IMHO, the recent general feature creep trend in the project is becoming somewhat worrying...

@MaykThewessen
Copy link
Author

Good points from both of you — agree on keeping this lean.

Plan: split into two pieces.

  1. This PR (darktable side) will be reduced to just the C client + pipeline tap:

    • src/common/hdr_viewer.c/.h — ~180 lines, pure POSIX, no new dependencies
    • src/develop/pixelpipe_hb.c — ~30-line tap before the gamma module, guarded by plugins/darkroom/hdr_viewer_enabled (default OFF)
    • src/CMakeLists.txt — one line addition

    When the viewer isn't running, connect() returns -1 immediately — zero overhead. The conf key is opt-in, so this is completely inert by default.

  2. Separate repo for the Swift Metal viewer: MaykThewessen/darktable-hdr-viewer

    Self-contained macOS app. Could move to darktable-org later if the project wants to adopt it. Users install it independently (Homebrew cask or download a signed .app from releases).

This addresses @kmilos's feature creep concern — the Swift/Metal code lives outside the dt tree entirely. The C client in darktable is minimal and platform-agnostic (compiles on Linux too, just returns -1 when no viewer is listening).

Will update this PR shortly with tools/hdr-viewer/ removed.

The Swift Metal HDR viewer app has been moved to its own repository at
https://github.com/MaykThewessen/darktable-hdr-viewer to address
feature creep concerns. Only the lightweight C client (~180 lines) and
the pipeline tap remain in the darktable tree.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@MaykThewessen MaykThewessen changed the title macOS: add HDR/EDR preview viewer for M1 displays (fixes #17710) macOS: add HDR/EDR preview pipeline tap for external viewer (fixes #17710) Mar 19, 2026
…f key

- Use send() with MSG_NOSIGNAL on Linux instead of write() to prevent
  SIGPIPE from killing darktable when the HDR viewer disconnects
- Use size_t for pixel loop counter and dimensions to avoid int overflow
  on large images
- Add 2-second cooldown after failed connect to avoid 200ms timeout on
  every preview frame when the viewer is not running
- Move alloc/OMP loop inside the connect-success branch so we only
  allocate and copy pixels when the viewer is actually reachable
- Register plugins/darkroom/hdr_viewer_enabled in darktableconfig.xml.in
  so the key persists correctly across restarts
- Add comment that socket calls must stay outside OMP parallel sections

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Request: HDR viewers on macOS

3 participants