Introduction
Introduction Statistics Contact Development Disclaimer Help
st-autosync-0.8.3.diff - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
st-autosync-0.8.3.diff (7328B)
---
1 From 1892290c3b0ef064083c8af4e4bec443a36ca5c8 Mon Sep 17 00:00:00 2001
2 From: "Avi Halachmi (:avih)" <[email protected]>
3 Date: Tue, 26 Feb 2019 22:37:49 +0200
4 Subject: [PATCH] auto-sync: draw on idle to avoid flicker/tearing
5
6 st could easily tear/flicker with animation or other unattended
7 output. This commit eliminates most of the tear/flicker.
8
9 Before this commit, the display timing had two "modes":
10
11 - Interactively, st was waiting fixed `1000/xfps` ms after forwarding
12 the kb/mouse event to the application and before drawing.
13
14 - Unattended, and specifically with animations, the draw frequency was
15 throttled to `actionfps`. Animation at a higher rate would throttle
16 and likely tear, and at lower rates it was tearing big frames
17 (specifically, when one `read` didn't get a full "frame").
18
19 The interactive behavior was decent, but it was impossible to get good
20 unattended-draw behavior even with carefully chosen configuration.
21
22 This commit changes the behavior such that it draws on idle instead of
23 using fixed latency/frequency. This means that it tries to draw only
24 when it's very likely that the application has completed its output
25 (or after some duration without idle), so it mostly succeeds to avoid
26 tear, flicker, and partial drawing.
27
28 The config values minlatency/maxlatency replace xfps/actionfps and
29 define the range which the algorithm is allowed to wait from the
30 initial draw-trigger until the actual draw. The range enables the
31 flexibility to choose when to draw - when least likely to flicker.
32
33 It also unifies the interactive and unattended behavior and config
34 values, which makes the code simpler as well - without sacrificing
35 latency during interactive use, because typically interactively idle
36 arrives very quickly, so the wait is typically minlatency.
37
38 While it only slighly improves interactive behavior, for animations
39 and other unattended-drawing it improves greatly, as it effectively
40 adapts to any [animation] output rate without tearing, throttling,
41 redundant drawing, or unnecessary delays (sounds impossible, but it
42 works).
43 ---
44 config.def.h | 11 +++--
45 x.c | 120 ++++++++++++++++++++++++---------------------------
46 2 files changed, 65 insertions(+), 66 deletions(-)
47
48 diff --git a/config.def.h b/config.def.h
49 index 0895a1f..fdbacfd 100644
50 --- a/config.def.h
51 +++ b/config.def.h
52 @@ -43,9 +43,14 @@ static unsigned int tripleclicktimeout = 600;
53 /* alt screens */
54 int allowaltscreen = 1;
55
56 -/* frames per second st should at maximum draw to the screen */
57 -static unsigned int xfps = 120;
58 -static unsigned int actionfps = 30;
59 +/*
60 + * draw latency range in ms - from new content/keypress/etc until drawi…
61 + * within this range, st draws when content stops arriving (idle). most…
62 + * near minlatency, but it waits longer for slow updates to avoid parti…
63 + * low minlatency will tear/flicker more, as it can "detect" idle too e…
64 + */
65 +static double minlatency = 8;
66 +static double maxlatency = 33;
67
68 /*
69 * blinking timeout (set to 0 to disable blinking) for the terminal bli…
70 diff --git a/x.c b/x.c
71 index e5f1737..cbbd11f 100644
72 --- a/x.c
73 +++ b/x.c
74 @@ -1867,10 +1867,9 @@ run(void)
75 XEvent ev;
76 int w = win.w, h = win.h;
77 fd_set rfd;
78 - int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw …
79 - int ttyfd;
80 - struct timespec drawtimeout, *tv = NULL, now, last, lastblink;
81 - long deltatime;
82 + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing;
83 + struct timespec seltv, *tv, now, lastblink, trigger;
84 + double timeout;
85
86 /* Waiting for window mapping */
87 do {
88 @@ -1891,82 +1890,77 @@ run(void)
89 ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd);
90 cresize(w, h);
91
92 - clock_gettime(CLOCK_MONOTONIC, &last);
93 - lastblink = last;
94 -
95 - for (xev = actionfps;;) {
96 + for (timeout = -1, drawing = 0, lastblink = (struct timespec){0…
97 FD_ZERO(&rfd);
98 FD_SET(ttyfd, &rfd);
99 FD_SET(xfd, &rfd);
100
101 + if (XPending(xw.dpy))
102 + timeout = 0; /* existing events might not set …
103 +
104 + seltv.tv_sec = timeout / 1E3;
105 + seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec);
106 + tv = timeout >= 0 ? &seltv : NULL;
107 +
108 if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NU…
109 if (errno == EINTR)
110 continue;
111 die("select failed: %s\n", strerror(errno));
112 }
113 - if (FD_ISSET(ttyfd, &rfd)) {
114 - ttyread();
115 - if (blinktimeout) {
116 - blinkset = tattrset(ATTR_BLINK);
117 - if (!blinkset)
118 - MODBIT(win.mode, 0, MODE_BLINK);
119 - }
120 - }
121 + clock_gettime(CLOCK_MONOTONIC, &now);
122
123 - if (FD_ISSET(xfd, &rfd))
124 - xev = actionfps;
125 + if (FD_ISSET(ttyfd, &rfd))
126 + ttyread();
127
128 - clock_gettime(CLOCK_MONOTONIC, &now);
129 - drawtimeout.tv_sec = 0;
130 - drawtimeout.tv_nsec = (1000 * 1E6)/ xfps;
131 - tv = &drawtimeout;
132 -
133 - dodraw = 0;
134 - if (blinktimeout && TIMEDIFF(now, lastblink) > blinktim…
135 - tsetdirtattr(ATTR_BLINK);
136 - win.mode ^= MODE_BLINK;
137 - lastblink = now;
138 - dodraw = 1;
139 - }
140 - deltatime = TIMEDIFF(now, last);
141 - if (deltatime > 1000 / (xev ? xfps : actionfps)) {
142 - dodraw = 1;
143 - last = now;
144 + xev = 0;
145 + while (XPending(xw.dpy)) {
146 + xev = 1;
147 + XNextEvent(xw.dpy, &ev);
148 + if (XFilterEvent(&ev, None))
149 + continue;
150 + if (handler[ev.type])
151 + (handler[ev.type])(&ev);
152 }
153
154 - if (dodraw) {
155 - while (XPending(xw.dpy)) {
156 - XNextEvent(xw.dpy, &ev);
157 - if (XFilterEvent(&ev, None))
158 - continue;
159 - if (handler[ev.type])
160 - (handler[ev.type])(&ev);
161 + /*
162 + * To reduce flicker and tearing, when new content or e…
163 + * triggers drawing, we first wait a bit to ensure we g…
164 + * everything, and if nothing new arrives - we draw.
165 + * We start with trying to wait minlatency ms. If more …
166 + * arrives sooner, we retry with shorter and shorter pr…
167 + * and eventually draw even without idle after maxlaten…
168 + * Typically this results in low latency while interact…
169 + * maximum latency intervals during `cat huge.txt`, and…
170 + * sync with periodic updates from animations/key-repea…
171 + */
172 + if (FD_ISSET(ttyfd, &rfd) || xev) {
173 + if (!drawing) {
174 + trigger = now;
175 + drawing = 1;
176 }
177 + timeout = (maxlatency - TIMEDIFF(now, trigger))…
178 + / maxlatency * minlatency;
179 + if (timeout > 0)
180 + continue; /* we have time, try to find…
181 + }
182
183 - draw();
184 - XFlush(xw.dpy);
185 -
186 - if (xev && !FD_ISSET(xfd, &rfd))
187 - xev--;
188 - if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &r…
189 - if (blinkset) {
190 - if (TIMEDIFF(now, lastblink) \
191 - > blinktimeout)…
192 - drawtimeout.tv_nsec = 1…
193 - } else {
194 - drawtimeout.tv_nsec = (…
195 - (blinktimeout -…
196 - TIMEDIFF(now,
197 - lastbli…
198 - }
199 - drawtimeout.tv_sec = \
200 - drawtimeout.tv_nsec / 1E9;
201 - drawtimeout.tv_nsec %= (long)1E…
202 - } else {
203 - tv = NULL;
204 - }
205 + /* idle detected or maxlatency exhausted -> draw */
206 + timeout = -1;
207 + if (blinktimeout && tattrset(ATTR_BLINK)) {
208 + timeout = blinktimeout - TIMEDIFF(now, lastblin…
209 + if (timeout <= 0) {
210 + if (-timeout > blinktimeout) /* start v…
211 + win.mode |= MODE_BLINK;
212 + win.mode ^= MODE_BLINK;
213 + tsetdirtattr(ATTR_BLINK);
214 + lastblink = now;
215 + timeout = blinktimeout;
216 }
217 }
218 +
219 + draw();
220 + XFlush(xw.dpy);
221 + drawing = 0;
222 }
223 }
224
225
226 base-commit: 43a395ae91f7d67ce694e65edeaa7bbc720dd027
227 --
228 2.17.1
229
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.