Display is not colour-managed — vendor sRGB colour mode exists but Sailfish never selects it

REPRODUCIBILITY: 100%
OS VERSION: 5.2.0.16
HARDWARE: Jolla Phone (2026), jp2601, MediaTek MT6858
UI LANGUAGE: Finnish (not language-dependent)
REGRESSION: N/A — new device, no earlier release to compare against

DESCRIPTION:

The display is not colour-managed. Sailfish never selects a display colour mode, so the panel runs in its native gamut and sRGB content is rendered directly onto the panel’s native primaries. The result is oversaturation across the board, most visibly in reds.

The vendor stack already provides the fix. /vendor/etc/cust_pq.xml defines eleven colour modes including a tuned HAL_sRGB (ModeID 7), with Default="0"HAL_native. MediaTek’s Picture Quality service that implements these modes is running. Nothing in Sailfish ever calls setColorMode, and Settings → Display exposes no colour controls at all.

The same HAL plumbing would close two further gaps. Android implements night mode and accessibility colour filters — colour-blindness correction, greyscale, colour inversion — through the neighbouring setColorTransform call, composing them into a single matrix that the display hardware applies during scanout. They therefore stack cleanly and cost nothing per frame (reference below). Sailfish has none of them, on hardware that supports all of them. Colour management and these features are one work item, not three.

PRECONDITIONS:

None. Affects all displayed content.

STEPS TO REPRODUCE:

  1. Display any sRGB-tagged image containing saturated reds — a photo, or a red UI element.
  2. Compare against the same file on a colour-managed device (an Android phone set to “Natural”/sRGB, or a calibrated monitor).
  3. Optionally confirm the cause: grep -E 'PQ_modes|<Mode ' /vendor/etc/cust_pq.xml

EXPECTED RESULT:

sRGB content rendered through the vendor’s sRGB colour mode, matching the reference rendering, with a Settings toggle between sRGB and native for users who prefer the saturated look.

Longer term, the same mechanism should also provide:

  • a night mode / blue-light filter applied in display hardware rather than by the compositor
  • accessibility colour filters: colour-blindness correction, greyscale, colour inversion

ACTUAL RESULT:

Content rendered in the panel’s native gamut with no conversion. Reds in particular are visibly oversaturated. No colour setting exists anywhere in the UI.

MODIFICATIONS:

Developer mode enabled. Storeman and Chum installed, plus community packages (File Browser, Patchmanager, Situations) — no display-related patches applied. Android App Support in use with F-Droid and Aurora Store. None of these affect the finding: the defaults above are stock.

ADDITIONAL INFORMATION:

Evidence gathered from a shell on the device, stock tools only:

$ grep '<Mode ' /vendor/etc/cust_pq.xml
<Mode ModeID="0"  Name="HAL_native"    ColorSpace="native"    DynamicRange="sdr">
<Mode ModeID="7"  Name="HAL_sRGB"      ColorSpace="sRGB"      DynamicRange="sdr">
<Mode ModeID="9"  Name="HAL_displayP3" ColorSpace="displayP3" DynamicRange="sdr">
<Mode ModeID="3"  Name="HAL_HDR"       ColorSpace="displayP3" DynamicRange="hdr">
... plus seven VND_* modes; enclosing element is <PQ_modes PQID="0" Counts="11" Default="0">

$ grep -ail colormode /vendor/lib64/hw/* /vendor/lib64/*.so
/vendor/lib64/hw/hwcomposer.mtk_common.so
/vendor/lib64/hw/vendor.mediatek.hardware.pq_aidl-impl.so
/vendor/lib64/android.hardware.graphics.composer3-*-ndk.so

# lsof /dev/dri/card0
composer@ 16141 system  /dev/dri/card0
binder:26  2628 system  /dev/dri/card0     (PID 2628 = vendor.mediatek.hardware.pq_aidl-service)

Composition runs through the Android composer via libhybris — Lipstick does not hold /dev/dri/card0 — so mode selection has to go through the HAL rather than DRM properties.

libhybris implements the getter internally (compat/hwc2/HWC2.cpp, Display::getColorModes) but does not export it through the C API used by Sailfish:

$ grep -aio 'color[A-Za-z_]*' /usr/lib64/libhwc2.so.1.0.0 | sort -u
color

(That grep recovered only two hwc2_compat_* strings from the library, so it may not be reaching the symbol table reliably — worth confirming with nm -D, which isn’t installed on the device.)

Suggested fix, three small changes: export colour mode get/set through libhybris’s hwc2_compat_layer; call it from the Qt hwcomposer QPA plugin, which already links that library; select HAL_sRGB at display init from Lipstick, behind a Settings toggle.

Supporting evidence for the night mode / accessibility part: setColorTransform is present in both hwcomposer.mtk_common.so and the PQ implementation, and the CCORR colour-correction driver is in the kernel (grep -c ccorr /proc/kallsyms → 74).

Two things I could not establish: whether cust_pq.xml is device-specific or generic MediaTek boilerplate (pq_flag.xml lists thirteen platform IDs and not mt6858, so some of these files clearly ship as-is), and whether the composer enumerates these modes at runtime as opposed to in the config file. Both need a runtime getColorModes call.

20 Likes

References:

6 Likes
7 Likes

Great find!

That also explains why black isn’t really black—it looks more like an LCD than an OLED. At first, I thought there might be a high-brightness mode enabled, which was causing it.

8 Likes

Great findings, but it was kind of expected that Jolla hasn’t done any optimizations for the panel (or camera etc). They could only do so much with the resources they had, and they had bigger priorities.

It will be interesting to see how much things improve when Jolla can finally start doing proper hardware optimization.

9 Likes

I think Jolla has done clean execution of reference designs which gives solid base , no frills. It is a good approach.

1 Like

Install binutils.

Maybe sth like strings /usr/lib64/libhwc2.so.1.0.0 | grep -i color gives better results.

I don’t have a J2 and the file /vendor/etc/cust_pq.xml is not present here. I wonde if/how your findings translate to other devices (Xperia 10 III in this case).

The command strings /vendor/lib64/hw/* /vendor/lib64/*.so|grep -i colormode 2>/dev/null gives plenty of result.

Maybe sth like strings /usr/lib64/libhwc2.so.1.0.0 | grep -i color gives better results.

$ strings /usr/lib64/libhwc2.so.1.0.0 | grep -i color
hwc2_compat_layer_set_color
hwc2_compat_layer_set_color

The command strings /vendor/lib64/hw/* /vendor/lib64/*.so|grep -i colormode gives plenty of result.

Plenty here too, 86 lines.

Without a public roadmap, it’s best we report bugs instead of assuming they will be fixed by Jolla anyways.

2 Likes

I don’t think @ahjolinna meant it that way.
I don’t think there was any criticism towards you for reporting this as a bug, quite the opposite.

3 Likes