summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2018-04-14 12:36:57 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2018-04-15 15:47:37 +0100
commit02dfb9193f410fc81762bb3bf6cdf57cf12c0147 (patch)
treef357d2425b01b03f5c0fae14d2f4ca0de02f859b
parent16820c4bfcfcdfad7c787bc4d04e03f08ee8f80a (diff)
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@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_present.c82
1 files changed, 49 insertions, 33 deletions
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__));