File U_13-Handle-RandR-1.4-slave-dirty-updates-via-radeon_drm_queue.patch of Package xf86-video-ati

From: Michel Dänzer <michel.daenzer@amd.com>
Date: Fri Nov 27 16:31:21 2015 +0900
Subject: [PATCH 13/20]Handle RandR 1.4 slave dirty updates via radeon_drm_queue
Patch-mainline: Upstream
Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati
Git-commit: ad0a0656dd0e74683e6d7789decba827aa29c221
References: bsc#990066
Signed-off-by: Max Staudt <mstaudt@suse.de>

This reduces PCIe bandwidth usage and tearing.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
---
 src/radeon_kms.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 90 insertions(+), 4 deletions(-)

diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 53994c9..07ba362 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -383,9 +383,9 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen)

 #ifdef RADEON_PIXMAP_SHARING
 static void
-redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
+redisplay_dirty(PixmapDirtyUpdatePtr dirty)
 {
-	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
+	ScrnInfoPtr pScrn = xf86ScreenToScrn(dirty->src->drawable.pScreen);
 	RegionRec pixregion;

 	PixmapRegionInit(&pixregion, dirty->slave_dst);
@@ -399,6 +399,90 @@ redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
 	radeon_cs_flush_indirect(pScrn);
 	DamageRegionProcessPending(&dirty->slave_dst->drawable);
 	RegionUninit(&pixregion);
+
+	DamageEmpty(dirty->damage);
+}
+
+static void
+radeon_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+void
+radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
+				    void *event_data)
+{
+    ScrnInfoPtr scrn = crtc->scrn;
+    ScreenPtr screen = scrn->pScreen;
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
+    PixmapDirtyUpdatePtr dirty;
+
+    xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
+	if (dirty->src == scanoutpix &&
+	    dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
+	    redisplay_dirty(dirty);
+	    break;
+	}
+    }
+
+    drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
+{
+    ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    xf86CrtcPtr xf86_crtc = NULL;
+    drmmode_crtc_private_ptr drmmode_crtc = NULL;
+    uintptr_t drm_queue_seq;
+    drmVBlank vbl;
+    int c;
+
+    /* Find the CRTC which is scanning out from this slave pixmap */
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+	xf86_crtc = xf86_config->crtc[c];
+	drmmode_crtc = xf86_crtc->driver_private;
+	if (drmmode_crtc->scanout[0].pixmap == dirty->slave_dst)
+	    break;
+    }
+
+    if (c == xf86_config->num_crtc ||
+	!xf86_crtc->enabled ||
+	drmmode_crtc->scanout_update_pending ||
+	!drmmode_crtc->scanout[0].pixmap ||
+	drmmode_crtc->pending_dpms_mode != DPMSModeOn)
+	return;
+
+    drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc,
+					   RADEON_DRM_QUEUE_CLIENT_DEFAULT,
+					   RADEON_DRM_QUEUE_ID_DEFAULT, NULL,
+					   radeon_prime_scanout_update_handler,
+					   radeon_prime_scanout_update_abort);
+    if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "radeon_drm_queue_alloc failed for PRIME update\n");
+	return;
+    }
+
+    vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+    vbl.request.type |= radeon_populate_vbl_request_type(xf86_crtc);
+    vbl.request.sequence = 1;
+    vbl.request.signal = drm_queue_seq;
+    if (drmWaitVBlank(RADEONPTR(scrn)->dri2.drm_fd, &vbl)) {
+	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		   "drmWaitVBlank failed for PRIME update: %s\n",
+		   strerror(errno));
+	radeon_drm_abort_entry(drm_queue_seq);
+	return;
+    }
+
+    drmmode_crtc->scanout_update_pending = TRUE;
 }

 static void
@@ -413,8 +497,10 @@ radeon_dirty_update(ScreenPtr screen)
 	xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
 		region = DamageRegion(ent->damage);
 		if (RegionNotEmpty(region)) {
-			redisplay_dirty(screen, ent);
-			DamageEmpty(ent->damage);
+			if (screen->isGPU)
+				radeon_prime_scanout_update(ent);
+			else
+				redisplay_dirty(ent);
 		}
 	}
 }