jay-compositor 1.15.0

The Jay compositor
# HDR & Color Management

Jay supports HDR (High Dynamic Range) output and the Wayland color management
protocol. This chapter explains how HDR works in Jay and walks through
enabling it.

## Prerequisites

HDR in Jay requires:

- The **Vulkan renderer**. The OpenGL renderer does not support color
  management or HDR. Vulkan is the default when available; you can verify
  with `jay randr show` (look for the "Api" field under your GPU) or switch
  to it in the [control center]control-center.md GPUs pane.
- A **monitor that supports HDR**. The display must advertise PQ (Perceptual
  Quantizer) support and BT.2020 colorimetry through its EDID. Run
  `jay randr show` to see which color spaces and EOTFs your display supports.

## Quick start

Enable HDR10 on a specific output using the CLI:

```shell
~$ jay randr output DP-1 colors set bt2020 pq
```

Or in your configuration file:

```toml
[[outputs]]
match.serial-number = "33K03894SL0"
color-space = "bt2020"
transfer-function = "pq"
```

Enable the color management protocol so that applications can communicate
their color spaces to the compositor:

```shell
~$ jay color-management enable
```

Or in your configuration file:

```toml
[color-management]
enabled = true
```

To return to SDR:

```shell
~$ jay randr output DP-1 colors set default default
```

> [!NOTE]
> Run `jay randr` to find connector names and serial numbers for your
> displays.

## Concepts

### Color space

The color space determines the range of colors (gamut) the output uses.

`default`
: sRGB gamut. This is the standard gamut for desktop displays.

`bt2020`
: BT.2020 gamut. A much wider gamut used by HDR10 and modern cinema standards.

### Transfer function (EOTF)

The transfer function (technically the Electro-Optical Transfer Function)
controls how encoded pixel values are mapped to display luminance.

`default`
: Gamma 2.2. The traditional SDR transfer function.

`pq`
: Perceptual Quantizer (SMPTE ST 2084). The HDR10 transfer function, designed
  to cover luminance levels from 0 to 10,000 cd/m^2.

Setting `color-space = "bt2020"` and `transfer-function = "pq"` together
activates HDR10 mode. Jay sends the appropriate HDR metadata infoframe to the
display, including the display's mastering luminance and primaries from its
EDID.

### Brightness

The brightness setting controls SDR content luminance in cd/m^2. This
determines how bright non-HDR content appears on an HDR display.

With the `default` (gamma 2.2) transfer function, the default brightness is
the maximum the display supports, anchored at 80 cd/m^2. Setting brightness
below 80 makes SDR content dimmer while creating HDR headroom above it.

With the `pq` transfer function, the default brightness is 203 cd/m^2 (the
ITU reference level for SDR content in an HDR signal).

```toml
[[outputs]]
match.serial-number = "33K03894SL0"
color-space = "bt2020"
transfer-function = "pq"
brightness = 250
```

```shell
~$ jay randr output DP-1 brightness 250
~$ jay randr output DP-1 brightness default
```

> [!NOTE]
> Brightness has no effect unless the Vulkan renderer is in use.

### Blend space

When Jay composites overlapping translucent surfaces, the blend space
determines in which color space the alpha blending is performed.

`srgb`
: Classic desktop blending in sRGB space. This is the default and matches the
  behavior of most other compositors.

`linear`
: Blending in linear light. This is physically correct but can make
  semi-transparent elements appear brighter than expected.

```toml
[[outputs]]
match.serial-number = "33K03894SL0"
blend-space = "linear"
```

```shell
~$ jay randr output DP-1 blend-space linear
```

### Native gamut

By default, Jay assumes all displays use sRGB primaries. This matches the
behavior of most other compositors, but most modern displays actually have a
wider gamut (e.g. 95% DCI-P3 coverage). Because the display interprets
sRGB-intended color values in its wider native gamut, colors appear more
saturated than they should.

Setting `use-native-gamut = true` tells Jay the display's actual primaries
from its EDID, allowing the compositor to map colors correctly. This produces
less saturated but more accurate colors, and allows color-managed applications
to address the full display gamut.

```toml
[[outputs]]
match.serial-number = "33K03894SL0"
use-native-gamut = true
```

```shell
~$ jay randr output DP-1 use-native-gamut true
```

This setting has no effect when the display is already operating in a wide
color space like BT.2020.

### Framebuffer format

The default framebuffer format (`xrgb8888`) uses 8 bits per channel, which
can cause banding in HDR content. For HDR, consider a higher-precision format:

- `xrgb2101010` or `argb2101010` -- 10 bits per channel. Good balance between
  precision and performance.
- `xbgr16161616f` or `abgr16161616f` -- 16-bit floating point per channel.
  Maximum precision.

```toml
[[outputs]]
match.serial-number = "33K03894SL0"
color-space = "bt2020"
transfer-function = "pq"
format = "xrgb2101010"
```

```shell
~$ jay randr output DP-1 format set xrgb2101010
```

> [!TIP]
> Run `jay randr show --formats` to see which formats your display supports.

## Color management protocol

The Wayland color management protocol (`wp_color_manager_v1`) lets
applications communicate their color space to the compositor. This enables
color-aware applications to render correctly regardless of the output's color
settings -- for example, an image viewer can tag its surfaces as sRGB and Jay
will map the colors to the output's actual gamut and transfer function.

The protocol is **disabled by default** and must be enabled explicitly:

```toml
[color-management]
enabled = true
```

Or at runtime:

```shell
~$ jay color-management enable
```

> [!NOTE]
> Changing this setting has no effect on applications that are already running.
> They must be restarted to discover the protocol.

Color management availability requires both the protocol to be enabled **and**
the Vulkan renderer to be active. Check with:

```shell
~$ jay color-management status
```

This prints one of:

`Enabled`
: The protocol is enabled and available to clients.

`Enabled (Unavailable)`
: The protocol is enabled but unavailable -- usually because the OpenGL
  renderer is in use.

`Disabled`
: The protocol is disabled.

The [control center](control-center.md) **Color Management** pane shows the
same information as a toggle and a read-only availability indicator.

### Supported capabilities

Jay's color management implementation supports:

- **Parametric image descriptions** with custom primaries, luminances, and
  transfer functions (including power curves).
- **Named primaries**: sRGB, BT.2020, DCI-P3, Display P3, Adobe RGB, and
  others.
- **Named transfer functions**: sRGB, PQ (ST 2084), gamma 2.2, gamma 2.4,
  BT.1886, linear, and others.
- **Mastering display metadata** for HDR content.
- **Windows scRGB** compatibility.

ICC profile creation is not supported.

## Checking display capabilities

Use `jay randr show` to inspect what your display supports:

```shell
~$ jay randr show
```

The output for each connector includes:

- **Color spaces** -- which color spaces the display supports (e.g. `default`,
  `bt2020`), with the current setting marked.
- **EOTFs** -- which transfer functions the display supports (e.g. `default`,
  `pq`), with the current setting marked.
- **Brightness range** -- minimum and maximum luminance from the EDID, in
  cd/m^2.
- **Current brightness** -- displayed if a custom value is set.
- **Blend space** -- current blend space setting.
- **Native gamut** -- the display's CIE xy primaries for red, green, blue, and
  white point.

## HDR screenshots

An ordinary screenshot is 8-bit sRGB, so any HDR content on screen is clipped
or flattened to the SDR range. Pass `--hdr10` to capture in HDR instead:

```shell
~$ jay screenshot --hdr10
~$ jay screenshot --hdr10 my-screenshot.png
```

The screen is captured with BT.2020 primaries and the PQ transfer function,
and written as a 16-bit-per-channel PNG. The file carries a `cICP` chunk
identifying the HDR10 color space, which is how a viewer knows to interpret
the pixels as PQ rather than sRGB.

Highlights are preserved up to the full PQ range, and SDR content is captured
at the reference level of 203 cd/m^2, matching what the `pq` transfer function
uses on a real output.

You do not need to put your display into HDR mode first. The flag controls how
the screenshot is encoded, not how the screen is driven, so an HDR10
screenshot on an SDR display is captured correctly -- you simply won't be able
to preview it accurately on that display.

> [!IMPORTANT]
> HDR screenshots require the Vulkan renderer, for the same reason HDR output
> does. See [Prerequisites]#prerequisites above.

> [!NOTE]
> `--hdr10` produces PNG only. It cannot be combined with `--format qoi`,
> because QOI has no way to describe a color space.

Support for HDR PNGs is still uneven across image viewers and browsers. A
viewer that ignores the `cICP` chunk treats the file as ordinary 16-bit sRGB,
which makes the image look flat and washed out. The file itself is still
correct.

## Complete example

A typical HDR configuration for a monitor that supports HDR10:

```toml
[[outputs]]
match.serial-number = "33K03894SL0"
color-space = "bt2020"
transfer-function = "pq"
brightness = 203
format = "xrgb2101010"
blend-space = "linear"

[color-management]
enabled = true
```

This sets the output to HDR10 with 10-bit color, physically correct blending,
and enables the color management protocol so applications can communicate
their color spaces.

## Control center

The Outputs pane in the [control center](control-center.md) (`alt-c` by
default) provides GUI controls for all HDR-related settings per output:
Colorimetry, EOTF, Custom Brightness, Format, Blend Space, Use Native Gamut,
and a read-only Native Gamut display. See
[Outputs (Monitors)](configuration/outputs.md) for details on each field.

The Color Management pane has a toggle to enable/disable the protocol and a
read-only indicator showing whether color management is currently available.

## See also

- [Outputs (Monitors)]configuration/outputs.md -- per-output configuration
  reference including all color and HDR fields
- [Miscellaneous]configuration/misc.md -- the `[color-management]` config
  table
- [Command-Line Interface]cli.md -- `jay randr output` color commands,
  `jay color-management`, and `jay screenshot --hdr10`
- [GPUs]configuration/gpu.md -- renderer selection (Vulkan is required for
  HDR)