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.

47 Likes

References:

12 Likes
15 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.

15 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.

17 Likes

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

5 Likes

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.

6 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.

7 Likes

Same here. No criticism meant, I believe.
I think this finding is very appreciated!
Thanks for sharing!

5 Likes

So that’s why the screen has a “mexico filter” on j2 :grinning_face:
Thank you for the detailed report and all the information!
I sure hope that it gets priority in the backlog.

1 Like

Good investigations here. Created an internal task to investigate.

24 Likes

Traced it further. In qt5-qpa-hwcomposer-plugin 5.6.2.27 — the version shipped in 5.2.0.16 — hwcomposer/hwcomposer_backend_v20.cpp line 225 hardcodes HAL_DATASPACE_UNKNOWN when submitting the client target, and the file contains no other reference to dataspace or colour anywhere in its 492 lines. hwc2_compat_layer_set_dataspace is exported by libhybris but never called.

So the compositor never tells the composer what colour space it’s sending, and never picks a colour mode. Vendor side stays at HAL_native as a result.

16 Likes

What’s the current status of this issue? Will it be fixed in a future update? I think this was brought up during the meeting, but they said they hadn’t started investigating it yet.

Of course.
Read the log of the community meeting from Aug. 20

So, is this why when I lower the brightness, starting at a certain brightness level, it starts to look weird and bad? It also happens with automatic brightness in the dark.

Could the following issue be related to this topic?

Link to the log

Timestamp 16:53:14

Unfortunately doesn’t seem to be upcoming very soon as far as I can tell

Maybe there are more pitfalls as an optimistic user want to see = :cockroach: vs. :magic_wand:

1 Like