On Tue, Feb 21, 2017 at 3:17 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. > > Signed-off-by: Michel Dänzer <michel.daenzer at amd.com> Series is: Reviewed-by: Alex Deucher <alexander.deucher at amd.com> > --- > > v2: Fix build against xserver 1.10 > > man/radeon.man | 15 +++-- > src/drmmode_display.c | 161 +++++++++++++++++++++++++++++++++++++++++++++----- > src/drmmode_display.h | 2 + > src/radeon.h | 2 +- > src/radeon_dri2.c | 35 ++++++++--- > src/radeon_kms.c | 43 +++++++++----- > 6 files changed, 216 insertions(+), 42 deletions(-) > > diff --git a/man/radeon.man b/man/radeon.man > index 8990ae21d..5301dd7f0 100644 > --- a/man/radeon.man > +++ b/man/radeon.man > @@ -281,10 +281,17 @@ Enable DRI2 page flipping. The default is > Pageflipping is supported on all radeon hardware. > .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 > Chooses between available acceleration architectures. Valid values are > diff --git a/src/drmmode_display.c b/src/drmmode_display.c > index fcac1562b..5b0236da4 100644 > --- a/src/drmmode_display.c > +++ b/src/drmmode_display.c > @@ -670,6 +670,34 @@ drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) > return TRUE; > } > > +static void > +drmmode_crtc_update_tear_free(xf86CrtcPtr crtc) > +{ > + RADEONInfoPtr info = RADEONPTR(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 && > + (radeon_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 > > static Bool > @@ -683,10 +711,11 @@ drmmode_handle_transform(xf86CrtcPtr crtc) > else > crtc->driverIsPerformingTransform = XF86DriverTransformNone; > #else > + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > RADEONInfoPtr info = RADEONPTR(crtc->scrn); > > crtc->driverIsPerformingTransform = crtc->transformPresent || > - (info->tear_free && crtc->rotation != RR_Rotate_0); > + (drmmode_crtc->tear_free && crtc->rotation != RR_Rotate_0); > #endif > > ret = xf86CrtcRotate(crtc); > @@ -706,24 +735,87 @@ drmmode_handle_transform(xf86CrtcPtr crtc) > > #endif > > +#ifdef RADEON_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); > + radeon_cs_flush_indirect(scrn); > + radeon_bo_wait(drmmode_crtc->scanout[0].bo); > + } > + } > + > + *fb_id = drmmode_crtc->scanout[scanout_id].fb_id; > + *x = *y = 0; > + drmmode_crtc->scanout_id = scanout_id; > +} > + > +#endif /* RADEON_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; > - RADEONInfoPtr info = RADEONPTR(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; > > @@ -762,7 +854,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > RADEONInfoPtr info = RADEONPTR(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; > @@ -804,6 +896,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); > > @@ -812,8 +908,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > fb_id = drmmode->fb_id; > #ifdef RADEON_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) { > @@ -821,7 +917,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, > x = y = 0; > > } else if (!radeon_is_gpu_screen(pScreen) && > - (info->tear_free || > + (drmmode_crtc->tear_free || > #if XF86_CRTC_VERSION >= 4 > crtc->driverIsPerformingTransform || > #endif > @@ -905,6 +1001,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]); > + } > } > > free(output_ids); > @@ -1142,7 +1242,6 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) > { > drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; > unsigned scanout_id = drmmode_crtc->scanout_id; > - RADEONInfoPtr info = RADEONPTR(crtc->scrn); > ScreenPtr screen = crtc->scrn->pScreen; > PixmapDirtyUpdatePtr dirty; > > @@ -1163,7 +1262,7 @@ 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)) { > @@ -1418,13 +1517,14 @@ drmmode_property_ignore(drmModePropertyPtr prop) > static void > drmmode_output_create_resources(xf86OutputPtr output) > { > + RADEONInfoPtr info = RADEONPTR(output->scrn); > drmmode_output_private_ptr drmmode_output = output->driver_private; > drmModeConnectorPtr mode_output = drmmode_output->mode_output; > drmmode_ptr drmmode = drmmode_output->drmmode; > - drmModePropertyPtr drmmode_prop; > + drmModePropertyPtr drmmode_prop, tearfree_prop; > int i, j, err; > > - drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); > + drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); > if (!drmmode_output->props) > return; > > @@ -1441,6 +1541,23 @@ 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; > @@ -1540,8 +1657,24 @@ 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(drmmode->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(drmmode->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 6bbf71c18..bd3f5f987 100644 > --- a/src/drmmode_display.h > +++ b/src/drmmode_display.h > @@ -89,6 +89,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; > @@ -124,6 +125,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; > > > diff --git a/src/radeon.h b/src/radeon.h > index 039a620be..bfff232c4 100644 > --- a/src/radeon.h > +++ b/src/radeon.h > @@ -507,7 +507,7 @@ typedef struct { > Bool accelOn; > Bool use_glamor; > Bool shadow_primary; > - Bool tear_free; > + int tear_free; > Bool exa_pixmaps; > Bool exa_force_create; > XF86ModReqInfo exaReq; > diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c > index d0dcf8906..c108ceab2 100644 > --- a/src/radeon_dri2.c > +++ b/src/radeon_dri2.c > @@ -47,6 +47,7 @@ > #include "radeon_bo_gem.h" > > #include <xf86Priv.h> > +#include <X11/extensions/dpmsconst.h> > > #if DRI2INFOREC_VERSION >= 9 > #define USE_DRI2_PRIME > @@ -756,14 +757,34 @@ can_flip(ScrnInfoPtr pScrn, DrawablePtr draw, > DRI2BufferPtr front, DRI2BufferPtr back) > { > RADEONInfoPtr info = RADEONPTR(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/radeon_kms.c b/src/radeon_kms.c > index 0ed7680e7..331f3f1c9 100644 > --- a/src/radeon_kms.c > +++ b/src/radeon_kms.c > @@ -669,7 +669,6 @@ 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; > @@ -677,7 +676,7 @@ radeon_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)) > @@ -687,7 +686,7 @@ radeon_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); > radeon_sync_scanout_pixmaps(crtc, region, scanout_id); > radeon_cs_flush_indirect(scrn); > @@ -823,7 +822,6 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent) > static void > radeon_dirty_update(ScrnInfoPtr scrn) > { > - RADEONInfoPtr info = RADEONPTR(scrn); > ScreenPtr screen = scrn->pScreen; > PixmapDirtyUpdatePtr ent; > RegionPtr region; > @@ -844,7 +842,13 @@ radeon_dirty_update(ScrnInfoPtr scrn) > region = dirty_region(region_ent); > > if (RegionNotEmpty(region)) { > - if (info->tear_free) > + xf86CrtcPtr crtc = radeon_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) > radeon_prime_scanout_flip(ent); > else > radeon_prime_scanout_update(ent); > @@ -890,7 +894,7 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) > if (!radeon_scanout_extents_intersect(xf86_crtc, &extents)) > return FALSE; > > - if (info->tear_free) { > + if (drmmode_crtc->tear_free) { > radeon_sync_scanout_pixmaps(xf86_crtc, pRegion, scanout_id); > RegionCopy(&drmmode_crtc->scanout_last_region, pRegion); > } > @@ -1112,14 +1116,17 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) > if (!radeon_is_gpu_screen(pScreen)) > { > for (c = 0; c < xf86_config->num_crtc; c++) { > - if (info->tear_free) > - radeon_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) > + radeon_scanout_flip(pScreen, info, crtc); > else if (info->shadow_primary > #if XF86_CRTC_VERSION >= 4 > - || xf86_config->crtc[c]->driverIsPerformingTransform > + || crtc->driverIsPerformingTransform > #endif > ) > - radeon_scanout_update(xf86_config->crtc[c]); > + radeon_scanout_update(crtc); > } > } > > @@ -1633,6 +1640,7 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) > { > RADEONInfoPtr info; > RADEONEntPtr pRADEONEnt; > + MessageType from; > DevUnion* pPriv; > Gamma zeros = { 0.0, 0.0, 0.0 }; > uint32_t tiling = 0; > @@ -1778,11 +1786,14 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) > #endif > > if (!info->r600_shadow_fb) { > - 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")); > } > > if (info->dri2.pKernelDRMVersion->version_minor >= 8) { > @@ -1791,13 +1802,13 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) > info->allowPageFlip = xf86ReturnOptValBool(info->Options, > OPTION_PAGE_FLIP, TRUE); > > - if (sw_cursor || info->tear_free || info->shadow_primary) { > + 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/TearFree") : ""); > + " because of ShadowPrimary") : ""); > info->allowPageFlip = FALSE; > } else { > xf86DrvMsg(pScrn->scrnIndex, X_INFO, > -- > 2.11.0 > > _______________________________________________ > amd-gfx mailing list > amd-gfx at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx