[PATCH xf86-video-amdgpu 11/11] Add Option "TearFree"
Michel Dänzer
michel at daenzer.net
Wed Jun 10 02:04:26 PDT 2015
From: Michel Dänzer <michel.daenzer at amd.com>
Avoids tearing by flipping between two scanout BOs per (non-rotated) CRTC
(Cherry picked from radeon commit 43159ef400c3b18b9f4d3e6fa1c4aef2d60d38fe)
Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
src/amdgpu_drv.h | 2 +
src/amdgpu_kms.c | 138 ++++++++++++++++++++++++++++++++++++++------------
src/drmmode_display.c | 79 ++++++++++++++++-------------
src/drmmode_display.h | 5 +-
4 files changed, 154 insertions(+), 70 deletions(-)
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 55be626..e7bdf7f 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -143,6 +143,7 @@ typedef enum {
OPTION_ACCEL_METHOD,
OPTION_DRI3,
OPTION_SHADOW_PRIMARY,
+ OPTION_TEAR_FREE,
} AMDGPUOpts;
#define AMDGPU_VSYNC_TIMEOUT 20000 /* Maximum wait for VSYNC (in usecs) */
@@ -205,6 +206,7 @@ typedef struct {
uint_fast32_t gpu_synced;
Bool use_glamor;
Bool shadow_primary;
+ Bool tear_free;
/* general */
OptionInfoPtr Options;
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 5a672c9..f6ccbd4 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -68,6 +68,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
{ OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
{OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
+ {OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
@@ -222,20 +223,9 @@ amdgpu_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
}
-static void
-amdgpu_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
-amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
- void *event_data)
+static Bool
+amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
{
- xf86CrtcPtr xf86_crtc = event_data;
drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
DamagePtr pDamage;
RegionPtr pRegion;
@@ -244,23 +234,24 @@ amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
GCPtr gc;
BoxRec extents;
- 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 (!amdgpu_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);
@@ -273,16 +264,30 @@ amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
extents.x1, extents.y1);
FreeScratchGC(gc);
- amdgpu_glamor_flush(scrn);
+ amdgpu_glamor_flush(xf86_crtc->scrn);
-clear_damage:
- RegionEmpty(pRegion);
+ return TRUE;
+}
+
+static void
+amdgpu_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
+amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+ void *event_data)
+{
+ amdgpu_scanout_do_update(event_data, 0);
+
+ amdgpu_scanout_update_abort(scrn, event_data);
+}
+
+static void
amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
{
drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
@@ -295,11 +300,11 @@ amdgpu_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;
@@ -307,7 +312,7 @@ amdgpu_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 (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
pDraw->width, pDraw->height))
@@ -339,6 +344,61 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
drmmode_crtc->scanout_update_pending = TRUE;
}
+
+static void
+amdgpu_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = event_data;
+
+ drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data)
+{
+ amdgpu_scanout_flip_abort(scrn, event_data);
+}
+
+static void
+amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
+ xf86CrtcPtr xf86_crtc)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+ ScrnInfoPtr scrn;
+ struct amdgpu_drm_queue_entry *drm_queue_entry;
+ unsigned scanout_id;
+
+ if (drmmode_crtc->scanout_update_pending)
+ return;
+
+ scanout_id = drmmode_crtc->scanout_id ^ 1;
+ if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id))
+ return;
+
+ scrn = xf86_crtc->scrn;
+ drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+ AMDGPU_DRM_QUEUE_ID_DEFAULT,
+ drmmode_crtc,
+ amdgpu_scanout_flip_handler,
+ amdgpu_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 in %s: %s\n",
+ __func__, strerror(errno));
+ return;
+ }
+
+ drmmode_crtc->scanout_id = scanout_id;
+ drmmode_crtc->scanout_update_pending = TRUE;
+}
+
static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
{
SCREEN_PTR(arg);
@@ -349,12 +409,16 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
pScreen->BlockHandler = AMDGPUBlockHandler_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++)
- amdgpu_scanout_update(xf86_config->crtc[c]);
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ if (info->tear_free)
+ amdgpu_scanout_flip(pScreen, info, xf86_config->crtc[c]);
+ else
+ amdgpu_scanout_update(xf86_config->crtc[c]);
+ }
}
if (info->use_glamor)
@@ -681,6 +745,13 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
}
if (info->use_glamor) {
+ info->tear_free = xf86ReturnOptValBool(info->Options,
+ OPTION_TEAR_FREE, FALSE);
+
+ if (info->tear_free)
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "TearFree enabled\n");
+
info->shadow_primary =
xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
@@ -691,11 +762,12 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
info->allowPageFlip = xf86ReturnOptValBool(info->Options,
OPTION_PAGE_FLIP,
TRUE);
- 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 {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 79fbecf..19f0f19 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -325,6 +325,10 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
scanout->bo = NULL;
}
+ if (scanout->damage) {
+ DamageDestroy(scanout->damage);
+ scanout->damage = NULL;
+ }
}
void
@@ -338,12 +342,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]);
}
}
@@ -527,43 +528,51 @@ 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(amdgpu_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(amdgpu_screen_damage_report,
+ NULL, DamageReportRawRegion,
+ TRUE, pScreen, NULL);
+ DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
+ drmmode_crtc->scanout[i].damage);
+ }
- 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);
+ 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);
+ }
+ }
- fb_id = drmmode_crtc->scanout.fb_id;
+ if (drmmode_crtc->scanout[0].pixmap &&
+ (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) {
+ drmmode_crtc->scanout_id = 0;
+ fb_id = drmmode_crtc->scanout[0].fb_id;
x = y = 0;
}
}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 0ba358e..8262e05 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -73,6 +73,7 @@ typedef struct {
struct drmmode_scanout {
struct amdgpu_buffer *bo;
PixmapPtr pixmap;
+ DamagePtr damage;
unsigned fb_id;
int width, height;
};
@@ -83,8 +84,8 @@ typedef struct {
int hw_id;
struct amdgpu_buffer *cursor_buffer;
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;
--
2.1.4
More information about the xorg-driver-ati
mailing list