On Fri, Oct 25, 2019 at 09:23:47PM +0200, Hans de Goede wrote:
> Hi,
> 
> On 21-10-2019 16:39, Ville Syrjälä wrote:
> > On Sun, Oct 20, 2019 at 08:19:33PM +0200, Hans de Goede wrote:
> >> Since commit 051a6d8d3ca0 ("drm/i915: Move LUT programming to happen after
> >> vblank waits"), I am seeing an ugly colored flash of the first few display
> >> lines on 2 Cherry Trail devices when the gamma table gets set for the first
> >> time. A blue flash on a GPD win and a yellow flash on an Asus T100HA.
> >>
> >> The problem is that since this change, the LUT is programmed after the
> >> write *and latching* of the double-buffered register which causes the LUT
> >> to be used starting at the next frame. This means that the old LUT is still
> >> used for the first couple of lines of the display. If no LUT was in use
> >> before then the LUT registers may contain bogus values. This leads to
> >> messed up colors until the new LUT values are written. At least on CHT DSI
> >> panels this causes messed up colors on the first few lines.
> >>
> >> This commit fixes this by adding a load_lut_before_commit boolean,
> >> modifying intel_begin_crtc_commit to load the luts earlier if this is set,
> >> and setting this from intel_color_check when a LUT table was not in use
> >> before (and thus may contain bogus values), or when the table size
> >> changes.
> > 
> > The real solution is vblank workers, which I have somewhat implemented
> > here:
> > git://github.com/vsyrjala/linux.git vblank_worker_8_kthread
> > 
> > Though even with the qos tricks there we still probably can't quite make
> > it in time. Essentially we have a bit less than one scanline after start
> > of vblank to do the work before pixels start to flow through the pipe.
> > We might be extend that to almost four scanlines but that partocular
> > thing is documeted as debug feature so not sure we should really use it.
> > Also I don't think four scanlines is always enough either. So it's still
> > very much possible that we get the first 100 or so pixels with the old LUT.
> 
> Thank you for the info and for the review.
> 
> 
> >> Fixes: 051a6d8d3ca0 ("drm/i915: Move LUT programming to happen after 
> >> vblank waits")
> >> Signed-off-by: Hans de Goede <[email protected]>
> >> ---
> >>   drivers/gpu/drm/i915/display/intel_color.c    | 26 +++++++++++++++++++
> >>   drivers/gpu/drm/i915/display/intel_display.c  |  7 +++++
> >>   .../drm/i915/display/intel_display_types.h    |  3 +++
> >>   3 files changed, 36 insertions(+)
> >>
> >> diff --git a/drivers/gpu/drm/i915/display/intel_color.c 
> >> b/drivers/gpu/drm/i915/display/intel_color.c
> >> index 71a0201437a9..0da6dcc5bebd 100644
> >> --- a/drivers/gpu/drm/i915/display/intel_color.c
> >> +++ b/drivers/gpu/drm/i915/display/intel_color.c
> >> @@ -1052,6 +1052,32 @@ intel_color_add_affected_planes(struct 
> >> intel_crtc_state *new_crtc_state)
> >>            new_crtc_state->update_planes |= BIT(plane->id);
> >>    }
> >>   
> >> +  /*
> >> +   * Normally we load the LUTs after vblank / after the double-buffer
> >> +   * registers written by commit have been latched, this avoids a
> >> +   * gamma change mid-way the screen. This does mean that the first
> >> +   * few lines of the display will (sometimes) still use the old
> >> +   * table. This is fine when changing an existing LUT, but if this
> >> +   * is the first time the LUT gets loaded, then the hw may contain
> >> +   * random values, causing the first lines to have funky colors.
> >> +   *
> >> +   * So if were enabling a LUT for the first time or changing the table
> >> +   * size, then we must do this before the commit to avoid corrupting
> >> +   * the first lines of the display.
> >> +   */
> >> +  if (!old_crtc_state->base.gamma_lut && new_crtc_state->base.gamma_lut)
> >> +          new_crtc_state->load_lut_before_commit = true;
> >> +  else if (!old_crtc_state->base.degamma_lut &&
> >> +           new_crtc_state->base.degamma_lut)
> >> +          new_crtc_state->load_lut_before_commit = true;
> >> +  else if (old_crtc_state->base.gamma_lut &&
> >> +           new_crtc_state->base.gamma_lut &&
> >> +           lut_is_legacy(old_crtc_state->base.gamma_lut) !=
> >> +                  lut_is_legacy(new_crtc_state->base.gamma_lut))
> >> +          new_crtc_state->load_lut_before_commit = true;
> >> +  else
> >> +          new_crtc_state->load_lut_before_commit = false;
> > 
> > The 'no gamma -> yes gamma' thing I might be willing to accept. The rest
> > not so much. I was already pondering about such optimizations for the
> > plane gamma/csc stuff in my vblank branch.
> 
> Ok, so I can submit a v2 based on dinq with only the
>       if (!old_crtc_state->base.gamma_lut && new_crtc_state->base.gamma_lut)
> check, or
> 
> > But for the fastboot case I think what we could do is just sanitize
> > the LUT(s) after readout if gamma wasn't enabled by the BIOS.
> 
> We could do this, but this falls a bit outside of my expertise, I would be
> more then happy to test a patch on one of the machines which needs this
> LUTS sanitizing though. I get a very visible flash of a couple of bright
> blue or yellow (2 different machines) on the upper few lines the first
> time the gamma table gets loaded, so verifying that the sanitation kicks
> in is easy.

Actually, how recent is your kernel?

Some issues with the gamma readout were fixed quite recently:
9b000b47cc18 ("drm/i915/color: fix broken gamma state-checker during boot")
d50341274d01 ("drm/i915/color: move check of gamma_enable to specific 
func/platform")

If those don't help we could try the quick path and just blast the
gamma from orbit like so:

@@ -16787,18 +16787,23 @@ static int intel_initial_commit(struct drm_device 
*dev)
                        goto out;
                }
 
+               /*
+                * Let's just turn off the BIOS leftover LUT(s).
+                *
+                * FIXME maybe we shouldn't do this, and instead
+                * we should let fb_helper/whatever replace the
+                * LUT(s) when they start to actually render stuff.
+                * But for now we may get an ugly flash due to
+                * non-atomic gamma updates.
+                */
+               drm_property_replace_blob(&crtc_state->degamma_lut, NULL);
+               drm_property_replace_blob(&crtc_state->gamma_lut, NULL);
+               crtc_state->color_mgmt_changed = true;
+
                if (crtc_state->active) {
                        ret = drm_atomic_add_affected_planes(state, crtc);
                        if (ret)
                                goto out;
-
-                       /*
-                        * FIXME hack to force a LUT update to avoid the
-                        * plane update forcing the pipe gamma on without
-                        * having a proper LUT loaded. Remove once we
-                        * have readout for pipe gamma enable.
-                        */
-                       crtc_state->color_mgmt_changed = true;
                }
        }

-- 
Ville Syrjälä
Intel
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to