Jolla Phone 2026 – Black crush below a certain brightness threshold

REPRODUCIBILITY: 100% always
OS VERSION: Sailfish OS 5.2
HARDWARE: Jolla Phone (2026)
UI LANGUAGE: Spanish
REGRESSION: Not tested in previous releases.

DESCRIPTION:

When I lower the brightness, details in dark colors are lost below a certain threshold. Ptu said this in another topic: “Your issue could be the panel switching from DC dimming to PWM at a threshold, so yet another issue.”

Photos taken with a CMF Phone camera:

13 intervals of brightness here, because It don’t let me upload more than 5 images: https://app-share.mailbox.org/appsuite/api/share/0f51be5e03143947f7e241e314394c6d81b41dedcf5e71b7/1/8/Mzg/MzgvNDM1

PRECONDITIONS:

Just changing the brightness.

STEPS TO REPRODUCE:

  1. Lower the brightness

  2. Check dark details

EXPECTED RESULT:

Keep the detail of the dark colors.

ACTUAL RESULT:

Detail lost at dark colors.

MODIFICATIONS:

None that affects de display.

ADDITIONAL INFORMATION:

None

7 Likes

Yeah, kind of a contrast or gamma or saturation problem.
Confirming here on JP2, B1

I also noticed the screen lose contrast when going darker.

Jolla phone 2026 Batch 1.

I imagine it can be fixed with an update. It shouldn’t be a hardware issue, right?

I think there’s a high chance this is a hardware issue, because in another forum thread, a lot of people posted the color accuracy results of their screens. Some of them proved that they never experienced this issue at all, while others clearly showed that they did.

So logically, this is how I looked at it: they have the exact same phone and the same software, yet one person experiences the issue and another person doesn’t. In that case, how likely is it really to be a software problem?

Am I wrong for thinking this way? That’s just where my opinion is leaning at the moment.

it feels like a driver issue as I can’t imagine this kind of behavior from hardware.

it could be that the screen get’s send just darker images instead of a dimmer image (by using the panels brightness setting) making it clip into the lower color range inside the panels range maybe.

on a LCD you would just dimm the backlight but on OLED you have to use different pwn frequencies when I am not wrong making it more difficult.

But I am unsure what the real cause could be and maybe will Jolla make a announcement or something.

The display looks too evenly illuminated in my case to conclude that it’s defective. I suspect that some displays may not be factory-calibrated, that there may be different revisions requiring different calibration, or that the combination of display driver chip and panel may vary.

3 Likes

6 posts were merged into an existing topic: Display is not colour-managed — vendor sRGB colour mode exists but Sailfish never selects it

I seem to have the same issue as OP and made this comparison.
i first made a simple gradient:

Then i put that onto 2 other devices that are not the jolla phone.
I took the images with a Pixel 6 Pro.

This shows first a Pixel 9 Pro XL on the left then to the middle the Jolla Phone 2026 then a nothing Phone 1 and all at max brightness:

Then the same arrangement Pixel 9 Pro XL, Jolla Phone 2026 and nothing Phone 1 but now all at the lowest brightness:

This shows the hard cut-off on the Jolla Phone 2026 i have noticed so far.

4 Likes

@filip.k Could you move the posts from @soloist up to and including the post by @0312birdzhang to the topic below to keep the issues separated?

2 Likes

Yeah, thats the same problem that I reported i think

3 Likes

Might be a dumb question, but how did you set the brightness? I tried to reproduce the test with the slider in setting with and without adaptive setting on, but I couldn’t make that edge appear like in the photos. But it didn’t feel really dim either so maybe it didn’t go low enough.

1 Like

i did it by going into settings then display in it the brightness slider. It also could be that you are lucky and are not effected, also what version of SailfishOS you have? i am on 5.2.0.17 and have the Batch 1 Jolla Phone.

I think its batch one, I got it a couple of weeks ago. But I don’t know where the line goes.

I have studied these display issues quite extensively and have pictured the pipeline as well as I could. I have a script that outputs each step like below. I can send the script too if you want to compare.

=== 0. DEVICE ===
release : 5.2.0.17 (Finlayson)
hw : Jolla Jolla Phone 1.0.0.17
kernel : 6.12.38-4k
soc : MT6858
board : k6858v1_64

=== 1. PANEL ===
– loaded panel modules (only one is bound) –
panel_vtdr6126_dphy_vdo_90hz_boe 163840 0
panel_xl_sd5207_dphy_vdo_boe 90112 0
panel_ocp2131_i2c 16384 0

– which driver claimed the DSI device –
panel-vtdr6126-dphy-vdo-90hz-boe <= 1401a000.dsi0.0

– panel candidates in the device tree –
panel1@0: vtdr6126,dphy,vdo
panel2@0: xl,sd5207,dphy,vdo
panel3@1: jdi,nt36672e,vdo,60hz

=== 2. DRM CONNECTOR ===
card0-DSI-1 status=connected enabled=enabled
modes: 1032x2272 / 1032x2272
output_bpc : Maximum: 0
vrr_range : Min: 0 Max: 0

=== 3. VENDOR COLOUR MODES ===
<PQ_modes PQID=“0” Counts=“11” Default=“0”>
ModeID=0 HAL_native native
ModeID=7 HAL_sRGB sRGB
ModeID=9 HAL_displayP3 displayP3
ModeID=3 HAL_HDR displayP3 (hdr)
ModeID=23,24,26,31,33,35,39 VND_* variants

– colour correction matrices (identity = no conversion applied) –
<ccorr_table_0> 0x400 0 0 / 0 0x400 0 / 0 0 0x400

=== 4. COLOUR-RELATED PROPERTIES ===
ro.surface_flinger.has_wide_color_display : true
ro.vendor.mtk_pq_color_mode : 3
ro.vendor.mtk_blulight_def_support : 1
ro.vendor.pq.mtk_aal_support : 1
ro.vendor.pq.mtk_caltm_support : 1
persist.vendor.sys.pq.disp.ccorr.bypass : 0
persist.vendor.sys.pq.disp.gamma.bypass : 0
persist.vendor.sys.pq.disp.color.bypass : 0
persist.vendor.sys.pq.disp.aal.bypass : 0

=== 5. HAL: COMPOSER AND PQ SERVICE ===
2642 /vendor/bin/hw/vendor.mediatek.hardware.pq_aidl-service
3544 /vendor/bin/hw/android.hardware.graphics.composer@3.4-service
5521 /system/bin/hw/android.hardware.graphics.composer@2.1-service (App Support)

– registered services –
android.hardware.graphics.composer3.IComposer/default
vendor.mediatek.hardware.composer_ext.IComposerExt/default
vendor.mediatek.hardware.pq_aidl.IPictureQuality_AIDL/default

– who holds /dev/dri/card0 –
pq_aidl-service (2642), composer@3.4 (3544) [not lipstick]

– colour entry points in the vendor HAL –
hwcomposer.mtk_common.so : getColorModeList, setColorMode,
setColorModeWithRenderIntent,
setColorTransform, getRenderIntents
pq_aidl-impl.so : setColorMode, setColorTransform

=== 6. KERNEL COLOUR BLOCKS ===
ccorr 74, aal 210, gamma 49, dither 60, c3d 85 symbols

=== 7. LIBHYBRIS BRIDGE <<< the gap >>> ===
– C API exported to the compositor (glibc side) –
29 entry points, colour-related: hwc2_compat_layer_set_color only
(that is per-layer solid colour for SolidColor composition, unrelated)

– implementation available underneath (bionic side) –
getColorModes, setColorMode, setColorTransform, getRenderIntents

=== 8. COMPOSITOR ===
qpa plugin colour/dataspace references : 0
Qt libraries querying EGL colourspace : 0

=== 9. EGL / GL CAPABILITY (what the driver could do) ===
EGL_KHR_gl_colorspace
EGL_EXT_pixel_format_float
EGL_EXT_gl_colorspace_display_p3 (+ _linear, _passthrough)
EGL_EXT_gl_colorspace_scrgb (+ _linear)
EGL_EXT_gl_colorspace_bt2020_pq / _hlg / _linear

1 Like

Send it please, I want to check with mine.

1 Like

This gradient is a nice test, I have exactly the same outcome. Because of this I currently don’t use adaptive brightness, as it get kind-of unusable when dimming too much.

1 Like

Can you paste it in a pastebin or something? It’s broken when I copy and paste. Thanks :smiley:

Hello, it may be like this for you, but we need to compare it. For example, some people among us had shared photos of their screens showing that they had no issues at all. I wonder what the output of this code looks like on their devices, since their blacks don’t have that green tint…

Please use preformatted text when pasting code. Otherwise, Discourse will apply its own formatting and replace certain characters, causing the script to fail for people who try to run it as is.

2 Likes
#!/bin/sh
# display-pipeline.sh — dump the display colour pipeline state, top to bottom.
#
# Read-only. Changes nothing. Safe to run and paste.
# No extra packages needed — uses binutils "strings" if installed, else python3.
#
#   devel-su sh display-pipeline.sh
#
# Output: /home/defaultuser/Documents/display-pipeline.txt

OUT=/home/defaultuser/Documents/display-pipeline.txt
GP=/system/bin/getprop
SVC=/system/bin/service

h() { echo; echo "=== $* ==="; }

# Portable printable-string extraction. Uses binutils strings when present,
# otherwise python3 (installed by default on Sailfish). Either way no extra
# packages are required.
if command -v strings >/dev/null 2>&1; then
    xstrings() { strings "$1" 2>/dev/null; }
else
    xstrings() {
        python3 -c 'import re,sys
d=open(sys.argv[1],"rb").read()
[print(s.decode()) for s in re.findall(rb"[ -~]{4,}",d)]' "$1" 2>/dev/null
    }
fi
q() { [ -r "$1" ] && sed 's/\x00/ /g' "$1" 2>/dev/null || echo "(n/a)"; }

{
echo "display-pipeline.sh  $(date -u '+%Y-%m-%d %H:%M UTC')"

h "0. DEVICE"
echo "release  : $(sed -n 's/^VERSION=//p' /etc/sailfish-release 2>/dev/null | tr -d '\"')"
echo "hw       : $(sed -n 's/^NAME=//p' /etc/hw-release 2>/dev/null | tr -d '\"') \
$(sed -n 's/^VERSION_ID=//p' /etc/hw-release 2>/dev/null | tr -d '\"')"
echo "kernel   : $(uname -r)"
echo "soc      : $(q /proc/device-tree/model)"
echo "board    : $($GP ro.product.board 2>/dev/null)"
echo "-- please add your batch number when pasting --"

h "1. PANEL"
echo "-- loaded panel modules (only one is bound) --"
lsmod 2>/dev/null | grep -i panel || echo "(none)"
echo
echo "-- which driver claimed the DSI device --"
for d in /sys/bus/mipi-dsi/drivers/*/; do
    n=$(basename "$d")
    dev=$(ls "$d" 2>/dev/null | grep -v -E '^(bind|unbind|uevent|module)$' | head -1)
    [ -n "$dev" ] && echo "$n  <= $dev"
done
echo
echo "-- panel candidates in the device tree --"
for p in /proc/device-tree/soc/dsi*/panel*/compatible; do
    [ -r "$p" ] && echo "$(dirname "$p" | xargs basename): $(sed 's/\x00/ /g' "$p")"
done
echo
echo "-- driver self-identification and geometry --"
D=$(dmesg 2>/dev/null | grep -iE 'lcm_probe|lcm_get_modes|panel original size' | head -8)
if [ -n "$D" ]; then echo "$D"
else echo "(not in the kernel ring buffer — it rotates fast; reboot and re-run for this)"; fi

h "2. DRM CONNECTOR"
for c in /sys/class/drm/card0-*/; do
    n=$(basename "$c")
    echo "$n status=$(cat "$c/status" 2>/dev/null) enabled=$(cat "$c/enabled" 2>/dev/null)"
    echo "  modes:"; sed 's/^/    /' "$c/modes" 2>/dev/null
done
echo "  output_bpc : $(cat /sys/kernel/debug/dri/0/DSI-1/output_bpc 2>/dev/null | tr '\n' ' ')"
echo "  vrr_range  : $(cat /sys/kernel/debug/dri/0/DSI-1/vrr_range 2>/dev/null | tr '\n' ' ')"

h "3. VENDOR COLOUR MODES"
if [ -r /vendor/etc/cust_pq.xml ]; then
    grep -o '<PQ_modes[^>]*>' /vendor/etc/cust_pq.xml | head -1
    grep -o '<Mode [^>]*' /vendor/etc/cust_pq.xml | head -20 | while read -r l; do
        printf '  %-12s %-18s %s\n' \
            "$(echo "$l" | grep -o 'ModeID="[0-9]*"')" \
            "$(echo "$l" | grep -o 'Name="[^"]*"')" \
            "$(echo "$l" | grep -o 'ColorSpace="[^"]*"')"
    done
else
    echo "(no /vendor/etc/cust_pq.xml — not a MediaTek PQ device)"
fi
echo
echo "-- colour correction matrices (identity = no conversion applied) --"
if [ -r /vendor/etc/cust_color.xml ]; then
    grep -A3 '<ccorr_table' /vendor/etc/cust_color.xml | head -8
else
    echo "(no cust_color.xml)"
fi

h "4. COLOUR-RELATED PROPERTIES"
echo "-- note: mtk_pq_color_mode names a mode ID; compare against section 3 --"
$GP 2>/dev/null | grep -iE 'wide_color|has_HDR|pq\.(disp|mtk)|blulight|ccorr|gamma|c3d|color' \
    | head -30

h "5. HAL: COMPOSER AND PQ SERVICE"
ps ax 2>/dev/null | grep -E '[c]omposer@|[p]q_aidl' | sed 's/^/  /'
echo
echo "-- registered services --"
$SVC list 2>/dev/null | grep -iE 'composer|PictureQuality' | sed 's/^/  /'
echo
echo "-- who holds the display device --"
lsof /dev/dri/card0 2>/dev/null | awk 'NR>1{print "  "$1" "$2}' | sort -u
echo
echo "-- colour entry points present in the vendor HAL --"
for f in /vendor/lib64/hw/hwcomposer*.so /vendor/lib64/hw/*pq_aidl*.so; do
    [ -r "$f" ] || continue
    echo "  $(basename "$f"):"
    for s in getColorModes getColorModeList setColorMode setColorModeWithRenderIntent \
             setColorTransform getRenderIntents; do
        c=$(xstrings "$f" | grep -c "$s")
        [ "$c" -gt 0 ] && echo "      $s ($c)"
    done
done

h "6. KERNEL COLOUR BLOCKS"
for k in ccorr aal gamma dither c3d; do
    echo "  $k symbols: $(grep -ci "$k" /proc/kallsyms 2>/dev/null)"
done

h "7. LIBHYBRIS BRIDGE  <<< the gap >>>"
G=/usr/lib64/libhwc2.so.1.0.0
B=/usr/libexec/droid-hybris/system/lib64/libhwc2_compat_layer.so
echo "-- C API exported to the compositor (glibc side) --"
if [ -r "$G" ]; then
    echo "  entry points: $(xstrings "$G" | grep -o '^hwc2_compat_[a-z_]*' | sort -u | wc -l)"
    echo "  colour-related:"
    xstrings "$G" | grep -i color | sed 's/^/      /' | sort -u
else
    echo "  ($G not present)"
fi
echo
echo "-- implementation available underneath (bionic side) --"
if [ -r "$B" ]; then
    for m in getColorModes setColorMode setColorTransform getRenderIntents; do
        c=$(xstrings "$B" | grep -c "$m")
        [ "$c" -gt 0 ] && echo "      $m ($c)"
    done
else
    echo "  ($B not present)"
fi

h "8. COMPOSITOR"
Q=/usr/lib64/qt5/plugins/platforms/libhwcomposer.so
echo "  qpa plugin      : $Q"
echo "  colour refs     : $(xstrings "$Q" | grep -ci 'colormode\|dataspace')"
echo "  Qt EGL colourspace queries: $(grep -al 'EGL_KHR_gl_colorspace\|EGL_EXT_gl_colorspace' \
    /usr/lib64/libQt5*.so* "$Q" 2>/dev/null | wc -l) libraries"
echo "  lipstick pid    : $(pgrep -f '[l]ipstick' | head -1)"

h "9. EGL / GL CAPABILITY (what the driver could do)"
for f in /usr/libexec/droid-hybris/system/lib64/libEGL*; do
    [ -r "$f" ] || continue
    xstrings "$f" | grep -oE 'EGL_(KHR|EXT)_gl_colorspace[a-z_0-9]*|EGL_EXT_pixel_format_float' \
        | sort -u | sed 's/^/  /'
    break
done

h "10. RUNTIME EVIDENCE"
echo "  colorMode changed events in kernel log: $(dmesg 2>/dev/null | grep -c 'colorMode changed')"
echo "  (note: this string lives in a userspace HAL library, so it may never"
echo "   reach dmesg at all — a zero here is not proof either way)"

echo
echo "=== END ==="
} > "$OUT" 2>&1

echo "written to $OUT"
wc -l "$OUT"