diff mbox

drm/i915: add support for Z-order of planes.

Message ID 1392941474-5349-1-git-send-email-yu.dai@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

yu.dai@intel.com Feb. 21, 2014, 12:11 a.m. UTC
From: "Yu(Alex) Dai" <yu.dai@intel.com>

Add "zorder" property to crtc to control Z-order of sprite and
primary planes. The alpha channel of the planes can be enabled
or disabled during Z-order change.

Signed-off-by: Yu(Alex) Dai <yu.dai@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |  1 +
 drivers/gpu/drm/i915/i915_reg.h      | 10 +++++
 drivers/gpu/drm/i915/intel_display.c | 51 +++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_drv.h     |  6 +++
 drivers/gpu/drm/i915/intel_sprite.c  | 81 ++++++++++++++++++++++++++++++++++--
 5 files changed, 142 insertions(+), 7 deletions(-)

Comments

Matt Roper Feb. 26, 2014, 12:19 a.m. UTC | #1
On Thu, Feb 20, 2014 at 04:11:14PM -0800, yu.dai@intel.com wrote:
> From: "Yu(Alex) Dai" <yu.dai@intel.com>
> 
> Add "zorder" property to crtc to control Z-order of sprite and
> primary planes. The alpha channel of the planes can be enabled
> or disabled during Z-order change.
> 
> Signed-off-by: Yu(Alex) Dai <yu.dai@intel.com>

It seems like this is pretty VLV-specific at the moment.  Aren't you
going to be writing bogus register values if you try to set this
property on a non-VLV platform?

I'm not sure if any of the other non-VLV platforms supported by i915
today can change plane z-orders or not, but this is likely to be
possible and useful on future platforms (or non-Intel platforms) as
well, which may have a different number of overall planes and different
ways of programming them.

Would it make more sense to move the z-order value to a plane property
so that the interface scales to any number of planes?  If you just set
an integer value as a per-plane zorder-value, the code that actually
programs the hardware can go collect the values for each plane, sort
them to determine an order, and figure out what that translates to in
terms of platform-specific register programming.  This would lend itself
nicely to the "check/calculate" step of the atomic/nuclear operation
once those interfaces land.


Matt

> ---
>  drivers/gpu/drm/i915/i915_drv.h      |  1 +
>  drivers/gpu/drm/i915/i915_reg.h      | 10 +++++
>  drivers/gpu/drm/i915/intel_display.c | 51 +++++++++++++++++++++--
>  drivers/gpu/drm/i915/intel_drv.h     |  6 +++
>  drivers/gpu/drm/i915/intel_sprite.c  | 81 ++++++++++++++++++++++++++++++++++--
>  5 files changed, 142 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 8c64831..7833479 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2581,6 +2581,7 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
>  			struct drm_file *file);
>  int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data,
>  			       struct drm_file *file);
> +extern int i915_set_plane_zorder(struct drm_device *dev, u32 zorder);
>  
>  /* overlay */
>  extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 2f564ce..c9a9993 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3743,6 +3743,16 @@
>  #define   SPRITE_INT_GAMMA_ENABLE	(1<<13)
>  #define   SPRITE_TILED			(1<<10)
>  #define   SPRITE_DEST_KEY		(1<<2)
> +#define   SPRITE_FORCE_BOTTOM		(1<<2)
> +#define   SPRITE_ZORDER_ENABLE		(1<<0)
> +
> +#define P1S1S2C1		0
> +#define P1S2S1C1		8
> +#define S2P1S1C1		1
> +#define S2S1P1C1		9
> +#define S1P1S2C1		4
> +#define S1S2P1C1		6
> +
>  #define _SPRA_LINOFF		0x70284
>  #define _SPRA_STRIDE		0x70288
>  #define _SPRA_POS		0x7028c
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index f19e6ea..8ddf6c2 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -2082,18 +2082,27 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  		break;
>  	case DRM_FORMAT_XRGB1555:
>  	case DRM_FORMAT_ARGB1555:
> -		dspcntr |= DISPPLANE_BGRX555;
> +		if (intel_crtc->primary_alpha)
> +			dspcntr |= DISPPLANE_BGRA555;
> +		else
> +			dspcntr |= DISPPLANE_BGRX555;
>  		break;
>  	case DRM_FORMAT_RGB565:
>  		dspcntr |= DISPPLANE_BGRX565;
>  		break;
>  	case DRM_FORMAT_XRGB8888:
>  	case DRM_FORMAT_ARGB8888:
> -		dspcntr |= DISPPLANE_BGRX888;
> +		if (intel_crtc->primary_alpha)
> +			dspcntr |= DISPPLANE_BGRA888;
> +		else
> +			dspcntr |= DISPPLANE_BGRX888;
>  		break;
>  	case DRM_FORMAT_XBGR8888:
>  	case DRM_FORMAT_ABGR8888:
> -		dspcntr |= DISPPLANE_RGBX888;
> +		if (intel_crtc->primary_alpha)
> +			dspcntr |= DISPPLANE_RGBA888;
> +		else
> +			dspcntr |= DISPPLANE_RGBX888;
>  		break;
>  	case DRM_FORMAT_XRGB2101010:
>  	case DRM_FORMAT_ARGB2101010:
> @@ -2101,7 +2110,10 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
>  		break;
>  	case DRM_FORMAT_XBGR2101010:
>  	case DRM_FORMAT_ABGR2101010:
> -		dspcntr |= DISPPLANE_RGBX101010;
> +		if (intel_crtc->primary_alpha)
> +			dspcntr |= DISPPLANE_RGBA101010;
> +		else
> +			dspcntr |= DISPPLANE_RGBX101010;
>  		break;
>  	default:
>  		BUG();
> @@ -8258,6 +8270,9 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
>  
>  	intel_crtc_cursor_set(crtc, NULL, 0, 0, 0);
>  
> +	if (intel_crtc->zorder_property)
> +		drm_property_destroy(dev, intel_crtc->zorder_property);
> +
>  	drm_crtc_cleanup(crtc);
>  
>  	kfree(intel_crtc);
> @@ -10160,6 +10175,22 @@ out_config:
>  	return ret;
>  }
>  
> +static int intel_crtc_set_property(struct drm_crtc *crtc,
> +				   struct drm_property *prop,
> +				   uint64_t val)
> +{
> +	struct intel_crtc *icrtc = to_intel_crtc(crtc);
> +	int ret = -ENOENT;
> +
> +	if (prop == icrtc->zorder_property) {
> +		u32 zorder = (uint32_t)val;
> +		icrtc->zorder = zorder;
> +		ret = i915_set_plane_zorder(crtc->dev, zorder);
> +	}
> +
> +	return ret;
> +}
> +
>  static const struct drm_crtc_funcs intel_crtc_funcs = {
>  	.cursor_set = intel_crtc_cursor_set,
>  	.cursor_move = intel_crtc_cursor_move,
> @@ -10167,6 +10198,7 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
>  	.set_config = intel_crtc_set_config,
>  	.destroy = intel_crtc_destroy,
>  	.page_flip = intel_crtc_page_flip,
> +	.set_property = intel_crtc_set_property,
>  };
>  
>  static void intel_cpu_pll_init(struct drm_device *dev)
> @@ -10274,6 +10306,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  {
>  	drm_i915_private_t *dev_priv = dev->dev_private;
>  	struct intel_crtc *intel_crtc;
> +	struct drm_property *prop = 0;
>  	int i;
>  
>  	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
> @@ -10306,6 +10339,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
>  	dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
>  
>  	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
> +
> +	intel_crtc->primary_alpha = false;
> +	intel_crtc->sprite0_alpha = true;
> +	intel_crtc->sprite1_alpha = true;
> +
> +	prop = drm_property_create(dev, 0, "zorder", 1);
> +	if (prop)
> +		drm_object_attach_property(&intel_crtc->base.base, prop, 0);
> +
> +	intel_crtc->zorder_property = prop;
>  }
>  
>  enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index a4ffc02..eb88959 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -371,6 +371,9 @@ struct intel_crtc {
>  	bool new_enabled;
>  
>  	uint32_t ddi_pll_sel;
> +	bool primary_alpha;
> +	bool sprite0_alpha;
> +	bool sprite1_alpha;
>  
>  	/* reset counter value when the last flip was submitted */
>  	unsigned int reset_counter;
> @@ -384,6 +387,9 @@ struct intel_crtc {
>  		/* watermarks currently being used  */
>  		struct intel_pipe_wm active;
>  	} wm;
> +
> +	struct drm_property *zorder_property;
> +	uint32_t zorder;
>  };
>  
>  struct intel_plane_wm_parameters {
> diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
> index 336ae6c..18f8200 100644
> --- a/drivers/gpu/drm/i915/intel_sprite.c
> +++ b/drivers/gpu/drm/i915/intel_sprite.c
> @@ -37,6 +37,63 @@
>  #include <drm/i915_drm.h>
>  #include "i915_drv.h"
>  
> +int i915_set_plane_zorder(struct drm_device *dev, u32 order)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	u32 val;
> +	int s1_zorder, s1_bottom, s2_zorder, s2_bottom;
> +	int pipe = (order >> 31) & 0x1;
> +	int z_order = order & 0x000F;
> +	struct intel_crtc *intel_crtc =
> +			to_intel_crtc(dev_priv->plane_to_crtc_mapping[pipe]);
> +
> +	s1_zorder = (order >> 3) & 0x1;
> +	s1_bottom = (order >> 2) & 0x1;
> +	s2_zorder = (order >> 1) & 0x1;
> +	s2_bottom = (order >> 0) & 0x1;
> +
> +	/* Clear the older Z-order */
> +	val = I915_READ(SPCNTR(pipe, 0));
> +	val &= ~(SPRITE_FORCE_BOTTOM | SPRITE_ZORDER_ENABLE);
> +	I915_WRITE(SPCNTR(pipe, 0), val);
> +
> +	val = I915_READ(SPCNTR(pipe, 1));
> +	val &= ~(SPRITE_FORCE_BOTTOM | SPRITE_ZORDER_ENABLE);
> +	I915_WRITE(SPCNTR(pipe, 1), val);
> +
> +	/* Program new Z-order */
> +	val = I915_READ(SPCNTR(pipe, 0));
> +	if (s1_zorder)
> +		val |= SPRITE_ZORDER_ENABLE;
> +	if (s1_bottom)
> +		val |= SPRITE_FORCE_BOTTOM;
> +	I915_WRITE(SPCNTR(pipe, 0), val);
> +
> +	val = I915_READ(SPCNTR(pipe, 1));
> +	if (s2_zorder)
> +		val |= SPRITE_ZORDER_ENABLE;
> +	if (s2_bottom)
> +		val |= SPRITE_FORCE_BOTTOM;
> +	I915_WRITE(SPCNTR(pipe, 1), val);
> +
> +	if (z_order != P1S1S2C1 && z_order != P1S2S1C1)
> +		intel_crtc->primary_alpha = true;
> +	else
> +		intel_crtc->primary_alpha = false;
> +
> +	if (z_order != S1P1S2C1 && z_order != S1S2P1C1)
> +		intel_crtc->sprite0_alpha = true;
> +	else
> +		intel_crtc->sprite0_alpha = false;
> +
> +	if (z_order != S2P1S1C1 && z_order != S2S1P1C1)
> +		intel_crtc->sprite1_alpha = true;
> +	else
> +		intel_crtc->sprite1_alpha = false;
> +
> +	return 0;
> +}
> +
>  static void
>  vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>  		 struct drm_framebuffer *fb,
> @@ -50,10 +107,19 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>  	struct intel_plane *intel_plane = to_intel_plane(dplane);
>  	int pipe = intel_plane->pipe;
>  	int plane = intel_plane->plane;
> +	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
>  	u32 sprctl;
> +	bool alpha = true;
>  	unsigned long sprsurf_offset, linear_offset;
>  	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
>  
> +	if (plane && intel_crtc->sprite1_alpha)
> +		alpha = true;
> +	else if (!plane && intel_crtc->sprite0_alpha)
> +		alpha = true;
> +	else
> +		alpha = false;
> +
>  	sprctl = I915_READ(SPCNTR(pipe, plane));
>  
>  	/* Mask out pixel format bits in case we change it */
> @@ -81,19 +147,28 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
>  		sprctl |= SP_FORMAT_BGRX8888;
>  		break;
>  	case DRM_FORMAT_ARGB8888:
> -		sprctl |= SP_FORMAT_BGRA8888;
> +		if (alpha)
> +			sprctl |= SP_FORMAT_BGRA8888;
> +		else
> +			sprctl |= SP_FORMAT_BGRX8888;
>  		break;
>  	case DRM_FORMAT_XBGR2101010:
>  		sprctl |= SP_FORMAT_RGBX1010102;
>  		break;
>  	case DRM_FORMAT_ABGR2101010:
> -		sprctl |= SP_FORMAT_RGBA1010102;
> +		if (alpha)
> +			sprctl |= SP_FORMAT_RGBA1010102;
> +		else
> +			sprctl |= SP_FORMAT_RGBX1010102;
>  		break;
>  	case DRM_FORMAT_XBGR8888:
>  		sprctl |= SP_FORMAT_RGBX8888;
>  		break;
>  	case DRM_FORMAT_ABGR8888:
> -		sprctl |= SP_FORMAT_RGBA8888;
> +		if (alpha)
> +			sprctl |= SP_FORMAT_RGBA8888;
> +		else
> +			sprctl |= SP_FORMAT_RGBX8888;
>  		break;
>  	default:
>  		/*
> -- 
> 1.8.5.2
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
Matt Roper Feb. 27, 2014, 11:44 p.m. UTC | #2
On Thu, Feb 27, 2014 at 02:36:06PM -0800, Yu Dai wrote:
> On 14-02-25 04:19 PM, Matt Roper wrote:
> 
> >On Thu, Feb 20, 2014 at 04:11:14PM -0800, yu.dai@intel.com wrote:
> >>From: "Yu(Alex) Dai" <yu.dai@intel.com>
> >>
> >>Add "zorder" property to crtc to control Z-order of sprite and
> >>primary planes. The alpha channel of the planes can be enabled
> >>or disabled during Z-order change.
> >>
> >>Signed-off-by: Yu(Alex) Dai <yu.dai@intel.com>
> >It seems like this is pretty VLV-specific at the moment.  Aren't you
> >going to be writing bogus register values if you try to set this
> >property on a non-VLV platform?
> >
> >I'm not sure if any of the other non-VLV platforms supported by i915
> >today can change plane z-orders or not, but this is likely to be
> >possible and useful on future platforms (or non-Intel platforms) as
> >well, which may have a different number of overall planes and different
> >ways of programming them.
> 
> Yes, this is for VLV. New patch-set V3 was submitted.
> 
> >Would it make more sense to move the z-order value to a plane property
> >so that the interface scales to any number of planes?  If you just set
> >an integer value as a per-plane zorder-value, the code that actually
> >programs the hardware can go collect the values for each plane, sort
> >them to determine an order, and figure out what that translates to in
> >terms of platform-specific register programming.  This would lend itself
> >nicely to the "check/calculate" step of the atomic/nuclear operation
> >once those interfaces land.
> 
> The z-order of a plane really has no meaning until the actual composition is
> triggered. In Android, the order is determined by HWC when there are changes
> in layers. Breaking up this into plane property will evoke more drm IOCTL
> calls from user. The current "one-shot" call limits the flexibility but makes
> it simple.

That's true today where we only really have the ability to set
properties one by one.  But I believe the end goal is to handle this
kind of functionality via the atomic/nuclear API's, where you wind up
shoving all the various things you want to change/program into a
property set (which happens in libdrm userspace) and then issue a single
ioctl which hands that property set to the kernel to be processed in a
sort of transactional model.

Without the atomic/nuclear operations, I'm not sure how well z-order
property will really work in practice.  If your compositor decides that
the next frame of content uses multiple hardware planes to display
various buffers, you really need to make sure that the z-order register
programming happens within the same vblank that the flips on each of
those planes take effect, otherwise things aren't going to look good to
the end user.  With the non-atomic API's, I don't think there's really
any way to guarantee this.


Matt

> 
> This patch is pretty much a straight copy from internal tree. The only change
> is that it uses property rather than a private i915 IOCTL.
> 
> Thanks,
> 
> Alex
>
Matt Roper Feb. 28, 2014, 7:28 p.m. UTC | #3
On Fri, Feb 28, 2014 at 06:03:11PM +0200, Ville Syrjälä wrote:
> On Thu, Feb 27, 2014 at 03:44:04PM -0800, Matt Roper wrote:
> > On Thu, Feb 27, 2014 at 02:36:06PM -0800, Yu Dai wrote:
> > > On 14-02-25 04:19 PM, Matt Roper wrote:
> > > 
> > > >On Thu, Feb 20, 2014 at 04:11:14PM -0800, yu.dai@intel.com wrote:
> > > >>From: "Yu(Alex) Dai" <yu.dai@intel.com>
> > > >>
> > > >>Add "zorder" property to crtc to control Z-order of sprite and
> > > >>primary planes. The alpha channel of the planes can be enabled
> > > >>or disabled during Z-order change.
> > > >>
> > > >>Signed-off-by: Yu(Alex) Dai <yu.dai@intel.com>
> > > >It seems like this is pretty VLV-specific at the moment.  Aren't you
> > > >going to be writing bogus register values if you try to set this
> > > >property on a non-VLV platform?
> > > >
> > > >I'm not sure if any of the other non-VLV platforms supported by i915
> > > >today can change plane z-orders or not, but this is likely to be
> > > >possible and useful on future platforms (or non-Intel platforms) as
> > > >well, which may have a different number of overall planes and different
> > > >ways of programming them.
> > > 
> > > Yes, this is for VLV. New patch-set V3 was submitted.
> > > 
> > > >Would it make more sense to move the z-order value to a plane property
> > > >so that the interface scales to any number of planes?  If you just set
> > > >an integer value as a per-plane zorder-value, the code that actually
> > > >programs the hardware can go collect the values for each plane, sort
> > > >them to determine an order, and figure out what that translates to in
> > > >terms of platform-specific register programming.  This would lend itself
> > > >nicely to the "check/calculate" step of the atomic/nuclear operation
> > > >once those interfaces land.
> > > 
> > > The z-order of a plane really has no meaning until the actual composition is
> > > triggered. In Android, the order is determined by HWC when there are changes
> > > in layers. Breaking up this into plane property will evoke more drm IOCTL
> > > calls from user. The current "one-shot" call limits the flexibility but makes
> > > it simple.
> > 
> > That's true today where we only really have the ability to set
> > properties one by one.  But I believe the end goal is to handle this
> > kind of functionality via the atomic/nuclear API's, where you wind up
> > shoving all the various things you want to change/program into a
> > property set (which happens in libdrm userspace) and then issue a single
> > ioctl which hands that property set to the kernel to be processed in a
> > sort of transactional model.
> > 
> > Without the atomic/nuclear operations, I'm not sure how well z-order
> > property will really work in practice.  If your compositor decides that
> > the next frame of content uses multiple hardware planes to display
> > various buffers, you really need to make sure that the z-order register
> > programming happens within the same vblank that the flips on each of
> > those planes take effect, otherwise things aren't going to look good to
> > the end user.  With the non-atomic API's, I don't think there's really
> > any way to guarantee this.
> 
> Yeah w/o the atomic API probably the only semi useable approach is to
> drop out from the sprite path when stuff actually moves around, and
> get back on it after the scene is again steady.
> 
> As far as the z-order property, I did have a sort of similar idea
> originally where we'd define a bunch of different plane z-order
> combinations as an enum property on the crtc, and then the user has
> to choose one. That would make it easier for the user to figure out
> which way the planes can be stacked. This would be especially nice
> with some old Intel hardware where the z-order for the planes was
> specified using a couple of magic bits which severeily limited the
> ways you could stack the half a dozen or so planes.
> 
> But then you'd either need to parse the string enum name to make any
> sense of it, or we'd need to encode the order in the value itself. But
> to be hardware agnostic, we'd need to use plane IDs in there, and those
> can in theory be up to 31bits, so we couldn't guarantee that the property
> value could hold more than two planes. Although I suppose we could use
> the plane index instead, which would then put the upper limit at 16 planes.
> Well, possibly more in case not all planes can be assigned to the same
> crtc.
> 
> The simple approach is of course to have a range property per plane
> which defines the z-order. But then we need to worry about conflicts
> between z-order assignment, and it's harder for the user to figure out
> which combinations are legal. But the benefit is that this is the most
> obvious way to present this information. IIRC some people were
> suggesting we pick this scheme despite the limitations.
> 
> -- 
> Ville Syrjälä
> Intel OTC

Conflicts between z-order assignments don't seem too worrisome to me;
I figure most display servers would probably (re-)program z-order values
for all planes when they want to make any kind of plane ordering change
at all, so you generally wouldn't accidentally hit the case where, for
example, you set a plane to level "1" while another plane was already
sitting at level "1."

Figuring out which orderings are legal on the given hardware is somewhat
more of a problem.  It seems like the natural solution is to expect the
compositor or DDX run through a few plane ordering possibilities with
the atomic "test only" flag set when it starts up; it can then adjust
its runtime plane ordering logic according to what it determines is
possible.


Matt
yu.dai@intel.com March 3, 2014, 10:31 p.m. UTC | #4
On 14-02-28 11:28 AM, Matt Roper wrote:

> On Fri, Feb 28, 2014 at 06:03:11PM +0200, Ville Syrjälä wrote:
>> On Thu, Feb 27, 2014 at 03:44:04PM -0800, Matt Roper wrote:
>>> On Thu, Feb 27, 2014 at 02:36:06PM -0800, Yu Dai wrote:
>>>> On 14-02-25 04:19 PM, Matt Roper wrote:
>>>>
>>>>> On Thu, Feb 20, 2014 at 04:11:14PM -0800, yu.dai@intel.com wrote:
>>>>>> From: "Yu(Alex) Dai" <yu.dai@intel.com>
>>>>>>
>>>>>> Add "zorder" property to crtc to control Z-order of sprite and
>>>>>> primary planes. The alpha channel of the planes can be enabled
>>>>>> or disabled during Z-order change.
>>>>>>
>>>>>> Signed-off-by: Yu(Alex) Dai <yu.dai@intel.com>
>>>>> It seems like this is pretty VLV-specific at the moment.  Aren't you
>>>>> going to be writing bogus register values if you try to set this
>>>>> property on a non-VLV platform?
>>>>>
>>>>> I'm not sure if any of the other non-VLV platforms supported by i915
>>>>> today can change plane z-orders or not, but this is likely to be
>>>>> possible and useful on future platforms (or non-Intel platforms) as
>>>>> well, which may have a different number of overall planes and different
>>>>> ways of programming them.
>>>> Yes, this is for VLV. New patch-set V3 was submitted.
>>>>
>>>>> Would it make more sense to move the z-order value to a plane property
>>>>> so that the interface scales to any number of planes?  If you just set
>>>>> an integer value as a per-plane zorder-value, the code that actually
>>>>> programs the hardware can go collect the values for each plane, sort
>>>>> them to determine an order, and figure out what that translates to in
>>>>> terms of platform-specific register programming.  This would lend itself
>>>>> nicely to the "check/calculate" step of the atomic/nuclear operation
>>>>> once those interfaces land.
>>>> The z-order of a plane really has no meaning until the actual composition is
>>>> triggered. In Android, the order is determined by HWC when there are changes
>>>> in layers. Breaking up this into plane property will evoke more drm IOCTL
>>>> calls from user. The current "one-shot" call limits the flexibility but makes
>>>> it simple.
>>> That's true today where we only really have the ability to set
>>> properties one by one.  But I believe the end goal is to handle this
>>> kind of functionality via the atomic/nuclear API's, where you wind up
>>> shoving all the various things you want to change/program into a
>>> property set (which happens in libdrm userspace) and then issue a single
>>> ioctl which hands that property set to the kernel to be processed in a
>>> sort of transactional model.
>>>
>>> Without the atomic/nuclear operations, I'm not sure how well z-order
>>> property will really work in practice.  If your compositor decides that
>>> the next frame of content uses multiple hardware planes to display
>>> various buffers, you really need to make sure that the z-order register
>>> programming happens within the same vblank that the flips on each of
>>> those planes take effect, otherwise things aren't going to look good to
>>> the end user.  With the non-atomic API's, I don't think there's really
>>> any way to guarantee this.
>> Yeah w/o the atomic API probably the only semi useable approach is to
>> drop out from the sprite path when stuff actually moves around, and
>> get back on it after the scene is again steady.
>>
>> As far as the z-order property, I did have a sort of similar idea
>> originally where we'd define a bunch of different plane z-order
>> combinations as an enum property on the crtc, and then the user has
>> to choose one. That would make it easier for the user to figure out
>> which way the planes can be stacked. This would be especially nice
>> with some old Intel hardware where the z-order for the planes was
>> specified using a couple of magic bits which severeily limited the
>> ways you could stack the half a dozen or so planes.
>>
>> But then you'd either need to parse the string enum name to make any
>> sense of it, or we'd need to encode the order in the value itself. But
>> to be hardware agnostic, we'd need to use plane IDs in there, and those
>> can in theory be up to 31bits, so we couldn't guarantee that the property
>> value could hold more than two planes. Although I suppose we could use
>> the plane index instead, which would then put the upper limit at 16 planes.
>> Well, possibly more in case not all planes can be assigned to the same
>> crtc.
>>
>> The simple approach is of course to have a range property per plane
>> which defines the z-order. But then we need to worry about conflicts
>> between z-order assignment, and it's harder for the user to figure out
>> which combinations are legal. But the benefit is that this is the most
>> obvious way to present this information. IIRC some people were
>> suggesting we pick this scheme despite the limitations.
>>
>> -- 
>> Ville Syrjälä
>> Intel OTC
> Conflicts between z-order assignments don't seem too worrisome to me;
> I figure most display servers would probably (re-)program z-order values
> for all planes when they want to make any kind of plane ordering change
> at all, so you generally wouldn't accidentally hit the case where, for
> example, you set a plane to level "1" while another plane was already
> sitting at level "1."
>
> Figuring out which orderings are legal on the given hardware is somewhat
> more of a problem.  It seems like the natural solution is to expect the
> compositor or DDX run through a few plane ordering possibilities with
> the atomic "test only" flag set when it starts up; it can then adjust
> its runtime plane ordering logic according to what it determines is
> possible.
>
>
> Matt
>
Thanks for the review. I submitted patch-set 4 for this. Message-Id: 
<1393884748-8508-1-git-send-email-yu.dai@intel.com>

Since this is for VLV only for now, I moved the majority code to 
vlv_set_plane_order. And it will be called by i915_set_plane_order. For 
the zorder property itself, it's now 64 bits. On current implementation 
for VLV, only 5 bits are needed.Be note that the planes information is 
setup by drmModeSetPlane.So, no need to pack things like plane id into 
this property. For other platform, hopefully the order can be packed 
into the 64 bits integer.

Alex
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8c64831..7833479 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2581,6 +2581,7 @@  int i915_reg_read_ioctl(struct drm_device *dev, void *data,
 			struct drm_file *file);
 int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data,
 			       struct drm_file *file);
+extern int i915_set_plane_zorder(struct drm_device *dev, u32 zorder);
 
 /* overlay */
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2f564ce..c9a9993 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -3743,6 +3743,16 @@ 
 #define   SPRITE_INT_GAMMA_ENABLE	(1<<13)
 #define   SPRITE_TILED			(1<<10)
 #define   SPRITE_DEST_KEY		(1<<2)
+#define   SPRITE_FORCE_BOTTOM		(1<<2)
+#define   SPRITE_ZORDER_ENABLE		(1<<0)
+
+#define P1S1S2C1		0
+#define P1S2S1C1		8
+#define S2P1S1C1		1
+#define S2S1P1C1		9
+#define S1P1S2C1		4
+#define S1S2P1C1		6
+
 #define _SPRA_LINOFF		0x70284
 #define _SPRA_STRIDE		0x70288
 #define _SPRA_POS		0x7028c
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f19e6ea..8ddf6c2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2082,18 +2082,27 @@  static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		break;
 	case DRM_FORMAT_XRGB1555:
 	case DRM_FORMAT_ARGB1555:
-		dspcntr |= DISPPLANE_BGRX555;
+		if (intel_crtc->primary_alpha)
+			dspcntr |= DISPPLANE_BGRA555;
+		else
+			dspcntr |= DISPPLANE_BGRX555;
 		break;
 	case DRM_FORMAT_RGB565:
 		dspcntr |= DISPPLANE_BGRX565;
 		break;
 	case DRM_FORMAT_XRGB8888:
 	case DRM_FORMAT_ARGB8888:
-		dspcntr |= DISPPLANE_BGRX888;
+		if (intel_crtc->primary_alpha)
+			dspcntr |= DISPPLANE_BGRA888;
+		else
+			dspcntr |= DISPPLANE_BGRX888;
 		break;
 	case DRM_FORMAT_XBGR8888:
 	case DRM_FORMAT_ABGR8888:
-		dspcntr |= DISPPLANE_RGBX888;
+		if (intel_crtc->primary_alpha)
+			dspcntr |= DISPPLANE_RGBA888;
+		else
+			dspcntr |= DISPPLANE_RGBX888;
 		break;
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_ARGB2101010:
@@ -2101,7 +2110,10 @@  static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 		break;
 	case DRM_FORMAT_XBGR2101010:
 	case DRM_FORMAT_ABGR2101010:
-		dspcntr |= DISPPLANE_RGBX101010;
+		if (intel_crtc->primary_alpha)
+			dspcntr |= DISPPLANE_RGBA101010;
+		else
+			dspcntr |= DISPPLANE_RGBX101010;
 		break;
 	default:
 		BUG();
@@ -8258,6 +8270,9 @@  static void intel_crtc_destroy(struct drm_crtc *crtc)
 
 	intel_crtc_cursor_set(crtc, NULL, 0, 0, 0);
 
+	if (intel_crtc->zorder_property)
+		drm_property_destroy(dev, intel_crtc->zorder_property);
+
 	drm_crtc_cleanup(crtc);
 
 	kfree(intel_crtc);
@@ -10160,6 +10175,22 @@  out_config:
 	return ret;
 }
 
+static int intel_crtc_set_property(struct drm_crtc *crtc,
+				   struct drm_property *prop,
+				   uint64_t val)
+{
+	struct intel_crtc *icrtc = to_intel_crtc(crtc);
+	int ret = -ENOENT;
+
+	if (prop == icrtc->zorder_property) {
+		u32 zorder = (uint32_t)val;
+		icrtc->zorder = zorder;
+		ret = i915_set_plane_zorder(crtc->dev, zorder);
+	}
+
+	return ret;
+}
+
 static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.cursor_set = intel_crtc_cursor_set,
 	.cursor_move = intel_crtc_cursor_move,
@@ -10167,6 +10198,7 @@  static const struct drm_crtc_funcs intel_crtc_funcs = {
 	.set_config = intel_crtc_set_config,
 	.destroy = intel_crtc_destroy,
 	.page_flip = intel_crtc_page_flip,
+	.set_property = intel_crtc_set_property,
 };
 
 static void intel_cpu_pll_init(struct drm_device *dev)
@@ -10274,6 +10306,7 @@  static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
 	struct intel_crtc *intel_crtc;
+	struct drm_property *prop = 0;
 	int i;
 
 	intel_crtc = kzalloc(sizeof(*intel_crtc), GFP_KERNEL);
@@ -10306,6 +10339,16 @@  static void intel_crtc_init(struct drm_device *dev, int pipe)
 	dev_priv->pipe_to_crtc_mapping[intel_crtc->pipe] = &intel_crtc->base;
 
 	drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs);
+
+	intel_crtc->primary_alpha = false;
+	intel_crtc->sprite0_alpha = true;
+	intel_crtc->sprite1_alpha = true;
+
+	prop = drm_property_create(dev, 0, "zorder", 1);
+	if (prop)
+		drm_object_attach_property(&intel_crtc->base.base, prop, 0);
+
+	intel_crtc->zorder_property = prop;
 }
 
 enum pipe intel_get_pipe_from_connector(struct intel_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a4ffc02..eb88959 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -371,6 +371,9 @@  struct intel_crtc {
 	bool new_enabled;
 
 	uint32_t ddi_pll_sel;
+	bool primary_alpha;
+	bool sprite0_alpha;
+	bool sprite1_alpha;
 
 	/* reset counter value when the last flip was submitted */
 	unsigned int reset_counter;
@@ -384,6 +387,9 @@  struct intel_crtc {
 		/* watermarks currently being used  */
 		struct intel_pipe_wm active;
 	} wm;
+
+	struct drm_property *zorder_property;
+	uint32_t zorder;
 };
 
 struct intel_plane_wm_parameters {
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 336ae6c..18f8200 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -37,6 +37,63 @@ 
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
+int i915_set_plane_zorder(struct drm_device *dev, u32 order)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val;
+	int s1_zorder, s1_bottom, s2_zorder, s2_bottom;
+	int pipe = (order >> 31) & 0x1;
+	int z_order = order & 0x000F;
+	struct intel_crtc *intel_crtc =
+			to_intel_crtc(dev_priv->plane_to_crtc_mapping[pipe]);
+
+	s1_zorder = (order >> 3) & 0x1;
+	s1_bottom = (order >> 2) & 0x1;
+	s2_zorder = (order >> 1) & 0x1;
+	s2_bottom = (order >> 0) & 0x1;
+
+	/* Clear the older Z-order */
+	val = I915_READ(SPCNTR(pipe, 0));
+	val &= ~(SPRITE_FORCE_BOTTOM | SPRITE_ZORDER_ENABLE);
+	I915_WRITE(SPCNTR(pipe, 0), val);
+
+	val = I915_READ(SPCNTR(pipe, 1));
+	val &= ~(SPRITE_FORCE_BOTTOM | SPRITE_ZORDER_ENABLE);
+	I915_WRITE(SPCNTR(pipe, 1), val);
+
+	/* Program new Z-order */
+	val = I915_READ(SPCNTR(pipe, 0));
+	if (s1_zorder)
+		val |= SPRITE_ZORDER_ENABLE;
+	if (s1_bottom)
+		val |= SPRITE_FORCE_BOTTOM;
+	I915_WRITE(SPCNTR(pipe, 0), val);
+
+	val = I915_READ(SPCNTR(pipe, 1));
+	if (s2_zorder)
+		val |= SPRITE_ZORDER_ENABLE;
+	if (s2_bottom)
+		val |= SPRITE_FORCE_BOTTOM;
+	I915_WRITE(SPCNTR(pipe, 1), val);
+
+	if (z_order != P1S1S2C1 && z_order != P1S2S1C1)
+		intel_crtc->primary_alpha = true;
+	else
+		intel_crtc->primary_alpha = false;
+
+	if (z_order != S1P1S2C1 && z_order != S1S2P1C1)
+		intel_crtc->sprite0_alpha = true;
+	else
+		intel_crtc->sprite0_alpha = false;
+
+	if (z_order != S2P1S1C1 && z_order != S2S1P1C1)
+		intel_crtc->sprite1_alpha = true;
+	else
+		intel_crtc->sprite1_alpha = false;
+
+	return 0;
+}
+
 static void
 vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 		 struct drm_framebuffer *fb,
@@ -50,10 +107,19 @@  vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 	struct intel_plane *intel_plane = to_intel_plane(dplane);
 	int pipe = intel_plane->pipe;
 	int plane = intel_plane->plane;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	u32 sprctl;
+	bool alpha = true;
 	unsigned long sprsurf_offset, linear_offset;
 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
 
+	if (plane && intel_crtc->sprite1_alpha)
+		alpha = true;
+	else if (!plane && intel_crtc->sprite0_alpha)
+		alpha = true;
+	else
+		alpha = false;
+
 	sprctl = I915_READ(SPCNTR(pipe, plane));
 
 	/* Mask out pixel format bits in case we change it */
@@ -81,19 +147,28 @@  vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 		sprctl |= SP_FORMAT_BGRX8888;
 		break;
 	case DRM_FORMAT_ARGB8888:
-		sprctl |= SP_FORMAT_BGRA8888;
+		if (alpha)
+			sprctl |= SP_FORMAT_BGRA8888;
+		else
+			sprctl |= SP_FORMAT_BGRX8888;
 		break;
 	case DRM_FORMAT_XBGR2101010:
 		sprctl |= SP_FORMAT_RGBX1010102;
 		break;
 	case DRM_FORMAT_ABGR2101010:
-		sprctl |= SP_FORMAT_RGBA1010102;
+		if (alpha)
+			sprctl |= SP_FORMAT_RGBA1010102;
+		else
+			sprctl |= SP_FORMAT_RGBX1010102;
 		break;
 	case DRM_FORMAT_XBGR8888:
 		sprctl |= SP_FORMAT_RGBX8888;
 		break;
 	case DRM_FORMAT_ABGR8888:
-		sprctl |= SP_FORMAT_RGBA8888;
+		if (alpha)
+			sprctl |= SP_FORMAT_RGBA8888;
+		else
+			sprctl |= SP_FORMAT_RGBX8888;
 		break;
 	default:
 		/*