[PATCH xf86-video-amdgpu 10/12] Make Option "TearFree" effective for rotated/reflected outputs as well

Michel Dänzer michel at daenzer.net
Fri Mar 18 10:01:35 UTC 2016


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

Support varies by xserver version:

< 1.12:    No support for the driver handling rotation/reflection
1.12-1.15: Support for driver handling rotation/reflection, but there's
           a bug preventing the HW cursor from being visible everywhere
           it should be on rotated outputs, so we can only support
           TearFree for reflection.
>= 1.16:   While the bug above is still there (fixes pending review),
           the driver can force SW cursor for rotated outputs, so we
           can support TearFree for rotation as well.

(Ported from radeon commit 798c4fd16d339b1ad5fd729cc884be084c60e38b)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/amdgpu_kms.c      | 119 +++++++++++++++++++++++++++++++-----------
 src/drmmode_display.c | 141 +++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 219 insertions(+), 41 deletions(-)

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index e8258f8..9fd3254 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -251,12 +251,22 @@ static void amdgpu_dirty_update(ScreenPtr screen)
 #endif
 
 static Bool
-amdgpu_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
+amdgpu_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w,
+				 int h)
 {
-	extents->x1 = max(extents->x1 - x, 0);
-	extents->y1 = max(extents->y1 - y, 0);
-	extents->x2 = min(extents->x2 - x, w);
-	extents->y2 = min(extents->y2 - y, h);
+	extents->x1 = max(extents->x1 - xf86_crtc->x, 0);
+	extents->y1 = max(extents->y1 - xf86_crtc->y, 0);
+
+	switch (xf86_crtc->rotation & 0xf) {
+	case RR_Rotate_90:
+	case RR_Rotate_270:
+		extents->x2 = min(extents->x2 - xf86_crtc->x, h);
+		extents->y2 = min(extents->y2 - xf86_crtc->y, w);
+		break;
+	default:
+		extents->x2 = min(extents->x2 - xf86_crtc->x, w);
+		extents->y2 = min(extents->y2 - xf86_crtc->y, h);
+	}
 
 	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
 }
@@ -269,7 +279,6 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 	RegionPtr pRegion;
 	DrawablePtr pDraw;
 	ScreenPtr pScreen;
-	GCPtr gc;
 	BoxRec extents;
 
 	if (!xf86_crtc->enabled ||
@@ -286,25 +295,79 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 		return FALSE;
 
 	pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
+	pScreen = pDraw->pScreen;
 	extents = *RegionExtents(pRegion);
 	RegionEmpty(pRegion);
-	if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
-					      pDraw->width, pDraw->height))
+	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width,
+					      pDraw->height))
 		return FALSE;
 
-	pScreen = pDraw->pScreen;
-	gc = GetScratchGC(pDraw->depth, pScreen);
+	if (xf86_crtc->driverIsPerformingTransform) {
+		SourceValidateProcPtr SourceValidate = pScreen->SourceValidate;
+		PictFormatPtr format = PictureWindowFormat(pScreen->root);
+		int error;
+		PicturePtr src, dst;
+		XID include_inferiors = IncludeInferiors;
+
+		src = CreatePicture(None,
+				    &pScreen->root->drawable,
+				    format,
+				    CPSubwindowMode,
+				    &include_inferiors, serverClient, &error);
+		if (!src) {
+			ErrorF("Failed to create source picture for transformed scanout "
+			       "update\n");
+			goto out;
+		}
 
-	ValidateGC(pDraw, gc);
-	(*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
-			     pDraw, gc,
-			     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
-			     extents.x2 - extents.x1, extents.y2 - extents.y1,
-			     extents.x1, extents.y1);
-	FreeScratchGC(gc);
+		dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error);
+		if (!dst) {
+			ErrorF("Failed to create destination picture for transformed scanout "
+			       "update\n");
+			goto out;
+		}
+		error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer);
+		if (error) {
+			ErrorF("SetPictureTransform failed for transformed scanout "
+			       "update\n");
+			goto out;
+		}
+
+		if (xf86_crtc->filter)
+			SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params,
+					     xf86_crtc->nparams);
+
+		extents.x1 += xf86_crtc->x - (xf86_crtc->filter_width >> 1);
+		extents.x2 += xf86_crtc->x + (xf86_crtc->filter_width >> 1);
+		extents.y1 += xf86_crtc->y - (xf86_crtc->filter_height >> 1);
+		extents.y2 += xf86_crtc->y + (xf86_crtc->filter_height >> 1);
+		pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, &extents);
+
+		pScreen->SourceValidate = NULL;
+		CompositePicture(PictOpSrc,
+				 src, NULL, dst,
+				 extents.x1, extents.y1, 0, 0, extents.x1,
+				 extents.y1, extents.x2 - extents.x1,
+				 extents.y2 - extents.y1);
+		pScreen->SourceValidate = SourceValidate;
+
+		FreePicture(src, None);
+		FreePicture(dst, None);
+	} else {
+		GCPtr gc = GetScratchGC(pDraw->depth, pScreen);
+
+		ValidateGC(pDraw, gc);
+		(*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
+				     pDraw, gc,
+				     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
+				     extents.x2 - extents.x1, extents.y2 - extents.y1,
+				     extents.x1, extents.y1);
+		FreeScratchGC(gc);
+	}
 
 	amdgpu_glamor_flush(xf86_crtc->scrn);
 
+out:
 	return TRUE;
 }
 
@@ -354,8 +417,8 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 
 	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))
+	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width,
+					      pDraw->height))
 		return;
 
 	scrn = xf86_crtc->scrn;
@@ -444,21 +507,19 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
 	SCREEN_PTR(arg);
 	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	int c;
 
 	pScreen->BlockHandler = info->BlockHandler;
 	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
 	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
 
-	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++) {
-			if (info->tear_free)
-				amdgpu_scanout_flip(pScreen, info, xf86_config->crtc[c]);
-			else
-				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 if (info->shadow_primary ||
+				 xf86_config->crtc[c]->driverIsPerformingTransform)
+			amdgpu_scanout_update(xf86_config->crtc[c]);
 	}
 
 	if (info->use_glamor)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 67cfe8a..56b025a 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -566,6 +566,34 @@ amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
 	damage->damage.data = NULL;
 }
 
+#if XF86_CRTC_VERSION >= 4
+
+static Bool
+drmmode_handle_transform(xf86CrtcPtr crtc)
+{
+	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
+	Bool ret;
+
+	crtc->driverIsPerformingTransform = info->tear_free &&
+		!crtc->transformPresent && crtc->rotation != RR_Rotate_0;
+
+	ret = xf86CrtcRotate(crtc);
+
+	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
+
+	return ret;
+}
+
+#else
+
+static Bool
+drmmode_handle_transform(xf86CrtcPtr crtc)
+{
+	return xf86CrtcRotate(crtc);
+}
+
+#endif
+
 static Bool
 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		       Rotation rotation, int x, int y)
@@ -636,9 +664,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 			output_count++;
 		}
 
-		if (!xf86CrtcRotate(crtc)) {
+		if (!drmmode_handle_transform(crtc))
 			goto done;
-		}
+
 		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
 				       crtc->gamma_blue, crtc->gamma_size);
 
@@ -660,7 +688,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 
 			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) {
+		} else if (info->tear_free || info->shadow_primary ||
+			   crtc->driverIsPerformingTransform) {
 			for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
 				drmmode_crtc_scanout_create(crtc,
 							    &drmmode_crtc->scanout[i],
@@ -686,8 +715,17 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 					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);
+
+					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);
+					}
 				}
 			}
 
@@ -760,30 +798,102 @@ static void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
 
+#if XF86_CRTC_VERSION >= 4
+	if (crtc->driverIsPerformingTransform) {
+		x += crtc->x;
+		y += crtc->y;
+		xf86CrtcTransformCursorPos(crtc, &x, &y);
+	}
+#endif
+
 	drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
 }
 
+#if XF86_CRTC_VERSION >= 4
+
+static int
+drmmode_cursor_src_offset(Rotation rotation, int width, int height,
+			  int x_dst, int y_dst)
+{
+	int t;
+
+	switch (rotation & 0xf) {
+	case RR_Rotate_90:
+		t = x_dst;
+		x_dst = height - y_dst - 1;
+		y_dst = t;
+		break;
+	case RR_Rotate_180:
+		x_dst = width - x_dst - 1;
+		y_dst = height - y_dst - 1;
+		break;
+	case RR_Rotate_270:
+		t = x_dst;
+		x_dst = y_dst;
+		y_dst = width - t - 1;
+		break;
+	}
+
+	if (rotation & RR_Reflect_X)
+		x_dst = width - x_dst - 1;
+	if (rotation & RR_Reflect_Y)
+		y_dst = height - y_dst - 1;
+
+	return y_dst * height + x_dst;
+}
+
+#endif
+
+static void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr)
+{
+	ScrnInfoPtr pScrn = crtc->scrn;
+	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
+
+#if XF86_CRTC_VERSION >= 4
+	if (crtc->driverIsPerformingTransform) {
+		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
+		int dstx, dsty;
+		int srcoffset;
+
+		for (dsty = 0; dsty < cursor_h; dsty++) {
+			for (dstx = 0; dstx < cursor_w; dstx++) {
+				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
+								      cursor_w,
+								      cursor_h,
+								      dstx, dsty);
+
+				ptr[dsty * info->cursor_w + dstx] =
+					cpu_to_le32(image[srcoffset]);
+			}
+		}
+	} else
+#endif
+	{
+		uint32_t cursor_size = info->cursor_w * info->cursor_h;
+		int i;
+
+		for (i = 0; i < cursor_size; i++)
+			ptr[i] = cpu_to_le32(image[i]);
+	}
+}
+
 static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
 {
 	ScrnInfoPtr pScrn = crtc->scrn;
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-	int i;
 	uint32_t cursor_size = info->cursor_w * info->cursor_h;
 
 	if (info->gbm) {
 		uint32_t ptr[cursor_size];
 
-		for (i = 0; i < cursor_size; i++)
-			ptr[i] = cpu_to_le32(image[i]);
-
+		drmmode_do_load_cursor_argb(crtc, image, ptr);
 		gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4);
 	} else {
 		/* cursor should be mapped already */
 		uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr);
 
-		for (i = 0; i < cursor_size; i++)
-			ptr[i] = cpu_to_le32(image[i]);
+		drmmode_do_load_cursor_argb(crtc, image, ptr);
 	}
 }
 
@@ -795,6 +905,13 @@ static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
 	if (crtc->transformPresent)
 		return FALSE;
 
+	/* Xorg doesn't correctly handle cursor position transform in the
+	 * rotation case
+	 */
+	if (crtc->driverIsPerformingTransform &&
+	    (crtc->rotation & 0xf) != RR_Rotate_0)
+		return FALSE;
+
 	drmmode_load_cursor_argb(crtc, image);
 	return TRUE;
 }
@@ -2098,7 +2215,7 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
 			crtc->rotation = crtc->desiredRotation;
 			crtc->x = crtc->desiredX;
 			crtc->y = crtc->desiredY;
-			if (!xf86CrtcRotate(crtc))
+			if (!drmmode_handle_transform(crtc))
 				return FALSE;
 		}
 	}
-- 
2.7.0



More information about the xorg-driver-ati mailing list