[PATCH] Add Option "TearFree"
Alex Deucher
alexdeucher at gmail.com
Mon Apr 20 06:45:52 PDT 2015
On Mon, Apr 20, 2015 at 5:54 AM, Michel Dänzer <michel at daenzer.net> wrote:
> From: Michel Dänzer <michel.daenzer at amd.com>
>
> Avoids tearing by flipping between two scanout BOs per (non-rotated) CRTC
>
> Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
> ---
> man/radeon.man | 7 +++
> src/drmmode_display.c | 78 ++++++++++++++++-------------
> src/drmmode_display.h | 5 +-
> src/radeon.h | 2 +
> src/radeon_kms.c | 136 ++++++++++++++++++++++++++++++++++++++------------
> 5 files changed, 158 insertions(+), 70 deletions(-)
>
> diff --git a/man/radeon.man b/man/radeon.man
> index 2703773..f0a6be1 100644
> --- a/man/radeon.man
> +++ b/man/radeon.man
> @@ -276,6 +276,13 @@ Enable DRI2 page flipping. The default is
> .B on.
> Pageflipping is supported on all radeon hardware.
> .TP
> +.BI "Option \*qTearFree\*q \*q" boolean \*q
> +Enable tearing prevention using the hardware page flipping mechanism. This
> +option currently doesn't have any effect for rotated CRTCs. It requires
> +allocating two separate scanout buffers for each non-rotated CRTC. Enabling
> +this option currently disables Option \*qEnablePageFlip\*q. The default is
> +.B off.
> +.TP
> .BI "Option \*qAccelMethod\*q \*q" "string" \*q
> Chooses between available acceleration architectures. Valid values are
> .B EXA
> diff --git a/src/drmmode_display.c b/src/drmmode_display.c
> index 1f22869..ce6cd80 100644
> --- a/src/drmmode_display.c
> +++ b/src/drmmode_display.c
> @@ -488,6 +488,10 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
> scanout->bo = NULL;
> }
>
> + if (scanout->damage) {
> + DamageDestroy(scanout->damage);
> + scanout->damage = NULL;
> + }
> }
>
> void
> @@ -501,12 +505,9 @@ drmmode_scanout_free(ScrnInfoPtr scrn)
> xf86_config->crtc[c]->driver_private;
>
> drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
> - &drmmode_crtc->scanout);
> -
> - if (drmmode_crtc->scanout_damage) {
> - DamageDestroy(drmmode_crtc->scanout_damage);
> - drmmode_crtc->scanout_damage = NULL;
> - }
> + &drmmode_crtc->scanout[0]);
> + drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
> + &drmmode_crtc->scanout[1]);
> }
> }
>
> @@ -704,44 +705,49 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
> x = drmmode_crtc->prime_pixmap_x;
> y = 0;
>
> - drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
> + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
> + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
> } else
> #endif
> if (drmmode_crtc->rotate.fb_id) {
> fb_id = drmmode_crtc->rotate.fb_id;
> x = y = 0;
>
> - drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout);
> - } else if (info->shadow_primary) {
> - drmmode_crtc_scanout_create(crtc,
> - &drmmode_crtc->scanout,
> - NULL, mode->HDisplay,
> - mode->VDisplay);
> -
> - if (drmmode_crtc->scanout.pixmap) {
> - RegionPtr pRegion;
> - BoxPtr pBox;
> -
> - if (!drmmode_crtc->scanout_damage) {
> - drmmode_crtc->scanout_damage =
> - DamageCreate(radeon_screen_damage_report,
> - NULL, DamageReportRawRegion,
> - TRUE, pScreen, NULL);
> - DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
> - drmmode_crtc->scanout_damage);
> + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
> + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
> + } else if (info->tear_free || info->shadow_primary) {
> + for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
> + drmmode_crtc_scanout_create(crtc,
> + &drmmode_crtc->scanout[i],
> + NULL, mode->HDisplay,
> + mode->VDisplay);
> +
> + if (drmmode_crtc->scanout[i].pixmap) {
> + RegionPtr pRegion;
> + BoxPtr pBox;
> +
> + if (!drmmode_crtc->scanout[i].damage) {
> + drmmode_crtc->scanout[i].damage =
> + DamageCreate(radeon_screen_damage_report,
> + NULL, DamageReportRawRegion,
> + TRUE, pScreen, NULL);
> + DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
> + drmmode_crtc->scanout[i].damage);
> + }
> +
> + pRegion = DamageRegion(drmmode_crtc->scanout[i].damage);
> + RegionUninit(pRegion);
> + pRegion->data = NULL;
> + pBox = RegionExtents(pRegion);
> + pBox->x1 = min(pBox->x1, x);
> + pBox->y1 = min(pBox->y1, y);
> + pBox->x2 = max(pBox->x2, x + mode->HDisplay);
> + pBox->y2 = max(pBox->y2, y + mode->VDisplay);
> +
> + x = y = 0;
> }
>
> - pRegion = DamageRegion(drmmode_crtc->scanout_damage);
> - RegionUninit(pRegion);
> - pRegion->data = NULL;
> - pBox = RegionExtents(pRegion);
> - pBox->x1 = min(pBox->x1, x);
> - pBox->y1 = min(pBox->y1, y);
> - pBox->x2 = max(pBox->x2, x + mode->HDisplay);
> - pBox->y2 = max(pBox->y2, y + mode->VDisplay);
> -
> - fb_id = drmmode_crtc->scanout.fb_id;
> - x = y = 0;
> + fb_id = drmmode_crtc->scanout[drmmode_crtc->scanout_id].fb_id;
> }
> }
> ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
> diff --git a/src/drmmode_display.h b/src/drmmode_display.h
> index 43a3a4a..1908b46 100644
> --- a/src/drmmode_display.h
> +++ b/src/drmmode_display.h
> @@ -75,6 +75,7 @@ typedef struct {
> struct drmmode_scanout {
> struct radeon_bo *bo;
> PixmapPtr pixmap;
> + DamagePtr damage;
> unsigned fb_id;
> int width, height;
> };
> @@ -85,8 +86,8 @@ typedef struct {
> int hw_id;
> struct radeon_bo *cursor_bo;
> struct drmmode_scanout rotate;
> - struct drmmode_scanout scanout;
> - DamagePtr scanout_damage;
> + struct drmmode_scanout scanout[2];
> + unsigned scanout_id;
> Bool scanout_update_pending;
> int dpms_mode;
> CARD64 dpms_last_ust;
> diff --git a/src/radeon.h b/src/radeon.h
> index dbc1660..1c794ce 100644
> --- a/src/radeon.h
> +++ b/src/radeon.h
> @@ -152,6 +152,7 @@ typedef enum {
> OPTION_DELETE_DP12,
> OPTION_DRI3,
> OPTION_SHADOW_PRIMARY,
> + OPTION_TEAR_FREE,
> } RADEONOpts;
>
>
> @@ -477,6 +478,7 @@ typedef struct {
> Bool accelOn;
> Bool use_glamor;
> Bool shadow_primary;
> + Bool tear_free;
> Bool exa_pixmaps;
> Bool exa_force_create;
> XF86ModReqInfo exaReq;
> diff --git a/src/radeon_kms.c b/src/radeon_kms.c
> index 64593ab..e18f85a 100644
> --- a/src/radeon_kms.c
> +++ b/src/radeon_kms.c
> @@ -78,6 +78,7 @@ const OptionInfoRec RADEONOptions_KMS[] = {
> { OPTION_SWAPBUFFERS_WAIT,"SwapbuffersWait", OPTV_BOOLEAN, {0}, FALSE },
> { OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE},
> { OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
> + { OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE },
> { -1, NULL, OPTV_NONE, {0}, FALSE }
> };
>
> @@ -320,21 +321,11 @@ radeon_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
> return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
> }
>
> -static void
> -radeon_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
> -{
> - xf86CrtcPtr xf86_crtc = event_data;
> - drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
> -
> - drmmode_crtc->scanout_update_pending = FALSE;
> -}
> -
> -static void
> -radeon_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
> - void *event_data)
> +static Bool
> +radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
> {
> - xf86CrtcPtr xf86_crtc = event_data;
> drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
> + ScrnInfoPtr scrn;
> DamagePtr pDamage;
> RegionPtr pRegion;
> DrawablePtr pDraw;
> @@ -344,26 +335,28 @@ radeon_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
> RADEONInfoPtr info;
> Bool force;
>
> - if (!drmmode_crtc->scanout.pixmap ||
> - drmmode_crtc->dpms_mode != DPMSModeOn)
> - goto out;
> + if (drmmode_crtc->dpms_mode != DPMSModeOn ||
> + !drmmode_crtc->scanout[scanout_id].pixmap)
> + return FALSE;
>
> - pDamage = drmmode_crtc->scanout_damage;
> + pDamage = drmmode_crtc->scanout[scanout_id].damage;
> if (!pDamage)
> - goto out;
> + return FALSE;
>
> pRegion = DamageRegion(pDamage);
> if (!RegionNotEmpty(pRegion))
> - goto out;
> + return FALSE;
>
> - pDraw = &drmmode_crtc->scanout.pixmap->drawable;
> + pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
> extents = *RegionExtents(pRegion);
> + RegionEmpty(pRegion);
> if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
> pDraw->width, pDraw->height))
> - goto clear_damage;
> + return FALSE;
>
> pScreen = pDraw->pScreen;
> gc = GetScratchGC(pDraw->depth, pScreen);
> + scrn = xf86_crtc->scrn;
> info = RADEONPTR(scrn);
> force = info->accel_state->force;
> info->accel_state->force = TRUE;
> @@ -380,14 +373,28 @@ radeon_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
>
> radeon_cs_flush_indirect(scrn);
>
> -clear_damage:
> - RegionEmpty(pRegion);
> + return TRUE;
> +}
> +
> +static void
> +radeon_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
> +{
> + xf86CrtcPtr xf86_crtc = event_data;
> + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
>
> -out:
> drmmode_crtc->scanout_update_pending = FALSE;
> }
>
> static void
> +radeon_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
> + void *event_data)
> +{
> + radeon_scanout_do_update(event_data, 0);
> +
> + radeon_scanout_update_abort(scrn, event_data);
> +}
> +
> +static void
> radeon_scanout_update(xf86CrtcPtr xf86_crtc)
> {
> drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
> @@ -400,11 +407,11 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
> BoxRec extents;
>
> if (drmmode_crtc->scanout_update_pending ||
> - !drmmode_crtc->scanout.pixmap ||
> + !drmmode_crtc->scanout[0].pixmap ||
> drmmode_crtc->dpms_mode != DPMSModeOn)
> return;
>
> - pDamage = drmmode_crtc->scanout_damage;
> + pDamage = drmmode_crtc->scanout[0].damage;
> if (!pDamage)
> return;
>
> @@ -412,7 +419,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
> if (!RegionNotEmpty(pRegion))
> return;
>
> - pDraw = &drmmode_crtc->scanout.pixmap->drawable;
> + pDraw = &drmmode_crtc->scanout[0].pixmap->drawable;
> extents = *RegionExtents(pRegion);
> if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
> pDraw->width, pDraw->height))
> @@ -445,6 +452,60 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
> drmmode_crtc->scanout_update_pending = TRUE;
> }
>
> +static void
> +radeon_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data)
> +{
> + drmmode_crtc_private_ptr drmmode_crtc = event_data;
> +
> + drmmode_crtc->scanout_update_pending = FALSE;
> +}
> +
> +static void
> +radeon_scanout_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data)
> +{
> + radeon_scanout_flip_abort(scrn, event_data);
> +}
> +
> +static void
> +radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
> + xf86CrtcPtr xf86_crtc)
> +{
> + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
> + ScrnInfoPtr scrn;
> + struct radeon_drm_queue_entry *drm_queue_entry;
> + unsigned scanout_id;
> +
> + if (drmmode_crtc->scanout_update_pending)
> + return;
> +
> + scanout_id = drmmode_crtc->scanout_id ^ 1;
> + if (!radeon_scanout_do_update(xf86_crtc, scanout_id))
> + return;
> +
> + scrn = xf86_crtc->scrn;
> + drm_queue_entry = radeon_drm_queue_alloc(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT,
> + RADEON_DRM_QUEUE_ID_DEFAULT,
> + drmmode_crtc,
> + radeon_scanout_flip_handler,
> + radeon_scanout_flip_abort);
> + if (!drm_queue_entry) {
> + xf86DrvMsg(scrn->scrnIndex, X_WARNING,
> + "Allocating DRM event queue entry failed.\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, drm_queue_entry)) {
> + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
> + strerror(errno));
> + return;
> + }
> +
> + drmmode_crtc->scanout_id = scanout_id;
> + drmmode_crtc->scanout_update_pending = TRUE;
> +}
> +
> static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
> {
> SCREEN_PTR(arg);
> @@ -455,12 +516,16 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
> (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
> pScreen->BlockHandler = RADEONBlockHandler_KMS;
>
> - if (info->shadow_primary) {
> + if (info->tear_free || info->shadow_primary) {
> xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
> int c;
>
> - for (c = 0; c < xf86_config->num_crtc; c++)
> - radeon_scanout_update(xf86_config->crtc[c]);
> + for (c = 0; c < xf86_config->num_crtc; c++) {
> + if (info->tear_free)
> + radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]);
> + else
> + radeon_scanout_update(xf86_config->crtc[c]);
> + }
> }
>
> radeon_cs_flush_indirect(pScrn);
> @@ -1092,15 +1157,22 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
> }
> #endif
>
> + info->tear_free = xf86ReturnOptValBool(info->Options, OPTION_TEAR_FREE,
> + FALSE);
> +
> + if (info->shadow_primary)
> + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TearFree enabled\n");
> +
> if (info->dri2.pKernelDRMVersion->version_minor >= 8) {
> info->allowPageFlip = xf86ReturnOptValBool(info->Options,
> OPTION_PAGE_FLIP, TRUE);
> #if USE_GLAMOR
> - if (info->shadow_primary) {
> + if (info->tear_free || info->shadow_primary) {
> xf86DrvMsg(pScrn->scrnIndex,
> info->allowPageFlip ? X_WARNING : X_DEFAULT,
> "KMS Pageflipping: disabled%s\n",
> - info->allowPageFlip ? " because of ShadowPrimary" : "");
> + info->allowPageFlip ?
> + " because of ShadowPrimary/TearFree" : "");
> info->allowPageFlip = FALSE;
> } else
> #endif
> --
> 2.1.4
>
> _______________________________________________
> xorg-driver-ati mailing list
> xorg-driver-ati at lists.x.org
> http://lists.x.org/mailman/listinfo/xorg-driver-ati
More information about the xorg-driver-ati
mailing list