wok-tiny view fbvnc/stuff/fbvnc.u @ rev 68

fbvnc: speedup
author Pascal Bellard <pascal.bellard@slitaz.org>
date Mon Sep 12 15:43:10 2011 +0200 (2011-09-12)
parents b529d4eabec0
children 067b5cbe1e8e
line source
1 --- draw.h
2 +++ draw.h
3 @@ -15,5 +15,11 @@
4 void fb_cmap(void);
6 /* helper functions */
7 +struct rgb_conv {
8 + int rshl, gshl;
9 + int rskp, gskp, bskp;
10 + int rmax, gmax, bmax;
11 +};
12 +void fill_rgb_conv(int mode, struct rgb_conv *s);
13 void fb_set(int r, int c, void *mem, int len);
14 unsigned fb_val(int r, int g, int b);
15 --- draw.c
16 +++ draw.c
17 @@ -72,11 +72,14 @@
19 int fb_init(void)
20 {
21 + int err = 1;
22 fd = open(FBDEV_PATH, O_RDWR);
23 if (fd == -1)
24 goto failed;
25 + err++;
26 if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
27 goto failed;
28 + err++;
29 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
30 goto failed;
31 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
32 @@ -85,6 +88,7 @@
33 ng = 1 << vinfo.blue.length;
34 nb = 1 << vinfo.green.length;
35 fb = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
36 + err++;
37 if (fb == MAP_FAILED)
38 goto failed;
39 fb_cmap_save(1);
40 @@ -93,7 +97,7 @@
41 failed:
42 perror("fb_init()");
43 close(fd);
44 - return 1;
45 + return err;
46 }
48 void fb_free(void)
49 @@ -123,16 +127,26 @@
50 memcpy(fb_mem(r) + (c + vinfo.xoffset) * bpp, mem, len * bpp);
51 }
53 +void fill_rgb_conv(int mode, struct rgb_conv *s)
54 +{
55 + int bits;
56 +
57 + bits = mode & 0xF; mode >>= 4;
58 + s->rshl = s->gshl = bits;
59 + s->bskp = 8 - bits; s->bmax = (1 << bits) -1;
60 + bits = mode & 0xF; mode >>= 4;
61 + s->rshl += bits;
62 + s->gskp = 8 - bits; s->gmax = (1 << bits) -1;
63 + bits = mode & 0xF;
64 + s->rskp = 8 - bits; s->rmax = (1 << bits) -1;
65 +}
66 +
67 unsigned fb_val(int r, int g, int b)
68 {
69 - switch (fb_mode() & 0x0fff) {
70 - default:
71 - fprintf(stderr, "fb_val: unknown fb_mode()\n");
72 - case 0x0888:
73 - return (r << 16) | (g << 8) | b;
74 - case 0x0565:
75 - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
76 - case 0x0233:
77 - return ((r >> 6) << 6) | ((g >> 5) << 3) | (b >> 5);
78 - }
79 + static struct rgb_conv c;
80 +
81 + if (c.rshl == 0)
82 + fill_rgb_conv(fb_mode(), &c);
83 + return ((r >> c.rskp) << c.rshl) | ((g >> c.gskp) << c.gshl)
84 + | (b >> c.bskp);
85 }
86 --- fbvnc.c
87 +++ fbvnc.c
88 @@ -1,4 +1,4 @@
89 -/*
90 +/* // TODO user/passwd RDP?
91 * fbvnc - a small linux framebuffer vnc viewer
92 *
93 * Copyright (C) 2009-2011 Ali Gholami Rudi
94 @@ -36,13 +36,15 @@
96 #define VNC_PORT "5900"
98 -#define MAXRES (1 << 21)
99 -#define MIN(a, b) ((a) < (b) ? (a) : (b))
100 +#define MAXRES (1 << 12)
102 static int cols, rows;
103 +static int srv_cols, srv_rows;
104 +static int or, oc;
105 static int mr, mc; /* mouse position */
107 static char buf[MAXRES];
108 +#define MAXPIX (MAXRES/sizeof(fbval_t))
110 static int vnc_connect(char *addr, char *port)
111 {
112 @@ -61,22 +63,26 @@
114 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) == -1) {
115 close(fd);
116 - freeaddrinfo(addrinfo);
117 - return -1;
118 + fd = -2;
119 }
120 freeaddrinfo(addrinfo);
121 return fd;
122 }
124 +static int bpp, vnc_mode;
125 +static struct rgb_conv format;
126 static int vnc_init(int fd)
127 {
128 - char vncver[] = "RFB 003.003\n";
129 + static int vncfmt[] = { 0x40888, 0x20565, 0x10233, 0 };
130 + char vncver[12];
131 + int i;
132 +
133 struct vnc_client_init clientinit;
134 struct vnc_server_init serverinit;
135 struct vnc_client_pixelfmt pixfmt_cmd;
136 int connstat = VNC_CONN_FAILED;
138 - write(fd, vncver, 12);
139 + write(fd, "RFB 003.003\n", 12);
140 read(fd, vncver, 12);
142 read(fd, &connstat, sizeof(connstat));
143 @@ -88,68 +94,78 @@
144 write(fd, &clientinit, sizeof(clientinit));
145 read(fd, &serverinit, sizeof(serverinit));
147 - if (fb_init())
148 - return -1;
149 - if (FBM_BPP(fb_mode()) != sizeof(fbval_t)) {
150 - fprintf(stderr, "fbvnc: fbval_t doesn't match fb depth\n");
151 - exit(1);
152 - }
153 - cols = MIN(ntohs(serverinit.w), fb_cols());
154 - rows = MIN(ntohs(serverinit.h), fb_rows());
155 + i = fb_init();
156 + if (i)
157 + return -1 - i;
158 + srv_cols = ntohs(serverinit.w);
159 + srv_rows = ntohs(serverinit.h);
160 + cols = MIN(srv_cols, fb_cols());
161 + rows = MIN(srv_rows, fb_rows());
162 mr = rows / 2;
163 mc = cols / 2;
164 + or = oc = 0;
166 read(fd, buf, ntohl(serverinit.len));
167 pixfmt_cmd.type = VNC_CLIENT_PIXFMT;
168 - pixfmt_cmd.format.bpp = 8;
169 - pixfmt_cmd.format.depth = 8;
170 pixfmt_cmd.format.bigendian = 0;
171 pixfmt_cmd.format.truecolor = 1;
173 - pixfmt_cmd.format.rmax = htons(3);
174 - pixfmt_cmd.format.gmax = htons(7);
175 - pixfmt_cmd.format.bmax = htons(7);
176 - pixfmt_cmd.format.rshl = 0;
177 - pixfmt_cmd.format.gshl = 2;
178 - pixfmt_cmd.format.bshl = 5;
179 -
180 + if (bpp < 1)
181 + bpp = 1;
182 + if (bpp >= 3)
183 + bpp = 4;
184 + for (i = 0; bpp <= FBM_BPP(vncfmt[i]); i++)
185 + vnc_mode = vncfmt[i];
186 + bpp = FBM_BPP(vnc_mode);
187 + pixfmt_cmd.format.bpp =
188 + pixfmt_cmd.format.depth = bpp << 3;
189 +
190 + fill_rgb_conv(FBM_COLORS(vnc_mode), &format);
191 + pixfmt_cmd.format.rmax = htons(format.rmax);
192 + pixfmt_cmd.format.gmax = htons(format.gmax);
193 + pixfmt_cmd.format.bmax = htons(format.bmax);
194 + pixfmt_cmd.format.rshl = format.rshl;
195 + pixfmt_cmd.format.gshl = format.gshl;
196 + pixfmt_cmd.format.bshl = 0;
197 write(fd, &pixfmt_cmd, sizeof(pixfmt_cmd));
198 return fd;
199 }
201 -static int vnc_free(void)
202 +static void vnc_free(void)
203 {
204 fb_free();
205 - return 0;
206 }
208 -static int vnc_refresh(int fd, int inc)
209 +static void vnc_refresh(int fd, int inc)
210 {
211 struct vnc_client_fbup fbup_req;
212 fbup_req.type = VNC_CLIENT_FBUP;
213 fbup_req.inc = inc;
214 - fbup_req.x = htons(0);
215 - fbup_req.y = htons(0);
216 - fbup_req.w = htons(cols);
217 - fbup_req.h = htons(rows);
218 + fbup_req.x = htons(oc);
219 + fbup_req.y = htons(or);
220 + fbup_req.w = htons(oc + cols);
221 + fbup_req.h = htons(or + rows);
222 write(fd, &fbup_req, sizeof(fbup_req));
223 - return 0;
224 }
226 -static void drawfb(char *s, int x, int y, int w, int h)
227 +static void drawfb(char *s, int x, int y, int w)
228 {
229 - fbval_t slice[1 << 14];
230 - int i, j;
231 - for (i = 0; i < h; i++) {
232 - for (j = 0; j < w; j++) {
233 - int c = *(unsigned char *) &s[i * w + j];
234 - int r = (c & 0x3) << 6;
235 - int g = ((c >> 2) & 0x7) << 5;
236 - int b = ((c >> 5) & 0x7) << 5;
237 - slice[j] = FB_VAL(r, g, b);
238 + int mode = fb_mode();
239 + if (mode != vnc_mode) {
240 + fbval_t slice[MAXRES];
241 + unsigned char *byte = (unsigned char *) slice;
242 + int j;
243 + int fb_bpp = FBM_BPP(mode);
244 + for (j = 0; j < w; j++, byte += fb_bpp, s += bpp) {
245 + fbval_t c = * (fbval_t *) s;
246 + int r = ((c >> format.rshl) & format.rmax) << format.rskp;
247 + int g = ((c >> format.gshl) & format.gmax) << format.gskp;
248 + int b = (c & format.bmax) << format.bskp;
249 + * (fbval_t *) byte = FB_VAL(r, g, b);
250 }
251 - fb_set(y + i, x, slice, w);
252 + s = (void *) slice;
253 }
254 + fb_set(y, x, s, w);
255 }
257 static void xread(int fd, void *buf, int len)
258 @@ -159,54 +175,79 @@
259 while (nr < len && (n = read(fd, buf + nr, len - nr)) > 0)
260 nr += n;
261 if (nr < len) {
262 - printf("partial vnc read!\n");
263 - exit(1);
264 + fprintf(stderr,"partial vnc read!\n");
265 + exit(99);
266 }
267 }
269 +static void skip(int fd, int len)
270 +{
271 + int n;
272 + while (len > 0 && (n = read(fd, buf, MIN(len, sizeof(buf)))) > 0)
273 + len -= n;
274 +}
275 +
276 static int vnc_event(int fd)
277 {
278 struct vnc_rect uprect;
279 - char msg[1 << 12];
280 - struct vnc_server_fbup *fbup = (void *) msg;
281 - struct vnc_server_cuttext *cuttext = (void *) msg;
282 - struct vnc_server_colormap *colormap = (void *) msg;
283 - int j;
284 - int n;
285 + union {
286 + struct vnc_server_fbup fbup;
287 + struct vnc_server_cuttext cuttext;
288 + struct vnc_server_colormap colormap;
289 + } msg;
290 + int j, n;
292 - if (read(fd, msg, 1) != 1)
293 + if (read(fd, &msg.fbup.type, 1) != 1)
294 return -1;
295 - switch (msg[0]) {
296 + switch (msg.fbup.type) {
297 case VNC_SERVER_FBUP:
298 - xread(fd, msg + 1, sizeof(*fbup) - 1);
299 - n = ntohs(fbup->n);
300 + xread(fd, &msg.fbup.pad, sizeof(msg.fbup) - 1);
301 + n = ntohs(msg.fbup.n);
302 for (j = 0; j < n; j++) {
303 - int x, y, w, h;
304 + int x, y, w, h, l, i;
305 xread(fd, &uprect, sizeof(uprect));
306 + if (uprect.enc != 0) {
307 + fprintf(stderr,"Encoding not RAW: %d\n",
308 + ntohl(uprect.enc));
309 + return -1;
310 + }
311 x = ntohs(uprect.x);
312 y = ntohs(uprect.y);
313 w = ntohs(uprect.w);
314 h = ntohs(uprect.h);
315 - if (x >= cols || x + w > cols)
316 - return -1;
317 - if (y >= rows || y + h > rows)
318 - return -1;
319 - xread(fd, buf, w * h);
320 - drawfb(buf, x, y, w, h);
321 + x -= oc;
322 + y -= or;
323 + i = 0;
324 + l = MIN(w, cols - x);
325 + if (x < 0) {
326 + l = MIN(w + x, cols);
327 + i = -x;
328 + x = 0;
329 + }
330 + for (; h--; y++) {
331 + int a, b, c = i;
332 + for (a = b = 0; w > b; b += a, c = 0) {
333 + a = MIN(w - b, MAXPIX);
334 + xread(fd, buf, a * bpp);
335 + if (y >= 0 && y < rows && l > b)
336 + drawfb(buf + (c * bpp), x + b,
337 + y, MIN(a, l - b) - c);
338 + }
339 + }
340 }
341 break;
342 case VNC_SERVER_BELL:
343 break;
344 case VNC_SERVER_CUTTEXT:
345 - xread(fd, msg + 1, sizeof(*cuttext) - 1);
346 - xread(fd, buf, ntohl(cuttext->len));
347 + xread(fd, &msg.cuttext.pad1, sizeof(msg.cuttext) - 1);
348 + skip(fd, ntohl(msg.cuttext.len));
349 break;
350 case VNC_SERVER_COLORMAP:
351 - xread(fd, msg + 1, sizeof(*colormap) - 1);
352 - xread(fd, buf, ntohs(colormap->n) * 3 * 2);
353 + xread(fd, &msg.colormap.pad, sizeof(msg.colormap) - 1);
354 + skip(fd, ntohs(msg.colormap.n) * 3 * 2);
355 break;
356 default:
357 - fprintf(stderr, "unknown vnc msg: %d\n", msg[0]);
358 + fprintf(stderr, "unknown vnc msg: %d\n", msg.fbup.type);
359 return -1;
360 }
361 return 0;
362 @@ -217,12 +258,31 @@
363 char ie[3];
364 struct vnc_client_ratevent me = {VNC_CLIENT_RATEVENT};
365 int mask = 0;
366 + int refresh = 2;
367 if (read(ratfd, &ie, sizeof(ie)) != 3)
368 return -1;
369 mc += ie[1];
370 mr -= ie[2];
371 - mc = MAX(0, MIN(cols - 1, mc));
372 - mr = MAX(0, MIN(rows - 1, mr));
373 + if (mc < oc) {
374 + if ((oc -= cols / 5) < 0)
375 + oc = 0;
376 + }
377 + else if (mc >= oc + cols && oc + cols < srv_cols) {
378 + if ((oc += cols / 5) > srv_cols - cols)
379 + oc = srv_cols - cols;
380 + }
381 + else refresh--;
382 + if (mr < or) {
383 + if ((or -= rows / 5) < 0)
384 + or = 0;
385 + }
386 + else if (mr >= or + rows && or + rows < srv_rows) {
387 + if ((or += rows / 5) > srv_rows - rows)
388 + or = srv_rows - rows;
389 + }
390 + else refresh--;
391 + mc = MAX(oc, MIN(oc + cols - 1, mc));
392 + mr = MAX(or, MIN(or + rows - 1, mr));
393 if (ie[0] & 0x01)
394 mask |= VNC_BUTTON1_MASK;
395 if (ie[0] & 0x04)
396 @@ -233,6 +293,8 @@
397 me.x = htons(mc);
398 me.mask = mask;
399 write(fd, &me, sizeof(me));
400 + if (refresh)
401 + vnc_refresh(fd, 0);
402 return 0;
403 }
405 @@ -292,12 +354,11 @@
406 k = 0xff0d;
407 break;
408 case 0x0c: /* ^L: redraw */
409 - if (vnc_refresh(fd, 0))
410 - return -1;
411 + vnc_refresh(fd, 0);
412 default:
413 k = (unsigned char) key[i];
414 }
415 - if (k >= 'A' && k <= 'Z' || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
416 + if ((k >= 'A' && k <= 'Z') || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
417 mod[nmod++] = 0xffe1;
418 if (k >= 1 && k <= 26) {
419 k = 'a' + k - 1;
420 @@ -339,40 +400,42 @@
421 write(STDIN_FILENO, show, strlen(show));
422 }
424 -static void mainloop(int vnc_fd, int kbd_fd, int rat_fd)
425 +static int mainloop(int vnc_fd, int kbd_fd, int rat_fd)
426 {
427 struct pollfd ufds[3];
428 int pending = 0;
429 int err;
430 ufds[0].fd = kbd_fd;
431 - ufds[0].events = POLLIN;
432 ufds[1].fd = vnc_fd;
433 - ufds[1].events = POLLIN;
434 ufds[2].fd = rat_fd;
435 + ufds[0].events =
436 + ufds[1].events =
437 ufds[2].events = POLLIN;
438 - if (vnc_refresh(vnc_fd, 0))
439 - return;
440 + vnc_refresh(vnc_fd, 0);
441 while (1) {
442 err = poll(ufds, 3, 500);
443 if (err == -1 && errno != EINTR)
444 break;
445 if (!err)
446 continue;
447 + err = -2;
448 if (ufds[0].revents & POLLIN)
449 if (kbd_event(vnc_fd, kbd_fd) == -1)
450 break;
451 + err--;
452 if (ufds[1].revents & POLLIN) {
453 if (vnc_event(vnc_fd) == -1)
454 break;
455 pending = 0;
456 }
457 + err--;
458 if (ufds[2].revents & POLLIN)
459 if (rat_event(vnc_fd, rat_fd) == -1)
460 break;
461 if (!pending++)
462 - if (vnc_refresh(vnc_fd, 1))
463 - break;
464 + vnc_refresh(vnc_fd, 1);
465 }
466 + return err;
467 }
469 int main(int argc, char * argv[])
470 @@ -380,27 +443,38 @@
471 char *port = VNC_PORT;
472 char *host = "127.0.0.1";
473 struct termios ti;
474 - int vnc_fd, rat_fd;
475 + int vnc_fd, rat_fd, status;
476 +
477 + if (argc < 2) {
478 + fprintf(stderr, "Usage : fbvnc [-bpp bits] server [port]\n");
479 + return 0;
480 + }
481 + if (*argv[1] == '-' && argc >= 3) {
482 + argc -= 2; argv += 2;
483 + bpp = atoi(argv[0]) >> 3;
484 + }
485 if (argc >= 2)
486 host = argv[1];
487 if (argc >= 3)
488 port = argv[2];
489 - if ((vnc_fd = vnc_connect(host, port)) == -1) {
490 - fprintf(stderr, "could not connect!\n");
491 + if ((vnc_fd = vnc_connect(host, port)) < 0) {
492 + fprintf(stderr, "could not connect! %s %s : %d\n",
493 + host,port,vnc_fd);
494 return 1;
495 }
496 - if (vnc_init(vnc_fd) == -1) {
497 - fprintf(stderr, "vnc init failed!\n");
498 - return 1;
499 + status = vnc_init(vnc_fd);
500 + if (status < 0) {
501 + fprintf(stderr, "vnc init failed! %d\n", status);
502 + return 2;
503 }
504 term_setup(&ti);
505 rat_fd = open("/dev/input/mice", O_RDONLY);
507 - mainloop(vnc_fd, 0, rat_fd);
508 + status = mainloop(vnc_fd, 0, rat_fd);
510 term_cleanup(&ti);
511 vnc_free();
512 close(vnc_fd);
513 close(rat_fd);
514 - return 0;
515 + return 2 - status;
516 }