[Intel-gfx] [PATCH v4 7/8] drm/i915: Do not compute watermarks on a noop.
Maarten Lankhorst
maarten.lankhorst at linux.intel.com
Tue Mar 1 10:11:51 UTC 2016
Op 18-02-16 om 21:51 schreef Zanoni, Paulo R:
> Em Qua, 2016-02-10 às 13:49 +0100, Maarten Lankhorst escreveu:
>> No atomic state should be included after all validation when nothing
>> has
>> changed. During modeset all active planes will be added to the state,
>> while disabled planes won't change their state.
> As someone who is also not super familiar with the new watermarks code,
> I really really wish I had a more detailed commit message to allow me
> to understand your train of thought. I'll ask some questions below to
> validate my understanding.
>
>> Signed-off-by: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
>> Cc: Matt Roper <matthew.d.roper at intel.com>
>> ---
>> drivers/gpu/drm/i915/intel_display.c | 3 +-
>> drivers/gpu/drm/i915/intel_drv.h | 13 ++++++++
>> drivers/gpu/drm/i915/intel_pm.c | 61 +++++++++++++++++++++-----
>> ----------
>> 3 files changed, 51 insertions(+), 26 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/intel_display.c
>> b/drivers/gpu/drm/i915/intel_display.c
>> index 00cb261c6787..6bb1f5dbc7a0 100644
>> --- a/drivers/gpu/drm/i915/intel_display.c
>> +++ b/drivers/gpu/drm/i915/intel_display.c
>> @@ -11910,7 +11910,8 @@ static int intel_crtc_atomic_check(struct
>> drm_crtc *crtc,
>> }
>>
>> ret = 0;
>> - if (dev_priv->display.compute_pipe_wm) {
>> + if (dev_priv->display.compute_pipe_wm &&
>> + (mode_changed || pipe_config->update_pipe || crtc_state-
>>> planes_changed)) {
>> ret = dev_priv->display.compute_pipe_wm(intel_crtc,
>> state);
>> if (ret)
>> return ret;
> Can't this chunk be on its own separate commit? I'm not sure why the
> rest of the commit is related to this change.
>
> It seems the rest of the commit is aimed reducing the number of planes
> we have to lock, not about not computing WMs if nothing in the pipe has
> changed.
>
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h
>> b/drivers/gpu/drm/i915/intel_drv.h
>> index 8effb9ece21e..144597ac74e3 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -1583,6 +1583,19 @@ intel_atomic_get_crtc_state(struct
>> drm_atomic_state *state,
>>
>> return to_intel_crtc_state(crtc_state);
>> }
>> +
>> +static inline struct intel_plane_state *
>> +intel_atomic_get_existing_plane_state(struct drm_atomic_state
>> *state,
>> + struct intel_plane *plane)
>> +{
>> + struct drm_plane_state *plane_state;
>> +
>> + plane_state = drm_atomic_get_existing_plane_state(state,
>> &plane->base);
>> +
>> + return to_intel_plane_state(plane_state);
>> +}
>> +
>> +
> Two newlines above.
>
> It seems you'll be able to simplify a lot of stuff with this new
> function. I'm looking forward to review that patch :)
>
>
>> int intel_atomic_setup_scalers(struct drm_device *dev,
>> struct intel_crtc *intel_crtc,
>> struct intel_crtc_state *crtc_state);
>> diff --git a/drivers/gpu/drm/i915/intel_pm.c
>> b/drivers/gpu/drm/i915/intel_pm.c
>> index 379eabe093cb..8fb8c6891ae6 100644
>> --- a/drivers/gpu/drm/i915/intel_pm.c
>> +++ b/drivers/gpu/drm/i915/intel_pm.c
>> @@ -2010,11 +2010,18 @@ static void ilk_compute_wm_level(const struct
>> drm_i915_private *dev_priv,
>> cur_latency *= 5;
>> }
>>
>> - result->pri_val = ilk_compute_pri_wm(cstate, pristate,
>> - pri_latency, level);
>> - result->spr_val = ilk_compute_spr_wm(cstate, sprstate,
>> spr_latency);
>> - result->cur_val = ilk_compute_cur_wm(cstate, curstate,
>> cur_latency);
>> - result->fbc_val = ilk_compute_fbc_wm(cstate, pristate,
>> result->pri_val);
>> + if (pristate) {
>> + result->pri_val = ilk_compute_pri_wm(cstate,
>> pristate,
>> + pri_latency,
>> level);
>> + result->fbc_val = ilk_compute_fbc_wm(cstate,
>> pristate, result->pri_val);
>> + }
>> +
>> + if (sprstate)
>> + result->spr_val = ilk_compute_spr_wm(cstate,
>> sprstate, spr_latency);
>> +
>> + if (curstate)
>> + result->cur_val = ilk_compute_cur_wm(cstate,
>> curstate, cur_latency);
>> +
>> result->enable = true;
>> }
>>
>> @@ -2287,7 +2294,6 @@ static int ilk_compute_pipe_wm(struct
>> intel_crtc *intel_crtc,
>> const struct drm_i915_private *dev_priv = dev->dev_private;
>> struct intel_crtc_state *cstate = NULL;
>> struct intel_plane *intel_plane;
>> - struct drm_plane_state *ps;
>> struct intel_plane_state *pristate = NULL;
>> struct intel_plane_state *sprstate = NULL;
>> struct intel_plane_state *curstate = NULL;
>> @@ -2306,30 +2312,37 @@ static int ilk_compute_pipe_wm(struct
>> intel_crtc *intel_crtc,
>> memset(pipe_wm, 0, sizeof(*pipe_wm));
>>
>> for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
>> - ps = drm_atomic_get_plane_state(state,
>> - &intel_plane->base);
>> - if (IS_ERR(ps))
>> - return PTR_ERR(ps);
>> + struct intel_plane_state *ps;
>> +
>> + ps = intel_atomic_get_existing_plane_state(state,
>> + intel_pla
>> ne);
>> + if (!ps)
>> + continue;
> Ok, let me see if I understood: if some of these planes is not part of
> the atomic commit, you're not going to include it in the calculations
> since its value is not going to change. This would allow us lock less
> planes, which is the main advantage. Is this correct?
>
> If yes, how much do we really gain by saving some plane locking?
>
> So by not assigning values to result->x_val at ilk_compute_wm_level()
> when NULL is passed you're going to preserve whatever correct values
> were already set earlier, so you don't need to recompute them. Is this
> correct?
>
> If the answer to the above is "yes", then don't we need to remove the
> memset(pipe_wm, 0) at the beginning of ilk_compute_wm_level? Otherwise,
> nothing will be preserved.
>
> There's also the zero-initialization of "config" to consider.
>
> Or maybe instead of all of the above, we're working under the
> assumption that if some of the planes is not part of the atomic commit,
> then all its relevant WM values will be zero?
>
>>
>> if (intel_plane->base.type ==
>> DRM_PLANE_TYPE_PRIMARY)
>> - pristate = to_intel_plane_state(ps);
>> - else if (intel_plane->base.type ==
>> DRM_PLANE_TYPE_OVERLAY)
>> - sprstate = to_intel_plane_state(ps);
>> - else if (intel_plane->base.type ==
>> DRM_PLANE_TYPE_CURSOR)
>> - curstate = to_intel_plane_state(ps);
>> + pristate = ps;
>> + else if (intel_plane->base.type ==
>> DRM_PLANE_TYPE_OVERLAY) {
>> + sprstate = ps;
>> +
>> + if (ps) {
>> + pipe_wm->sprites_enabled = sprstate-
>>> visible;
>> + pipe_wm->sprites_scaled = sprstate-
>>> visible &&
> You're setting these values here...
>
>> + (drm_rect_width(&sprstate-
>>> dst) != drm_rect_width(&sprstate->src) >> 16 ||
>> + drm_rect_height(&sprstate-
>>> dst) != drm_rect_height(&sprstate->src) >> 16);
>> + }
>> + } else if (intel_plane->base.type ==
>> DRM_PLANE_TYPE_CURSOR)
> (missing brackets here, but if you follow my suggestion below you won't
> need them)
>
>> + curstate = ps;
>> }
>>
>> - config.sprites_enabled = sprstate->visible;
>> - config.sprites_scaled = sprstate->visible &&
>> - (drm_rect_width(&sprstate->dst) !=
>> drm_rect_width(&sprstate->src) >> 16 ||
>> - drm_rect_height(&sprstate->dst) !=
>> drm_rect_height(&sprstate->src) >> 16);
>> + config.sprites_enabled = pipe_wm->sprites_enabled;
>> + config.sprites_scaled = pipe_wm->sprites_scaled;
>>
>> pipe_wm->pipe_enabled = cstate->base.active;
>> pipe_wm->sprites_enabled = config.sprites_enabled;
>> pipe_wm->sprites_scaled = config.sprites_scaled;
> ...but then we re-set them here.
>
> Either you could remove these assignments here, or you could move the
> "if (ps)" from the loop to outside it, becoming "if (sprstate)", making
> the post-patch code similar to the pre-patch code. Since both pipe_wm
> and config are zero-initialized you don't even need to think about the
> !sprstate case.
Makes sense, will do so.
>>
>> /* ILK/SNB: LP2+ watermarks only w/o sprites */
>> - if (INTEL_INFO(dev)->gen <= 6 && sprstate->visible)
>> + if (INTEL_INFO(dev)->gen <= 6 && pipe_wm->sprites_enabled)
>> max_level = 1;
>>
>> /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
>> @@ -2352,20 +2365,18 @@ static int ilk_compute_pipe_wm(struct
>> intel_crtc *intel_crtc,
>> ilk_compute_wm_reg_maximums(dev, 1, &max);
>>
>> for (level = 1; level <= max_level; level++) {
>> - struct intel_wm_level wm = {};
>> + struct intel_wm_level *wm = &pipe_wm->wm[level];
>>
>> ilk_compute_wm_level(dev_priv, intel_crtc, level,
>> cstate,
>> - pristate, sprstate, curstate,
>> &wm);
>> + pristate, sprstate, curstate,
>> wm);
>>
>> /*
>> * Disable any watermark level that exceeds the
>> * register maximums since such watermarks are
>> * always invalid.
>> */
>> - if (!ilk_validate_wm_level(level, &max, &wm))
>> + if (!ilk_validate_wm_level(level, &max, wm))
>> break;
>> -
>> - pipe_wm->wm[level] = wm;
> The change in the chunk above is that we're now leaving with non-zero
> wm->{pri,spr,cur}_val if some level is invalid. Given the current
> complexity of the code, it's not trivial verify whether nothing later
> is assuming that invalid levels are all-zero, but it looks like we're
> safe. Anyway, could you please move this to a separate patch that comes
> before the other changes? It seems this change would be safe alone, and
> we're seeing problems with WMs these days, so having nice bisectability
> is a huge plus.
>
Well caught, I think we need to calculate even invalid values, but set ->enable = false in that case.
That is the only way we can ensure that the wm levels are calculated correctly.
I've sent those as separate patches, so I get a full CI run from them.
[PATCH 1/2] drm/i915: Allow preservation of watermarks.
[PATCH 2/2] drm/i915: Only recalculate wm's for planes part of the state, v2.
More information about the Intel-gfx
mailing list