xf86-video-intel: src/sna/sna_present.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Apr 15 14:48:13 UTC 2018


 src/sna/sna_present.c |   82 +++++++++++++++++++++++++++++---------------------
 1 file changed, 49 insertions(+), 33 deletions(-)

New commits:
commit 02dfb9193f410fc81762bb3bf6cdf57cf12c0147
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 14 12:36:57 2018 +0100

    sna/present: Only add the first element to the Timer queue
    
    TimerSet scales linearly with the number of elements in the queue as it
    performs an insertion sort, duplicating the sorting we also perform to
    keep the per-crtc vblank queue in an orderly fashion. As we already
    maintain the ordered timeline of vblanks, we can simply queue the next
    when the current vblank completes.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
index 523261cd..6bb7b927 100644
--- a/src/sna/sna_present.c
+++ b/src/sna/sna_present.c
@@ -45,7 +45,8 @@ struct sna_present_event {
 	uint64_t *event_id;
 	uint64_t target_msc;
 	int n_event_id;
-	bool queued;
+	bool queued:1;
+	bool active:1;
 };
 
 static void sna_present_unflip(ScreenPtr screen, uint64_t event_id);
@@ -140,31 +141,39 @@ static uint64_t gettime_ust64(void)
 static void vblank_complete(struct sna_present_event *info,
 			    uint64_t ust, uint64_t msc)
 {
+	struct list * const q = sna_crtc_vblank_queue(info->crtc);
 	int n;
 
-	if (msc_before(msc, info->target_msc)) {
-		DBG(("%s: event=%d too early, now %lld, expected %lld\n",
-		     __FUNCTION__,
-		     info->event_id[0],
-		     (long long)msc, (long long)info->target_msc));
-		if (sna_present_queue(info, msc))
-			return;
-	}
+	do {
+		assert(sna_crtc_vblank_queue(info->crtc) == q);
 
-	DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id));
-	for (n = 0; n < info->n_event_id; n++) {
-		DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__,
-		     sna_crtc_pipe(info->crtc),
-		     (int)(ust / 1000000), (int)(ust % 1000000),
-		     (long long)msc, (long long)info->target_msc,
-		     (long long)info->event_id[n],
-		     info->target_msc && msc == (uint32_t)info->target_msc ? "" : ": MISS"));
-		present_event_notify(info->event_id[n], ust, msc);
-	}
-	if (info->n_event_id > 1)
-		free(info->event_id);
-	list_del(&info->link);
-	info_free(info);
+		if (msc_before(msc, info->target_msc)) {
+			DBG(("%s: event=%d too early, now %lld, expected %lld\n",
+			     __FUNCTION__,
+			     info->event_id[0],
+			     (long long)msc, (long long)info->target_msc));
+			if (sna_present_queue(info, msc))
+				return;
+		}
+
+		DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id));
+		for (n = 0; n < info->n_event_id; n++) {
+			DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__,
+			     sna_crtc_pipe(info->crtc),
+			     (int)(ust / 1000000), (int)(ust % 1000000),
+			     (long long)msc, (long long)info->target_msc,
+			     (long long)info->event_id[n],
+			     info->target_msc && msc == (uint32_t)info->target_msc ? "" : ": MISS"));
+			present_event_notify(info->event_id[n], ust, msc);
+		}
+		if (info->n_event_id > 1)
+			free(info->event_id);
+
+		_list_del(&info->link);
+		info_free(info);
+
+		info = list_entry(info->link.next, typeof(*info), link);
+	} while (q != &info->link && !info->queued);
 }
 
 static uint32_t msc_to_delay(xf86CrtcPtr crtc, uint64_t target)
@@ -200,7 +209,7 @@ static uint32_t msc_to_delay(xf86CrtcPtr crtc, uint64_t target)
 static void add_to_crtc_vblank(struct sna_present_event *info,
 				int delta)
 {
-	info->queued = true;
+	info->active = true;
 	if (delta == 1 && info->crtc) {
 		sna_crtc_set_vblank(info->crtc);
 		info->crtc = mark_crtc(info->crtc);
@@ -214,6 +223,7 @@ static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
 	uint64_t msc, ust;
 
 	DBG(("%s(event=%lldx%d, now=%d)\n", __FUNCTION__, (long long)info->event_id[0], info->n_event_id, now));
+	assert(info->queued);
 
 	VG_CLEAR(vbl);
 	vbl.request.type = DRM_VBLANK_RELATIVE;
@@ -335,6 +345,7 @@ static bool sna_present_queue(struct sna_present_event *info,
 		add_to_crtc_vblank(info, delta);
 	}
 
+	info->queued = true;
 	return true;
 }
 
@@ -364,10 +375,11 @@ sna_present_get_crtc(WindowPtr window)
 
 static void add_keepalive(struct sna *sna, xf86CrtcPtr crtc, uint64_t msc)
 {
+	struct list *q = sna_crtc_vblank_queue(crtc);
 	struct sna_present_event *info, *tmp;
 	union drm_wait_vblank vbl;
 
-	list_for_each_entry(tmp, sna_crtc_vblank_queue(crtc), link) {
+	list_for_each_entry(tmp, q, link) {
 		if (tmp->target_msc == msc) {
 			DBG(("%s: vblank already queued for target_msc=%lld\n",
 			     __FUNCTION__, (long long)msc));
@@ -396,9 +408,10 @@ static void add_keepalive(struct sna *sna, xf86CrtcPtr crtc, uint64_t msc)
 	vbl.request.sequence = msc;
 	vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
 
-	if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
+	if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(crtc)) == 0) {
 		list_add_tail(&info->link, &tmp->link);
 		add_to_crtc_vblank(info, 1);
+		info->queued = true;
 	} else
 		info_free(info);
 }
@@ -446,8 +459,8 @@ sna_present_vblank_handler(struct drm_event_vblank *event)
 	struct sna_present_event *info = to_present_event(event->user_data);
 	uint64_t msc;
 
-	if (!info->queued) {
-		DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__));
+	if (!info->active) {
+		DBG(("%s: arrived unexpectedly early (not active)\n", __FUNCTION__));
 		assert(!has_vblank(info->crtc));
 		return;
 	}
@@ -469,6 +482,7 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	struct sna *sna = to_sna_from_screen(crtc->pScreen);
 	struct sna_present_event *info, *tmp;
 	const struct ust_msc *swap;
+	struct list *q;
 
 	if (!sna_crtc_is_on(crtc->devPrivate))
 		return BadAlloc;
@@ -490,7 +504,8 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	if (warn_unless(msc - swap->msc < 1ull<<31))
 		return BadValue;
 
-	list_for_each_entry(tmp, sna_crtc_vblank_queue(crtc->devPrivate), link) {
+	q = sna_crtc_vblank_queue(crtc->devPrivate);
+	list_for_each_entry(tmp, q, link) {
 		if (tmp->target_msc == msc) {
 			uint64_t *events = tmp->event_id;
 
@@ -532,8 +547,9 @@ sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
 	info->n_event_id = 1;
 	list_add_tail(&info->link, &tmp->link);
 	info->queued = false;
+	info->active = false;
 
-	if (!sna_present_queue(info, swap->msc)) {
+	if (info->link.prev == q && !sna_present_queue(info, swap->msc)) {
 		list_del(&info->link);
 		info_free(info);
 		return BadAlloc;
@@ -695,8 +711,8 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
 
 	DBG(("%s(sequence=%d): event=%lld\n", __FUNCTION__, event->sequence, (long long)info->event_id[0]));
 	assert(info->n_event_id == 1);
-	if (!info->queued) {
-		DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__));
+	if (!info->active) {
+		DBG(("%s: arrived unexpectedly early (not active)\n", __FUNCTION__));
 		return;
 	}
 
@@ -756,7 +772,7 @@ flip(struct sna *sna,
 	info->event_id[0] = event_id;
 	info->n_event_id = 1;
 	info->target_msc = target_msc;
-	info->queued = false;
+	info->active = false;
 
 	if (!sna_page_flip(sna, bo, present_flip_handler, info)) {
 		DBG(("%s: pageflip failed\n", __FUNCTION__));


More information about the xorg-commit mailing list