On Thu, Mar 2, 2017 at 4:18 AM, Michel Dänzer <michel at daenzer.net> wrote: > From: Michel Dänzer <michel.daenzer at amd.com> > > Option "TearFree" now sets the default value of the output property. > See the manpage update for details. > > TearFree is now enabled by default for outputs using rotation or other > RandR transforms, and for RandR 1.4 slave outputs. > > (Ported from radeon commit 58cd1600057e41aade0106d4acf78e23eac6e44f) > > Signed-off-by: Michel Dänzer <michel.daenzer at amd.com> Series is: Reviewed-by: Alex Deucher <alexander.deucher at amd.com> > --- > man/amdgpu.man | 15 +++-- > src/amdgpu_dri2.c | 34 +++++++++-- > src/amdgpu_drv.h | 2 +- > src/amdgpu_kms.c | 57 ++++++++++-------- > src/drmmode_display.c | 162 +++++++++++++++++++++++++++++++++++++++++++++----- > src/drmmode_display.h | 2 + > 6 files changed, 221 insertions(+), 51 deletions(-) > > diff --git a/man/amdgpu.man b/man/amdgpu.man > index 0e5c291d..53bd768a 100644 > --- a/man/amdgpu.man > +++ b/man/amdgpu.man > @@ -73,10 +73,17 @@ Enable DRI2 page flipping. The default is > .B on. > .TP > .BI "Option \*qTearFree\*q \*q" boolean \*q > -Enable tearing prevention using the hardware page flipping mechanism. Requires allocating two > -separate scanout buffers for each CRTC. Enabling this option currently disables Option > -\*qEnablePageFlip\*q. The default is > -.B off. > +Set the default value of the per-output 'TearFree' property, which controls > +tearing prevention using the hardware page flipping mechanism. TearFree is > +on for any CRTC associated with one or more outputs with TearFree on. Two > +separate scanout buffers need to be allocated for each CRTC with TearFree > +on. While TearFree is on for any CRTC, it currently prevents clients from using > +DRI page flipping. If this option is set, the default value of the property is > +'on' or 'off' accordingly. If this option isn't set, the default value of the > +property is > +.B auto, > +which means that TearFree is on for outputs with rotation or other RandR > +transforms, and for RandR 1.4 slave outputs, otherwise off. > .TP > .BI "Option \*qAccelMethod\*q \*q" string \*q > Setting this option to > diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c > index a83d2177..8dde2930 100644 > --- a/src/amdgpu_dri2.c > +++ b/src/amdgpu_dri2.c > @@ -51,6 +51,7 @@ > #include "amdgpu_list.h" > > #include <xf86Priv.h> > +#include <X11/extensions/dpmsconst.h> > > #if DRI2INFOREC_VERSION >= 9 > #define USE_DRI2_PRIME > @@ -637,13 +638,34 @@ can_flip(ScrnInfoPtr pScrn, DrawablePtr draw, > DRI2BufferPtr front, DRI2BufferPtr back) > { > AMDGPUInfoPtr info = AMDGPUPTR(pScrn); > + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); > + int num_crtcs_on; > + int i; > + > + if (draw->type != DRAWABLE_WINDOW || > + !info->allowPageFlip || > + info->hwcursor_disabled || > + info->drmmode.present_flipping || > + !pScrn->vtSema || > + !DRI2CanFlip(draw)) > + return FALSE; > + > + for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { > + xf86CrtcPtr crtc = config->crtc[i]; > + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > + > + if (!crtc->enabled) > + continue; > + > + if (!drmmode_crtc || drmmode_crtc->rotate.bo || > + drmmode_crtc->scanout[0].bo) > + return FALSE; > + > + if (drmmode_crtc->pending_dpms_mode == DPMSModeOn) > + num_crtcs_on++; > + } > > - return draw->type == DRAWABLE_WINDOW && > - info->allowPageFlip && > - !info->hwcursor_disabled && > - !info->drmmode.present_flipping && > - pScrn->vtSema && > - DRI2CanFlip(draw) && can_exchange(pScrn, draw, front, back); > + return num_crtcs_on > 0 && can_exchange(pScrn, draw, front, back); > } > > static void > diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h > index 3a24fa73..2aaafe43 100644 > --- a/src/amdgpu_drv.h > +++ b/src/amdgpu_drv.h > @@ -221,7 +221,7 @@ typedef struct { > Bool use_glamor; > Bool force_accel; > Bool shadow_primary; > - Bool tear_free; > + int tear_free; > > /* general */ > OptionInfoPtr Options; > diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c > index 10a68fbd..bafcb9bb 100644 > --- a/src/amdgpu_kms.c > +++ b/src/amdgpu_kms.c > @@ -575,7 +575,6 @@ amdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id) > { > ScrnInfoPtr scrn = crtc->scrn; > ScreenPtr screen = scrn->pScreen; > - AMDGPUInfoPtr info = AMDGPUPTR(scrn); > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap; > PixmapDirtyUpdatePtr dirty; > @@ -583,7 +582,7 @@ amdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id) > > xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { > if (dirty->src == scanoutpix && dirty->slave_dst == > - drmmode_crtc->scanout[scanout_id ^ info->tear_free].pixmap) { > + drmmode_crtc->scanout[scanout_id ^ drmmode_crtc->tear_free].pixmap) { > RegionPtr region; > > if (master_has_sync_shared_pixmap(scrn, dirty)) > @@ -593,7 +592,7 @@ amdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id) > if (RegionNil(region)) > goto destroy; > > - if (info->tear_free) { > + if (drmmode_crtc->tear_free) { > RegionTranslate(region, crtc->x, crtc->y); > amdgpu_sync_scanout_pixmaps(crtc, region, scanout_id); > amdgpu_glamor_flush(scrn); > @@ -730,7 +729,6 @@ amdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent) > static void > amdgpu_dirty_update(ScrnInfoPtr scrn) > { > - AMDGPUInfoPtr info = AMDGPUPTR(scrn); > ScreenPtr screen = scrn->pScreen; > PixmapDirtyUpdatePtr ent; > RegionPtr region; > @@ -751,7 +749,13 @@ amdgpu_dirty_update(ScrnInfoPtr scrn) > region = dirty_region(region_ent); > > if (RegionNotEmpty(region)) { > - if (info->tear_free) > + xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent); > + drmmode_crtc_private_ptr drmmode_crtc = NULL; > + > + if (crtc) > + drmmode_crtc = crtc->driver_private; > + > + if (drmmode_crtc && drmmode_crtc->tear_free) > amdgpu_prime_scanout_flip(ent); > else > amdgpu_prime_scanout_update(ent); > @@ -779,7 +783,6 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) > RegionPtr pRegion = DamageRegion(drmmode_crtc->scanout_damage); > ScrnInfoPtr scrn = xf86_crtc->scrn; > ScreenPtr pScreen = scrn->pScreen; > - AMDGPUInfoPtr info = AMDGPUPTR(scrn); > DrawablePtr pDraw; > BoxRec extents; > > @@ -796,7 +799,7 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) > if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) > return FALSE; > > - if (info->tear_free) { > + if (drmmode_crtc->tear_free) { > amdgpu_sync_scanout_pixmaps(xf86_crtc, pRegion, scanout_id); > RegionCopy(&drmmode_crtc->scanout_last_region, pRegion); > } > @@ -1014,14 +1017,17 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) > if (!amdgpu_is_gpu_screen(pScreen)) > { > for (c = 0; c < xf86_config->num_crtc; c++) { > - if (info->tear_free) > - amdgpu_scanout_flip(pScreen, info, xf86_config->crtc[c]); > + xf86CrtcPtr crtc = xf86_config->crtc[c]; > + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > + > + if (drmmode_crtc->tear_free) > + amdgpu_scanout_flip(pScreen, info, crtc); > else if (info->shadow_primary > #if XF86_CRTC_VERSION >= 4 > - || xf86_config->crtc[c]->driverIsPerformingTransform > + || crtc->driverIsPerformingTransform > #endif > ) > - amdgpu_scanout_update(xf86_config->crtc[c]); > + amdgpu_scanout_update(crtc); > } > } > > @@ -1265,6 +1271,7 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags) > AMDGPUInfoPtr info; > AMDGPUEntPtr pAMDGPUEnt; > struct amdgpu_gpu_info gpu_info; > + MessageType from; > DevUnion *pPriv; > Gamma zeros = { 0.0, 0.0, 0.0 }; > int cpp; > @@ -1359,12 +1366,14 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags) > } > > if (info->use_glamor) { > - info->tear_free = xf86ReturnOptValBool(info->Options, > - OPTION_TEAR_FREE, FALSE); > + from = X_DEFAULT; > > - if (info->tear_free) > - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, > - "TearFree enabled\n"); > + info->tear_free = 2; > + if (xf86GetOptValBool(info->Options, OPTION_TEAR_FREE, > + &info->tear_free)) > + from = X_CONFIG; > + xf86DrvMsg(pScrn->scrnIndex, from, "TearFree property default: %s\n", > + info->tear_free == 2 ? "auto" : (info->tear_free ? "on" : "off")); > > info->shadow_primary = > xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE); > @@ -1378,14 +1387,14 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags) > info->allowPageFlip = xf86ReturnOptValBool(info->Options, > OPTION_PAGE_FLIP, > TRUE); > - if (sw_cursor || info->tear_free || info->shadow_primary) { > - xf86DrvMsg(pScrn->scrnIndex, > - info->allowPageFlip ? X_WARNING : X_DEFAULT, > - "KMS Pageflipping: disabled%s\n", > - info->allowPageFlip ? > - (sw_cursor ? " because of SWcursor" : > - " because of ShadowPrimary/TearFree") : ""); > - info->allowPageFlip = FALSE; > + if (sw_cursor || info->shadow_primary) { > + xf86DrvMsg(pScrn->scrnIndex, > + info->allowPageFlip ? X_WARNING : X_DEFAULT, > + "KMS Pageflipping: disabled%s\n", > + info->allowPageFlip ? > + (sw_cursor ? " because of SWcursor" : > + " because of ShadowPrimary") : ""); > + info->allowPageFlip = FALSE; > } else { > xf86DrvMsg(pScrn->scrnIndex, X_INFO, > "KMS Pageflipping: %sabled\n", > diff --git a/src/drmmode_display.c b/src/drmmode_display.c > index 303848f3..40439dd2 100644 > --- a/src/drmmode_display.c > +++ b/src/drmmode_display.c > @@ -587,6 +587,34 @@ drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) > return TRUE; > } > > +static void > +drmmode_crtc_update_tear_free(xf86CrtcPtr crtc) > +{ > + AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); > + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); > + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > + int i; > + > + drmmode_crtc->tear_free = FALSE; > + > + for (i = 0; i < xf86_config->num_output; i++) { > + xf86OutputPtr output = xf86_config->output[i]; > + drmmode_output_private_ptr drmmode_output = output->driver_private; > + > + if (output->crtc != crtc) > + continue; > + > + if (drmmode_output->tear_free == 1 || > + (drmmode_output->tear_free == 2 && > + (amdgpu_is_gpu_screen(crtc->scrn->pScreen) || > + info->shadow_primary || > + crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { > + drmmode_crtc->tear_free = TRUE; > + return; > + } > + } > +} > + > #if XF86_CRTC_VERSION >= 4 > > #if XF86_CRTC_VERSION < 7 > @@ -621,24 +649,86 @@ drmmode_handle_transform(xf86CrtcPtr crtc) > > #endif > > +#ifdef AMDGPU_PIXMAP_SHARING > + > +static void > +drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, > + unsigned scanout_id, int *fb_id, int *x, > + int *y) > +{ > + ScrnInfoPtr scrn = crtc->scrn; > + ScreenPtr screen = scrn->pScreen; > + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > + > + if (drmmode_crtc->tear_free && > + !drmmode_crtc->scanout[1].pixmap) { > + RegionPtr region; > + BoxPtr box; > + > + drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], > + mode->HDisplay, > + mode->VDisplay); > + region = &drmmode_crtc->scanout_last_region; > + RegionUninit(region); > + region->data = NULL; > + box = RegionExtents(region); > + box->x1 = crtc->x; > + box->y1 = crtc->y; > + box->x2 = crtc->x + mode->HDisplay; > + box->y2 = crtc->y + mode->VDisplay; > + } > + > + if (scanout_id != drmmode_crtc->scanout_id) { > + PixmapDirtyUpdatePtr dirty = NULL; > + > + xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, > + ent) { > + if (dirty->src == crtc->randr_crtc->scanout_pixmap && > + dirty->slave_dst == > + drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap) { > + dirty->slave_dst = > + drmmode_crtc->scanout[scanout_id].pixmap; > + break; > + } > + } > + > + if (!drmmode_crtc->tear_free) { > + GCPtr gc = GetScratchGC(scrn->depth, screen); > + > + ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); > + gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, > + &drmmode_crtc->scanout[0].pixmap->drawable, > + gc, 0, 0, mode->HDisplay, mode->VDisplay, > + 0, 0); > + FreeScratchGC(gc); > + amdgpu_glamor_finish(scrn); > + } > + } > + > + *fb_id = drmmode_crtc->scanout[scanout_id].fb_id; > + *x = *y = 0; > + drmmode_crtc->scanout_id = scanout_id; > +} > + > +#endif /* AMDGPU_PIXMAP_SHARING */ > + > static void > drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, > unsigned scanout_id, int *fb_id, int *x, int *y) > { > ScrnInfoPtr scrn = crtc->scrn; > ScreenPtr screen = scrn->pScreen; > - AMDGPUInfoPtr info = AMDGPUPTR(scrn); > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > > drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], > mode->HDisplay, mode->VDisplay); > - if (info->tear_free) { > + if (drmmode_crtc->tear_free) { > drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], > mode->HDisplay, mode->VDisplay); > } > > if (drmmode_crtc->scanout[0].pixmap && > - (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) { > + (!drmmode_crtc->tear_free || drmmode_crtc->scanout[1].pixmap)) { > RegionPtr region; > BoxPtr box; > > @@ -678,7 +768,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); > xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > - unsigned scanout_id = drmmode_crtc->scanout_id ^ info->tear_free; > + unsigned scanout_id = 0; > drmmode_ptr drmmode = drmmode_crtc->drmmode; > int saved_x, saved_y; > Rotation saved_rotation; > @@ -722,6 +812,10 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > if (!drmmode_handle_transform(crtc)) > goto done; > > + drmmode_crtc_update_tear_free(crtc); > + if (drmmode_crtc->tear_free) > + scanout_id = drmmode_crtc->scanout_id; > + > crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, > crtc->gamma_blue, crtc->gamma_size); > > @@ -730,8 +824,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > fb_id = drmmode->fb_id; > #ifdef AMDGPU_PIXMAP_SHARING > if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { > - fb_id = drmmode_crtc->scanout[scanout_id].fb_id; > - x = y = 0; > + drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, > + &fb_id, &x, &y); > } else > #endif > if (drmmode_crtc->rotate.fb_id) { > @@ -739,7 +833,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > x = y = 0; > > } else if (!amdgpu_is_gpu_screen(pScreen) && > - (info->tear_free || > + (drmmode_crtc->tear_free || > #if XF86_CRTC_VERSION >= 4 > crtc->driverIsPerformingTransform || > #endif > @@ -828,6 +922,10 @@ done: > > if (fb_id != drmmode_crtc->scanout[scanout_id].fb_id) > drmmode_crtc_scanout_free(drmmode_crtc); > + else if (!drmmode_crtc->tear_free) { > + drmmode_crtc_scanout_destroy(drmmode, > + &drmmode_crtc->scanout[1]); > + } > } > > return ret; > @@ -1086,7 +1184,6 @@ static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) > { > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > unsigned scanout_id = drmmode_crtc->scanout_id; > - AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); > ScreenPtr screen = crtc->scrn->pScreen; > PixmapDirtyUpdatePtr dirty; > > @@ -1107,7 +1204,7 @@ static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) > ppix->drawable.height)) > return FALSE; > > - if (info->tear_free && > + if (drmmode_crtc->tear_free && > !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], > ppix->drawable.width, > ppix->drawable.height)) { > @@ -1354,14 +1451,15 @@ static Bool drmmode_property_ignore(drmModePropertyPtr prop) > > static void drmmode_output_create_resources(xf86OutputPtr output) > { > + AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); > drmmode_output_private_ptr drmmode_output = output->driver_private; > drmModeConnectorPtr mode_output = drmmode_output->mode_output; > AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); > - drmModePropertyPtr drmmode_prop; > + drmModePropertyPtr drmmode_prop, tearfree_prop; > int i, j, err; > > drmmode_output->props = > - calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); > + calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); > if (!drmmode_output->props) > return; > > @@ -1379,6 +1477,23 @@ static void drmmode_output_create_resources(xf86OutputPtr output) > j++; > } > > + /* Userspace-only property for TearFree */ > + tearfree_prop = calloc(1, sizeof(*tearfree_prop)); > + tearfree_prop->flags = DRM_MODE_PROP_ENUM; > + strncpy(tearfree_prop->name, "TearFree", 8); > + tearfree_prop->count_enums = 3; > + tearfree_prop->enums = calloc(tearfree_prop->count_enums, > + sizeof(*tearfree_prop->enums)); > + strncpy(tearfree_prop->enums[0].name, "off", 3); > + strncpy(tearfree_prop->enums[1].name, "on", 2); > + tearfree_prop->enums[1].value = 1; > + strncpy(tearfree_prop->enums[2].name, "auto", 4); > + tearfree_prop->enums[2].value = 2; > + drmmode_output->props[j].mode_prop = tearfree_prop; > + drmmode_output->props[j].value = info->tear_free; > + drmmode_output->tear_free = info->tear_free; > + drmmode_output->num_props++; > + > for (i = 0; i < drmmode_output->num_props; i++) { > drmmode_prop_ptr p = &drmmode_output->props[i]; > drmmode_prop = p->mode_prop; > @@ -1504,11 +1619,26 @@ drmmode_output_set_property(xf86OutputPtr output, Atom property, > /* search for matching name string, then set its value down */ > for (j = 0; j < p->mode_prop->count_enums; j++) { > if (!strcmp(p->mode_prop->enums[j].name, name)) { > - drmModeConnectorSetProperty(pAMDGPUEnt->fd, > - drmmode_output->output_id, > - p->mode_prop->prop_id, > - p->mode_prop->enums > - [j].value); > + if (i == (drmmode_output->num_props - 1)) { > + if (drmmode_output->tear_free != j) { > + xf86CrtcPtr crtc = output->crtc; > + > + drmmode_output->tear_free = j; > + if (crtc) { > + drmmode_set_mode_major(crtc, > + &crtc->mode, > + crtc->rotation, > + crtc->x, > + crtc->y); > + } > + } > + } else { > + drmModeConnectorSetProperty(pAMDGPUEnt->fd, > + drmmode_output->output_id, > + p->mode_prop->prop_id, > + p->mode_prop->enums[j].value); > + } > + > return TRUE; > } > } > diff --git a/src/drmmode_display.h b/src/drmmode_display.h > index e9967a26..fa15a4f7 100644 > --- a/src/drmmode_display.h > +++ b/src/drmmode_display.h > @@ -85,6 +85,7 @@ typedef struct { > RegionRec scanout_last_region; > unsigned scanout_id; > Bool scanout_update_pending; > + Bool tear_free; > int dpms_mode; > /* For when a flip is pending when DPMS off requested */ > int pending_dpms_mode; > @@ -117,6 +118,7 @@ typedef struct { > drmmode_prop_ptr props; > int enc_mask; > int enc_clone_mask; > + int tear_free; > } drmmode_output_private_rec, *drmmode_output_private_ptr; > > > -- > 2.11.0 > > _______________________________________________ > amd-gfx mailing list > amd-gfx at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx