xf86-video-amdgpu: Branch 'master' - 12 commits

Michel Dänzer daenzer at kemper.freedesktop.org
Wed Mar 23 09:59:55 UTC 2016


 src/amdgpu_dri2.c      |   45 +++----
 src/amdgpu_drm_queue.c |   28 +++-
 src/amdgpu_drm_queue.h |    8 -
 src/amdgpu_drv.h       |    2 
 src/amdgpu_kms.c       |  151 +++++++++++++++++---------
 src/amdgpu_present.c   |   28 ++--
 src/drmmode_display.c  |  284 +++++++++++++++++++++++++++++++++++--------------
 src/drmmode_display.h  |    8 -
 8 files changed, 377 insertions(+), 177 deletions(-)

New commits:
commit 37bd79652a8ec612b94a1863e8c580b1cfaf3960
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 18:51:00 2016 +0900

    present: Return rotated CRTCs from amdgpu_present_get_crtc
    
    Sync-to-vblank works fine with rotation. We're still checking for
    rotation in amdgpu_present_check_flip.
    
    Returning NULL from here resulted in the xserver present code falling
    back to the fake CRTC running at 1 fps.
    
    (Ported from radeon commit a03271de5ecdaa7790d1316e993c4450b91fe936)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index c11a807..67b59b7 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -77,8 +77,7 @@ amdgpu_present_get_crtc(WindowPtr window)
 				     window->drawable.y,
 				     window->drawable.y + window->drawable.height);
 
-	/* Make sure the CRTC is valid and this is the real front buffer */
-	if (crtc != NULL && !crtc->rotatedData)
+	if (crtc)
 		randr_crtc = crtc->randr_crtc;
 
 	return randr_crtc;
commit 6b930fb3285dea4a6440e31099c96f08da508d49
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 18:47:10 2016 +0900

    present: Clear drmmode->fb_id before calling set_mode_major for unflip
    
    Without this, drmmode_set_mode_major may just re-set the FB for the
    last flipped BO, in which case the display will probably freeze.
    
    Reproduction recipe: Enable rotation while a fullscreen client is
    flipping.
    
    (Ported from radeon commit 40191d82370eb7e58bd34c44966cbf44c3703229)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index 5de1d19..c11a807 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -324,6 +324,7 @@ static void
 amdgpu_present_unflip(ScreenPtr screen, uint64_t event_id)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	struct amdgpu_present_vblank_event *event;
@@ -348,6 +349,12 @@ amdgpu_present_unflip(ScreenPtr screen, uint64_t event_id)
 		return;
 
 modeset:
+	/* info->drmmode.fb_id still points to the FB for the last flipped BO.
+	 * Clear it, drmmode_set_mode_major will re-create it
+	 */
+	drmModeRmFB(pAMDGPUEnt->fd, info->drmmode.fb_id);
+	info->drmmode.fb_id = 0;
+
 	for (i = 0; i < config->num_crtc; i++) {
 		xf86CrtcPtr crtc = config->crtc[i];
 		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
commit 6889e091442b6ba1b9351e72bd067425e87d96e9
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 18:18:04 2016 +0900

    Make Option "TearFree" effective for rotated/reflected outputs as well
    
    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)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

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;
 		}
 	}
commit da4e0c66fcbcf63143372720e3d606a462332e3a
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 18:15:34 2016 +0900

    Consolidate pScreen usage in drmmode_set_mode_major
    
    We were already relying on pScrn->pScreen being non-NULL in some cases,
    which is supposedly always true ever since this function is no longer
    getting called from ScreenInit.
    
    (Ported from radeon commit eb611a2e4ecce7a1ab85fd72b9b78e3269311dd5)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 9a2c70b..67cfe8a 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -571,6 +571,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		       Rotation rotation, int x, int y)
 {
 	ScrnInfoPtr pScrn = crtc->scrn;
+	ScreenPtr pScreen = pScrn->pScreen;
 	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
 	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
@@ -622,8 +623,6 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 			goto done;
 		}
 
-		ScreenPtr pScreen = pScrn->pScreen;
-
 		for (i = 0; i < xf86_config->num_output; i++) {
 			xf86OutputPtr output = xf86_config->output[i];
 			drmmode_output_private_ptr drmmode_output;
@@ -719,8 +718,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		} else
 			ret = TRUE;
 
-		if (crtc->scrn->pScreen)
-			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
+		if (pScreen)
+			xf86CrtcSetScreenSubpixelOrder(pScreen);
 
 		drmmode_crtc->need_modeset = FALSE;
 
@@ -735,9 +734,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		}
 	}
 
-	if (pScrn->pScreen &&
-	    !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
-		xf86_reload_cursors(pScrn->pScreen);
+	if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
+		xf86_reload_cursors(pScreen);
 
 done:
 	free(output_ids);
commit 0bbf09dd7ef54133b3e534becb3ba15c0cf3eed2
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 18:14:28 2016 +0900

    Remove check for XF86_CRTC_VERSION 3
    
    We require xserver >= 1.8, which was already at version 3.
    
    (Ported from radeon commit 06602171386e538081c298645fb7ca1a70fe80cc)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 2c75f82..9a2c70b 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -746,11 +746,8 @@ done:
 		crtc->y = saved_y;
 		crtc->rotation = saved_rotation;
 		crtc->mode = saved_mode;
-	}
-#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
-	else
+	} else
 		crtc->active = TRUE;
-#endif
 
 	return ret;
 }
commit 3485ca0051a224d00135d4024a97a6c4e85a9644
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 18:07:07 2016 +0900

    Deal with modesets and page flips crossing on a CRTC
    
    If we set a mode while a flip is pending, the kernel driver may program
    the flip to the hardware after the modeset. If that happens, the hardware
    will display the BO from the flip, whereas we will assume it displays the
    BO from the modeset. In other words, the display will most likely freeze,
    at least until another modeset.
    
    Prevent this condition by waiting for a pending flip to finish before
    setting a mode.
    
    Fixes display freezing when setting rotation or a transform with
    TearFree enabled.
    
    (Ported from radeon commit a88985f5d1e39caca49ceb65678aaa9cb622a0d2)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index be8c2bf..e8258f8 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -393,6 +393,7 @@ amdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
 	drmmode_crtc_private_ptr drmmode_crtc = event_data;
 
 	drmmode_crtc->scanout_update_pending = FALSE;
+	drmmode_crtc->flip_pending = FALSE;
 }
 
 static void
@@ -435,6 +436,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 
 	drmmode_crtc->scanout_id = scanout_id;
 	drmmode_crtc->scanout_update_pending = TRUE;
+	drmmode_crtc->flip_pending = TRUE;
 }
 
 static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 2ce9f3d..2c75f82 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -702,6 +702,12 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 				amdgpu_glamor_finish(pScrn);
 			}
 		}
+
+		/* Wait for any pending flip to finish */
+		do {} while (drmmode_crtc->flip_pending &&
+			     drmHandleEvent(pAMDGPUEnt->fd,
+					    &drmmode->event_context) > 0);
+
 		if (drmModeSetCrtc(pAMDGPUEnt->fd,
 				   drmmode_crtc->mode_crtc->crtc_id,
 				   fb_id, x, y, output_ids,
@@ -1857,6 +1863,7 @@ static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
 static void
 drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
 {
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	drmmode_flipdata_ptr flipdata = event_data;
 
 	if (--flipdata->flip_count == 0) {
@@ -1865,11 +1872,14 @@ drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
 		flipdata->abort(crtc, flipdata->event_data);
 		free(flipdata);
 	}
+
+	drmmode_crtc->flip_pending = FALSE;
 }
 
 static void
 drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
 {
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
 	drmmode_flipdata_ptr flipdata = event_data;
 
@@ -1892,6 +1902,8 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
 
 		free(flipdata);
 	}
+
+	drmmode_crtc->flip_pending = FALSE;
 }
 
 static void drm_wakeup_handler(pointer data, int err, pointer p)
@@ -2405,6 +2417,7 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 				   "flip queue failed: %s\n", strerror(errno));
 			goto error;
 		}
+		drmmode_crtc->flip_pending = TRUE;
 		drm_queue = NULL;
 	}
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index e5e5de6..24d517d 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -97,6 +97,8 @@ typedef struct {
 
 	/* Modeset needed for DPMS on */
 	Bool need_modeset;
+	/* A flip is pending for this CRTC */
+	Bool flip_pending;
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {
commit b9d00fa7aaf946d985897380bfa42faafbf1b3fb
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 17:18:00 2016 +0900

    Make DRM event queue xf86CrtcPtr based instead of ScrnInfoPtr based
    
    This allows for a minor simplification of the code.
    
    (Ported from radeon commit f5d968cbba3c9b7ec202161f2157d8d64778c817)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c
index 6867959..5778268 100644
--- a/src/amdgpu_dri2.c
+++ b/src/amdgpu_dri2.c
@@ -524,19 +524,20 @@ xf86CrtcPtr amdgpu_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled)
 }
 
 static void
-amdgpu_dri2_flip_event_abort(ScrnInfoPtr scrn, void *event_data)
+amdgpu_dri2_flip_event_abort(xf86CrtcPtr crtc, void *event_data)
 {
-	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
 
 	info->drmmode.dri2_flipping = FALSE;
 	free(event_data);
 }
 
 static void
-amdgpu_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+amdgpu_dri2_flip_event_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
 			       void *event_data)
 {
 	DRI2FrameEventPtr flip = event_data;
+	ScrnInfoPtr scrn = crtc->scrn;
 	unsigned tv_sec, tv_usec;
 	DrawablePtr drawable;
 	ScreenPtr screen;
@@ -548,9 +549,7 @@ amdgpu_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 	if (status != Success)
 		goto abort;
 
-	if (!flip->crtc)
-		goto abort;
-	frame += amdgpu_get_msc_delta(drawable, flip->crtc);
+	frame += amdgpu_get_msc_delta(drawable, crtc);
 
 	screen = scrn->pScreen;
 	pixmap = screen->GetScreenPixmap(screen);
@@ -589,21 +588,20 @@ amdgpu_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 	}
 
 abort:
-	amdgpu_dri2_flip_event_abort(scrn, event_data);
+	amdgpu_dri2_flip_event_abort(crtc, event_data);
 }
 
 static Bool
-amdgpu_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
+amdgpu_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client,
 			  DrawablePtr draw, DRI2BufferPtr front,
 			  DRI2BufferPtr back, DRI2SwapEventPtr func,
 			  void *data, unsigned int target_msc)
 {
+	ScrnInfoPtr scrn = crtc->scrn;
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	struct dri2_buffer_priv *back_priv;
 	DRI2FrameEventPtr flip_info;
-	/* Main crtc for this drawable shall finally deliver pageflip event. */
-	xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, FALSE);
-	int ref_crtc_hw_id = crtc ? drmmode_get_crtc_id(crtc) : -1;
+	int ref_crtc_hw_id = drmmode_get_crtc_id(crtc);
 
 	flip_info = calloc(1, sizeof(DRI2FrameEventRec));
 	if (!flip_info)
@@ -752,7 +750,7 @@ amdgpu_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front,
 	DamageRegionProcessPending(&front_priv->pixmap->drawable);
 }
 
-static void amdgpu_dri2_frame_event_abort(ScrnInfoPtr scrn, void *event_data)
+static void amdgpu_dri2_frame_event_abort(xf86CrtcPtr crtc, void *event_data)
 {
 	DRI2FrameEventPtr event = event_data;
 
@@ -763,30 +761,28 @@ static void amdgpu_dri2_frame_event_abort(ScrnInfoPtr scrn, void *event_data)
 	free(event);
 }
 
-static void amdgpu_dri2_frame_event_handler(ScrnInfoPtr scrn, uint32_t seq,
+static void amdgpu_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq,
 					    uint64_t usec, void *event_data)
 {
 	DRI2FrameEventPtr event = event_data;
+	ScrnInfoPtr scrn = crtc->scrn;
 	DrawablePtr drawable;
 	int status;
 	int swap_type;
 	BoxRec box;
 	RegionRec region;
 
-	if (!event->crtc)
-		goto cleanup;
-
 	status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
 				   M_ANY, DixWriteAccess);
 	if (status != Success)
 		goto cleanup;
 
-	seq += amdgpu_get_msc_delta(drawable, event->crtc);
+	seq += amdgpu_get_msc_delta(drawable, crtc);
 
 	switch (event->type) {
 	case DRI2_FLIP:
 		if (can_flip(scrn, drawable, event->front, event->back) &&
-		    amdgpu_dri2_schedule_flip(scrn,
+		    amdgpu_dri2_schedule_flip(crtc,
 					      event->client,
 					      drawable,
 					      event->front,
@@ -833,7 +829,7 @@ static void amdgpu_dri2_frame_event_handler(ScrnInfoPtr scrn, uint32_t seq,
 	}
 
 cleanup:
-	amdgpu_dri2_frame_event_abort(scrn, event_data);
+	amdgpu_dri2_frame_event_abort(crtc, event_data);
 }
 
 drmVBlankSeqType amdgpu_populate_vbl_request_type(xf86CrtcPtr crtc)
@@ -990,7 +986,7 @@ CARD32 amdgpu_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data)
 			amdgpu_drm_queue_handler(pAMDGPUEnt->fd, 0, 0, 0,
 						 event_info->drm_queue);
 		else
-			amdgpu_dri2_frame_event_handler(scrn, 0, 0, data);
+			amdgpu_dri2_frame_event_handler(crtc, 0, 0, data);
 		return 0;
 	}
 	/*
@@ -1006,7 +1002,7 @@ CARD32 amdgpu_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data)
 		amdgpu_drm_queue_handler(pAMDGPUEnt->fd, frame, drm_now / 1000000,
 					 drm_now % 1000000, event_info->drm_queue);
 	else
-		amdgpu_dri2_frame_event_handler(scrn, frame, drm_now, data);
+		amdgpu_dri2_frame_event_handler(crtc, frame, drm_now, data);
 	return 0;
 }
 
@@ -1091,7 +1087,7 @@ static int amdgpu_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 	current_msc = vbl.reply.sequence + msc_delta;
 	current_msc &= 0xffffffff;
 
-	wait = amdgpu_drm_queue_alloc(scrn, client, AMDGPU_DRM_QUEUE_ID_DEFAULT,
+	wait = amdgpu_drm_queue_alloc(crtc, client, AMDGPU_DRM_QUEUE_ID_DEFAULT,
 				      wait_info, amdgpu_dri2_frame_event_handler,
 				      amdgpu_dri2_frame_event_abort);
 	if (!wait) {
@@ -1239,7 +1235,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 	swap_info->back = back;
 	swap_info->crtc = crtc;
 
-	swap = amdgpu_drm_queue_alloc(scrn, client, AMDGPU_DRM_QUEUE_ID_DEFAULT,
+	swap = amdgpu_drm_queue_alloc(crtc, client, AMDGPU_DRM_QUEUE_ID_DEFAULT,
 				      swap_info, amdgpu_dri2_frame_event_handler,
 				      amdgpu_dri2_frame_event_abort);
 	if (!swap) {
diff --git a/src/amdgpu_drm_queue.c b/src/amdgpu_drm_queue.c
index b5aead2..11b74a0 100644
--- a/src/amdgpu_drm_queue.c
+++ b/src/amdgpu_drm_queue.c
@@ -42,7 +42,7 @@ struct amdgpu_drm_queue_entry {
 	uint64_t id;
 	void *data;
 	ClientPtr client;
-	ScrnInfoPtr scrn;
+	xf86CrtcPtr crtc;
 	amdgpu_drm_handler_proc handler;
 	amdgpu_drm_abort_proc abort;
 };
@@ -65,11 +65,11 @@ amdgpu_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
 		if (e == user_data) {
 			xorg_list_del(&e->list);
 			if (e->handler)
-				e->handler(e->scrn, frame,
+				e->handler(e->crtc, frame,
 					   (uint64_t)sec * 1000000 + usec,
 					   e->data);
 			else
-				e->abort(e->scrn, e->data);
+				e->abort(e->crtc, e->data);
 			free(e);
 			break;
 		}
@@ -81,7 +81,7 @@ amdgpu_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
  * appears, we've got data to pass to the handler from here
  */
 struct amdgpu_drm_queue_entry *
-amdgpu_drm_queue_alloc(ScrnInfoPtr scrn, ClientPtr client,
+amdgpu_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
 		       uint64_t id, void *data,
 		       amdgpu_drm_handler_proc handler,
 		       amdgpu_drm_abort_proc abort)
@@ -93,7 +93,7 @@ amdgpu_drm_queue_alloc(ScrnInfoPtr scrn, ClientPtr client,
 		return NULL;
 
 	e->client = client;
-	e->scrn = scrn;
+	e->crtc = crtc;
 	e->id = id;
 	e->data = data;
 	e->handler = handler;
@@ -113,7 +113,7 @@ static void
 amdgpu_drm_abort_one(struct amdgpu_drm_queue_entry *e)
 {
 	xorg_list_del(&e->list);
-	e->abort(e->scrn, e->data);
+	e->abort(e->crtc, e->data);
 	free(e);
 }
 
@@ -181,7 +181,7 @@ amdgpu_drm_queue_close(ScrnInfoPtr scrn)
 	struct amdgpu_drm_queue_entry *e, *tmp;
 
 	xorg_list_for_each_entry_safe(e, tmp, &amdgpu_drm_queue, list) {
-		if (e->scrn == scrn)
+		if (e->crtc->scrn == scrn)
 			amdgpu_drm_abort_one(e);
 	}
 
diff --git a/src/amdgpu_drm_queue.h b/src/amdgpu_drm_queue.h
index 96841f6..892ba13 100644
--- a/src/amdgpu_drm_queue.h
+++ b/src/amdgpu_drm_queue.h
@@ -29,19 +29,21 @@
 #ifndef _AMDGPU_DRM_QUEUE_H_
 #define _AMDGPU_DRM_QUEUE_H_
 
+#include <xf86Crtc.h>
+
 #define AMDGPU_DRM_QUEUE_CLIENT_DEFAULT serverClient
 #define AMDGPU_DRM_QUEUE_ID_DEFAULT ~0ULL
 
 struct amdgpu_drm_queue_entry;
 
-typedef void (*amdgpu_drm_handler_proc)(ScrnInfoPtr scrn, uint32_t seq,
+typedef void (*amdgpu_drm_handler_proc)(xf86CrtcPtr crtc, uint32_t seq,
 					uint64_t usec, void *data);
-typedef void (*amdgpu_drm_abort_proc)(ScrnInfoPtr scrn, void *data);
+typedef void (*amdgpu_drm_abort_proc)(xf86CrtcPtr crtc, void *data);
 
 void amdgpu_drm_queue_handler(int fd, unsigned int frame,
 			      unsigned int tv_sec, unsigned int tv_usec,
 			      void *user_ptr);
-struct amdgpu_drm_queue_entry *amdgpu_drm_queue_alloc(ScrnInfoPtr scrn,
+struct amdgpu_drm_queue_entry *amdgpu_drm_queue_alloc(xf86CrtcPtr crtc,
 						      ClientPtr client,
 						      uint64_t id,
 						      void *data,
diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h
index 0e7b3b5..3b074fc 100644
--- a/src/amdgpu_drv.h
+++ b/src/amdgpu_drv.h
@@ -282,7 +282,7 @@ typedef struct {
 Bool amdgpu_dri3_screen_init(ScreenPtr screen);
 
 /* amdgpu_kms.c */
-void amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame,
+void amdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame,
 				   uint64_t usec, void *event_data);
 
 /* amdgpu_present.c */
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index e6e3d5f..be8c2bf 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -309,21 +309,20 @@ amdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
 }
 
 static void
-amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
+amdgpu_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
 {
-	xf86CrtcPtr xf86_crtc = event_data;
-	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+	drmmode_crtc_private_ptr drmmode_crtc = event_data;
 
 	drmmode_crtc->scanout_update_pending = FALSE;
 }
 
 void
-amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+amdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
 							  void *event_data)
 {
-	amdgpu_scanout_do_update(event_data, 0);
+	amdgpu_scanout_do_update(crtc, 0);
 
-	amdgpu_scanout_update_abort(scrn, event_data);
+	amdgpu_scanout_update_abort(crtc, event_data);
 }
 
 static void
@@ -360,9 +359,10 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 		return;
 
 	scrn = xf86_crtc->scrn;
-	drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+	drm_queue_entry = amdgpu_drm_queue_alloc(xf86_crtc,
+						 AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
 						 AMDGPU_DRM_QUEUE_ID_DEFAULT,
-						 xf86_crtc,
+						 drmmode_crtc,
 						 amdgpu_scanout_update_handler,
 						 amdgpu_scanout_update_abort);
 	if (!drm_queue_entry) {
@@ -388,7 +388,7 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 }
 
 static void
-amdgpu_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data)
+amdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
 {
 	drmmode_crtc_private_ptr drmmode_crtc = event_data;
 
@@ -413,7 +413,8 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 		return;
 
 	scrn = xf86_crtc->scrn;
-	drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+	drm_queue_entry = amdgpu_drm_queue_alloc(xf86_crtc,
+						 AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
 						 AMDGPU_DRM_QUEUE_ID_DEFAULT,
 						 drmmode_crtc, NULL,
 						 amdgpu_scanout_flip_abort);
diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index 73ebb4c..5de1d19 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -50,7 +50,7 @@
 
 struct amdgpu_present_vblank_event {
 	uint64_t event_id;
-	xf86CrtcPtr crtc;
+	Bool unflip;
 };
 
 static uint32_t crtc_select(int crtc_id)
@@ -125,7 +125,7 @@ amdgpu_present_flush_drm_events(ScreenPtr screen)
  * Called when the queued vblank event has occurred
  */
 static void
-amdgpu_present_vblank_handler(ScrnInfoPtr scrn, unsigned int msc,
+amdgpu_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc,
 			      uint64_t usec, void *data)
 {
 	struct amdgpu_present_vblank_event *event = data;
@@ -138,7 +138,7 @@ amdgpu_present_vblank_handler(ScrnInfoPtr scrn, unsigned int msc,
  * Called when the queued vblank is aborted
  */
 static void
-amdgpu_present_vblank_abort(ScrnInfoPtr scrn, void *data)
+amdgpu_present_vblank_abort(xf86CrtcPtr crtc, void *data)
 {
 	struct amdgpu_present_vblank_event *event = data;
 
@@ -166,7 +166,7 @@ amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	if (!event)
 		return BadAlloc;
 	event->event_id = event_id;
-	queue = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+	queue = amdgpu_drm_queue_alloc(xf86_crtc, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
 				       event_id, event,
 				       amdgpu_present_vblank_handler,
 				       amdgpu_present_vblank_abort);
@@ -257,12 +257,12 @@ amdgpu_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
  * extension code telling it when that happened
  */
 static void
-amdgpu_present_flip_event(ScrnInfoPtr scrn, uint32_t msc, uint64_t ust, void *pageflip_data)
+amdgpu_present_flip_event(xf86CrtcPtr crtc, uint32_t msc, uint64_t ust, void *pageflip_data)
 {
-	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
 	struct amdgpu_present_vblank_event *event = pageflip_data;
 
-	if (!event->crtc)
+	if (event->unflip)
 		info->drmmode.present_flipping = FALSE;
 
 	present_event_notify(event->event_id, ust, msc);
@@ -273,7 +273,7 @@ amdgpu_present_flip_event(ScrnInfoPtr scrn, uint32_t msc, uint64_t ust, void *pa
  * The flip has been aborted, free the structure
  */
 static void
-amdgpu_present_flip_abort(ScrnInfoPtr scrn, void *pageflip_data)
+amdgpu_present_flip_abort(xf86CrtcPtr crtc, void *pageflip_data)
 {
 	struct amdgpu_present_vblank_event *event = pageflip_data;
 
@@ -304,7 +304,6 @@ amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
 		return FALSE;
 
 	event->event_id = event_id;
-	event->crtc = xf86_crtc;
 
 	ret = amdgpu_do_pageflip(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
 				 pixmap, event_id, event, crtc_id,
@@ -341,6 +340,7 @@ amdgpu_present_unflip(ScreenPtr screen, uint64_t event_id)
 	}
 
 	event->event_id = event_id;
+	event->unflip = TRUE;
 
 	if (amdgpu_do_pageflip(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, pixmap,
 			       event_id, event, -1, amdgpu_present_flip_event,
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 7316226..2ce9f3d 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -698,7 +698,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 				fb_id = drmmode_crtc->scanout[0].fb_id;
 				x = y = 0;
 
-				amdgpu_scanout_update_handler(pScrn, 0, 0, crtc);
+				amdgpu_scanout_update_handler(crtc, 0, 0, drmmode_crtc);
 				amdgpu_glamor_finish(pScrn);
 			}
 		}
@@ -1855,55 +1855,43 @@ static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
 };
 
 static void
-drmmode_flip_free(drmmode_flipevtcarrier_ptr flipcarrier)
+drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
 {
-	drmmode_flipdata_ptr flipdata = flipcarrier->flipdata;
+	drmmode_flipdata_ptr flipdata = event_data;
 
-	free(flipcarrier);
-
-	if (--flipdata->flip_count > 0)
-		return;
-
-	free(flipdata);
-}
-
-static void
-drmmode_flip_abort(ScrnInfoPtr scrn, void *event_data)
-{
-	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
-	drmmode_flipdata_ptr flipdata = flipcarrier->flipdata;
-
-	if (flipdata->flip_count == 1)
-		flipdata->abort(scrn, flipdata->event_data);
-
-	drmmode_flip_free(flipcarrier);
+	if (--flipdata->flip_count == 0) {
+		if (flipdata->fe_crtc)
+			crtc = flipdata->fe_crtc;
+		flipdata->abort(crtc, flipdata->event_data);
+		free(flipdata);
+	}
 }
 
 static void
-drmmode_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data)
+drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
 {
-	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
-	drmmode_flipdata_ptr flipdata = flipcarrier->flipdata;
+	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
+	drmmode_flipdata_ptr flipdata = event_data;
 
 	/* Is this the event whose info shall be delivered to higher level? */
-	if (flipcarrier->dispatch_me) {
+	if (crtc == flipdata->fe_crtc) {
 		/* Yes: Cache msc, ust for later delivery. */
 		flipdata->fe_frame = frame;
 		flipdata->fe_usec = usec;
 	}
 
-	if (flipdata->flip_count == 1) {
+	if (--flipdata->flip_count == 0) {
 		/* Deliver cached msc, ust from reference crtc to flip event handler */
-		if (flipdata->event_data)
-			flipdata->handler(scrn, flipdata->fe_frame,
-					  flipdata->fe_usec,
-					  flipdata->event_data);
+		if (flipdata->fe_crtc)
+			crtc = flipdata->fe_crtc;
+		flipdata->handler(crtc, flipdata->fe_frame, flipdata->fe_usec,
+				  flipdata->event_data);
 
 		/* Release framebuffer */
-		drmModeRmFB(flipdata->fd, flipdata->old_fb_id);
-	}
+		drmModeRmFB(pAMDGPUEnt->fd, flipdata->old_fb_id);
 
-	drmmode_flip_free(flipcarrier);
+		free(flipdata);
+	}
 }
 
 static void drm_wakeup_handler(pointer data, int err, pointer p)
@@ -2340,11 +2328,11 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 {
 	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
 	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+	xf86CrtcPtr crtc = NULL;
 	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
 	drmmode_ptr drmmode = drmmode_crtc->drmmode;
 	int i;
-	drmmode_flipdata_ptr flipdata = NULL;
-	drmmode_flipevtcarrier_ptr flipcarrier = NULL;
+	drmmode_flipdata_ptr flipdata;
 	struct amdgpu_drm_queue_entry *drm_queue = NULL;
 	uint32_t new_front_handle;
 
@@ -2382,33 +2370,26 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	 */
 
 	flipdata->event_data = data;
-	flipdata->fd = pAMDGPUEnt->fd;
 	flipdata->handler = handler;
 	flipdata->abort = abort;
 
 	for (i = 0; i < config->num_crtc; i++) {
-		if (!config->crtc[i]->enabled)
+		crtc = config->crtc[i];
+
+		if (!crtc->enabled)
 			continue;
 
 		flipdata->flip_count++;
-		drmmode_crtc = config->crtc[i]->driver_private;
-
-		flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
-		if (!flipcarrier) {
-			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-				   "flip queue: carrier alloc failed.\n");
-			goto error;
-		}
+		drmmode_crtc = crtc->driver_private;
 
 		/* Only the reference crtc will finally deliver its page flip
 		 * completion event. All other crtc's events will be discarded.
 		 */
-		flipcarrier->dispatch_me =
-		    (drmmode_crtc->hw_id == ref_crtc_hw_id);
-		flipcarrier->flipdata = flipdata;
+		if (drmmode_crtc->hw_id == ref_crtc_hw_id)
+			flipdata->fe_crtc = crtc;
 
-		drm_queue = amdgpu_drm_queue_alloc(scrn, client, id,
-						   flipcarrier,
+		drm_queue = amdgpu_drm_queue_alloc(crtc, client, id,
+						   flipdata,
 						   drmmode_flip_handler,
 						   drmmode_flip_abort);
 		if (!drm_queue) {
@@ -2424,7 +2405,6 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 				   "flip queue failed: %s\n", strerror(errno));
 			goto error;
 		}
-		flipcarrier = NULL;
 		drm_queue = NULL;
 	}
 
@@ -2439,8 +2419,8 @@ error:
 
 	if (drm_queue)
 		amdgpu_drm_abort_entry(drm_queue);
-	else if (flipcarrier)
-		drmmode_flip_abort(scrn, flipcarrier);
+	else if (crtc)
+		drmmode_flip_abort(crtc, flipdata);
 	else if (flipdata && flipdata->flip_count <= 1)
 		free(flipdata);
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 92b7457..e5e5de6 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -65,15 +65,11 @@ typedef struct {
 	void *event_data;
 	unsigned int fe_frame;
 	uint64_t fe_usec;
+	xf86CrtcPtr fe_crtc;
 	amdgpu_drm_handler_proc handler;
 	amdgpu_drm_abort_proc abort;
 } drmmode_flipdata_rec, *drmmode_flipdata_ptr;
 
-typedef struct {
-	drmmode_flipdata_ptr flipdata;
-	Bool dispatch_me;
-} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
-
 struct drmmode_scanout {
 	struct amdgpu_buffer *bo;
 	PixmapPtr pixmap;
commit e0ed26151bfeadf309da53d001751c0a014dbd24
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 17:11:47 2016 +0900

    Remove amdgpu_scanout_flip_handler
    
    No longer necessary now that amdgpu_drm_queue_handler can handle
    e->handler == NULL.
    
    (Ported from radeon commit d5dbb07db22d5420c81dfebc060f0dd86e7b8a20)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 7bbef32..e6e3d5f 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -396,12 +396,6 @@ amdgpu_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data)
 }
 
 static void
-amdgpu_scanout_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data)
-{
-	amdgpu_scanout_flip_abort(scrn, event_data);
-}
-
-static void
 amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 					xf86CrtcPtr xf86_crtc)
 {
@@ -421,8 +415,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 	scrn = xf86_crtc->scrn;
 	drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
 						 AMDGPU_DRM_QUEUE_ID_DEFAULT,
-						 drmmode_crtc,
-						 amdgpu_scanout_flip_handler,
+						 drmmode_crtc, NULL,
 						 amdgpu_scanout_flip_abort);
 	if (!drm_queue_entry) {
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
commit acd5da56f502d6ad115501e77bce06fe72b1895c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 17:14:49 2016 +0900

    DRI2: Also clear dri2_flipping when client disconnects before event
    
    Fixes the following problem:
    
    With DRI3 enabled, run glxgears with LIBGL_DRI3_DISABLE=1, make it
    fullscreen and press Escape while it's still fullscreen. This could
    result in dri2_flipping not getting cleared, spuriously preventing apps
    using DRI3 from flipping.
    
    (Ported from radeon commit e87365117acbd80b7d80fbb5eb30890ef7153291)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c
index bcb5dae..6867959 100644
--- a/src/amdgpu_dri2.c
+++ b/src/amdgpu_dri2.c
@@ -526,6 +526,9 @@ xf86CrtcPtr amdgpu_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled)
 static void
 amdgpu_dri2_flip_event_abort(ScrnInfoPtr scrn, void *event_data)
 {
+	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+
+	info->drmmode.dri2_flipping = FALSE;
 	free(event_data);
 }
 
@@ -533,7 +536,6 @@ static void
 amdgpu_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 			       void *event_data)
 {
-	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	DRI2FrameEventPtr flip = event_data;
 	unsigned tv_sec, tv_usec;
 	DrawablePtr drawable;
@@ -578,7 +580,6 @@ amdgpu_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
 		DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
 				 DRI2_FLIP_COMPLETE, flip->event_complete,
 				 flip->event_data);
-		info->drmmode.dri2_flipping = FALSE;
 		break;
 	default:
 		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
commit a58bfa98208cc092014d3f36a08714eb1e0d8814
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 17:07:47 2016 +0900

    drm_queue: Don't abort events immediately from amdgpu_drm_abort_client
    
    Keep them around until the DRM event arrives, but then call the abort
    functions instead of the handler functions.
    
    This is a prerequisite for the following fix.
    
    (Ported from radeon commit 3989766edde85d1abe7024577b98fc9b007bc02a)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/amdgpu_drm_queue.c b/src/amdgpu_drm_queue.c
index 9bec658..b5aead2 100644
--- a/src/amdgpu_drm_queue.c
+++ b/src/amdgpu_drm_queue.c
@@ -64,8 +64,12 @@ amdgpu_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
 	xorg_list_for_each_entry_safe(e, tmp, &amdgpu_drm_queue, list) {
 		if (e == user_data) {
 			xorg_list_del(&e->list);
-			e->handler(e->scrn, frame,
-				   (uint64_t)sec * 1000000 + usec, e->data);
+			if (e->handler)
+				e->handler(e->scrn, frame,
+					   (uint64_t)sec * 1000000 + usec,
+					   e->data);
+			else
+				e->abort(e->scrn, e->data);
 			free(e);
 			break;
 		}
@@ -115,15 +119,19 @@ amdgpu_drm_abort_one(struct amdgpu_drm_queue_entry *e)
 
 /*
  * Abort drm queue entries for a client
+ *
+ * NOTE: This keeps the entries in the list until the DRM event arrives,
+ * but then it calls the abort functions instead of the handler
+ * functions.
  */
 void
 amdgpu_drm_abort_client(ClientPtr client)
 {
-	struct amdgpu_drm_queue_entry *e, *tmp;
+	struct amdgpu_drm_queue_entry *e;
 
-	xorg_list_for_each_entry_safe(e, tmp, &amdgpu_drm_queue, list) {
+	xorg_list_for_each_entry(e, &amdgpu_drm_queue, list) {
 		if (e->client == client)
-			amdgpu_drm_abort_one(e);
+			e->handler = NULL;
 	}
 }
 
commit e4888df6e32bb817bf0d6166a22b19c14e189a84
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 17:04:10 2016 +0900

    Fix RandR CRTC transforms
    
    Currently, Xorg will only transform the cursor as of the first time the
    cursor image changes after a transform is set.
    
    Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=80678
    
    (Ported from radeon commit 9483a3d777919b224f70c3b4d01e4b320a57db31)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 17a0f67..7316226 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -615,7 +615,6 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
 		crtc->x = x;
 		crtc->y = y;
 		crtc->rotation = rotation;
-		crtc->transformPresent = FALSE;
 
 		output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
 		if (!output_ids) {
@@ -787,6 +786,20 @@ static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
 	}
 }
 
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
+
+static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
+{
+	/* Fall back to SW cursor if the CRTC is transformed */
+	if (crtc->transformPresent)
+		return FALSE;
+
+	drmmode_load_cursor_argb(crtc, image);
+	return TRUE;
+}
+
+#endif
+
 static void drmmode_hide_cursor(xf86CrtcPtr crtc)
 {
 	ScrnInfoPtr pScrn = crtc->scrn;
@@ -951,6 +964,9 @@ static xf86CrtcFuncsRec drmmode_crtc_funcs = {
 	.show_cursor = drmmode_show_cursor,
 	.hide_cursor = drmmode_hide_cursor,
 	.load_cursor_argb = drmmode_load_cursor_argb,
+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
+	.load_cursor_argb_check = drmmode_load_cursor_argb_check,
+#endif
 
 	.gamma_set = drmmode_crtc_gamma_set,
 	.shadow_create = drmmode_crtc_shadow_create,
commit 43af92ede0968f2108f9562aa4c2c861ac703617
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Mar 18 16:58:07 2016 +0900

    Build RandR 1.4 provider name from chipset name and bus ID
    
    Instead of just "amdgpu", it's now e.g. "TONGA @ pci:0000:01:00.0".
    
    (Ported from radeon commit c7cf00487cd6d4a5d0f39d5b92ff04f6420d6a32)
    
    Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 658eb90..17a0f67 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -43,6 +43,10 @@
 #include "amdgpu_glamor.h"
 #include "amdgpu_pixmap.h"
 
+#ifdef AMDGPU_PIXMAP_SHARING
+#include <dri.h>
+#endif
+
 /* DPMS */
 #ifdef HAVE_XEXTPROTO_71
 #include <X11/extensions/dpmsconst.h>
@@ -1904,6 +1908,9 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
 	int i, num_dvi = 0, num_hdmi = 0;
 	unsigned int crtcs_needed = 0;
 	drmModeResPtr mode_res;
+#ifdef AMDGPU_PIXMAP_SHARING
+	char *bus_id_string, *provider_name;
+#endif
 
 	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
 
@@ -1947,7 +1954,11 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
 	drmmode_clones_init(pScrn, drmmode, mode_res);
 
 #ifdef AMDGPU_PIXMAP_SHARING
-	xf86ProviderSetup(pScrn, NULL, "amdgpu");
+	bus_id_string = DRICreatePCIBusID(info->PciInfo);
+	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
+	free(bus_id_string);
+	xf86ProviderSetup(pScrn, NULL, provider_name);
+	free(provider_name);
 #endif
 
 	xf86InitialConfiguration(pScrn, TRUE);


More information about the xorg-commit mailing list