[PATCH xf86-video-amdgpu 09/10] Always allow Present page flipping with TearFree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Michel Dänzer <michel.daenzer@xxxxxxx>

Even if TearFree is active for the the CRTC we're synchronizing to. In
that case, for Present flips synchronized to vertical blank, the other
scanout buffer is immediately synchronized and flipped to during the
target vertical blank period. For Present flips not synchronized to
vertical blank, we simply use the MSC and timestamp values of the last
vertical blank period for timing purposes, and let the normal TearFree
mechanism handle display updates.

(Ported from radeon commit 4445765af5b97d0cfd10889fe6d6f58f2ce85659)

Signed-off-by: Michel Dänzer <michel.daenzer at amd.com>
---
 src/amdgpu_kms.c      | 27 ++++++++++++++++---
 src/amdgpu_present.c  | 75 +++++++++++++++++++++++++++++++++++++++++++--------
 src/drmmode_display.c | 61 ++++++++++++++++++++++++++++++++++++-----
 src/drmmode_display.h | 12 ++++++++-
 4 files changed, 152 insertions(+), 23 deletions(-)

diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index aedb3f066..b0f1a3d94 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -41,6 +41,10 @@
 #include "shadow.h"
 #include <xf86Priv.h>
 
+#if HAVE_PRESENT_H
+#include <present.h>
+#endif
+
 /* DPMS */
 #ifdef HAVE_XEXTPROTO_71
 #include <X11/extensions/dpmsconst.h>
@@ -681,6 +685,15 @@ amdgpu_prime_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
 	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
 			     drmmode_crtc->flip_pending);
 	amdgpu_prime_scanout_flip_abort(crtc, event_data);
+
+#ifdef HAVE_PRESENT_H
+	if (drmmode_crtc->present_vblank_event_id) {
+		present_event_notify(drmmode_crtc->present_vblank_event_id,
+				     drmmode_crtc->present_vblank_usec,
+				     drmmode_crtc->present_vblank_msc);
+		drmmode_crtc->present_vblank_event_id = 0;
+	}
+#endif
 }
 
 static void
@@ -895,10 +908,14 @@ amdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
 	ScreenPtr screen = crtc->scrn->pScreen;
 	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
 
-	amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
-				 &screen->GetWindowPixmap(screen->root)->drawable,
-				 &region->extents);
-	RegionEmpty(region);
+	if (crtc->enabled &&
+	    !drmmode_crtc->flip_pending &&
+	    drmmode_crtc->dpms_mode == DPMSModeOn) {
+		if (amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
+					     &screen->GetWindowPixmap(screen->root)->drawable,
+					     &region->extents))
+			RegionEmpty(region);
+	}
 
 	amdgpu_scanout_update_abort(crtc, event_data);
 }
@@ -915,6 +932,7 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
 
 	if (!xf86_crtc->enabled ||
 	    drmmode_crtc->scanout_update_pending ||
+	    drmmode_crtc->flip_pending ||
 	    drmmode_crtc->dpms_mode != DPMSModeOn)
 		return;
 
@@ -982,6 +1000,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
 	unsigned scanout_id;
 
 	if (drmmode_crtc->scanout_update_pending ||
+	    drmmode_crtc->flip_pending ||
 	    drmmode_crtc->dpms_mode != DPMSModeOn)
 		return;
 
diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index c7fc402cd..cef93c068 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -52,6 +52,7 @@ static present_screen_info_rec amdgpu_present_screen_info;
 
 struct amdgpu_present_vblank_event {
 	uint64_t event_id;
+	Bool vblank_for_flip;
 	Bool unflip;
 };
 
@@ -119,9 +120,26 @@ static void
 amdgpu_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc,
 			      uint64_t usec, void *data)
 {
+	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 	struct amdgpu_present_vblank_event *event = data;
 
-	present_event_notify(event->event_id, usec, msc);
+	if (event->vblank_for_flip &&
+	    drmmode_crtc->tear_free &&
+	    drmmode_crtc->scanout_update_pending) {
+		if (drmmode_crtc->present_vblank_event_id != 0) {
+			xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
+				   "Need to handle previously deferred vblank event\n");
+			present_event_notify(drmmode_crtc->present_vblank_event_id,
+					     drmmode_crtc->present_vblank_usec,
+					     drmmode_crtc->present_vblank_msc);
+		}
+
+		drmmode_crtc->present_vblank_event_id = event->event_id;
+		drmmode_crtc->present_vblank_msc = msc;
+		drmmode_crtc->present_vblank_usec = usec;
+	} else
+		present_event_notify(event->event_id, usec, msc);
+
 	free(event);
 }
 
@@ -144,6 +162,7 @@ static int
 amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 {
 	xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 	ScreenPtr screen = crtc->pScreen;
 	struct amdgpu_present_vblank_event *event;
 	uintptr_t drm_queue_seq;
@@ -152,6 +171,9 @@ amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	if (!event)
 		return BadAlloc;
 	event->event_id = event_id;
+	event->vblank_for_flip = drmmode_crtc->present_flip_expected;
+	drmmode_crtc->present_flip_expected = FALSE;
+
 	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
 					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
 					       event_id, event,
@@ -211,8 +233,17 @@ amdgpu_present_check_unflip(ScrnInfoPtr scrn)
 		return FALSE;
 
 	for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) {
-		if (drmmode_crtc_can_flip(config->crtc[i]))
-			num_crtcs_on++;
+		xf86CrtcPtr crtc = config->crtc[i];
+
+		if (drmmode_crtc_can_flip(crtc)) {
+			drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+			if (drmmode_crtc->flip_pending)
+				return FALSE;
+
+			if (!drmmode_crtc->tear_free)
+				num_crtcs_on++;
+		}
 	}
 
 	return num_crtcs_on > 0;
@@ -225,9 +256,19 @@ static Bool
 amdgpu_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
 			  Bool sync_flip)
 {
+	xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 	ScreenPtr screen = window->drawable.pScreen;
-	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	ScrnInfoPtr scrn = xf86_crtc->scrn;
+	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+	int num_crtcs_on;
+	int i;
+
+	drmmode_crtc->present_flip_expected = FALSE;
+
+	if (!scrn->vtSema)
+		return FALSE;
 
 	if (!info->allowPageFlip)
 		return FALSE;
@@ -245,10 +286,18 @@ amdgpu_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
 	    amdgpu_pixmap_get_tiling_info(screen->GetScreenPixmap(screen)))
 		return FALSE;
 
-	if (!drmmode_crtc_can_flip(crtc->devPrivate))
+	for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) {
+		if (drmmode_crtc_can_flip(config->crtc[i]))
+			num_crtcs_on++;
+		else if (config->crtc[i] == crtc->devPrivate)
+			return FALSE;
+	}
+
+	if (num_crtcs_on == 0)
 		return FALSE;
 
-	return amdgpu_present_check_unflip(scrn);
+	drmmode_crtc->present_flip_expected = TRUE;
+	return TRUE;
 }
 
 /*
@@ -287,18 +336,20 @@ static Bool
 amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
                    PixmapPtr pixmap, Bool sync_flip)
 {
+	xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
 	ScreenPtr screen = crtc->pScreen;
-	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+	ScrnInfoPtr scrn = xf86_crtc->scrn;
 	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
 	struct amdgpu_present_vblank_event *event;
-	Bool ret;
+	Bool ret = FALSE;
 
 	if (!amdgpu_present_check_flip(crtc, screen->root, pixmap, sync_flip))
-		return FALSE;
+		goto out;
 
 	event = calloc(1, sizeof(struct amdgpu_present_vblank_event));
 	if (!event)
-		return FALSE;
+		goto out;
 
 	event->event_id = event_id;
 
@@ -315,6 +366,8 @@ amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
 	else
 		info->drmmode.present_flipping = TRUE;
 
+ out:
+	drmmode_crtc->present_flip_expected = FALSE;
 	return ret;
 }
 
@@ -358,7 +411,7 @@ modeset:
 		xf86CrtcPtr crtc = config->crtc[i];
 		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
 
-		if (!crtc->enabled)
+		if (!crtc->enabled || drmmode_crtc->tear_free)
 			continue;
 
 		if (drmmode_crtc->dpms_mode == DPMSModeOn)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index fa19fd7ab..edd955ece 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -550,6 +550,14 @@ error:
 static void
 amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
 {
+	drmmode_crtc_private_ptr drmmode_crtc = closure;
+
+	if (drmmode_crtc->ignore_damage) {
+		RegionEmpty(&damage->damage);
+		drmmode_crtc->ignore_damage = FALSE;
+		return;
+	}
+
 	/* Only keep track of the extents */
 	RegionUninit(&damage->damage);
 	damage->damage.data = NULL;
@@ -2253,7 +2261,8 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
 
 	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
 			     flipdata->fb);
-	if (drmmode_crtc->flip_pending == flipdata->fb) {
+	if (drmmode_crtc->tear_free ||
+	    drmmode_crtc->flip_pending == flipdata->fb) {
 		drmmode_fb_reference(pAMDGPUEnt->fd,
 				     &drmmode_crtc->flip_pending, NULL);
 	}
@@ -2798,13 +2807,16 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 	flipdata->fe_crtc = ref_crtc;
 
 	for (i = 0; i < config->num_crtc; i++) {
+		struct drmmode_fb *fb = flipdata->fb;
+
 		crtc = config->crtc[i];
+		drmmode_crtc = crtc->driver_private;
 
-		if (!drmmode_crtc_can_flip(crtc))
+		if (!drmmode_crtc_can_flip(crtc) ||
+		    (drmmode_crtc->tear_free && crtc != ref_crtc))
 			continue;
 
 		flipdata->flip_count++;
-		drmmode_crtc = crtc->driver_private;
 
 		drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id,
 						       flipdata,
@@ -2816,10 +2828,39 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 			goto error;
 		}
 
+		if (drmmode_crtc->tear_free) {
+			BoxRec extents = { .x1 = 0, .y1 = 0,
+					   .x2 = new_front->drawable.width,
+					   .y2 = new_front->drawable.height };
+			int scanout_id = drmmode_crtc->scanout_id ^ 1;
+
+			if (flip_sync == FLIP_ASYNC) {
+				if (!drmmode_wait_vblank(crtc,
+							 DRM_VBLANK_RELATIVE |
+							 DRM_VBLANK_EVENT,
+							 0, drm_queue_seq,
+							 NULL, NULL))
+					goto flip_error;
+				goto next;
+			}
+
+			fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+			if (!fb) {
+				ErrorF("Failed to get FB for TearFree flip\n");
+				goto error;
+			}
+
+			amdgpu_scanout_do_update(crtc, scanout_id,
+						 &new_front->drawable, &extents);
+
+			drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd,
+							drmmode_crtc->scanout_update_pending);
+		}
+
 		if (crtc == ref_crtc) {
 			if (drmmode_page_flip_target_absolute(pAMDGPUEnt,
 							      drmmode_crtc,
-							      flipdata->fb->handle,
+							      fb->handle,
 							      flip_flags,
 							      drm_queue_seq,
 							      target_msc) != 0)
@@ -2827,14 +2868,20 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
 		} else {
 			if (drmmode_page_flip_target_relative(pAMDGPUEnt,
 							      drmmode_crtc,
-							      flipdata->fb->handle,
+							      fb->handle,
 							      flip_flags,
 							      drm_queue_seq, 0) != 0)
 				goto flip_error;
 		}
 
-		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
-				     flipdata->fb);
+		if (drmmode_crtc->tear_free) {
+			drmmode_crtc->scanout_id ^= 1;
+			drmmode_crtc->ignore_damage = TRUE;
+		}
+
+	next:
+		drmmode_fb_reference(pAMDGPUEnt->fd,
+				     &drmmode_crtc->flip_pending, fb);
 		drm_queue_seq = 0;
 	}
 
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index b5788e295..1a6454c12 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -81,6 +81,7 @@ typedef struct {
 	struct drmmode_scanout rotate;
 	struct drmmode_scanout scanout[2];
 	DamagePtr scanout_damage;
+	Bool ignore_damage;
 	RegionRec scanout_last_region;
 	unsigned scanout_id;
 	Bool scanout_update_pending;
@@ -100,6 +101,14 @@ typedef struct {
 	struct drmmode_fb *flip_pending;
 	/* The FB currently being scanned out by this CRTC, if any */
 	struct drmmode_fb *fb;
+
+#ifdef HAVE_PRESENT_H
+	/* Deferred processing of Present vblank event */
+	uint64_t present_vblank_event_id;
+	uint64_t present_vblank_usec;
+	unsigned present_vblank_msc;
+	Bool present_flip_expected;
+#endif
 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
 
 typedef struct {
@@ -139,7 +148,8 @@ drmmode_crtc_can_flip(xf86CrtcPtr crtc)
 	return crtc->enabled &&
 		drmmode_crtc->dpms_mode == DPMSModeOn &&
 		!drmmode_crtc->rotate.bo &&
-		!drmmode_crtc->scanout[drmmode_crtc->scanout_id].bo;
+		(drmmode_crtc->tear_free ||
+		 !drmmode_crtc->scanout[drmmode_crtc->scanout_id].bo);
 }
 
 
-- 
2.14.1



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux