xf86-video-ati: Branch 'master' - 13 commits

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Dec 28 11:15:54 UTC 2018


 src/drmmode_display.c  |  225 ++++++++++++++++++++++++++++++++-----------------
 src/drmmode_display.h  |   18 +++
 src/radeon.h           |    1 
 src/radeon_bo_helper.c |    2 
 src/radeon_dri2.c      |    4 
 src/radeon_drm_queue.c |  110 +++++++++++++----------
 src/radeon_drm_queue.h |    3 
 src/radeon_glamor.c    |    7 +
 src/radeon_kms.c       |  147 +++++++++++++++++++++++---------
 src/radeon_present.c   |    3 
 10 files changed, 352 insertions(+), 168 deletions(-)

New commits:
commit 803f872f7d4b2d80be434bb42ce64dfd295b122c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 18:04:21 2018 +0100

    Use two HW cursor buffers per CRTC
    
    Switch to the other buffer when xf86_config->cursor changes. Avoids
    these issues possible when re-using the same buffer:
    
    * The HW may intermittently display a mix of the old and new cursor
      images.
    * If the hotspot changes, the HW may intermittently display the new
      cursor image at the location corresponding to the old image's hotspot.
    
    Bugzilla: https://bugs.freedesktop.org/108832
    (Ported from amdgpu commit 0d60233d26ec70d4e1faa343b438e33829c6d5e4)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index bec309e5..d433e061 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1122,13 +1122,18 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 	ScrnInfoPtr pScrn = crtc->scrn;
 	RADEONInfoPtr info = RADEONPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	unsigned id = drmmode_crtc->cursor_id;
 	Bool premultiplied = TRUE;
 	Bool apply_gamma = TRUE;
 	uint32_t argb;
 	uint32_t *ptr;
 
+	if (drmmode_crtc->cursor &&
+	    XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor)
+		id ^= 1;
+
 	/* cursor should be mapped already */
-	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
+	ptr = (uint32_t *)(drmmode_crtc->cursor_bo[id]->ptr);
 
 	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
 		apply_gamma = FALSE;
@@ -1170,6 +1175,11 @@ retry:
 			ptr[i] = cpu_to_le32(argb);
 		}
 	}
+
+	if (id != drmmode_crtc->cursor_id) {
+		drmmode_crtc->cursor_id = id;
+		crtc->funcs->show_cursor(crtc);
+	}
 }
 
 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
@@ -1195,7 +1205,7 @@ drmmode_hide_cursor (xf86CrtcPtr crtc)
 
 	drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
 			 info->cursor_w, info->cursor_h);
-
+	drmmode_crtc->cursor = NULL;
 }
 
 static void
@@ -1212,9 +1222,11 @@ drmmode_show_cursor (xf86CrtcPtr crtc)
 	static Bool use_set_cursor2 = TRUE;
 	struct drm_mode_cursor2 arg;
 
+	drmmode_crtc->cursor = xf86_config->cursor;
+
 	memset(&arg, 0, sizeof(arg));
 
-	arg.handle = drmmode_crtc->cursor_bo->handle;
+	arg.handle = drmmode_crtc->cursor_bo[drmmode_crtc->cursor_id]->handle;
 	arg.flags = DRM_MODE_CURSOR_BO;
 	arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id;
 	arg.width = info->cursor_w;
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 49893ab0..2c2c3d57 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -88,11 +88,14 @@ typedef struct {
     drmModeCrtcPtr mode_crtc;
     int hw_id;
 
+    CursorPtr cursor;
     int cursor_x;
     int cursor_y;
     int cursor_xhot;
     int cursor_yhot;
-    struct radeon_bo *cursor_bo;
+    unsigned cursor_id;
+    struct radeon_bo *cursor_bo[2];
+
     struct drmmode_scanout rotate;
     struct drmmode_scanout scanout[2];
     DamagePtr scanout_damage;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 27a02109..bb6885fb 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -2755,27 +2755,29 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 
     {
 	int cursor_size;
-	int c;
+	int c, i;
 
 	cursor_size = info->cursor_w * info->cursor_h * 4;
 	cursor_size = RADEON_ALIGN(cursor_size, RADEON_GPU_PAGE_SIZE);
 	for (c = 0; c < xf86_config->num_crtc; c++) {
 	    drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
 
-	    if (!drmmode_crtc->cursor_bo) {
-		drmmode_crtc->cursor_bo = radeon_bo_open(info->bufmgr, 0,
-							 cursor_size, 0,
-							 RADEON_GEM_DOMAIN_VRAM, 0);
-		if (!(drmmode_crtc->cursor_bo)) {
-                    ErrorF("Failed to allocate cursor buffer memory\n");
-                    return FALSE;
-                }
-
-		if (radeon_bo_map(drmmode_crtc->cursor_bo, 1)) {
-                    ErrorF("Failed to map cursor buffer memory\n");
-                }
-            }
-        }
+	    for (i = 0; i < 2; i++) {
+		if (!drmmode_crtc->cursor_bo[i]) {
+		    drmmode_crtc->cursor_bo[i] =
+			radeon_bo_open(info->bufmgr, 0, cursor_size, 0,
+				       RADEON_GEM_DOMAIN_VRAM, 0);
+
+		    if (!(drmmode_crtc->cursor_bo[i])) {
+			ErrorF("Failed to allocate cursor buffer memory\n");
+			return FALSE;
+		    }
+
+		    if (radeon_bo_map(drmmode_crtc->cursor_bo[i], 1))
+			ErrorF("Failed to map cursor buffer memory\n");
+		}
+	    }
+	}
     }
 
     if (!info->front_buffer) {
@@ -2841,7 +2843,7 @@ void radeon_kms_update_vram_limit(ScrnInfoPtr pScrn, uint32_t new_fb_size)
     for (c = 0; c < xf86_config->num_crtc; c++) {
 	drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
 
-	if (drmmode_crtc->cursor_bo)
+	if (drmmode_crtc->cursor_bo[0])
 	    new_fb_size += (64 * 4 * 64);
     }
 
commit 91e557f78ad261e76a1829f54722c2c0781742d2
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 18:00:09 2018 +0100

    Update cursor position in drmmode_show_cursor if hotspot changed
    
    The cursor position is updated to be consistent with the new hotspot in
    the same ioctl call.
    
    (Ported from amdgpu commit b04697de5270e8e45744a7025c24df1f454a4cf0)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index c2a59da7..bec309e5 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1017,6 +1017,9 @@ drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
 	}
 #endif
 
+	drmmode_crtc->cursor_x = x;
+	drmmode_crtc->cursor_y = y;
+
 	drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
 }
 
@@ -1202,6 +1205,10 @@ drmmode_show_cursor (xf86CrtcPtr crtc)
 	RADEONInfoPtr info = RADEONPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+	CursorPtr cursor = xf86_config->cursor;
+	int xhot = cursor->bits->xhot;
+	int yhot = cursor->bits->yhot;
 	static Bool use_set_cursor2 = TRUE;
 	struct drm_mode_cursor2 arg;
 
@@ -1213,41 +1220,45 @@ drmmode_show_cursor (xf86CrtcPtr crtc)
 	arg.width = info->cursor_w;
 	arg.height = info->cursor_h;
 
+	if (crtc->rotation != RR_Rotate_0 &&
+	    crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
+			       RR_Reflect_Y)) {
+	    int t;
+
+	    /* Reflect & rotate hotspot position */
+	    if (crtc->rotation & RR_Reflect_X)
+		xhot = info->cursor_w - xhot - 1;
+	    if (crtc->rotation & RR_Reflect_Y)
+		yhot = info->cursor_h - yhot - 1;
+
+	    switch (crtc->rotation & 0xf) {
+	    case RR_Rotate_90:
+		t = xhot;
+		xhot = yhot;
+		yhot = info->cursor_w - t - 1;
+		break;
+	    case RR_Rotate_180:
+		xhot = info->cursor_w - xhot - 1;
+		yhot = info->cursor_h - yhot - 1;
+		break;
+	    case RR_Rotate_270:
+		t = xhot;
+		xhot = info->cursor_h - yhot - 1;
+		yhot = t;
+	    }
+	}
+
+	if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) {
+	    arg.flags |= DRM_MODE_CURSOR_MOVE;
+	    arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot;
+	    arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot;
+	    drmmode_crtc->cursor_xhot = xhot;
+	    drmmode_crtc->cursor_yhot = yhot;
+	}
+
 	if (use_set_cursor2) {
-	    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
-	    CursorPtr cursor = xf86_config->cursor;
-	    int xhot = cursor->bits->xhot;
-	    int yhot = cursor->bits->yhot;
 	    int ret;
 
-	    if (crtc->rotation != RR_Rotate_0 &&
-		crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
-				   RR_Reflect_Y)) {
-		int t;
-
-		/* Reflect & rotate hotspot position */
-		if (crtc->rotation & RR_Reflect_X)
-		    xhot = info->cursor_w - xhot - 1;
-		if (crtc->rotation & RR_Reflect_Y)
-		    yhot = info->cursor_h - yhot - 1;
-
-		switch (crtc->rotation & 0xf) {
-		case RR_Rotate_90:
-		    t = xhot;
-		    xhot = yhot;
-		    yhot = info->cursor_w - t - 1;
-		    break;
-		case RR_Rotate_180:
-		    xhot = info->cursor_w - xhot - 1;
-		    yhot = info->cursor_h - yhot - 1;
-		    break;
-		case RR_Rotate_270:
-		    t = xhot;
-		    xhot = info->cursor_h - yhot - 1;
-		    yhot = t;
-		}
-	    }
-
 	    arg.hot_x = xhot;
 	    arg.hot_y = yhot;
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index d7ab9d7e..49893ab0 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -87,6 +87,11 @@ typedef struct {
     drmmode_ptr drmmode;
     drmModeCrtcPtr mode_crtc;
     int hw_id;
+
+    int cursor_x;
+    int cursor_y;
+    int cursor_xhot;
+    int cursor_yhot;
     struct radeon_bo *cursor_bo;
     struct drmmode_scanout rotate;
     struct drmmode_scanout scanout[2];
commit 92df709786830d4e30a106dd49d8e0355c50c8f0
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 17:54:36 2018 +0100

    Use drmIoctl in drmmode_show_cursor
    
    This should be functionally equivalent to what drmModeSetCursor(2) do
    behind the scenes, but allows for new tricks in following changes.
    
    (Ported from amdgpu commit b344e1559e936046ef02c777fc4f6bcefa3830bc)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index ef235bd2..c2a59da7 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1202,8 +1202,16 @@ drmmode_show_cursor (xf86CrtcPtr crtc)
 	RADEONInfoPtr info = RADEONPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
-	uint32_t handle = drmmode_crtc->cursor_bo->handle;
 	static Bool use_set_cursor2 = TRUE;
+	struct drm_mode_cursor2 arg;
+
+	memset(&arg, 0, sizeof(arg));
+
+	arg.handle = drmmode_crtc->cursor_bo->handle;
+	arg.flags = DRM_MODE_CURSOR_BO;
+	arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id;
+	arg.width = info->cursor_w;
+	arg.height = info->cursor_h;
 
 	if (use_set_cursor2) {
 	    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
@@ -1240,18 +1248,17 @@ drmmode_show_cursor (xf86CrtcPtr crtc)
 		}
 	    }
 
-	    ret =
-		drmModeSetCursor2(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
-				  handle, info->cursor_w, info->cursor_h,
-				  xhot, yhot);
+	    arg.hot_x = xhot;
+	    arg.hot_y = yhot;
+
+	    ret = drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg);
 	    if (ret == -EINVAL)
 		use_set_cursor2 = FALSE;
 	    else
 		return;
 	}
 
-	drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, handle,
-			 info->cursor_w, info->cursor_h);
+	drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg);
 }
 
 /* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
commit e14c3d2f86c7be2b5c3d06a47bf0abe954207d0b
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 17:38:51 2018 +0100

    Drop RADEONInfoRec::cursor_bo array
    
    Not needed or even useful for anything.
    
    (Ported from amdgpu commit e95044e45350870fa7e237860e89ade91ac03550)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 34c88c8e..ef235bd2 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -2967,15 +2967,6 @@ miPointerSpriteFuncRec drmmode_sprite_funcs = {
 };
 
 	
-void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
-{
-	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
-	xf86CrtcPtr crtc = xf86_config->crtc[id];
-	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
-
-	drmmode_crtc->cursor_bo = bo;
-}
-
 void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
 {
 	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index f5659664..d7ab9d7e 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -213,7 +213,6 @@ extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp);
 extern void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 extern void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode);
 extern Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr);
-extern void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo);
 void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y);
 extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
 				      Bool set_hw);
diff --git a/src/radeon.h b/src/radeon.h
index cde922c6..74454c30 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -572,7 +572,6 @@ typedef struct {
     struct radeon_cs_manager *csm;
     struct radeon_cs *cs;
 
-    struct radeon_bo *cursor_bo[32];
     uint64_t vram_size;
     uint64_t gart_size;
     drmmode_rec drmmode;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index dd9955da..27a02109 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -2760,21 +2760,20 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
 	cursor_size = info->cursor_w * info->cursor_h * 4;
 	cursor_size = RADEON_ALIGN(cursor_size, RADEON_GPU_PAGE_SIZE);
 	for (c = 0; c < xf86_config->num_crtc; c++) {
-	    /* cursor objects */
-            if (!info->cursor_bo[c]) {
-                info->cursor_bo[c] = radeon_bo_open(info->bufmgr, 0,
-                                                    cursor_size, 0,
-                                                    RADEON_GEM_DOMAIN_VRAM, 0);
-                if (!info->cursor_bo[c]) {
+	    drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
+
+	    if (!drmmode_crtc->cursor_bo) {
+		drmmode_crtc->cursor_bo = radeon_bo_open(info->bufmgr, 0,
+							 cursor_size, 0,
+							 RADEON_GEM_DOMAIN_VRAM, 0);
+		if (!(drmmode_crtc->cursor_bo)) {
                     ErrorF("Failed to allocate cursor buffer memory\n");
                     return FALSE;
                 }
 
-                if (radeon_bo_map(info->cursor_bo[c], 1)) {
+		if (radeon_bo_map(drmmode_crtc->cursor_bo, 1)) {
                     ErrorF("Failed to map cursor buffer memory\n");
                 }
-
-                drmmode_set_cursor(pScrn, &info->drmmode, c, info->cursor_bo[c]);
             }
         }
     }
@@ -2840,7 +2839,9 @@ void radeon_kms_update_vram_limit(ScrnInfoPtr pScrn, uint32_t new_fb_size)
     int c;
 
     for (c = 0; c < xf86_config->num_crtc; c++) {
-	if (info->cursor_bo[c])
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
+
+	if (drmmode_crtc->cursor_bo)
 	    new_fb_size += (64 * 4 * 64);
     }
 
commit f66254c171f5a3b052a2a9e0339f17dfb5a60dc2
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 12:49:27 2018 +0100

    Automatically try re-enabling TearFree after a flip failed
    
    Specifically, after both the page flip and vblank ioctls failed, but
    then the vblank ioctl started working again. This can happen
    intermittently e.g. when hotplugging a DP display. Previously, TearFree
    would stay disabled in that case until a modeset was triggered somehow.
    
    Bugzilla: https://bugs.freedesktop.org/103791
    (Ported from amdgpu commit bcfa6c258fdf41a9928f8a3c78fc528d0fafee25)

diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index bfc13010..f5659664 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -71,6 +71,12 @@ struct drmmode_fb {
 	uint32_t handle;
 };
 
+enum drmmode_scanout_status {
+    DRMMODE_SCANOUT_OK,
+    DRMMODE_SCANOUT_FLIP_FAILED = 1u << 0,
+    DRMMODE_SCANOUT_VBLANK_FAILED = 1u << 1,
+};
+
 struct drmmode_scanout {
     struct radeon_buffer *bo;
     PixmapPtr pixmap;
@@ -90,6 +96,7 @@ typedef struct {
     unsigned scanout_id;
     uintptr_t scanout_update_pending;
     Bool tear_free;
+    enum drmmode_scanout_status scanout_status;
 
     PixmapPtr prime_scanout_pixmap;
 
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 796dac5f..dd9955da 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -783,15 +783,32 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
 
     if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
 			     1, drm_queue_seq, NULL, NULL)) {
-	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-		   "drmmode_wait_vblank failed for PRIME update: %s\n",
-		   strerror(errno));
+	if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
+	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		       "drmmode_wait_vblank failed for PRIME update: %s\n",
+		       strerror(errno));
+	    drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
+	}
+
 	drmmode_crtc->drmmode->event_context.vblank_handler(pRADEONEnt->fd,
 							    0, 0, 0,
 							    (void*)drm_queue_seq);
 	drmmode_crtc->wait_flip_nesting_level++;
 	radeon_drm_queue_handle_deferred(xf86_crtc);
+	return;
+    }
+
+    if (drmmode_crtc->scanout_status ==
+	(DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
+	/* The page flip and vblank ioctls failed before, but the vblank
+	 * ioctl is working again, so we can try re-enabling TearFree
+	 */
+	xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
+					 xf86_crtc->rotation,
+					 xf86_crtc->x, xf86_crtc->y);
     }
+
+    drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
 }
 
 static void
@@ -842,12 +859,22 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
     if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc,
 					  drmmode_crtc->flip_pending->handle,
 					  0, drm_queue_seq, 0) != 0) {
-	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n",
-		   __func__, strerror(errno));
+	if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
+	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		       "flip queue failed in %s: %s, TearFree inactive\n",
+		       __func__, strerror(errno));
+	    drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
+	}
+
 	radeon_drm_abort_entry(drm_queue_seq);
 	return;
     }
 
+    if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
+	xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
+	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
+    }
+
     drmmode_crtc->scanout_id = scanout_id;
     drmmode_crtc->scanout_update_pending = drm_queue_seq;
 }
@@ -1072,15 +1099,32 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
 
     if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
 			     1, drm_queue_seq, NULL, NULL)) {
-	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
-		   "drmmode_wait_vblank failed for scanout update: %s\n",
-		   strerror(errno));
+	if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
+	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		       "drmmode_wait_vblank failed for scanout update: %s\n",
+		       strerror(errno));
+	    drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
+	}
+
 	drmmode_crtc->drmmode->event_context.vblank_handler(pRADEONEnt->fd,
 							    0, 0, 0,
 							    (void*)drm_queue_seq);
 	drmmode_crtc->wait_flip_nesting_level++;
 	radeon_drm_queue_handle_deferred(xf86_crtc);
+	return;
+    }
+
+    if (drmmode_crtc->scanout_status ==
+	(DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
+	/* The page flip and vblank ioctls failed before, but the vblank
+	 * ioctl is working again, so we can try re-enabling TearFree
+	 */
+	xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
+					 xf86_crtc->rotation,
+					 xf86_crtc->x, xf86_crtc->y);
     }
+
+    drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
 }
 
 static void
@@ -1132,9 +1176,13 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
     if (drmmode_page_flip_target_relative(pRADEONEnt, drmmode_crtc,
 					  drmmode_crtc->flip_pending->handle,
 					  0, drm_queue_seq, 0) != 0) {
-	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s, "
-		   "TearFree inactive until next modeset\n",
-		   __func__, strerror(errno));
+	if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
+	    xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+		       "flip queue failed in %s: %s, TearFree inactive\n",
+		       __func__, strerror(errno));
+	    drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
+	}
+
 	radeon_drm_abort_entry(drm_queue_seq);
 	RegionCopy(DamageRegion(drmmode_crtc->scanout_damage),
 		   &drmmode_crtc->scanout_last_region);
@@ -1146,6 +1194,11 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
 	return;
     }
 
+    if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
+	xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
+	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
+    }
+
     drmmode_crtc->scanout_id = scanout_id;
     drmmode_crtc->scanout_update_pending = drm_queue_seq;
 }
commit ce7db51020d32f17e442338bfd305220feb51630
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 12:47:18 2018 +0100

    Cancel pending scanout update in drmmode_crtc_scanout_update
    
    drmmode_crtc_scanout_update does the equivalent of a scanout update,
    so no need to do it again. This might also avoid issues if there's a
    pending scanout update at this point.
    
    (Ported from amdgpu commit 4e7a24ac5a64e402146953ec5850d13c05742116)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 134b0f72..34c88c8e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -781,11 +781,17 @@ drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
 		*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
 		*x = *y = 0;
 
-		radeon_scanout_do_update(crtc, scanout_id,
-					 screen->GetWindowPixmap(screen->root),
-					 extents);
-		RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage));
-		radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo);
+		if (radeon_scanout_do_update(crtc, scanout_id,
+					     screen->GetWindowPixmap(screen->root),
+					     extents)) {
+			RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage));
+			radeon_glamor_finish(scrn);
+
+			if (!drmmode_crtc->flip_pending) {
+				radeon_drm_abort_entry(drmmode_crtc->
+						       scanout_update_pending);
+			}
+		}
 	}
 }
 
commit 21d65e5b78c8889e363aee8596cd0b0f942fee46
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Fri Dec 21 12:38:04 2018 +0100

    Perform scanout buffer update immediately if drmmode_wait_vblank fails
    
    Otherwise the damaged screen contents may never be displayed in that
    case.
    
    (Ported from amdgpu commit 500fadb16285146e91f62fce3a0ce1360ca684ba)

diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index a7aade70..796dac5f 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -752,6 +752,7 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
 {
     ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
     xf86CrtcPtr xf86_crtc = radeon_prime_dirty_to_crtc(dirty);
     drmmode_crtc_private_ptr drmmode_crtc;
     uintptr_t drm_queue_seq;
@@ -774,19 +775,23 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "radeon_drm_queue_alloc failed for PRIME update\n");
+	radeon_prime_scanout_update_handler(xf86_crtc, 0, 0, NULL);
 	return;
     }
 
+    drmmode_crtc->scanout_update_pending = drm_queue_seq;
+
     if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
 			     1, drm_queue_seq, NULL, NULL)) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "drmmode_wait_vblank failed for PRIME update: %s\n",
 		   strerror(errno));
-	radeon_drm_abort_entry(drm_queue_seq);
-	return;
+	drmmode_crtc->drmmode->event_context.vblank_handler(pRADEONEnt->fd,
+							    0, 0, 0,
+							    (void*)drm_queue_seq);
+	drmmode_crtc->wait_flip_nesting_level++;
+	radeon_drm_queue_handle_deferred(xf86_crtc);
     }
-
-    drmmode_crtc->scanout_update_pending = drm_queue_seq;
 }
 
 static void
@@ -1022,8 +1027,9 @@ static void
 radeon_scanout_update(xf86CrtcPtr xf86_crtc)
 {
     drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+    ScrnInfoPtr scrn = xf86_crtc->scrn;
+    RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
     uintptr_t drm_queue_seq;
-    ScrnInfoPtr scrn;
     DamagePtr pDamage;
     RegionPtr pRegion;
     BoxRec extents;
@@ -1048,7 +1054,6 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
 	return;
     }
 
-    scrn = xf86_crtc->scrn;
     drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc,
 					   RADEON_DRM_QUEUE_CLIENT_DEFAULT,
 					   RADEON_DRM_QUEUE_ID_DEFAULT,
@@ -1059,19 +1064,23 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "radeon_drm_queue_alloc failed for scanout update\n");
+	radeon_scanout_update_handler(xf86_crtc, 0, 0, drmmode_crtc);
 	return;
     }
 
+    drmmode_crtc->scanout_update_pending = drm_queue_seq;
+
     if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
 			     1, drm_queue_seq, NULL, NULL)) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "drmmode_wait_vblank failed for scanout update: %s\n",
 		   strerror(errno));
-	radeon_drm_abort_entry(drm_queue_seq);
-	return;
+	drmmode_crtc->drmmode->event_context.vblank_handler(pRADEONEnt->fd,
+							    0, 0, 0,
+							    (void*)drm_queue_seq);
+	drmmode_crtc->wait_flip_nesting_level++;
+	radeon_drm_queue_handle_deferred(xf86_crtc);
     }
-
-    drmmode_crtc->scanout_update_pending = drm_queue_seq;
 }
 
 static void
commit 64942d2c49f9fa1afcc42c07943d076a40963e51
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Dec 20 19:00:08 2018 +0100

    Move deferred vblank events to separate drm_vblank_deferred list
    
    It was still possible for nested xorg_list_for_each_entry_safe loops
    to occur over the drm_vblank_signalled list, which could mess up that
    list. Moving deferred events to a separate list allows processing the
    drm_vblank_signalled list without xorg_list_for_each_entry_safe.
    
    Bugzilla: https://bugs.freedesktop.org/108600
    (Ported from amdgpu commit 51ba6dddee40c3688d4c7b12eabeab516ed153b7)

diff --git a/src/radeon_drm_queue.c b/src/radeon_drm_queue.c
index acfea3da..d8a8243c 100644
--- a/src/radeon_drm_queue.c
+++ b/src/radeon_drm_queue.c
@@ -56,6 +56,7 @@ static int radeon_drm_queue_refcnt;
 static struct xorg_list radeon_drm_queue;
 static struct xorg_list radeon_drm_flip_signalled;
 static struct xorg_list radeon_drm_vblank_signalled;
+static struct xorg_list radeon_drm_vblank_deferred;
 static uintptr_t radeon_drm_queue_seq;
 
 
@@ -112,6 +113,31 @@ radeon_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
 }
 
 /*
+ * Handle signalled vblank events. If we're waiting for a flip event,
+ * put events for that CRTC in the vblank_deferred list.
+ */
+static void
+radeon_drm_handle_vblank_signalled(void)
+{
+    drmmode_crtc_private_ptr drmmode_crtc;
+    struct radeon_drm_queue_entry *e;
+
+    while (!xorg_list_is_empty(&radeon_drm_vblank_signalled)) {
+	e = xorg_list_first_entry(&radeon_drm_vblank_signalled,
+				  struct radeon_drm_queue_entry, list);
+	drmmode_crtc = e->crtc->driver_private;
+
+	if (drmmode_crtc->wait_flip_nesting_level == 0) {
+	    radeon_drm_queue_handle_one(e);
+	    continue;
+	}
+
+	xorg_list_del(&e->list);
+	xorg_list_append(&e->list, &radeon_drm_vblank_deferred);
+    }
+}
+
+/*
  * Handle deferred DRM vblank events
  *
  * This function must be called after radeon_drm_wait_pending_flip, once
@@ -127,12 +153,18 @@ radeon_drm_queue_handle_deferred(xf86CrtcPtr crtc)
 	--drmmode_crtc->wait_flip_nesting_level > 0)
 	return;
 
-    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_vblank_signalled, list) {
-	drmmode_crtc_private_ptr drmmode_crtc = e->crtc->driver_private;
+    /* Put previously deferred vblank events for this CRTC back in the
+     * signalled queue
+     */
+    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_vblank_deferred, list) {
+	if (e->crtc != crtc)
+	    continue;
 
-	if (drmmode_crtc->wait_flip_nesting_level == 0)
-	    radeon_drm_queue_handle_one(e);
+	xorg_list_del(&e->list);
+	xorg_list_append(&e->list, &radeon_drm_vblank_signalled);
     }
+
+    radeon_drm_handle_vblank_signalled();
 }
 
 /*
@@ -205,6 +237,13 @@ radeon_drm_abort_entry(uintptr_t seq)
 	}
     }
 
+    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_vblank_deferred, list) {
+	if (e->seq == seq) {
+	    radeon_drm_abort_one(e);
+	    return;
+	}
+    }
+
     xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) {
 	if (e->seq == seq) {
 	    radeon_drm_abort_one(e);
@@ -235,7 +274,7 @@ radeon_drm_abort_id(uint64_t id)
 int
 radeon_drm_handle_event(int fd, drmEventContext *event_context)
 {
-    struct radeon_drm_queue_entry *e, *tmp;
+    struct radeon_drm_queue_entry *e;
     int r;
 
     r = drmHandleEvent(fd, event_context);
@@ -246,12 +285,7 @@ radeon_drm_handle_event(int fd, drmEventContext *event_context)
 	radeon_drm_queue_handle_one(e);
     }
 
-    xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_vblank_signalled, list) {
-	drmmode_crtc_private_ptr drmmode_crtc = e->crtc->driver_private;
-
-	if (drmmode_crtc->wait_flip_nesting_level == 0)
-	    radeon_drm_queue_handle_one(e);
-    }
+    radeon_drm_handle_vblank_signalled();
 
     return r;
 }
@@ -298,6 +332,7 @@ radeon_drm_queue_init(ScrnInfoPtr scrn)
     xorg_list_init(&radeon_drm_queue);
     xorg_list_init(&radeon_drm_flip_signalled);
     xorg_list_init(&radeon_drm_vblank_signalled);
+    xorg_list_init(&radeon_drm_vblank_deferred);
 }
 
 /*
commit f450632077843a95a6ef269febbfb64a605045ed
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Dec 20 18:48:19 2018 +0100

    Explicitly keep track of whether a DRM event is for a flip or not
    
    When an async flip is performed, and TearFree is enabled on the CRTC
    used for timing, we schedule a vblank event for completing the page
    flip. The DRM event queuing code treated this event like a vblank event,
    but it needs to be treated like a page flip event.
    
    (Ported from amdgpu commit e2c7369cae65069aa93eed1c0b678f975ce5c274)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 831394d4..134b0f72 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -3397,7 +3397,8 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 		drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id,
 						       flipdata,
 						       drmmode_flip_handler,
-						       drmmode_flip_abort);
+						       drmmode_flip_abort,
+						       TRUE);
 		if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 				   "Allocating DRM queue event entry failed.\n");
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index 4d12fc09..922ed4fb 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -1076,7 +1076,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw,
 
     drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT,
 					   wait_info, radeon_dri2_frame_event_handler,
-					   radeon_dri2_frame_event_abort);
+					   radeon_dri2_frame_event_abort, FALSE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "Allocating DRM queue event entry failed.\n");
@@ -1215,7 +1215,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
 
     drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT,
 					   swap_info, radeon_dri2_frame_event_handler,
-					   radeon_dri2_frame_event_abort);
+					   radeon_dri2_frame_event_abort, FALSE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
         xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "Allocating DRM queue entry failed.\n");
diff --git a/src/radeon_drm_queue.c b/src/radeon_drm_queue.c
index ebc6a5b6..acfea3da 100644
--- a/src/radeon_drm_queue.c
+++ b/src/radeon_drm_queue.c
@@ -48,6 +48,7 @@ struct radeon_drm_queue_entry {
     xf86CrtcPtr crtc;
     radeon_drm_handler_proc handler;
     radeon_drm_abort_proc abort;
+    Bool is_flip;
     unsigned int frame;
 };
 
@@ -86,8 +87,8 @@ radeon_drm_abort_one(struct radeon_drm_queue_entry *e)
 }
 
 static void
-radeon_drm_queue_handler(struct xorg_list *signalled, unsigned int frame,
-			 unsigned int sec, unsigned int usec, void *user_ptr)
+radeon_drm_queue_handler(int fd, unsigned int frame, unsigned int sec,
+			 unsigned int usec, void *user_ptr)
 {
     uintptr_t seq = (uintptr_t)user_ptr;
     struct radeon_drm_queue_entry *e, *tmp;
@@ -102,35 +103,15 @@ radeon_drm_queue_handler(struct xorg_list *signalled, unsigned int frame,
 	    xorg_list_del(&e->list);
 	    e->usec = (uint64_t)sec * 1000000 + usec;
 	    e->frame = frame;
-	    xorg_list_append(&e->list, signalled);
+	    xorg_list_append(&e->list, e->is_flip ?
+			     &radeon_drm_flip_signalled :
+			     &radeon_drm_vblank_signalled);
 	    break;
 	}
     }
 }
 
 /*
- * Signal a DRM page flip event
- */
-static void
-radeon_drm_page_flip_handler(int fd, unsigned int frame, unsigned int sec,
-			     unsigned int usec, void *user_ptr)
-{
-    radeon_drm_queue_handler(&radeon_drm_flip_signalled, frame, sec, usec,
-			     user_ptr);
-}
-
-/*
- * Signal a DRM vblank event
- */
-static void
-radeon_drm_vblank_handler(int fd, unsigned int frame, unsigned int sec,
-			  unsigned int usec, void *user_ptr)
-{
-    radeon_drm_queue_handler(&radeon_drm_vblank_signalled, frame, sec, usec,
-			     user_ptr);
-}
-
-/*
  * Handle deferred DRM vblank events
  *
  * This function must be called after radeon_drm_wait_pending_flip, once
@@ -162,7 +143,8 @@ uintptr_t
 radeon_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
 		       uint64_t id, void *data,
 		       radeon_drm_handler_proc handler,
-		       radeon_drm_abort_proc abort)
+		       radeon_drm_abort_proc abort,
+		       Bool is_flip)
 {
     struct radeon_drm_queue_entry *e;
 
@@ -180,6 +162,7 @@ radeon_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
     e->data = data;
     e->handler = handler;
     e->abort = abort;
+    e->is_flip = is_flip;
 
     xorg_list_append(&e->list, &radeon_drm_queue);
 
@@ -306,8 +289,8 @@ radeon_drm_queue_init(ScrnInfoPtr scrn)
     drmmode_ptr drmmode = &info->drmmode;
 
     drmmode->event_context.version = 2;
-    drmmode->event_context.vblank_handler = radeon_drm_vblank_handler;
-    drmmode->event_context.page_flip_handler = radeon_drm_page_flip_handler;
+    drmmode->event_context.vblank_handler = radeon_drm_queue_handler;
+    drmmode->event_context.page_flip_handler = radeon_drm_queue_handler;
 
     if (radeon_drm_queue_refcnt++)
 	return;
diff --git a/src/radeon_drm_queue.h b/src/radeon_drm_queue.h
index 334c4ca6..19d42e93 100644
--- a/src/radeon_drm_queue.h
+++ b/src/radeon_drm_queue.h
@@ -44,7 +44,8 @@ void radeon_drm_queue_handle_deferred(xf86CrtcPtr crtc);
 uintptr_t radeon_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
 				 uint64_t id, void *data,
 				 radeon_drm_handler_proc handler,
-				 radeon_drm_abort_proc abort);
+				 radeon_drm_abort_proc abort,
+				 Bool is_flip);
 void radeon_drm_abort_client(ClientPtr client);
 void radeon_drm_abort_entry(uintptr_t seq);
 void radeon_drm_abort_id(uint64_t id);
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index cd5efd53..a7aade70 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -769,7 +769,8 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
 					   RADEON_DRM_QUEUE_CLIENT_DEFAULT,
 					   RADEON_DRM_QUEUE_ID_DEFAULT, NULL,
 					   radeon_prime_scanout_update_handler,
-					   radeon_prime_scanout_update_abort);
+					   radeon_prime_scanout_update_abort,
+					   FALSE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "radeon_drm_queue_alloc failed for PRIME update\n");
@@ -817,7 +818,7 @@ radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
 					   RADEON_DRM_QUEUE_ID_DEFAULT,
 					   NULL,
 					   radeon_scanout_flip_handler,
-					   radeon_scanout_flip_abort);
+					   radeon_scanout_flip_abort, TRUE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "Allocating DRM event queue entry failed for PRIME flip.\n");
@@ -1053,7 +1054,8 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
 					   RADEON_DRM_QUEUE_ID_DEFAULT,
 					   drmmode_crtc,
 					   radeon_scanout_update_handler,
-					   radeon_scanout_update_abort);
+					   radeon_scanout_update_abort,
+					   FALSE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "radeon_drm_queue_alloc failed for scanout update\n");
@@ -1102,7 +1104,7 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
 					   RADEON_DRM_QUEUE_ID_DEFAULT,
 					   NULL,
 					   radeon_scanout_flip_handler,
-					   radeon_scanout_flip_abort);
+					   radeon_scanout_flip_abort, TRUE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
 		   "Allocating DRM event queue entry failed.\n");
diff --git a/src/radeon_present.c b/src/radeon_present.c
index d0a0c68c..0b55117e 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -157,7 +157,8 @@ radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 					   RADEON_DRM_QUEUE_CLIENT_DEFAULT,
 					   event_id, event,
 					   radeon_present_vblank_handler,
-					   radeon_present_vblank_abort);
+					   radeon_present_vblank_abort,
+					   FALSE);
     if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
 	free(event);
 	return BadAlloc;
commit 189b6facb3988c00c96d970f8c13ed8d58fa3998
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Dec 20 18:44:24 2018 +0100

    Use drm_abort_one in drm_queue_handler
    
    At this point, we've already established that e->handler is NULL, no
    need to check again in drm_queue_handle_one. This also makes it clearer
    what's happening.
    
    (Ported from amdgpu commit eda571222f5a6be47f8897e82d85199bb9d95251)

diff --git a/src/radeon_drm_queue.c b/src/radeon_drm_queue.c
index ea78e8e2..ebc6a5b6 100644
--- a/src/radeon_drm_queue.c
+++ b/src/radeon_drm_queue.c
@@ -72,6 +72,19 @@ radeon_drm_queue_handle_one(struct radeon_drm_queue_entry *e)
     free(e);
 }
 
+/*
+ * Abort one queued DRM entry, removing it
+ * from the list, calling the abort function and
+ * freeing the memory
+ */
+static void
+radeon_drm_abort_one(struct radeon_drm_queue_entry *e)
+{
+    xorg_list_del(&e->list);
+    e->abort(e->crtc, e->data);
+    free(e);
+}
+
 static void
 radeon_drm_queue_handler(struct xorg_list *signalled, unsigned int frame,
 			 unsigned int sec, unsigned int usec, void *user_ptr)
@@ -82,7 +95,7 @@ radeon_drm_queue_handler(struct xorg_list *signalled, unsigned int frame,
     xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) {
 	if (e->seq == seq) {
 	    if (!e->handler) {
-		radeon_drm_queue_handle_one(e);
+		radeon_drm_abort_one(e);
 		break;
 	    }
 
@@ -174,19 +187,6 @@ radeon_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client,
 }
 
 /*
- * Abort one queued DRM entry, removing it
- * from the list, calling the abort function and
- * freeing the memory
- */
-static void
-radeon_drm_abort_one(struct radeon_drm_queue_entry *e)
-{
-    xorg_list_del(&e->list);
-    e->abort(e->crtc, e->data);
-    free(e);
-}
-
-/*
  * Abort drm queue entries for a client
  *
  * NOTE: This keeps the entries in the list until the DRM event arrives,
commit 06957e3067b9eb38d30b32d98a07895399f4cb36
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Dec 20 18:40:19 2018 +0100

    glamor: Can work at depth >= 15 with current xserver Git master
    
    (Ported from amdgpu commit 0734cdf544ffd3f2ac8749ad0e4bf43f8a5cea50)

diff --git a/src/radeon_bo_helper.c b/src/radeon_bo_helper.c
index da5a484f..8b3e5797 100644
--- a/src/radeon_bo_helper.c
+++ b/src/radeon_bo_helper.c
@@ -39,6 +39,8 @@ radeon_get_gbm_format(int depth, int bitsPerPixel)
     case 8:
 	return GBM_FORMAT_R8;
 #endif
+    case 15:
+	return GBM_FORMAT_ARGB1555;
     case 16:
 	return GBM_FORMAT_RGB565;
     case 32:
diff --git a/src/radeon_glamor.c b/src/radeon_glamor.c
index bffc89ec..f1098381 100644
--- a/src/radeon_glamor.c
+++ b/src/radeon_glamor.c
@@ -109,9 +109,14 @@ radeon_glamor_pre_init(ScrnInfoPtr scrn)
 			   "glamor may not work (well) with GPUs < RV515.\n");
 	}
 
+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,20,99,0,0)
 	if (scrn->depth < 24) {
+#else
+	if (scrn->depth < 15) {
+#endif
 		xf86DrvMsg(scrn->scrnIndex, s ? X_ERROR : X_WARNING,
-			   "glamor requires depth >= 24, disabling.\n");
+			   "Depth %d not supported with glamor, disabling\n",
+			   scrn->depth);
 		return FALSE;
 	}
 
commit 99ac121770da53196124d80375a5c8edbcf827fa
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Dec 20 18:38:33 2018 +0100

    Skip gamma correction of cursor data if premultiplied R/G/B > alpha
    
    The un-premultiplied R/G/B values would overflow the gamma LUT, so just
    pass through the data unchanged, and leave it up to the HW how to
    interpret such weird premultiplied alpha pixels.
    
    Bugzilla: https://bugs.freedesktop.org/108355
    (Ported from amdgpu commit 13c94a373b4858a2d2aa14c22b5f98d53c84c0d9)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 9a9e092a..831394d4 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1050,8 +1050,8 @@ drmmode_cursor_src_offset(Rotation rotation, int width, int height,
 #endif
 
 static Bool
-drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool premultiplied,
-		     Bool apply_gamma)
+drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied,
+		     Bool *apply_gamma)
 {
 	uint32_t alpha = *argb >> 24;
 	uint32_t rgb[3];
@@ -1059,13 +1059,23 @@ drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool premultiplied,
 
 	if (premultiplied) {
 #if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0)
-		if (alpha == 0 && (*argb & 0xffffff) != 0)
+		if (alpha == 0 && (*argb & 0xffffff) != 0) {
 			/* Doesn't look like premultiplied alpha */
+			*premultiplied = FALSE;
 			return FALSE;
+		}
 #endif
 
-		if (!apply_gamma)
+		if (!(*apply_gamma))
 			return TRUE;
+
+		if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) {
+			/* Un-premultiplied R/G/B would overflow gamma LUT,
+			 * don't apply gamma correction
+			 */
+			*apply_gamma = FALSE;
+			return FALSE;
+		}
 	}
 
 	if (!alpha) {
@@ -1083,7 +1093,7 @@ drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool premultiplied,
 			rgb[i] = rgb[i] * 0xff / alpha;
 	}
 
-	if (apply_gamma) {
+	if (*apply_gamma) {
 		rgb[0] = crtc->gamma_blue[rgb[0]] >> 8;
 		rgb[1] = crtc->gamma_green[rgb[1]] >> 8;
 		rgb[2] = crtc->gamma_red[rgb[2]] >> 8;
@@ -1128,11 +1138,10 @@ retry_transform:
 								      cursor_h,
 								      dstx, dsty);
 				argb = image[srcoffset];
-				if (!drmmode_cursor_pixel(crtc, &argb, premultiplied,
-							  apply_gamma)) {
-					premultiplied = FALSE;
+				if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied,
+							  &apply_gamma))
 					goto retry_transform;
-				}
+
 				ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb);
 			}
 		}
@@ -1145,11 +1154,10 @@ retry_transform:
 retry:
 		for (i = 0; i < cursor_size; i++) {
 			argb = image[i];
-			if (!drmmode_cursor_pixel(crtc, &argb, premultiplied,
-						  apply_gamma)) {
-				premultiplied = FALSE;
+			if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied,
+						  &apply_gamma))
 				goto retry;
-			}
+
 			ptr[i] = cpu_to_le32(argb);
 		}
 	}
commit 0c40a76d1c050d018e6d59bebb5efc9c62be308c
Author: Michel Dänzer <michel.daenzer at amd.com>
Date:   Thu Dec 20 18:25:21 2018 +0100

    Detect and fix up non-premultiplied cursor data
    
    X server >= 1.18 already has code for this, but handle it with older X
    servers as well.
    
    (Ported from amdgpu commits ad6dfb0124860cf67730bde85867f81d9258c84d &
     426f9a49655f01863cf4d898f525e5f95984e0c4)

diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 00d94449..9a9e092a 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1049,29 +1049,52 @@ drmmode_cursor_src_offset(Rotation rotation, int width, int height,
 
 #endif
 
-static uint32_t
-drmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb)
+static Bool
+drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool premultiplied,
+		     Bool apply_gamma)
 {
-	uint32_t alpha = argb >> 24;
+	uint32_t alpha = *argb >> 24;
 	uint32_t rgb[3];
 	int i;
 
-	if (!alpha)
-		return 0;
+	if (premultiplied) {
+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0)
+		if (alpha == 0 && (*argb & 0xffffff) != 0)
+			/* Doesn't look like premultiplied alpha */
+			return FALSE;
+#endif
 
-	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
-		return argb;
+		if (!apply_gamma)
+			return TRUE;
+	}
 
-	/* Un-premultiply alpha */
+	if (!alpha) {
+		*argb = 0;
+		return TRUE;
+	}
+
+	/* Extract RGB */
 	for (i = 0; i < 3; i++)
-		rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha;
+		rgb[i] = (*argb >> (i * 8)) & 0xff;
+
+	if (premultiplied) {
+		/* Un-premultiply alpha */
+		for (i = 0; i < 3; i++)
+			rgb[i] = rgb[i] * 0xff / alpha;
+	}
+
+	if (apply_gamma) {
+		rgb[0] = crtc->gamma_blue[rgb[0]] >> 8;
+		rgb[1] = crtc->gamma_green[rgb[1]] >> 8;
+		rgb[2] = crtc->gamma_red[rgb[2]] >> 8;
+	}
 
-	/* Apply gamma correction and pre-multiply alpha */
-	rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff;
-	rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff;
-	rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff;
+	/* Premultiply alpha */
+	for (i = 0; i < 3; i++)
+		rgb[i] = rgb[i] * alpha / 0xff;
 
-	return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
+	*argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
+	return TRUE;
 }
 
 static void
@@ -1080,27 +1103,37 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 	ScrnInfoPtr pScrn = crtc->scrn;
 	RADEONInfoPtr info = RADEONPTR(pScrn);
 	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+	Bool premultiplied = TRUE;
+	Bool apply_gamma = TRUE;
+	uint32_t argb;
 	uint32_t *ptr;
 
 	/* cursor should be mapped already */
 	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
 
+	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
+		apply_gamma = FALSE;
+
 #if XF86_CRTC_VERSION < 7
 	if (crtc->driverIsPerformingTransform) {
 		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
 		int dstx, dsty;
 		int srcoffset;
 
+retry_transform:
 		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(drmmode_cursor_gamma(crtc,
-									 image[srcoffset]));
+				argb = image[srcoffset];
+				if (!drmmode_cursor_pixel(crtc, &argb, premultiplied,
+							  apply_gamma)) {
+					premultiplied = FALSE;
+					goto retry_transform;
+				}
+				ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb);
 			}
 		}
 	} else
@@ -1109,8 +1142,16 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
 		uint32_t cursor_size = info->cursor_w * info->cursor_h;
 		int i;
 
-		for (i = 0; i < cursor_size; i++)
-			ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i]));
+retry:
+		for (i = 0; i < cursor_size; i++) {
+			argb = image[i];
+			if (!drmmode_cursor_pixel(crtc, &argb, premultiplied,
+						  apply_gamma)) {
+				premultiplied = FALSE;
+				goto retry;
+			}
+			ptr[i] = cpu_to_le32(argb);
+		}
 	}
 }
 


More information about the xorg-commit mailing list