Skip to content

Commit 1aa4df7

Browse files
vsyrjalarodrigovivi
authored andcommitted
drm/i915: Preload LUTs if the hw isn't currently using them
The LUTs are single buffered so in order to program them without tearing we'd have to do it during vblank (actually to be 100% effective it has to happen between start of vblank and frame start). We have no proper mechanism for that at the moment so we just defer loading them after the vblank waits have happened. That is not quite sufficient (especially when committing multiple pipes whose vblanks don't line up) so the LUT load will often leak into the following frame causing tearing. However in case the hardware wasn't previously using the LUT we can preload it before setting the enable bit (which is double buffered so won't tear). Let's determine if we can do such preloading and make it happen. Slight variation between the hardware requires some platforms specifics in the checks. Hans is seeing ugly colored flash on VLV/CHV macchines (GPD win and Asus T100HA) when the gamma LUT gets loaded for the first time as the BIOS has left some junk in the LUT memory. v2: Deal with uapi vs. hw crtc state split s/GCM/CGM/ typo fix Cc: Hans de Goede <[email protected]> Fixes: 051a6d8 ("drm/i915: Move LUT programming to happen after vblank waits") Signed-off-by: Ville Syrjälä <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Tested-by: Hans de Goede <[email protected]> Reviewed-by: Hans de Goede <[email protected]> (cherry picked from commit 0ccc42a) Signed-off-by: Joonas Lahtinen <[email protected]> (cherry picked from commit f770213) Signed-off-by: Rodrigo Vivi <[email protected]>
1 parent 8ac495f commit 1aa4df7

File tree

4 files changed

+69
-0
lines changed

4 files changed

+69
-0
lines changed

drivers/gpu/drm/i915/display/intel_atomic.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc)
201201
crtc_state->update_wm_post = false;
202202
crtc_state->fb_changed = false;
203203
crtc_state->fifo_changed = false;
204+
crtc_state->preload_luts = false;
204205
crtc_state->wm.need_postvbl_update = false;
205206
crtc_state->fb_bits = 0;
206207
crtc_state->update_planes = 0;

drivers/gpu/drm/i915/display/intel_color.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,55 @@ void intel_color_commit(const struct intel_crtc_state *crtc_state)
990990
dev_priv->display.color_commit(crtc_state);
991991
}
992992

993+
static bool intel_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
994+
{
995+
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
996+
struct intel_atomic_state *state =
997+
to_intel_atomic_state(new_crtc_state->base.state);
998+
const struct intel_crtc_state *old_crtc_state =
999+
intel_atomic_get_old_crtc_state(state, crtc);
1000+
1001+
return !old_crtc_state->base.gamma_lut &&
1002+
!old_crtc_state->base.degamma_lut;
1003+
}
1004+
1005+
static bool chv_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
1006+
{
1007+
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
1008+
struct intel_atomic_state *state =
1009+
to_intel_atomic_state(new_crtc_state->base.state);
1010+
const struct intel_crtc_state *old_crtc_state =
1011+
intel_atomic_get_old_crtc_state(state, crtc);
1012+
1013+
/*
1014+
* CGM_PIPE_MODE is itself single buffered. We'd have to
1015+
* somehow split it out from chv_load_luts() if we wanted
1016+
* the ability to preload the CGM LUTs/CSC without tearing.
1017+
*/
1018+
if (old_crtc_state->cgm_mode || new_crtc_state->cgm_mode)
1019+
return false;
1020+
1021+
return !old_crtc_state->base.gamma_lut;
1022+
}
1023+
1024+
static bool glk_can_preload_luts(const struct intel_crtc_state *new_crtc_state)
1025+
{
1026+
struct intel_crtc *crtc = to_intel_crtc(new_crtc_state->base.crtc);
1027+
struct intel_atomic_state *state =
1028+
to_intel_atomic_state(new_crtc_state->base.state);
1029+
const struct intel_crtc_state *old_crtc_state =
1030+
intel_atomic_get_old_crtc_state(state, crtc);
1031+
1032+
/*
1033+
* The hardware degamma is active whenever the pipe
1034+
* CSC is active. Thus even if the old state has no
1035+
* software degamma we need to avoid clobbering the
1036+
* linear hardware degamma mid scanout.
1037+
*/
1038+
return !old_crtc_state->csc_enable &&
1039+
!old_crtc_state->base.gamma_lut;
1040+
}
1041+
9931042
int intel_color_check(struct intel_crtc_state *crtc_state)
9941043
{
9951044
struct drm_i915_private *dev_priv = to_i915(crtc_state->base.crtc->dev);
@@ -1133,6 +1182,8 @@ static int i9xx_color_check(struct intel_crtc_state *crtc_state)
11331182
if (ret)
11341183
return ret;
11351184

1185+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
1186+
11361187
return 0;
11371188
}
11381189

@@ -1185,6 +1236,8 @@ static int chv_color_check(struct intel_crtc_state *crtc_state)
11851236
if (ret)
11861237
return ret;
11871238

1239+
crtc_state->preload_luts = chv_can_preload_luts(crtc_state);
1240+
11881241
return 0;
11891242
}
11901243

@@ -1224,6 +1277,8 @@ static int ilk_color_check(struct intel_crtc_state *crtc_state)
12241277
if (ret)
12251278
return ret;
12261279

1280+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
1281+
12271282
return 0;
12281283
}
12291284

@@ -1281,6 +1336,8 @@ static int ivb_color_check(struct intel_crtc_state *crtc_state)
12811336
if (ret)
12821337
return ret;
12831338

1339+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
1340+
12841341
return 0;
12851342
}
12861343

@@ -1319,6 +1376,8 @@ static int glk_color_check(struct intel_crtc_state *crtc_state)
13191376
if (ret)
13201377
return ret;
13211378

1379+
crtc_state->preload_luts = glk_can_preload_luts(crtc_state);
1380+
13221381
return 0;
13231382
}
13241383

@@ -1368,6 +1427,8 @@ static int icl_color_check(struct intel_crtc_state *crtc_state)
13681427

13691428
crtc_state->csc_mode = icl_csc_mode(crtc_state);
13701429

1430+
crtc_state->preload_luts = intel_can_preload_luts(crtc_state);
1431+
13711432
return 0;
13721433
}
13731434

drivers/gpu/drm/i915/display/intel_display.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13743,6 +13743,11 @@ static void intel_update_crtc(struct intel_crtc *crtc,
1374313743
/* vblanks work again, re-enable pipe CRC. */
1374413744
intel_crtc_enable_pipe_crc(crtc);
1374513745
} else {
13746+
if (new_crtc_state->preload_luts &&
13747+
(new_crtc_state->base.color_mgmt_changed ||
13748+
new_crtc_state->update_pipe))
13749+
intel_color_load_luts(new_crtc_state);
13750+
1374613751
intel_pre_plane_update(old_crtc_state, new_crtc_state);
1374713752

1374813753
if (new_crtc_state->update_pipe)
@@ -14037,6 +14042,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
1403714042
for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state, i) {
1403814043
if (new_crtc_state->base.active &&
1403914044
!needs_modeset(new_crtc_state) &&
14045+
!new_crtc_state->preload_luts &&
1404014046
(new_crtc_state->base.color_mgmt_changed ||
1404114047
new_crtc_state->update_pipe))
1404214048
intel_color_load_luts(new_crtc_state);

drivers/gpu/drm/i915/display/intel_display_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ struct intel_crtc_state {
761761
bool update_wm_pre, update_wm_post; /* watermarks are updated */
762762
bool fb_changed; /* fb on any of the planes is changed */
763763
bool fifo_changed; /* FIFO split is changed */
764+
bool preload_luts;
764765

765766
/* Pipe source size (ie. panel fitter input size)
766767
* All planes will be positioned inside this space,

0 commit comments

Comments
 (0)