[PATCH xf86-video-ati 3/3] Allow toggling TearFree at runtime via output property
Michel Dänzer
michel at daenzer.net
Tue Feb 21 07:51:43 UTC 2017
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>
---
man/radeon.man | 15 +++--
src/drmmode_display.c | 161 +++++++++++++++++++++++++++++++++++++++++++++-----
src/drmmode_display.h | 2 +
src/radeon.h | 2 +-
src/radeon_dri2.c | 34 ++++++++---
src/radeon_kms.c | 43 +++++++++-----
6 files changed, 215 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..489e93395 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 &&
+ (crtc->scrn->is_gpu ||
+ 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..2e5f1a34d 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -756,14 +756,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
More information about the amd-gfx
mailing list