All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Ville Syrjälä" <ville.syrjala@linux.intel.com>
To: Daniel Vetter <daniel@ffwll.ch>
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [PATCH 15/18] drm/i915: alloc/free the FBC CFB during enable/disable
Date: Wed, 21 Oct 2015 10:20:55 +0300	[thread overview]
Message-ID: <20151021072055.GT26517@intel.com> (raw)
In-Reply-To: <20151021071108.GK13786@phenom.ffwll.local>

On Wed, Oct 21, 2015 at 09:11:08AM +0200, Daniel Vetter wrote:
> On Tue, Oct 20, 2015 at 11:50:01AM -0200, Paulo Zanoni wrote:
> > One of the problems with the current code is that it frees the CFB and
> > releases its drm_mm node as soon as we flip FBC's enable bit. This is
> > bad because after we disbale FBC the hardware may still use the CFB
> > for the rest of the frame, so in theory we should only release the
> > drm_mm node one frame after we disable FBC. Otherwise, a stolen memory
> > allocation done right after an FBC disable may result in either
> > corrupted memory for the new owner of that memory region or corrupted
> > screen/underruns in case the new owner changes it while the hardware
> > is still reading it. This case is not exactly easy to reproduce since
> > we currently don't do a lot of stolen memory allocations, but I see
> > patches on the mailing list trying to expose stolen memory to user
> > space, so races will be possible.
> > 
> > I thought about three different approaches to solve this, and they all
> > have downsides.
> > 
> > The first approach would be to simply use multiple drm_mm nodes and
> > freeing the unused ones only after a frame has passed. The problem
> > with this approach is that since stolen memory is rather small,
> > there's a risk we just won't be able to allocate a new CFB from stolen
> > if the previous one was not freed yet. This could happen in case we
> > quickly disable FBC from pipe A and decide to enable it on pipe B, or
> > just if we change pipe A's fb stride while FBC is enabled.
> > 
> > The second approach would be similar to the first one, but maintaining
> > a single drm_mm node and keeping track of when it can be reused. This
> > would remove the disadvantage of not having enough space for two
> > nodes, but would create the new problem where we may not be able to
> > enable FBC at the point intel_fbc_update() is called, so we would have
> > to add more code to retry updating FBC after the time has passed. And
> > that can quickly get too complex since we can get invalidate, flush,
> > flip_prepare, disable and other calls in the middle of the wait.
> > 
> > Both solutions above - and also the current code - have the problem
> > that we unnecessarily free+realloc FBC during invalidate+flush
> > operations even if the CFB size doesn't change.
> > 
> > The third option would be to move the allocation/deallocation to
> > enable/disable. This makes sure that the pipe is always disabled when
> > we allocate/deallocate the CFB, so there's no risk that the FBC
> > hardware may read or write to the memory right after it is freed from
> > drm_mm. The downside is that it is possible for user space to change
> > the buffer stride without triggering a disable/enable - only
> > deactivate/activate -, so we'll have to handle this case somehow, even
> > though it is uncommon - see igt's kms_frontbuffer_tracking test,
> > fbc-stridechange subtest. It could be possible to implement a way to
> > free+alloc the CFB during said stride change, but it would involve a
> > lot of book-keeping - exactly as mentioned above - just for a rare
> > case, so for now I'll keep it simple and just deactivate FBC. Besides,
> > we may not even need to disable FBC since we do CFB over-allocation.
> > 
> > Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_fbc.c | 132 ++++++++++++++++++++-------------------
> >  1 file changed, 68 insertions(+), 64 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
> > index bf855b2..48d8cfc 100644
> > --- a/drivers/gpu/drm/i915/intel_fbc.c
> > +++ b/drivers/gpu/drm/i915/intel_fbc.c
> > @@ -59,6 +59,45 @@ static unsigned int get_crtc_fence_y_offset(struct intel_crtc *crtc)
> >  	return crtc->base.y - crtc->adjusted_y;
> >  }
> >  
> > +/*
> > + * For SKL+, the plane source size used by the hardware is based on the value we
> > + * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value
> > + * we wrote to PIPESRC.
> > + */
> > +static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc,
> > +					    int *width, int *height)
> > +{
> > +	struct intel_plane_state *plane_state =
> > +			to_intel_plane_state(crtc->base.primary->state);
> > +	int w, h;
> > +
> > +	if (intel_rotation_90_or_270(plane_state->base.rotation)) {
> > +		w = drm_rect_height(&plane_state->src) >> 16;
> > +		h = drm_rect_width(&plane_state->src) >> 16;
> > +	} else {
> > +		w = drm_rect_width(&plane_state->src) >> 16;
> > +		h = drm_rect_height(&plane_state->src) >> 16;
> > +	}
> > +
> > +	if (width)
> > +		*width = w;
> > +	if (height)
> > +		*height = h;
> > +}
> > +
> > +static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc,
> > +					struct drm_framebuffer *fb)
> > +{
> > +	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > +	int lines;
> > +
> > +	intel_fbc_get_plane_source_size(crtc, NULL, &lines);
> > +	if (INTEL_INFO(dev_priv)->gen >= 7)
> > +		lines = min(lines, 2048);
> > +
> > +	return lines * fb->pitches[0];
> 
> Why are we even looking at fb->pitches here? I thought that for fbc we
> only compress what we actually scan out, i.e. the source rectangle of the
> plane in pixels. Maybe some rounding involved perhaps.

IIRC the docs do say the hw uses the plane stride register figure this
out. It's something I've been wondering for a few years now, but never
actually tested to see if we can get away with less.

> 
> Or did I miss something?
> -Daniel
> 
> > +}
> > +
> >  static void i8xx_fbc_deactivate(struct drm_i915_private *dev_priv)
> >  {
> >  	u32 fbc_ctl;
> > @@ -604,11 +643,17 @@ again:
> >  	}
> >  }
> >  
> > -static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, int size,
> > -			       int fb_cpp)
> > +static int intel_fbc_alloc_cfb(struct intel_crtc *crtc)
> >  {
> > +	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > +	struct drm_framebuffer *fb = crtc->base.primary->state->fb;
> >  	struct drm_mm_node *uninitialized_var(compressed_llb);
> > -	int ret;
> > +	int size, fb_cpp, ret;
> > +
> > +	WARN_ON(dev_priv->fbc.compressed_fb.allocated);
> > +
> > +	size = intel_fbc_calculate_cfb_size(crtc, fb);
> > +	fb_cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> >  
> >  	ret = find_compression_threshold(dev_priv, &dev_priv->fbc.compressed_fb,
> >  					 size, fb_cpp);
> > @@ -685,64 +730,6 @@ void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv)
> >  	mutex_unlock(&dev_priv->fbc.lock);
> >  }
> >  
> > -/*
> > - * For SKL+, the plane source size used by the hardware is based on the value we
> > - * write to the PLANE_SIZE register. For BDW-, the hardware looks at the value
> > - * we wrote to PIPESRC.
> > - */
> > -static void intel_fbc_get_plane_source_size(struct intel_crtc *crtc,
> > -					    int *width, int *height)
> > -{
> > -	struct intel_plane_state *plane_state =
> > -			to_intel_plane_state(crtc->base.primary->state);
> > -	int w, h;
> > -
> > -	if (intel_rotation_90_or_270(plane_state->base.rotation)) {
> > -		w = drm_rect_height(&plane_state->src) >> 16;
> > -		h = drm_rect_width(&plane_state->src) >> 16;
> > -	} else {
> > -		w = drm_rect_width(&plane_state->src) >> 16;
> > -		h = drm_rect_height(&plane_state->src) >> 16;
> > -	}
> > -
> > -	if (width)
> > -		*width = w;
> > -	if (height)
> > -		*height = h;
> > -}
> > -
> > -static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc)
> > -{
> > -	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->base.primary->fb;
> > -	int lines;
> > -
> > -	intel_fbc_get_plane_source_size(crtc, NULL, &lines);
> > -	if (INTEL_INFO(dev_priv)->gen >= 7)
> > -		lines = min(lines, 2048);
> > -
> > -	return lines * fb->pitches[0];
> > -}
> > -
> > -static int intel_fbc_setup_cfb(struct intel_crtc *crtc)
> > -{
> > -	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
> > -	struct drm_framebuffer *fb = crtc->base.primary->fb;
> > -	int size, cpp;
> > -
> > -	size = intel_fbc_calculate_cfb_size(crtc);
> > -	cpp = drm_format_plane_cpp(fb->pixel_format, 0);
> > -
> > -	if (dev_priv->fbc.compressed_fb.allocated &&
> > -	    size <= dev_priv->fbc.compressed_fb.size * dev_priv->fbc.threshold)
> > -		return 0;
> > -
> > -	/* Release any current block */
> > -	__intel_fbc_cleanup_cfb(dev_priv);
> > -
> > -	return intel_fbc_alloc_cfb(dev_priv, size, cpp);
> > -}
> > -
> >  static bool stride_is_valid(struct drm_i915_private *dev_priv,
> >  			    unsigned int stride)
> >  {
> > @@ -904,8 +891,19 @@ static void __intel_fbc_update(struct intel_crtc *crtc)
> >  		goto out_disable;
> >  	}
> >  
> > -	if (intel_fbc_setup_cfb(crtc)) {
> > -		set_no_fbc_reason(dev_priv, "not enough stolen memory");
> > +	/* It is possible for the required CFB size change without a
> > +	 * crtc->disable + crtc->enable since it is possible to change the
> > +	 * stride without triggering a full modeset. Since we try to
> > +	 * over-allocate the CFB, there's a chance we may keep FBC enabled even
> > +	 * if this happens, but if we exceed the current CFB size we'll have to
> > +	 * disable FBC. Notice that it would be possible to disable FBC, wait
> > +	 * for a frame, free the stolen node, then try to reenable FBC in case
> > +	 * we didn't get any invalidate/deactivate calls, but this would require
> > +	 * a lot of tracking just for a case we expect to be uncommon, so we
> > +	 * just don't have this code for now. */
> > +	if (intel_fbc_calculate_cfb_size(crtc, fb) >
> > +	    dev_priv->fbc.compressed_fb.size * dev_priv->fbc.threshold) {
> > +		set_no_fbc_reason(dev_priv, "CFB requirements changed");
> >  		goto out_disable;
> >  	}
> >  
> > @@ -958,7 +956,6 @@ out_disable:
> >  		DRM_DEBUG_KMS("unsupported config, deactivating FBC\n");
> >  		__intel_fbc_deactivate(dev_priv);
> >  	}
> > -	__intel_fbc_cleanup_cfb(dev_priv);
> >  }
> >  
> >  /*
> > @@ -1102,6 +1099,11 @@ void intel_fbc_enable(struct intel_crtc *crtc)
> >  		goto out;
> >  	}
> >  
> > +	if (intel_fbc_alloc_cfb(crtc)) {
> > +		set_no_fbc_reason(dev_priv, "not enough stolen memory");
> > +		goto out;
> > +	}
> > +
> >  	DRM_DEBUG_KMS("Enabling FBC on pipe %c\n", pipe_name(crtc->pipe));
> >  	dev_priv->fbc.no_fbc_reason = "FBC enabled but not active yet\n";
> >  
> > @@ -1129,6 +1131,8 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
> >  
> >  	DRM_DEBUG_KMS("Disabling FBC on pipe %c\n", pipe_name(crtc->pipe));
> >  
> > +	__intel_fbc_cleanup_cfb(dev_priv);
> > +
> >  	dev_priv->fbc.enabled = false;
> >  	dev_priv->fbc.crtc = NULL;
> >  }
> > -- 
> > 2.6.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

  reply	other threads:[~2015-10-21  7:20 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-20 13:49 [PATCH 00/18] Yet another FBC series Paulo Zanoni
2015-10-20 13:49 ` [PATCH 01/18] drm/i915: change no_fbc_reason from enum to string Paulo Zanoni
2015-10-21  6:52   ` Daniel Vetter
2015-10-20 13:49 ` [PATCH 02/18] drm/i915: don't stop+start FBC at every flip Paulo Zanoni
2015-10-21  7:04   ` Daniel Vetter
2015-10-21  7:12     ` Ville Syrjälä
2015-10-21  7:40       ` Ville Syrjälä
2015-10-20 13:49 ` [PATCH 03/18] drm/i915: only nuke FBC when a drawing operation triggers a flush Paulo Zanoni
2015-10-20 15:59   ` Chris Wilson
2015-10-21 17:08     ` Zanoni, Paulo R
2015-10-21 17:31       ` chris
2015-10-21 17:51         ` Zanoni, Paulo R
2015-10-20 13:49 ` [PATCH 04/18] drm/i915: extract crtc_is_valid() on the FBC code Paulo Zanoni
2015-10-20 15:52   ` Chris Wilson
2015-10-21 17:16     ` Zanoni, Paulo R
2015-10-21 17:28       ` chris
2015-10-22  7:52   ` Maarten Lankhorst
2015-10-22 19:26     ` Zanoni, Paulo R
2015-10-22 19:42       ` Ville Syrjälä
2015-10-20 13:49 ` [PATCH 05/18] drm/i915: set dev_priv->fbc.crtc before scheduling the enable work Paulo Zanoni
2015-10-20 16:03   ` Chris Wilson
2015-10-21 17:27     ` Zanoni, Paulo R
2015-10-21 18:15       ` chris
2015-10-20 13:49 ` [PATCH 06/18] drm/i915: use struct intel_crtc *crtc at __intel_fbc_update() Paulo Zanoni
2015-10-20 13:49 ` [PATCH 07/18] drm/i915: fix the __intel_fbc_update() comments Paulo Zanoni
2015-10-21 12:37   ` Chris Wilson
2015-10-21 17:32     ` Zanoni, Paulo R
2015-10-21 17:38       ` chris
2015-10-22 20:15         ` Zanoni, Paulo R
2015-10-20 13:49 ` [PATCH 08/18] drm/i915: pass the crtc as an argument to intel_fbc_update() Paulo Zanoni
2015-10-20 13:49 ` [PATCH 09/18] drm/i915: don't disable_fbc() if FBC is already disabled Paulo Zanoni
2015-10-20 13:49 ` [PATCH 10/18] drm/i915: introduce is_active/activate/deactivate to the FBC terminology Paulo Zanoni
2015-10-21 12:34   ` Chris Wilson
2015-10-21 17:45     ` Zanoni, Paulo R
2015-10-21 17:55       ` chris
2015-10-20 13:49 ` [PATCH 11/18] drm/i915: refactor FBC deactivation at init Paulo Zanoni
2015-10-21 12:59   ` Chris Wilson
2015-10-20 13:49 ` [PATCH 12/18] drm/i915: introduce intel_fbc_{enable, disable} Paulo Zanoni
2015-10-20 15:55   ` Chris Wilson
2015-10-20 13:49 ` [PATCH 13/18] drm/i915: remove too-frequent FBC debug message Paulo Zanoni
2015-10-21 13:01   ` Chris Wilson
2015-10-21 18:19     ` Zanoni, Paulo R
2015-10-22 19:52       ` chris
2015-10-20 13:50 ` [PATCH 14/18] drm/i915: fix the CFB size check Paulo Zanoni
2015-10-20 13:50 ` [PATCH 15/18] drm/i915: alloc/free the FBC CFB during enable/disable Paulo Zanoni
2015-10-21  7:11   ` Daniel Vetter
2015-10-21  7:20     ` Ville Syrjälä [this message]
2015-10-21  7:24       ` Daniel Vetter
2015-10-21 18:30         ` Zanoni, Paulo R
2015-10-22  7:59           ` Daniel Vetter
2015-10-20 13:50 ` [PATCH 16/18] drm/i915: move adjusted_mode checks from fbc_update to fbc_enable Paulo Zanoni
2015-10-20 13:50 ` [PATCH 17/18] drm/i915: move clock frequency " Paulo Zanoni
2015-10-20 13:50 ` [PATCH 18/18] drm/i915: check for FBC planes in the same place as the pipes Paulo Zanoni
2015-10-20 21:22 ` [PATCH igt 1/4] kms_frontbuffer_tracking: unset crtcs after getting the base blue CRC Paulo Zanoni
2015-10-20 21:22   ` [PATCH igt 2/4] kms_frontbuffer_tracking: add flag to not assert feature status Paulo Zanoni
2015-10-20 21:22   ` [PATCH igt 3/4] kms_frontbuffer_tracking: add stridechange subtest Paulo Zanoni
2015-10-20 21:22   ` [PATCH igt 4/4] kms_frontbuffer_tracking: remove opt.only_feature Paulo Zanoni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151021072055.GT26517@intel.com \
    --to=ville.syrjala@linux.intel.com \
    --cc=daniel@ffwll.ch \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.