[PATCH xf86-video-ati 1/2] Only copy from screen pixmap to shared pixmap on demand for slave scanout

Michel Dänzer michel at daenzer.net
Wed Aug 31 08:55:42 UTC 2016


From: Michel Dänzer <michel.daenzer at amd.com>

Only copy once for each time we update the corresponding scanout pixmap.
This can significantly reduce the bandwidth usage when there are
frequent updates to the screen pixmap.

This initial implementation only works when both the master and slave
screens use this driver.

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/radeon_kms.c | 100 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 78 insertions(+), 22 deletions(-)

diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 51f320c..0c8996d 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -440,6 +440,9 @@ redisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
 {
 	ScrnInfoPtr pScrn = xf86ScreenToScrn(dirty->src->drawable.pScreen);
 
+	if (RegionNil(region))
+		goto out;
+
 	if (dirty->slave_dst->master_pixmap)
 	    DamageRegionAppend(&dirty->slave_dst->drawable, region);
 
@@ -453,6 +456,7 @@ redisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
 	if (dirty->slave_dst->master_pixmap)
 	    DamageRegionProcessPending(&dirty->slave_dst->drawable);
 
+out:
 	DamageEmpty(dirty->damage);
 }
 
@@ -465,6 +469,39 @@ radeon_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
 }
 
 void
+radeon_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
+{
+    ScreenPtr master_screen = dirty->src->master_pixmap->drawable.pScreen;
+    PixmapDirtyUpdatePtr ent;
+    RegionPtr region;
+
+    xorg_list_for_each_entry(ent, &master_screen->pixmap_dirty_list, ent) {
+	if (ent->slave_dst != dirty->src)
+	    continue;
+
+	region = dirty_region(ent);
+	redisplay_dirty(ent, region);
+	RegionDestroy(region);
+    }
+}
+
+static Bool
+master_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
+{
+    ScrnInfoPtr master_scrn = xf86ScreenToScrn(dirty->src->master_pixmap->drawable.pScreen);
+
+    return master_scrn->driverName == scrn->driverName;
+}
+
+static Bool
+slave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
+{
+    ScrnInfoPtr slave_scrn = xf86ScreenToScrn(dirty->slave_dst->drawable.pScreen);
+
+    return slave_scrn->driverName == scrn->driverName;
+}
+
+void
 radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
 				    void *event_data)
 {
@@ -473,16 +510,20 @@ radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t u
     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
     PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
     PixmapDirtyUpdatePtr dirty;
+    RegionPtr region;
 
     xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
-	if (dirty->src == scanoutpix &&
-	    dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
-	    RegionPtr region = dirty_region(dirty);
+	if (dirty->src != scanoutpix ||
+	    dirty->slave_dst != drmmode_crtc->scanout[0].pixmap)
+	    continue;
 
-	    redisplay_dirty(dirty, region);
-	    RegionDestroy(region);
-	    break;
-	}
+	if (master_has_sync_shared_pixmap(scrn, dirty))
+	    radeon_sync_shared_pixmap(dirty);
+
+	region = dirty_region(dirty);
+	redisplay_dirty(dirty, region);
+	RegionDestroy(region);
+	break;
     }
 
     drmmode_crtc->scanout_update_pending = FALSE;
@@ -542,26 +583,41 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
 }
 
 static void
-radeon_dirty_update(ScreenPtr screen)
+radeon_dirty_update(ScrnInfoPtr scrn)
 {
+	ScreenPtr screen = scrn->pScreen;
 	PixmapDirtyUpdatePtr ent;
-
-	if (xorg_list_is_empty(&screen->pixmap_dirty_list))
-		return;
+	RegionPtr region;
 
 	xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
-		RegionPtr region = dirty_region(ent);
-
-		if (RegionNotEmpty(region)) {
-			if (screen->isGPU)
-				radeon_prime_scanout_update(ent);
-			else
-				redisplay_dirty(ent, region);
+		if (screen->isGPU) {
+			ScreenPtr master_screen = ent->src->master_pixmap->drawable.pScreen;
+			PixmapDirtyUpdatePtr master_ent;
+
+			xorg_list_for_each_entry(master_ent, &master_screen->pixmap_dirty_list, ent) {
+				if (master_ent->slave_dst != ent->src)
+					continue;
+
+				if (master_has_sync_shared_pixmap(scrn, ent))
+					region = dirty_region(master_ent);
+				else
+					region = dirty_region(ent);
+
+				if (RegionNotEmpty(region))
+					radeon_prime_scanout_update(ent);
+				else
+					DamageEmpty(ent->damage);
+
+				RegionDestroy(region);
+			}
 		} else {
-			DamageEmpty(ent->damage);
-		}
+			if (slave_has_sync_shared_pixmap(scrn, ent))
+				continue;
 
-		RegionDestroy(region);
+			region = dirty_region(ent);
+			redisplay_dirty(ent, region);
+			RegionDestroy(region);
+		}
 	}
 }
 #endif
@@ -861,7 +917,7 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
     radeon_cs_flush_indirect(pScrn);
 
 #ifdef RADEON_PIXMAP_SHARING
-    radeon_dirty_update(pScreen);
+    radeon_dirty_update(pScrn);
 #endif
 }
 
-- 
2.9.3



More information about the amd-gfx mailing list