[PATCH xf86-video-ati 3/4] Synchronize scanout pixmaps for TearFree

Michel Dänzer michel at daenzer.net
Fri Sep 2 10:03:30 UTC 2016


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

Copy the damaged areas which are still valid in the other scanout pixmap
from there, then only copy the remaining damaged area from the screen
pixmap.

This is slightly more efficient, and will be significantly more efficient
with the following change.

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/drmmode_display.c | 95 +++++++++++++++++++++++++--------------------------
 src/drmmode_display.h |  3 +-
 src/radeon_kms.c      | 92 ++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 124 insertions(+), 66 deletions(-)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 2afeeb0..2b80c21 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -523,10 +523,20 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
 		radeon_bo_unref(scanout->bo);
 		scanout->bo = NULL;
 	}
+}
 
-	if (scanout->damage) {
-		DamageDestroy(scanout->damage);
-		scanout->damage = NULL;
+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->scanout_damage) {
+		DamageDestroy(drmmode_crtc->scanout_damage);
+		drmmode_crtc->scanout_damage = NULL;
+		RegionUninit(&drmmode_crtc->scanout_last_region);
 	}
 }
 
@@ -536,15 +546,8 @@ drmmode_scanout_free(ScrnInfoPtr scrn)
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
 	int c;
 
-	for (c = 0; c < xf86_config->num_crtc; c++) {
-		drmmode_crtc_private_ptr drmmode_crtc =
-			xf86_config->crtc[c]->driver_private;
-
-		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
-					     &drmmode_crtc->scanout[0]);
-		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
-					     &drmmode_crtc->scanout[1]);
-	}
+	for (c = 0; c < xf86_config->num_crtc; c++)
+		drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private);
 }
 
 static void *
@@ -797,8 +800,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 			fb_id = drmmode_crtc->rotate.fb_id;
 			x = y = 0;
 
-			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
-			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
+			drmmode_crtc_scanout_free(drmmode_crtc);
 		} else if (
 #ifdef RADEON_PIXMAP_SHARING
 			!pScreen->isGPU &&
@@ -813,42 +815,40 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 							    &drmmode_crtc->scanout[i],
 							    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(radeon_screen_damage_report,
-								     NULL, DamageReportRawRegion,
-								     TRUE, pScreen, NULL);
-						DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
-							       drmmode_crtc->scanout[i].damage);
-					}
-
-					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);
-
-					switch (crtc->rotation & 0xf) {
-					case RR_Rotate_90:
-					case RR_Rotate_270:
-						pBox->x2 = max(pBox->x2, x + mode->VDisplay);
-						pBox->y2 = max(pBox->y2, y + mode->HDisplay);
-						break;
-					default:
-						pBox->x2 = max(pBox->x2, x + mode->HDisplay);
-						pBox->y2 = max(pBox->y2, y + mode->VDisplay);
-					}
-				}
 			}
 
 			if (drmmode_crtc->scanout[0].pixmap &&
 			    (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) {
+				RegionPtr pRegion;
+				BoxPtr pBox;
+
+				if (!drmmode_crtc->scanout_damage) {
+					drmmode_crtc->scanout_damage =
+						DamageCreate(radeon_screen_damage_report,
+							     NULL, DamageReportRawRegion,
+							     TRUE, pScreen, NULL);
+					DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
+						       drmmode_crtc->scanout_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);
+
+				switch (crtc->rotation & 0xf) {
+				case RR_Rotate_90:
+				case RR_Rotate_270:
+					pBox->x2 = max(pBox->x2, x + mode->VDisplay);
+					pBox->y2 = max(pBox->y2, y + mode->HDisplay);
+					break;
+				default:
+					pBox->x2 = max(pBox->x2, x + mode->HDisplay);
+					pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+				}
+
 				drmmode_crtc->scanout_id = 0;
 				fb_id = drmmode_crtc->scanout[0].fb_id;
 				x = y = 0;
@@ -1125,8 +1125,7 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
 		if (crtc->randr_crtc->scanout_pixmap)
 			PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap,
 						drmmode_crtc->scanout[0].pixmap);
-		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
-					     &drmmode_crtc->scanout[0]);
+		drmmode_crtc_scanout_free(drmmode_crtc);
 		return TRUE;
 	}
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 53c7926..5df9773 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -73,7 +73,6 @@ typedef struct {
 struct drmmode_scanout {
     struct radeon_bo *bo;
     PixmapPtr pixmap;
-    DamagePtr damage;
     unsigned fb_id;
     int width, height;
 };
@@ -85,6 +84,8 @@ typedef struct {
     struct radeon_bo *cursor_bo;
     struct drmmode_scanout rotate;
     struct drmmode_scanout scanout[2];
+    DamagePtr scanout_damage;
+    RegionRec scanout_last_region;
     unsigned scanout_id;
     Bool scanout_update_pending;
     int dpms_mode;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 568c49e..bcaa024 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -402,8 +402,6 @@ radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w,
     return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
 }
 
-#ifdef RADEON_PIXMAP_SHARING
-
 static RegionPtr
 transform_region(RegionPtr region, struct pict_f_transform *transform,
 		 int w, int h)
@@ -442,6 +440,70 @@ transform_region(RegionPtr region, struct pict_f_transform *transform,
 	return transformed;
 }
 
+static void
+radeon_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region,
+			    int scanout_id)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+    DrawablePtr dst = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
+    DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1].pixmap->drawable;
+    RegionPtr last_region = &drmmode_crtc->scanout_last_region;
+    ScrnInfoPtr scrn = xf86_crtc->scrn;
+    ScreenPtr pScreen = scrn->pScreen;
+    RADEONInfoPtr info = RADEONPTR(scrn);
+    RegionRec remaining;
+    RegionPtr sync_region = NULL;
+    BoxRec extents;
+    Bool force;
+    GCPtr gc;
+
+    if (RegionNil(last_region))
+	return;
+
+    RegionNull(&remaining);
+    RegionSubtract(&remaining, last_region, new_region);
+    if (RegionNil(&remaining))
+	goto uninit;
+
+    extents = *RegionExtents(&remaining);
+    if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, dst->width,
+					  dst->height))
+	goto uninit;
+
+#if XF86_CRTC_VERSION >= 4
+    if (xf86_crtc->driverIsPerformingTransform) {
+	sync_region = transform_region(&remaining,
+				       &xf86_crtc->f_framebuffer_to_crtc,
+				       dst->width, dst->height);
+    } else
+#endif /* XF86_CRTC_VERSION >= 4 */
+    {
+	sync_region = RegionDuplicate(&remaining);
+	RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y);
+    }
+
+    force = info->accel_state->force;
+    info->accel_state->force = TRUE;
+
+    gc = GetScratchGC(dst->depth, pScreen);
+    if (gc) {
+	ValidateGC(dst, gc);
+	gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0);
+	sync_region = NULL;
+	gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0);
+	FreeScratchGC(gc);
+    }
+
+    info->accel_state->force = force;
+
+ uninit:
+    if (sync_region)
+	RegionDestroy(sync_region);
+    RegionUninit(&remaining);
+}
+
+#ifdef RADEON_PIXMAP_SHARING
+
 static RegionPtr
 dirty_region(PixmapDirtyUpdatePtr dirty)
 {
@@ -660,13 +722,12 @@ static Bool
 radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 {
     drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
-    ScrnInfoPtr scrn;
-    DamagePtr pDamage;
-    RegionPtr pRegion;
+    RegionPtr pRegion = DamageRegion(drmmode_crtc->scanout_damage);
+    ScrnInfoPtr scrn = xf86_crtc->scrn;
+    ScreenPtr pScreen = scrn->pScreen;
+    RADEONInfoPtr info = RADEONPTR(scrn);
     DrawablePtr pDraw;
-    ScreenPtr pScreen;
     BoxRec extents;
-    RADEONInfoPtr info;
     Bool force;
 
     if (!xf86_crtc->enabled ||
@@ -674,24 +735,21 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 	!drmmode_crtc->scanout[scanout_id].pixmap)
 	return FALSE;
 
-    pDamage = drmmode_crtc->scanout[scanout_id].damage;
-    if (!pDamage)
-	return FALSE;
-
-    pRegion = DamageRegion(pDamage);
     if (!RegionNotEmpty(pRegion))
 	return FALSE;
 
     pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
-    pScreen = pDraw->pScreen;
     extents = *RegionExtents(pRegion);
-    RegionEmpty(pRegion);
     if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width,
 					  pDraw->height))
 	return FALSE;
 
-    scrn = xf86_crtc->scrn;
-    info = RADEONPTR(scrn);
+    if (info->tear_free) {
+	radeon_sync_scanout_pixmaps(xf86_crtc, pRegion, scanout_id);
+	RegionCopy(&drmmode_crtc->scanout_last_region, pRegion);
+    }
+    RegionEmpty(pRegion);
+
     force = info->accel_state->force;
     info->accel_state->force = TRUE;
 
@@ -807,7 +865,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
 	drmmode_crtc->pending_dpms_mode != DPMSModeOn)
 	return;
 
-    pDamage = drmmode_crtc->scanout[0].damage;
+    pDamage = drmmode_crtc->scanout_damage;
     if (!pDamage)
 	return;
 
-- 
2.9.3



More information about the amd-gfx mailing list