On Mon, Apr 20, 2015 at 5:54 AM, Michel Dänzer <mic...@daenzer.net> wrote: > From: Michel Dänzer <michel.daen...@amd.com> > > Avoids tearing by flipping between two scanout BOs per (non-rotated) CRTC > > Signed-off-by: Michel Dänzer <michel.daen...@amd.com>
Reviewed-by: Alex Deucher <alexander.deuc...@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@lists.x.org > http://lists.x.org/mailman/listinfo/xorg-driver-ati _______________________________________________ xorg-driver-ati mailing list xorg-driver-ati@lists.x.org http://lists.x.org/mailman/listinfo/xorg-driver-ati