Bug 2502786 - Horizontal lines around moving objects on Thinkpad X1 Carbon Gen14 camera
Summary: Horizontal lines around moving objects on Thinkpad X1 Carbon Gen14 camera
Keywords:
Status: NEW
Alias: None
Product: Fedora
Classification: Fedora
Component: libcamera
Version: 44
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Javier Martinez Canillas
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks: 2184978
TreeView+ depends on / blocked
 
Reported: 2026-07-20 13:14 UTC by Kamil Páral
Modified: 2026-08-31 05:43 UTC (History)
11 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Type: Bug
Embargoed:


Attachments (Terms of Use)
example photo with horizontal lines (5.71 MB, image/png)
2026-07-20 13:19 UTC, Kamil Páral
no flags Details

Description Kamil Páral 2026-07-20 13:14:27 UTC
Description of problem:
This is a follow-up of bug 2483180. The camera on Thinkpad X1 Carbon Gen14 now works, but displays colored (mostly blue and orange) horizontal lines, around the edges of moving objects. It doesn't happen all the time, but very frequently, with cyclicly lowering and increasing density.

An example photo is attached.

Quite interestingly, when I tried to record video, the lines almost disappeared. Not fully, but enough to be hardly visible in the recorded video. This happened both when I started recording in Snapshot (a GNOME video app) and integrated GNOME desktop recording. So I had to capture the screen at the right time instead with Printscreen, and make it a photo instead.

Version-Release number of selected component (if applicable):
kernel-7.1.4-200.fc44.x86_64
libcamera-0.7.1-1.fc44.x86_64
intel-vsc-firmware-20260622-1.fc44.noarch

How reproducible:
always

Steps to Reproduce:
1. start the camera (e.g. Snapshot or qcam)
2. move objects in front of the camera
3. see colored horizontal lines from time to time (every few seconds at least)

Comment 1 Kamil Páral 2026-07-20 13:19:57 UTC
Created attachment 2149312 [details]
example photo with horizontal lines

Comment 2 Mark Pearson 2026-07-20 14:48:45 UTC
Just to rule out it being a graphics/panel issue - could you try adding xe.enable_psr=0 xe.enable_panel_replay=0 to the kernel bootargs and see if it makes a difference?

We've been having a ton of issues with the SDC OLED panel on various platform - but not (so far) on the X1 Carbon. I just want to make sure you're not seeing an effect here related to that.

Mark

Comment 3 Kate Hsuan 2026-07-21 06:56:30 UTC
Hi Mark,

I noticed this issue on X9-15 (haven't test it on 14) with Fedora 7.1 kenrel.
It seemed to be mitigated by reducing the default exposure value when I worked on upstreamming it. .
(#define IMX471_EXPOSURE_DEFAULT			1270)
After it got merged into upstream, I patched the Fedora 7.1 kernel and it showed again. I haven't addressed what component causes this issue and try to tune the sensor's parameter to find the solution.

Comment 4 Kamil Páral 2026-07-21 12:12:30 UTC
(In reply to Mark Pearson from comment #2)
> Just to rule out it being a graphics/panel issue - could you try adding
> xe.enable_psr=0 xe.enable_panel_replay=0 to the kernel bootargs and see if
> it makes a difference?

No difference. I haven't seen it anywhere else than in the camera app, so it seems camera-related.

Comment 5 Robert Mader 2026-08-14 20:30:57 UTC
I'm pretty sure to have seen this before with libcamera/Snapshot. IIRC Hand de Goede was running into it while still working on Intel devices and if I'm not mistaken it's likely a Intel GPU driver synchronization bug. Note that we're dealing with a zero-copy pipeline (from libcameras softISP/DebayerEGL, through pipewire, into the GTK4 renderer).

Could you check if disabling Vulkan in Snapshot helps ("GDK_DISABLE=vulkan snapshot")? Or, alternatively, running it with a software GL driver (`GDK_DISABLE=vulkan LIBGL_ALWAYS_SOFTWARE=1 snapshot`)?

Comment 6 Kamil Páral 2026-08-18 13:49:39 UTC
(In reply to Robert Mader from comment #5)
> Could you check if disabling Vulkan in Snapshot helps ("GDK_DISABLE=vulkan
> snapshot")? 

This doesn't help.

> Or, alternatively, running it with a software GL driver
> (`GDK_DISABLE=vulkan LIBGL_ALWAYS_SOFTWARE=1 snapshot`)?

This helps indeed. No colored bars anymore.

Should this get re-assigned somewhere else? Or are you aware of an upstream issue for this?

Comment 7 Kate Hsuan 2026-08-22 03:02:38 UTC
(In reply to Mark Pearson from comment #2)
> Just to rule out it being a graphics/panel issue - could you try adding
> xe.enable_psr=0 xe.enable_panel_replay=0 to the kernel bootargs and see if
> it makes a difference?
> 
> We've been having a ton of issues with the SDC OLED panel on various
> platform - but not (so far) on the X1 Carbon. I just want to make sure
> you're not seeing an effect here related to that.
> 
> Mark

Hi Mark,

I tested again, and this issue is not caused by the panel issue.

Comment 8 Rendoe 2026-08-26 06:44:35 UTC
(In reply to Kate Hsuan from comment #3)
> Hi Mark,
> 
> I noticed this issue on X9-15 (haven't test it on 14) with Fedora 7.1 kenrel.
> It seemed to be mitigated by reducing the default exposure value when I
> worked on upstreamming it. .
> (#define IMX471_EXPOSURE_DEFAULT			1270)
> After it got merged into upstream, I patched the Fedora 7.1 kernel and it
> showed again. I haven't addressed what component causes this issue and try
> to tune the sensor's parameter to find the solution.

Hi Kate,

Thank you for working on the imx471 driver! In regards to the lines artefacts issue, it actually occurs with the in-tree staging intel_ipu7 driver on both libcamera (qcam, `gst-launch-1.0 libcamerasrc ! autovideosink`) and icamera (`gst-launch-1.0 icamerasrc ! autovideosink`).

For ThinkPad x9 15p (Panther Lake) using imx471-dkms ( https://github.com/BenBJD/imx471-dkms ) on NixOS (kernel 7.0, 7.1, 7.2), I found that it's resolved after using this specific patch/v7.0.0_iot/0003-media-ipu-Dma-sync-at-buffer_prepare-callback-as-DMA.patch from intel/ipu7-drivers ( https://github.com/intel/ipu7-drivers/blob/main/patch/v7.0.0_iot/0003-media-ipu-Dma-sync-at-buffer_prepare-callback-as-DMA.patch ) applied on the in-tree staging ipu7 drivers (ipu7-isys-queue.c).
The staging one must be used with the patch as forcing the full out-of-tree intel/ipu7-drivers (overriding the KV_IPU7_ISYS := 6.17.0) does not work with the error `intel_ipu7_isys.isys intel_ipu7.isys.40: no subdevice info provided` preventing the working `intel_ipu7_isys.isys intel_ipu7.isys.40: bind imx471 0-001a nlanes is 4 port is 0` `All sensor registration completed`. I've packaged the staging intel_ipu7 driver with the intel/ipu7-drivers (intel_ipu7_psys & staging patches) together as DKMS ( https://github.com/Rend0e/staging-ipu7-dkms ) to avoid needing kernel rebuilds (for other distros). 
So it would be great if that 0003-media-ipu-Dma-sync-at-buffer_prepare-callback-as-DMA.patch also makes it to linux-media.git v7.3 together with the imx471 + ipu-bridge to get the kernel side working out of the box in 7.3!


On that note for kernel 7.3, I believe the imx471 driver should also revert
> Changes in v4:
> ...
> 3. Decrease the max analog gain to 800 to mitigate the image flickering problem.
> https://lore.kernel.org/all/20260609124926.1038981-1-hpa@redhat.com/

`#define IMX471_ANA_GAIN_MAX			800`
back to
`#define IMX471_ANA_GAIN_MAX			960`

since the gain multiplier seems limitingly capped at 4.57143x instead of reaching up to the expected 16x, so it doesn't reach the full/expected brightness for most lighting conditions. On libcamera, it results in dimmed lighting from incorrect IPASoft: Exposure 1-1290, gain 1-4.57143 instead of `IPASoft: Exposure 1-1290, gain 1-16 (0.15)`. On icamera, this causes extreme green image in most low-medium lighting conditions. I've tested that reverting ANA_GAIN_GLOBAL back to 960 fixes both brightness issues ( https://github.com/BenBJD/imx471-dkms/pull/14 ) although icamera still remains green at lower lighting conditions ( probably from incorrect AIQB tuning https://github.com/intel/ipu7-camera-hal/issues/45 ).

Regarding libcamera, I've attempted the colour tuning for imx471 ( https://github.com/BenBJD/imx471-dkms/pull/15 ) with trial and error, ended up with some sort of ad hoc method: 
 - parse_aiqb.py (https://jetm.github.io/blog/posts/ipu6-aiqb-calibration/) was used on IMX471_AAJH5-D_LNL.aiqb (ipu6-camera-hal), IMX471_BBG803N3_PTL.aiqb (ipu7-camera-hal), extracted X9 15p Lenovo Windows driver including TBE0020A0_AAJH5-D_PTL.aiqb and identical TBE0020A0_CBG802N3AP_PTL.aiqb, TBE0020A0_CBG802N3A_PTL.aiqb, TBE0020A0_CJFPE90P_PTL.aiqb, TBE0020A0_CJFPE90_PTL.aiqb). 
- From the output of parse_aiqb.py, the ratio of "Advanced color matrices (id=25, 5 entries, float CCMs)" R/G and B/G of each colour temperature (ct) were multiplied by 2.2 (default libcamera gamma value) while the G value was manually adjusted (at 0.88, 0.68) to reduce the remaining green tint with the ccm as an diagonal matrix [R G B]! It was tested under my room's lighting condition that I've been using in video meeting all fine so far. So it may need more refinement/testing under different lighting conditions/temperatures but may be usable indoors if bright enough? 

I've also noticed that upstream git ( https://gitlab.freedesktop.org/camera/libcamera/-/commit/59e7f18952de3aaa5e4948928e7602779a02296d https://gitlab.freedesktop.org/camera/libcamera/-/commit/e64b507de18774352cbe0bdfd51b637b00a56873 ) has `.unitCellSize = { 1400, 1400 },` instead of `.unitCellSize = { 1000, 1000 },` matching imx471 datasheet (Unit cell size = 1.00 μm 1.00 μm). 
There seems to be conflicting info for the unitCellSize value of:
- 1000 (imx471 datasheet, https://github.com/intel/ipu6-drivers/issues/346#issuecomment-3371507666, https://github.com/NixOS/nixpkgs/issues/516743#issue-4381751765 )
- 1220 ( https://github.com/gdamjan/libcamera/compare/67fd7d720b4845a22d3e97009212d20cd22df83d...87c38c3a5b96ecbf7d7f79ad9ddc019c4ef0f211 )
- 1550 ( https://github.com/TE-ShinnosukeUsami/libcamera/compare/6ddd79b5bdbedc1f61007aed35391f1559f9e29a...7c67c4b3b1b28f71ba9e1da5f780b046347fd56b#diff-afeb5a3fe77bb3514cc5d8712bdff9115bfcdf64ebdae124bc267a7855fa3cdbR127 )
- 1400 ( https://lists.libcamera.org/pipermail/libcamera-devel/2026-July/060695.html )?
I've also attempted experimenting with delay values but I'm not too familiar with it where I couldn't really tell the difference ( https://github.com/Rend0e/libcamera/blob/0.7.2/libcamera-imx471.patch ). I assumed delay values were all 2 from datasheet ("Register settings for Gain are updated 2 frames after those set with GPH." ... "There are always 2 frames delays for the update timing with this sensor." but https://github.com/TE-ShinnosukeUsami/libcamera/compare/6ddd79b5bdbedc1f61007aed35391f1559f9e29a...7c67c4b3b1b28f71ba9e1da5f780b046347fd56b#diff-e6dff53a5e2e9d0a766a52e74480b44a00f9bde7d80e8769d0956395d6d09356R165-R168  has
> exposureDelay = 2;
> gainDelay = 2;
> vblankDelay = 3;
> hblankDelay = 3;
Do you perhaps have any ideas on these? Thanks!

Comment 9 Kate Hsuan 2026-08-27 07:46:40 UTC
(In reply to Rendoe from comment #8)

Hi Rendoe,

Thank you for the input.

> Hi Kate,
> 
> Thank you for working on the imx471 driver! In regards to the lines
> artefacts issue, it actually occurs with the in-tree staging intel_ipu7
> driver on both libcamera (qcam, `gst-launch-1.0 libcamerasrc !
> autovideosink`) and icamera (`gst-launch-1.0 icamerasrc ! autovideosink`).
> 
> For ThinkPad x9 15p (Panther Lake) using imx471-dkms (
> https://github.com/BenBJD/imx471-dkms ) on NixOS (kernel 7.0, 7.1, 7.2), I
> found that it's resolved after using this specific
> patch/v7.0.0_iot/0003-media-ipu-Dma-sync-at-buffer_prepare-callback-as-DMA.
> patch from intel/ipu7-drivers (
> https://github.com/intel/ipu7-drivers/blob/main/patch/v7.0.0_iot/0003-media-
> ipu-Dma-sync-at-buffer_prepare-callback-as-DMA.patch ) applied on the
> in-tree staging ipu7 drivers (ipu7-isys-queue.c).
> The staging one must be used with the patch as forcing the full out-of-tree
> intel/ipu7-drivers (overriding the KV_IPU7_ISYS := 6.17.0) does not work
> with the error `intel_ipu7_isys.isys intel_ipu7.isys.40: no subdevice info
> provided` preventing the working `intel_ipu7_isys.isys intel_ipu7.isys.40:
> bind imx471 0-001a nlanes is 4 port is 0` `All sensor registration
> completed`. I've packaged the staging intel_ipu7 driver with the
> intel/ipu7-drivers (intel_ipu7_psys & staging patches) together as DKMS (
> https://github.com/Rend0e/staging-ipu7-dkms ) to avoid needing kernel
> rebuilds (for other distros). 
> So it would be great if that
> 0003-media-ipu-Dma-sync-at-buffer_prepare-callback-as-DMA.patch also makes
> it to linux-media.git v7.3 together with the imx471 + ipu-bridge to get the
> kernel side working out of the box in 7.3!
> 
> 
> On that note for kernel 7.3, I believe the imx471 driver should also revert
> > Changes in v4:
> > ...
> > 3. Decrease the max analog gain to 800 to mitigate the image flickering problem.
> > https://lore.kernel.org/all/20260609124926.1038981-1-hpa@redhat.com/
> 
> `#define IMX471_ANA_GAIN_MAX			800`
> back to
> `#define IMX471_ANA_GAIN_MAX			960`
> 
> since the gain multiplier seems limitingly capped at 4.57143x instead of
> reaching up to the expected 16x, so it doesn't reach the full/expected
> brightness for most lighting conditions. On libcamera, it results in dimmed
> lighting from incorrect IPASoft: Exposure 1-1290, gain 1-4.57143 instead of
> `IPASoft: Exposure 1-1290, gain 1-16 (0.15)`. On icamera, this causes
> extreme green image in most low-medium lighting conditions. I've tested that
> reverting ANA_GAIN_GLOBAL back to 960 fixes both brightness issues (
> https://github.com/BenBJD/imx471-dkms/pull/14 ) although icamera still
> remains green at lower lighting conditions ( probably from incorrect AIQB
> tuning https://github.com/intel/ipu7-camera-hal/issues/45 ).

If set up the max gain to 960 and max exposure to 1280, I only get a complete white and over exposure image at that time. I guess it is this issue for the libcamera at that time.
I can fix the default exposure to 1280 and max analog gain to 960 and submit to upstream if no obvious issue was found with the latest libcamera.

> 
> Regarding libcamera, I've attempted the colour tuning for imx471 (
> https://github.com/BenBJD/imx471-dkms/pull/15 ) with trial and error, ended
> up with some sort of ad hoc method: 
>  - parse_aiqb.py (https://jetm.github.io/blog/posts/ipu6-aiqb-calibration/)
> was used on IMX471_AAJH5-D_LNL.aiqb (ipu6-camera-hal),
> IMX471_BBG803N3_PTL.aiqb (ipu7-camera-hal), extracted X9 15p Lenovo Windows
> driver including TBE0020A0_AAJH5-D_PTL.aiqb and identical
> TBE0020A0_CBG802N3AP_PTL.aiqb, TBE0020A0_CBG802N3A_PTL.aiqb,
> TBE0020A0_CJFPE90P_PTL.aiqb, TBE0020A0_CJFPE90_PTL.aiqb). 
> - From the output of parse_aiqb.py, the ratio of "Advanced color matrices
> (id=25, 5 entries, float CCMs)" R/G and B/G of each colour temperature (ct)
> were multiplied by 2.2 (default libcamera gamma value) while the G value was
> manually adjusted (at 0.88, 0.68) to reduce the remaining green tint with
> the ccm as an diagonal matrix [R G B]! It was tested under my room's
> lighting condition that I've been using in video meeting all fine so far. So
> it may need more refinement/testing under different lighting
> conditions/temperatures but may be usable indoors if bright enough? 
> 
> I've also noticed that upstream git (
> https://gitlab.freedesktop.org/camera/libcamera/-/commit/
> 59e7f18952de3aaa5e4948928e7602779a02296d
> https://gitlab.freedesktop.org/camera/libcamera/-/commit/
> e64b507de18774352cbe0bdfd51b637b00a56873 ) has `.unitCellSize = { 1400, 1400
> },` instead of `.unitCellSize = { 1000, 1000 },` matching imx471 datasheet
> (Unit cell size = 1.00 μm 1.00 μm). 

You are right. The cell size is 1.00 µm (H) × 1.00 µm (V)

> There seems to be conflicting info for the unitCellSize value of:
> - 1000 (imx471 datasheet,
> https://github.com/intel/ipu6-drivers/issues/346#issuecomment-3371507666,
> https://github.com/NixOS/nixpkgs/issues/516743#issue-4381751765 )
> - 1220 (
> https://github.com/gdamjan/libcamera/compare/
> 67fd7d720b4845a22d3e97009212d20cd22df83d...
> 87c38c3a5b96ecbf7d7f79ad9ddc019c4ef0f211 )
> - 1550 (
> https://github.com/TE-ShinnosukeUsami/libcamera/compare/
> 6ddd79b5bdbedc1f61007aed35391f1559f9e29a...
> 7c67c4b3b1b28f71ba9e1da5f780b046347fd56b#diff-
> afeb5a3fe77bb3514cc5d8712bdff9115bfcdf64ebdae124bc267a7855fa3cdbR127 )
> - 1400 (
> https://lists.libcamera.org/pipermail/libcamera-devel/2026-July/060695.html
> )?
> I've also attempted experimenting with delay values but I'm not too familiar
> with it where I couldn't really tell the difference (
> https://github.com/Rend0e/libcamera/blob/0.7.2/libcamera-imx471.patch ). I
> assumed delay values were all 2 from datasheet ("Register settings for Gain
> are updated 2 frames after those set with GPH." ... "There are always 2
> frames delays for the update timing with this sensor." but
> https://github.com/TE-ShinnosukeUsami/libcamera/compare/
> 6ddd79b5bdbedc1f61007aed35391f1559f9e29a...
> 7c67c4b3b1b28f71ba9e1da5f780b046347fd56b#diff-
> e6dff53a5e2e9d0a766a52e74480b44a00f9bde7d80e8769d0956395d6d09356R165-R168 
> has
> > exposureDelay = 2;
> > gainDelay = 2;
> > vblankDelay = 3;
> > hblankDelay = 3;
> Do you perhaps have any ideas on these? Thanks!

I have no idea about the libcamera works since I haven't deep dive into that :(. Could you please submit your fix to the libcamera mail list and describe your fix to them?
libcamera-devel.org
https://lists.libcamera.org/listinfo/libcamera-devel

Comment 10 Christian Murphy 2026-08-30 09:08:32 UTC
Hi all, I have an X1 Carbon Gen 14 here with the same camera. I hit this issue a couple weeks back, and ended up going after it in the kernel.

Rendoe, nice spot on the Intel patch, I sent the same fix to linux-media on Aug 24th: https://lore.kernel.org/linux-media/20260824224139.21256-1-christian@themurphys.eu/

It does what Intel's 0003 does, ipu7_dma_sync_sgtable in buf_prepare, and also syncs in buf_finish and checks the sg table in buf_init since the queue takes DMABUF. As far as I can tell Intel's patch was never posted to linux-media, it's only in their out-of-tree repo. Mine hasn't had any replies yet, so if either of you can give it a run and reply with a Tested-by that would be really helpful.

For what it's worth the cause is missing cache invalidation on x86. In raw capture with no ISP, 7.3% of each frame is identical to the frame four buffers earlier, i.e. one rotation of libcamera's pool. Memory traffic evicts the stale lines, which is why LIBGL_ALWAYS_SOFTWARE and recording look like they help.

Kate, one thing on the driver. It never writes LINE_LENGTH_PCK, so llp 2328 and 160MHz pixel_rate aren't what the sensor actually runs. Measured line time is 13.22us, which works out to 193.6MHz with llp 2560 from the mode's own PLL registers. Every ExposureTime and FrameDuration libcamera reports is about 10% long, it currently claims an 18.77ms exposure inside a 17.3ms frame. I have a patch drafted and will send it to the list with you CC'd.

One more for this sensor, unrelated to the dashes. libcamera's GPU debayer (default softISP path) gets the Bayer row parity wrong when it downscales 1088 rows to 480. Shows up as a magenta line every 15 rows, static across the frame. 720p and native are fine. I have a two patch fix against libcamera master I'll be sending to libcamera-devel.

I think this bug should move from libcamera to kernel.

Comment 11 Kate Hsuan 2026-08-31 05:43:09 UTC
Hi,

Thank you for your work.

We are working on the same thing :)

I'll test your upstream work in this couple days.


Note You need to log in before you can comment on or make changes to this bug.