[PATCH xf86-video-ati 4/4] Make TearFree effective with PRIME slave scanout

Deucher, Alexander Alexander.Deucher at amd.com
Fri Sep 2 13:47:38 UTC 2016


> -----Original Message-----
> From: amd-gfx [mailto:amd-gfx-bounces at lists.freedesktop.org] On Behalf
> Of Michel Dänzer
> Sent: Friday, September 02, 2016 6:04 AM
> To: amd-gfx at lists.freedesktop.org
> Subject: [PATCH xf86-video-ati 4/4] Make TearFree effective with PRIME
> slave scanout
> 
> From: Michel Dänzer <michel.daenzer at amd.com>
> 
> TearFree can now prevent tearing with any possible display
> configuration.
> 
> Note that with PRIME slave scanout, there may still be inter-GPU tearing
> if the primary GPU uses a different driver.
> 
> Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>

For the series:
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  src/drmmode_display.c |  33 ++++++++++++---
>  src/drmmode_display.h |   1 +
>  src/radeon_kms.c      | 110
> ++++++++++++++++++++++++++++++++++++++++++++++----
>  3 files changed, 131 insertions(+), 13 deletions(-)
> 
> diff --git a/src/drmmode_display.c b/src/drmmode_display.c
> index 2b80c21..34f7735 100644
> --- a/src/drmmode_display.c
> +++ b/src/drmmode_display.c
> @@ -528,10 +528,19 @@ drmmode_crtc_scanout_destroy(drmmode_ptr
> drmmode,
>  static void
>  drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
>  {
> -	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
> -				     &drmmode_crtc->scanout[0]);
> -	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
> -				     &drmmode_crtc->scanout[1]);
> +	if (drmmode_crtc->flip_pending) {
> +		drmmode_crtc->scanout_destroy[0] = drmmode_crtc-
> >scanout[0];
> +		drmmode_crtc->scanout[0].pixmap = NULL;
> +		drmmode_crtc->scanout[0].bo = NULL;
> +		drmmode_crtc->scanout_destroy[1] = drmmode_crtc-
> >scanout[1];
> +		drmmode_crtc->scanout[1].pixmap = NULL;
> +		drmmode_crtc->scanout[1].bo = NULL;
> +	} else {
> +		drmmode_crtc_scanout_destroy(drmmode_crtc-
> >drmmode,
> +					     &drmmode_crtc->scanout[0]);
> +		drmmode_crtc_scanout_destroy(drmmode_crtc-
> >drmmode,
> +					     &drmmode_crtc->scanout[1]);
> +	}
> 
>  	if (drmmode_crtc->scanout_damage) {
>  		DamageDestroy(drmmode_crtc->scanout_damage);
> @@ -1120,11 +1129,12 @@ static Bool
>  drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
>  {
>  	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
> +	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
> 
>  	if (!ppix) {
>  		if (crtc->randr_crtc->scanout_pixmap)
>  			PixmapStopDirtyTracking(crtc->randr_crtc-
> >scanout_pixmap,
> -						drmmode_crtc-
> >scanout[0].pixmap);
> +						drmmode_crtc-
> >scanout[drmmode_crtc->scanout_id].pixmap);
>  		drmmode_crtc_scanout_free(drmmode_crtc);
>  		return TRUE;
>  	}
> @@ -1134,6 +1144,14 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc,
> PixmapPtr ppix)
>  					 ppix->drawable.height))
>  		return FALSE;
> 
> +	if (info->tear_free &&
> +	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc-
> >scanout[1],
> +					 ppix->drawable.width,
> +					 ppix->drawable.height)) {
> +		drmmode_crtc_scanout_free(drmmode_crtc);
> +		return FALSE;
> +	}
> +
>  #ifdef HAS_DIRTYTRACKING_ROTATION
>  	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap,
>  				 0, 0, 0, 0, RR_Rotate_0);
> @@ -2200,6 +2218,11 @@ drmmode_clear_pending_flip(xf86CrtcPtr crtc)
> 
>  		drmmode_crtc_dpms(crtc, drmmode_crtc-
> >pending_dpms_mode);
>  	}
> +
> +	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
> +				     &drmmode_crtc->scanout_destroy[0]);
> +	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
> +				     &drmmode_crtc->scanout_destroy[1]);
>  }
> 
>  static void
> diff --git a/src/drmmode_display.h b/src/drmmode_display.h
> index 5df9773..7602eb8 100644
> --- a/src/drmmode_display.h
> +++ b/src/drmmode_display.h
> @@ -84,6 +84,7 @@ typedef struct {
>      struct radeon_bo *cursor_bo;
>      struct drmmode_scanout rotate;
>      struct drmmode_scanout scanout[2];
> +    struct drmmode_scanout scanout_destroy[2];
>      DamagePtr scanout_damage;
>      RegionRec scanout_last_region;
>      unsigned scanout_id;
> diff --git a/src/radeon_kms.c b/src/radeon_kms.c
> index bcaa024..3418716 100644
> --- a/src/radeon_kms.c
> +++ b/src/radeon_kms.c
> @@ -597,31 +597,55 @@ slave_has_sync_shared_pixmap(ScrnInfoPtr scrn,
> PixmapDirtyUpdatePtr dirty)
>      return slave_scrn->driverName == scrn->driverName;
>  }
> 
> -void
> -radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame,
> uint64_t usec,
> -				    void *event_data)
> +static Bool
> +radeon_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id)
>  {
>      ScrnInfoPtr scrn = crtc->scrn;
>      ScreenPtr screen = scrn->pScreen;
> +    RADEONInfoPtr info = RADEONPTR(scrn);
>      drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
>      PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
>      PixmapDirtyUpdatePtr dirty;
> +    Bool ret = FALSE;
> 
>      xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
> -	if (dirty->src == scanoutpix &&
> -	    dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
> +	if (dirty->src == scanoutpix) {
>  	    RegionPtr region;
> 
>  	    if (master_has_sync_shared_pixmap(scrn, dirty))
>  		radeon_sync_shared_pixmap(dirty);
> 
>  	    region = dirty_region(dirty);
> +	    if (RegionNil(region))
> +		goto destroy;
> +
> +	    if (info->tear_free) {
> +		RegionTranslate(region, crtc->x, crtc->y);
> +		radeon_sync_scanout_pixmaps(crtc, region, scanout_id);
> +		radeon_cs_flush_indirect(scrn);
> +		RegionCopy(&drmmode_crtc->scanout_last_region, region);
> +		RegionTranslate(region, -crtc->x, -crtc->y);
> +		dirty->slave_dst = drmmode_crtc-
> >scanout[scanout_id].pixmap;
> +	    }
> +
>  	    redisplay_dirty(dirty, region);
> +	    ret = TRUE;
> +	destroy:
>  	    RegionDestroy(region);
>  	    break;
>  	}
>      }
> 
> +    return ret;
> +}
> +
> +void
> +radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame,
> uint64_t usec,
> +				    void *event_data)
> +{
> +    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
> +
> +    radeon_prime_scanout_do_update(crtc, 0);
>      drmmode_crtc->scanout_update_pending = FALSE;
>  }
> 
> @@ -679,8 +703,74 @@
> radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
>  }
> 
>  static void
> +radeon_prime_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
> +{
> +    drmmode_crtc_private_ptr drmmode_crtc = event_data;
> +
> +    drmmode_crtc->scanout_update_pending = FALSE;
> +    drmmode_clear_pending_flip(crtc);
> +}
> +
> +static void
> +radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
> +{
> +    ScreenPtr screen = ent->slave_dst->drawable.pScreen;
> +    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
> +    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
> +    xf86CrtcPtr crtc = NULL;
> +    drmmode_crtc_private_ptr drmmode_crtc = NULL;
> +    uintptr_t drm_queue_seq;
> +    unsigned scanout_id;
> +    int c;
> +
> +    /* Find the CRTC which is scanning out from this slave pixmap */
> +    for (c = 0; c < xf86_config->num_crtc; c++) {
> +	crtc = xf86_config->crtc[c];
> +	drmmode_crtc = crtc->driver_private;
> +	scanout_id = drmmode_crtc->scanout_id;
> +	if (drmmode_crtc->scanout[scanout_id].pixmap == ent->slave_dst)
> +	    break;
> +    }
> +
> +    if (c == xf86_config->num_crtc ||
> +	!crtc->enabled ||
> +	drmmode_crtc->scanout_update_pending ||
> +	!drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap ||
> +	drmmode_crtc->pending_dpms_mode != DPMSModeOn)
> +	return;
> +
> +    scanout_id = drmmode_crtc->scanout_id ^ 1;
> +    if (!radeon_prime_scanout_do_update(crtc, scanout_id))
> +	return;
> +
> +    drm_queue_seq = radeon_drm_queue_alloc(crtc,
> +
> RADEON_DRM_QUEUE_CLIENT_DEFAULT,
> +
> RADEON_DRM_QUEUE_ID_DEFAULT,
> +					   drmmode_crtc, NULL,
> +					   radeon_prime_scanout_flip_abort);
> +    if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
> +	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> +		   "Allocating DRM event queue entry failed for PRIME
> flip.\n");
> +	return;
> +    }
> +
> +    if (drmModePageFlip(drmmode_crtc->drmmode->fd, drmmode_crtc-
> >mode_crtc->crtc_id,
> +			drmmode_crtc->scanout[scanout_id].fb_id,
> +			DRM_MODE_PAGE_FLIP_EVENT,
> (void*)drm_queue_seq)) {
> +	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s:
> %s\n",
> +		   __func__, strerror(errno));
> +	return;
> +    }
> +
> +    drmmode_crtc->scanout_id = scanout_id;
> +    drmmode_crtc->scanout_update_pending = TRUE;
> +    drmmode_crtc->flip_pending = TRUE;
> +}
> +
> +static void
>  radeon_dirty_update(ScrnInfoPtr scrn)
>  {
> +	RADEONInfoPtr info = RADEONPTR(scrn);
>  	ScreenPtr screen = scrn->pScreen;
>  	PixmapDirtyUpdatePtr ent;
>  	RegionPtr region;
> @@ -700,10 +790,14 @@ radeon_dirty_update(ScrnInfoPtr scrn)
> 
>  			region = dirty_region(region_ent);
> 
> -			if (RegionNotEmpty(region))
> -				radeon_prime_scanout_update(ent);
> -			else
> +			if (RegionNotEmpty(region)) {
> +				if (info->tear_free)
> +					radeon_prime_scanout_flip(ent);
> +				else
> +
> 	radeon_prime_scanout_update(ent);
> +			} else {
>  				DamageEmpty(region_ent->damage);
> +			}
> 
>  			RegionDestroy(region);
>  		} else {
> --
> 2.9.3
> 
> _______________________________________________
> amd-gfx mailing list
> amd-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/amd-gfx


More information about the amd-gfx mailing list