[PATCH 6/6] drm: Add DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags

Daniel Vetter daniel at ffwll.ch
Thu Aug 4 10:56:09 UTC 2016


On Thu, Aug 04, 2016 at 12:39:41PM +0900, Michel Dänzer wrote:
> From: Michel Dänzer <michel.daenzer at amd.com>
> 
> These flags allow userspace to explicitly specify the target vertical
> blank period when a flip should take effect.
> 
> Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
> ---
> 
> Note that the previous patches in this series can avoid delaying page
> flips in some cases even without this patch or any corresponding
> userspace changes. Here are examples of how userspace can take advantage
> of this patch to avoid delaying page flips in even more cases:
> 
> https://cgit.freedesktop.org/~daenzer/xf86-video-ati/commit/?id=fc884a8af25345c32bd4104c864ecfeb9bb3db9b
> 
> https://cgit.freedesktop.org/~daenzer/xf86-video-amdgpu/commit/?id=b8631a9ba49c0d0ebe5dcd1dbfb68fcfe907296f
> 
>  drivers/gpu/drm/drm_crtc.c  | 46 +++++++++++++++++++++++++++++++++++++++------
>  drivers/gpu/drm/drm_ioctl.c |  8 ++++++++
>  include/uapi/drm/drm.h      |  1 +
>  include/uapi/drm/drm_mode.h | 24 +++++++++++++++++++----
>  4 files changed, 69 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 15ad7e2..b2fd860 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -5421,11 +5421,19 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  	struct drm_crtc *crtc;
>  	struct drm_framebuffer *fb = NULL;
>  	struct drm_pending_vblank_event *e = NULL;
> -	u32 target_vblank = 0;
> +	u32 target_vblank = page_flip->sequence;
>  	int ret = -EINVAL;
>  
> -	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
> -	    page_flip->reserved != 0)
> +	if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS)
> +		return -EINVAL;
> +
> +	if (page_flip->sequence != 0 && !(page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
> +		return -EINVAL;
> +
> +	/* Only one of the DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags
> +	 * can be specified
> +	 */
> +	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) == DRM_MODE_PAGE_FLIP_TARGET)
>  		return -EINVAL;
>  
>  	if ((page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC) && !dev->mode_config.async_page_flip)
> @@ -5436,15 +5444,41 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
>  		return -ENOENT;
>  
>  	if (crtc->funcs->page_flip_target) {
> +		u32 current_vblank;
>  		int r;
>  
>  		r = drm_crtc_vblank_get(crtc);
>  		if (r)
>  			return r;
>  
> -		target_vblank = drm_crtc_vblank_count(crtc) +
> -			!(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
> -	} else if (crtc->funcs->page_flip == NULL)
> +		current_vblank = drm_crtc_vblank_count(crtc);
> +
> +		switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
> +		case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
> +			if ((int)(target_vblank - current_vblank) > 1) {
> +				DRM_DEBUG("Invalid absolute flip target %u, "
> +					  "must be <= %u\n", target_vblank,
> +					  current_vblank + 1);
> +				drm_crtc_vblank_put(crtc);
> +				return -EINVAL;
> +			}
> +			break;
> +		case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
> +			if (target_vblank != 0 && target_vblank != 1) {
> +				DRM_DEBUG("Invalid relative flip target %u, "
> +					  "must be 0 or 1\n", target_vblank);
> +				drm_crtc_vblank_put(crtc);
> +				return -EINVAL;
> +			}
> +			target_vblank += current_vblank;
> +			break;
> +		default:
> +			target_vblank = current_vblank +
> +				!(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
> +			break;
> +		}
> +	} else if (crtc->funcs->page_flip == NULL ||
> +		   (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET))
>  		return -EINVAL;
>  
>  	drm_modeset_lock_crtc(crtc, crtc->primary);
> diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
> index 33af4a5..0099d2a 100644
> --- a/drivers/gpu/drm/drm_ioctl.c
> +++ b/drivers/gpu/drm/drm_ioctl.c
> @@ -228,6 +228,7 @@ static int drm_getstats(struct drm_device *dev, void *data,
>  static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
>  {
>  	struct drm_get_cap *req = data;
> +	struct drm_crtc *crtc;
>  
>  	req->value = 0;
>  	switch (req->capability) {
> @@ -254,6 +255,13 @@ static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_
>  	case DRM_CAP_ASYNC_PAGE_FLIP:
>  		req->value = dev->mode_config.async_page_flip;
>  		break;
> +	case DRM_CAP_PAGE_FLIP_TARGET:
> +		req->value = 1;
> +		drm_for_each_crtc(crtc, dev) {
> +			if (!crtc->funcs->page_flip_target)
> +				req->value = 0;
> +		}
> +		break;
>  	case DRM_CAP_CURSOR_WIDTH:
>  		if (dev->mode_config.cursor_width)
>  			req->value = dev->mode_config.cursor_width;
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index 452675f..b2c5284 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -646,6 +646,7 @@ struct drm_gem_open {
>  #define DRM_CAP_CURSOR_WIDTH		0x8
>  #define DRM_CAP_CURSOR_HEIGHT		0x9
>  #define DRM_CAP_ADDFB2_MODIFIERS	0x10
> +#define DRM_CAP_PAGE_FLIP_TARGET	0x11
>  
>  /** DRM_IOCTL_GET_CAP ioctl argument type */
>  struct drm_get_cap {
> diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
> index 49a7265..175aa1f 100644
> --- a/include/uapi/drm/drm_mode.h
> +++ b/include/uapi/drm/drm_mode.h
> @@ -520,7 +520,13 @@ struct drm_color_lut {
>  
>  #define DRM_MODE_PAGE_FLIP_EVENT 0x01
>  #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
> -#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT|DRM_MODE_PAGE_FLIP_ASYNC)
> +#define DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE 0x4
> +#define DRM_MODE_PAGE_FLIP_TARGET_RELATIVE 0x8
> +#define DRM_MODE_PAGE_FLIP_TARGET (DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE | \
> +				   DRM_MODE_PAGE_FLIP_TARGET_RELATIVE)
> +#define DRM_MODE_PAGE_FLIP_FLAGS (DRM_MODE_PAGE_FLIP_EVENT | \
> +				  DRM_MODE_PAGE_FLIP_ASYNC | \
> +				  DRM_MODE_PAGE_FLIP_TARGET)
>  
>  /*
>   * Request a page flip on the specified crtc.
> @@ -543,15 +549,25 @@ struct drm_color_lut {
>   * 'as soon as possible', meaning that it not delay waiting for vblank.
>   * This may cause tearing on the screen.
>   *
> - * The reserved field must be zero until we figure out something
> - * clever to use it for.
> + * The sequence field must be zero unless either of the
> + * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is specified. When
> + * the ABSOLUTE flag is specified, the sequence field denotes the absolute
> + * vblank sequence when the flip should take effect. When the RELATIVE
> + * flag is specified, the sequence field denotes the relative (to the
> + * current one when the ioctl is called) vblank sequence when the flip
> + * should take effect. NOTE: DRM_IOCTL_WAIT_VBLANK must still be used to
> + * make sure the vblank sequence before the target one has passed before
> + * calling this ioctl. The purpose of the
> + * DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE/RELATIVE flags is merely to clarify
> + * the target for when code dealing with a page flip runs during a
> + * vertical blank period.
>   */
>  
>  struct drm_mode_crtc_page_flip {
>  	__u32 crtc_id;
>  	__u32 fb_id;
>  	__u32 flags;
> -	__u32 reserved;
> +	__u32 sequence;

Might break abi somewhere. I think it'd be better to create a
struct drm_mode_crtc_page_flip2 with the renamed field. Otherwise this
looks great, and the only other quibble I have is that we extend the old
page_flip path here instead of atomic. But given all the fun we have
trying to port i915 to atomic I fully understand that you can't simply
first port amdgpu over ;-)

With or without the above (but strongingly in support of a new struct):

Reviewed-by: Daniel Vetter <daniel.vetter at ffwll.ch>

>  	__u64 user_data;
>  };
>  
> -- 
> 2.8.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


More information about the dri-devel mailing list