- U_01-* ... U_20-* : Include patches that haven't made it into the 7.7.1 release. This means almost all commits between xf86-video-ati-7.7.0 and 12d30eeb9711bd2b1609d6bbb74c4a1760596f72. Fixes (bsc#990066). OBS-URL: https://build.opensuse.org/request/show/438260 OBS-URL: https://build.opensuse.org/package/show/X11:XOrg/xf86-video-ati?expand=0&rev=51
266 lines
8.4 KiB
Diff
266 lines
8.4 KiB
Diff
From: Michel Dänzer <michel.daenzer@amd.com>
|
|
Date: Fri Sep 2 11:08:28 2016 +0900
|
|
Subject: [PATCH 20/20]Make TearFree effective with PRIME slave scanout
|
|
Patch-mainline: Upstream
|
|
Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati
|
|
Git-commit: 38797a33117222dadbc89e5f21ed8cd5deef9bea
|
|
References: bsc#990066
|
|
Signed-off-by: Max Staudt <mstaudt@suse.de>
|
|
|
|
TearFree can now prevent tearing with any possible display
|
|
configuration.
|
|
|
|
Note that there may still be inter-GPU tearing if the primary GPU uses
|
|
a different driver.
|
|
|
|
v2:
|
|
* Also test dirty->slave_dst in radeon_prime_scanout_do_update
|
|
|
|
Reviewed-by: Alex Deucher <alexander.deucher@amd.com> [v1]
|
|
---
|
|
src/drmmode_display.c | 33 ++++++++++++---
|
|
src/drmmode_display.h | 1 +
|
|
src/radeon_kms.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++----
|
|
3 files changed, 132 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
|
|
index 44a4032..44615d3 100644
|
|
--- a/src/drmmode_display.c
|
|
+++ b/src/drmmode_display.c
|
|
@@ -524,10 +524,19 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
|
|
static void
|
|
drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
|
|
{
|
|
- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
|
|
- &drmmode_crtc->scanout[0]);
|
|
- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
|
|
- &drmmode_crtc->scanout[1]);
|
|
+ if (drmmode_crtc->flip_pending) {
|
|
+ drmmode_crtc->scanout_destroy[0] = drmmode_crtc->scanout[0];
|
|
+ drmmode_crtc->scanout[0].pixmap = NULL;
|
|
+ drmmode_crtc->scanout[0].bo = NULL;
|
|
+ drmmode_crtc->scanout_destroy[1] = drmmode_crtc->scanout[1];
|
|
+ drmmode_crtc->scanout[1].pixmap = NULL;
|
|
+ drmmode_crtc->scanout[1].bo = NULL;
|
|
+ } else {
|
|
+ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
|
|
+ &drmmode_crtc->scanout[0]);
|
|
+ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
|
|
+ &drmmode_crtc->scanout[1]);
|
|
+ }
|
|
|
|
if (drmmode_crtc->scanout_damage) {
|
|
DamageDestroy(drmmode_crtc->scanout_damage);
|
|
@@ -1116,11 +1125,12 @@ static Bool
|
|
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
|
|
{
|
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
+ RADEONInfoPtr info = RADEONPTR(crtc->scrn);
|
|
|
|
if (!ppix) {
|
|
if (crtc->randr_crtc->scanout_pixmap)
|
|
PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap,
|
|
- drmmode_crtc->scanout[0].pixmap);
|
|
+ drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap);
|
|
drmmode_crtc_scanout_free(drmmode_crtc);
|
|
return TRUE;
|
|
}
|
|
@@ -1130,6 +1140,14 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
|
|
ppix->drawable.height))
|
|
return FALSE;
|
|
|
|
+ if (info->tear_free &&
|
|
+ !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
|
|
+ ppix->drawable.width,
|
|
+ ppix->drawable.height)) {
|
|
+ drmmode_crtc_scanout_free(drmmode_crtc);
|
|
+ return FALSE;
|
|
+ }
|
|
+
|
|
#ifdef HAS_DIRTYTRACKING_ROTATION
|
|
PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap,
|
|
0, 0, 0, 0, RR_Rotate_0);
|
|
@@ -2196,6 +2214,11 @@ drmmode_clear_pending_flip(xf86CrtcPtr crtc)
|
|
|
|
drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode);
|
|
}
|
|
+
|
|
+ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
|
|
+ &drmmode_crtc->scanout_destroy[0]);
|
|
+ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
|
|
+ &drmmode_crtc->scanout_destroy[1]);
|
|
}
|
|
|
|
static void
|
|
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
|
|
index 5df9773..7602eb8 100644
|
|
--- a/src/drmmode_display.h
|
|
+++ b/src/drmmode_display.h
|
|
@@ -84,6 +84,7 @@ typedef struct {
|
|
struct radeon_bo *cursor_bo;
|
|
struct drmmode_scanout rotate;
|
|
struct drmmode_scanout scanout[2];
|
|
+ struct drmmode_scanout scanout_destroy[2];
|
|
DamagePtr scanout_damage;
|
|
RegionRec scanout_last_region;
|
|
unsigned scanout_id;
|
|
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
|
|
index bcaa024..9bcf657 100644
|
|
--- a/src/radeon_kms.c
|
|
+++ b/src/radeon_kms.c
|
|
@@ -597,31 +597,56 @@ slave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
|
|
return slave_scrn->driverName == scrn->driverName;
|
|
}
|
|
|
|
-void
|
|
-radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
|
|
- void *event_data)
|
|
+static Bool
|
|
+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;
|
|
+ Bool ret = FALSE;
|
|
|
|
xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
|
|
- if (dirty->src == scanoutpix &&
|
|
- dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
|
|
+ if (dirty->src == scanoutpix && dirty->slave_dst ==
|
|
+ drmmode_crtc->scanout[scanout_id ^ info->tear_free].pixmap) {
|
|
RegionPtr region;
|
|
|
|
if (master_has_sync_shared_pixmap(scrn, dirty))
|
|
radeon_sync_shared_pixmap(dirty);
|
|
|
|
region = dirty_region(dirty);
|
|
+ if (RegionNil(region))
|
|
+ goto destroy;
|
|
+
|
|
+ if (info->tear_free) {
|
|
+ RegionTranslate(region, crtc->x, crtc->y);
|
|
+ radeon_sync_scanout_pixmaps(crtc, region, scanout_id);
|
|
+ radeon_cs_flush_indirect(scrn);
|
|
+ RegionCopy(&drmmode_crtc->scanout_last_region, region);
|
|
+ RegionTranslate(region, -crtc->x, -crtc->y);
|
|
+ dirty->slave_dst = drmmode_crtc->scanout[scanout_id].pixmap;
|
|
+ }
|
|
+
|
|
redisplay_dirty(dirty, region);
|
|
+ ret = TRUE;
|
|
+ destroy:
|
|
RegionDestroy(region);
|
|
break;
|
|
}
|
|
}
|
|
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void
|
|
+radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
|
|
+ void *event_data)
|
|
+{
|
|
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
|
+
|
|
+ radeon_prime_scanout_do_update(crtc, 0);
|
|
drmmode_crtc->scanout_update_pending = FALSE;
|
|
}
|
|
|
|
@@ -679,8 +704,74 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
|
|
}
|
|
|
|
static void
|
|
+radeon_prime_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
|
|
+{
|
|
+ drmmode_crtc_private_ptr drmmode_crtc = event_data;
|
|
+
|
|
+ drmmode_crtc->scanout_update_pending = FALSE;
|
|
+ drmmode_clear_pending_flip(crtc);
|
|
+}
|
|
+
|
|
+static void
|
|
+radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
|
|
+{
|
|
+ ScreenPtr screen = ent->slave_dst->drawable.pScreen;
|
|
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
|
|
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
|
|
+ xf86CrtcPtr crtc = NULL;
|
|
+ drmmode_crtc_private_ptr drmmode_crtc = NULL;
|
|
+ uintptr_t drm_queue_seq;
|
|
+ unsigned scanout_id;
|
|
+ int c;
|
|
+
|
|
+ /* Find the CRTC which is scanning out from this slave pixmap */
|
|
+ for (c = 0; c < xf86_config->num_crtc; c++) {
|
|
+ crtc = xf86_config->crtc[c];
|
|
+ drmmode_crtc = crtc->driver_private;
|
|
+ scanout_id = drmmode_crtc->scanout_id;
|
|
+ if (drmmode_crtc->scanout[scanout_id].pixmap == ent->slave_dst)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (c == xf86_config->num_crtc ||
|
|
+ !crtc->enabled ||
|
|
+ drmmode_crtc->scanout_update_pending ||
|
|
+ !drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap ||
|
|
+ drmmode_crtc->pending_dpms_mode != DPMSModeOn)
|
|
+ return;
|
|
+
|
|
+ scanout_id = drmmode_crtc->scanout_id ^ 1;
|
|
+ if (!radeon_prime_scanout_do_update(crtc, scanout_id))
|
|
+ return;
|
|
+
|
|
+ drm_queue_seq = radeon_drm_queue_alloc(crtc,
|
|
+ RADEON_DRM_QUEUE_CLIENT_DEFAULT,
|
|
+ RADEON_DRM_QUEUE_ID_DEFAULT,
|
|
+ drmmode_crtc, NULL,
|
|
+ radeon_prime_scanout_flip_abort);
|
|
+ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
|
|
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
|
|
+ "Allocating DRM event queue entry failed for PRIME flip.\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, (void*)drm_queue_seq)) {
|
|
+ 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;
|
|
+ drmmode_crtc->flip_pending = TRUE;
|
|
+}
|
|
+
|
|
+static void
|
|
radeon_dirty_update(ScrnInfoPtr scrn)
|
|
{
|
|
+ RADEONInfoPtr info = RADEONPTR(scrn);
|
|
ScreenPtr screen = scrn->pScreen;
|
|
PixmapDirtyUpdatePtr ent;
|
|
RegionPtr region;
|
|
@@ -700,10 +791,14 @@ radeon_dirty_update(ScrnInfoPtr scrn)
|
|
|
|
region = dirty_region(region_ent);
|
|
|
|
- if (RegionNotEmpty(region))
|
|
- radeon_prime_scanout_update(ent);
|
|
- else
|
|
+ if (RegionNotEmpty(region)) {
|
|
+ if (info->tear_free)
|
|
+ radeon_prime_scanout_flip(ent);
|
|
+ else
|
|
+ radeon_prime_scanout_update(ent);
|
|
+ } else {
|
|
DamageEmpty(region_ent->damage);
|
|
+ }
|
|
|
|
RegionDestroy(region);
|
|
} else {
|