[PATCH xf86-video-amdgpu 6/6] Allow toggling TearFree at runtime via output property
Michel Dänzer
michel at daenzer.net
Thu Mar 2 09:18:00 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.
(Ported from radeon commit 58cd1600057e41aade0106d4acf78e23eac6e44f)
Signed-off-by: Michel Dänzer <michel.daenzer 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
More information about the amd-gfx
mailing list