305
|
1 /*
|
|
2 * Video driver for Framebuffer device
|
|
3 * by Szabolcs Berecz <szabi@inf.elte.hu>
|
359
|
4 * (C) 2001
|
305
|
5 *
|
|
6 * Some idea and code borrowed from Chris Lawrence's ppmtofb-0.27
|
|
7 */
|
|
8
|
393
|
9 #define FBDEV "fbdev: "
|
|
10
|
225
|
11 #include <stdio.h>
|
|
12 #include <stdlib.h>
|
|
13 #include <string.h>
|
|
14 #include <fcntl.h>
|
|
15 #include <unistd.h>
|
|
16 #include <errno.h>
|
359
|
17 #include <ctype.h>
|
|
18 #include <assert.h>
|
225
|
19
|
|
20 #include <sys/mman.h>
|
|
21 #include <sys/ioctl.h>
|
|
22 #include <linux/fb.h>
|
|
23
|
|
24 #include "config.h"
|
|
25 #include "video_out.h"
|
|
26 #include "video_out_internal.h"
|
658
|
27 #include "fastmemcpy.h"
|
633
|
28 #include "sub.h"
|
225
|
29 #include "yuv2rgb.h"
|
|
30
|
|
31 LIBVO_EXTERN(fbdev)
|
|
32
|
|
33 static vo_info_t vo_info = {
|
|
34 "Framebuffer Device",
|
|
35 "fbdev",
|
|
36 "Szabolcs Berecz <szabi@inf.elte.hu>",
|
|
37 ""
|
|
38 };
|
|
39
|
950
|
40 extern void rgb15to16_mmx(char *s0, char *d0, int count);
|
379
|
41 extern int verbose;
|
|
42
|
359
|
43 /******************************
|
393
|
44 * fb.modes support *
|
359
|
45 ******************************/
|
|
46
|
|
47 typedef struct {
|
|
48 char *name;
|
|
49 uint32_t xres, yres, vxres, vyres, depth;
|
|
50 uint32_t pixclock, left, right, upper, lower, hslen, vslen;
|
|
51 uint32_t sync;
|
|
52 uint32_t vmode;
|
|
53 } fb_mode_t;
|
|
54
|
|
55 #define PRINT_LINENUM printf(" at line %d\n", line_num)
|
|
56
|
|
57 #define MAX_NR_TOKEN 16
|
|
58
|
|
59 #define MAX_LINE_LEN 1000
|
|
60
|
|
61 #define RET_EOF -1
|
|
62 #define RET_EOL -2
|
|
63
|
|
64 static int validate_mode(fb_mode_t *m)
|
|
65 {
|
|
66 if (!m->xres) {
|
|
67 printf("needs geometry ");
|
|
68 return 0;
|
|
69 }
|
|
70 if (!m->pixclock) {
|
|
71 printf("needs timings ");
|
|
72 return 0;
|
|
73 }
|
|
74 return 1;
|
|
75 }
|
|
76
|
|
77 static FILE *fp;
|
|
78 static int line_num = 0;
|
|
79 static char *line;
|
|
80 static char *token[MAX_NR_TOKEN];
|
|
81
|
|
82 static int get_token(int num)
|
|
83 {
|
|
84 static int read_nextline = 1;
|
|
85 static int line_pos;
|
|
86 int i;
|
|
87 char c;
|
|
88
|
|
89 if (num >= MAX_NR_TOKEN) {
|
|
90 printf("get_token(): max >= MAX_NR_TOKEN!");
|
|
91 goto out_eof;
|
|
92 }
|
|
93
|
|
94 if (read_nextline) {
|
|
95 if (!fgets(line, MAX_LINE_LEN, fp))
|
|
96 goto out_eof;
|
|
97 line_pos = 0;
|
|
98 ++line_num;
|
|
99 read_nextline = 0;
|
|
100 }
|
|
101 for (i = 0; i < num; i++) {
|
|
102 while (isspace(line[line_pos]))
|
|
103 ++line_pos;
|
|
104 if (line[line_pos] == '\0' || line[line_pos] == '#') {
|
|
105 read_nextline = 1;
|
|
106 goto out_eol;
|
|
107 }
|
|
108 token[i] = line + line_pos;
|
|
109 c = line[line_pos];
|
|
110 if (c == '"' || c == '\'') {
|
|
111 token[i]++;
|
|
112 while (line[++line_pos] != c && line[line_pos])
|
|
113 /* NOTHING */;
|
950
|
114 if (!line[line_pos])
|
|
115 goto out_eol;
|
|
116 line[line_pos] = ' ';
|
359
|
117 } else {
|
|
118 for (/* NOTHING */; !isspace(line[line_pos]) &&
|
|
119 line[line_pos]; line_pos++)
|
|
120 /* NOTHING */;
|
|
121 }
|
|
122 if (!line[line_pos]) {
|
|
123 read_nextline = 1;
|
|
124 if (i == num - 1)
|
|
125 goto out_ok;
|
|
126 goto out_eol;
|
|
127 }
|
950
|
128 line[line_pos++] = '\0';
|
359
|
129 }
|
|
130 out_ok:
|
|
131 return i;
|
|
132 out_eof:
|
|
133 return RET_EOF;
|
|
134 out_eol:
|
|
135 return RET_EOL;
|
|
136 }
|
|
137
|
|
138 static fb_mode_t *fb_modes = NULL;
|
|
139 static int nr_modes = 0;
|
|
140
|
|
141 static int parse_fbmode_cfg(char *cfgfile)
|
|
142 {
|
977
|
143 #define CHECK_IN_MODE_DEF\
|
|
144 do {\
|
|
145 if (!in_mode_def) {\
|
|
146 printf("'needs 'mode' first");\
|
|
147 goto err_out_print_linenum;\
|
|
148 }\
|
|
149 } while (0)
|
|
150
|
359
|
151 fb_mode_t *mode = NULL;
|
|
152 char *endptr; // strtoul()...
|
977
|
153 int in_mode_def = 0;
|
359
|
154 int tmp, i;
|
|
155
|
950
|
156 if (verbose > 0)
|
|
157 printf("Reading %s: ", cfgfile);
|
359
|
158
|
|
159 if ((fp = fopen(cfgfile, "r")) == NULL) {
|
|
160 printf("can't open '%s': %s\n", cfgfile, strerror(errno));
|
|
161 return -1;
|
|
162 }
|
|
163
|
|
164 if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) {
|
|
165 printf("can't get memory for 'line': %s\n", strerror(errno));
|
|
166 return -2;
|
|
167 }
|
|
168
|
|
169 /*
|
|
170 * check if the cfgfile starts with 'mode'
|
|
171 */
|
|
172 while ((tmp = get_token(1)) == RET_EOL)
|
|
173 /* NOTHING */;
|
|
174 if (tmp == RET_EOF)
|
|
175 goto out;
|
|
176 if (!strcmp(token[0], "mode"))
|
|
177 goto loop_enter;
|
|
178 goto err_out_parse_error;
|
|
179
|
|
180 while ((tmp = get_token(1)) != RET_EOF) {
|
|
181 if (tmp == RET_EOL)
|
|
182 continue;
|
|
183 if (!strcmp(token[0], "mode")) {
|
977
|
184 if (in_mode_def) {
|
|
185 printf("'endmode' required");
|
|
186 goto err_out_print_linenum;
|
|
187 }
|
359
|
188 if (!validate_mode(mode))
|
|
189 goto err_out_not_valid;
|
|
190 loop_enter:
|
|
191 if (!(fb_modes = (fb_mode_t *) realloc(fb_modes,
|
|
192 sizeof(fb_mode_t) * (nr_modes + 1)))) {
|
950
|
193 printf("can't realloc 'fb_modes' (nr_modes = %d):"
|
|
194 " %s\n", nr_modes, strerror(errno));
|
359
|
195 goto err_out;
|
|
196 }
|
|
197 mode=fb_modes + nr_modes;
|
|
198 ++nr_modes;
|
|
199 memset(mode,0,sizeof(fb_mode_t));
|
225
|
200
|
359
|
201 if (get_token(1) < 0)
|
|
202 goto err_out_parse_error;
|
|
203 for (i = 0; i < nr_modes - 1; i++) {
|
|
204 if (!strcmp(token[0], fb_modes[i].name)) {
|
|
205 printf("mode name '%s' isn't unique", token[0]);
|
|
206 goto err_out_print_linenum;
|
|
207 }
|
|
208 }
|
|
209 if (!(mode->name = strdup(token[0]))) {
|
|
210 printf("can't strdup -> 'name': %s\n", strerror(errno));
|
|
211 goto err_out;
|
|
212 }
|
977
|
213 in_mode_def = 1;
|
359
|
214 } else if (!strcmp(token[0], "geometry")) {
|
977
|
215 CHECK_IN_MODE_DEF;
|
359
|
216 if (get_token(5) < 0)
|
|
217 goto err_out_parse_error;
|
|
218 mode->xres = strtoul(token[0], &endptr, 0);
|
|
219 if (*endptr)
|
|
220 goto err_out_parse_error;
|
|
221 mode->yres = strtoul(token[1], &endptr, 0);
|
|
222 if (*endptr)
|
|
223 goto err_out_parse_error;
|
|
224 mode->vxres = strtoul(token[2], &endptr, 0);
|
|
225 if (*endptr)
|
|
226 goto err_out_parse_error;
|
|
227 mode->vyres = strtoul(token[3], &endptr, 0);
|
|
228 if (*endptr)
|
|
229 goto err_out_parse_error;
|
|
230 mode->depth = strtoul(token[4], &endptr, 0);
|
|
231 if (*endptr)
|
|
232 goto err_out_parse_error;
|
|
233 } else if (!strcmp(token[0], "timings")) {
|
977
|
234 CHECK_IN_MODE_DEF;
|
359
|
235 if (get_token(7) < 0)
|
|
236 goto err_out_parse_error;
|
|
237 mode->pixclock = strtoul(token[0], &endptr, 0);
|
|
238 if (*endptr)
|
|
239 goto err_out_parse_error;
|
|
240 mode->left = strtoul(token[1], &endptr, 0);
|
|
241 if (*endptr)
|
|
242 goto err_out_parse_error;
|
|
243 mode->right = strtoul(token[2], &endptr, 0);
|
|
244 if (*endptr)
|
|
245 goto err_out_parse_error;
|
|
246 mode->upper = strtoul(token[3], &endptr, 0);
|
|
247 if (*endptr)
|
|
248 goto err_out_parse_error;
|
|
249 mode->lower = strtoul(token[4], &endptr, 0);
|
|
250 if (*endptr)
|
|
251 goto err_out_parse_error;
|
|
252 mode->hslen = strtoul(token[5], &endptr, 0);
|
|
253 if (*endptr)
|
|
254 goto err_out_parse_error;
|
|
255 mode->vslen = strtoul(token[6], &endptr, 0);
|
|
256 if (*endptr)
|
|
257 goto err_out_parse_error;
|
|
258 } else if (!strcmp(token[0], "endmode")) {
|
977
|
259 CHECK_IN_MODE_DEF;
|
|
260 in_mode_def = 0;
|
383
|
261 } else if (!strcmp(token[0], "accel")) {
|
977
|
262 CHECK_IN_MODE_DEF;
|
383
|
263 if (get_token(1) < 0)
|
|
264 goto err_out_parse_error;
|
393
|
265 /*
|
|
266 * it's only used for text acceleration
|
|
267 * so we just ignore it.
|
|
268 */
|
359
|
269 } else if (!strcmp(token[0], "hsync")) {
|
977
|
270 CHECK_IN_MODE_DEF;
|
359
|
271 if (get_token(1) < 0)
|
|
272 goto err_out_parse_error;
|
|
273 if (!strcmp(token[0], "low"))
|
|
274 mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
|
|
275 else if(!strcmp(token[0], "high"))
|
|
276 mode->sync |= FB_SYNC_HOR_HIGH_ACT;
|
|
277 else
|
|
278 goto err_out_parse_error;
|
|
279 } else if (!strcmp(token[0], "vsync")) {
|
977
|
280 CHECK_IN_MODE_DEF;
|
359
|
281 if (get_token(1) < 0)
|
|
282 goto err_out_parse_error;
|
|
283 if (!strcmp(token[0], "low"))
|
|
284 mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
|
|
285 else if(!strcmp(token[0], "high"))
|
|
286 mode->sync |= FB_SYNC_VERT_HIGH_ACT;
|
|
287 else
|
|
288 goto err_out_parse_error;
|
|
289 } else if (!strcmp(token[0], "csync")) {
|
977
|
290 CHECK_IN_MODE_DEF;
|
359
|
291 if (get_token(1) < 0)
|
|
292 goto err_out_parse_error;
|
|
293 if (!strcmp(token[0], "low"))
|
|
294 mode->sync &= ~FB_SYNC_COMP_HIGH_ACT;
|
|
295 else if(!strcmp(token[0], "high"))
|
|
296 mode->sync |= FB_SYNC_COMP_HIGH_ACT;
|
|
297 else
|
|
298 goto err_out_parse_error;
|
|
299 } else if (!strcmp(token[0], "extsync")) {
|
977
|
300 CHECK_IN_MODE_DEF;
|
359
|
301 if (get_token(1) < 0)
|
|
302 goto err_out_parse_error;
|
|
303 if (!strcmp(token[0], "false"))
|
|
304 mode->sync &= ~FB_SYNC_EXT;
|
|
305 else if(!strcmp(token[0], "true"))
|
|
306 mode->sync |= FB_SYNC_EXT;
|
|
307 else
|
|
308 goto err_out_parse_error;
|
|
309 } else if (!strcmp(token[0], "laced")) {
|
977
|
310 CHECK_IN_MODE_DEF;
|
359
|
311 if (get_token(1) < 0)
|
|
312 goto err_out_parse_error;
|
|
313 if (!strcmp(token[0], "false"))
|
|
314 mode->vmode = FB_VMODE_NONINTERLACED;
|
|
315 else if (!strcmp(token[0], "true"))
|
|
316 mode->vmode = FB_VMODE_INTERLACED;
|
|
317 else
|
|
318 goto err_out_parse_error;
|
479
|
319 } else if (!strcmp(token[0], "double")) {
|
977
|
320 CHECK_IN_MODE_DEF;
|
359
|
321 if (get_token(1) < 0)
|
|
322 goto err_out_parse_error;
|
|
323 if (!strcmp(token[0], "false"))
|
|
324 ;
|
|
325 else if (!strcmp(token[0], "true"))
|
|
326 mode->vmode = FB_VMODE_DOUBLE;
|
|
327 else
|
|
328 goto err_out_parse_error;
|
|
329 } else
|
|
330 goto err_out_parse_error;
|
|
331 }
|
|
332 if (!validate_mode(mode))
|
|
333 goto err_out_not_valid;
|
|
334 out:
|
950
|
335 if (verbose > 0)
|
|
336 printf("%d modes\n", nr_modes);
|
359
|
337 free(line);
|
|
338 fclose(fp);
|
|
339 return nr_modes;
|
|
340 err_out_parse_error:
|
|
341 printf("parse error");
|
|
342 err_out_print_linenum:
|
|
343 PRINT_LINENUM;
|
|
344 err_out:
|
393
|
345 if (fb_modes) {
|
359
|
346 free(fb_modes);
|
393
|
347 fb_modes = NULL;
|
|
348 }
|
|
349 nr_modes = 0;
|
359
|
350 free(line);
|
|
351 free(fp);
|
|
352 return -2;
|
|
353 err_out_not_valid:
|
950
|
354 printf("previous mode is not correct");
|
359
|
355 goto err_out_print_linenum;
|
|
356 }
|
|
357
|
|
358 static fb_mode_t *find_mode_by_name(char *name)
|
|
359 {
|
|
360 int i;
|
|
361
|
658
|
362 for (i = 0; i < nr_modes; i++)
|
359
|
363 if (!strcmp(name, fb_modes[i].name))
|
|
364 return fb_modes + i;
|
|
365 return NULL;
|
|
366 }
|
|
367
|
393
|
368 static float dcf(fb_mode_t *m) //driving clock frequency
|
|
369 {
|
519
|
370 return 1e12f / m->pixclock;
|
393
|
371 }
|
|
372
|
|
373 static float hsf(fb_mode_t *m) //horizontal scan frequency
|
|
374 {
|
|
375 int htotal = m->left + m->xres + m->right + m->hslen;
|
|
376 return dcf(m) / htotal;
|
|
377 }
|
|
378
|
|
379 static float vsf(fb_mode_t *m) //vertical scan frequency
|
|
380 {
|
|
381 int vtotal = m->upper + m->yres + m->lower + m->vslen;
|
|
382 return hsf(m) / vtotal;
|
|
383 }
|
|
384
|
|
385 typedef struct {
|
|
386 float min;
|
|
387 float max;
|
418
|
388 } range_t;
|
393
|
389
|
418
|
390 static int in_range(range_t *r, float f)
|
393
|
391 {
|
658
|
392 for (/* NOTHING */; (r->min != -1 && r->max != -1); r++)
|
393
|
393 if (f >= r->min && f <= r->max)
|
|
394 return 1;
|
|
395 return 0;
|
|
396 }
|
|
397
|
418
|
398 static fb_mode_t *find_best_mode(int xres, int yres, range_t *hfreq,
|
|
399 range_t *vfreq, range_t *dotclock)
|
393
|
400 {
|
|
401 int i;
|
|
402 fb_mode_t *best = fb_modes;
|
519
|
403 fb_mode_t *curr;
|
|
404
|
|
405 /* find first working mode */
|
950
|
406 for (i = 0; i < nr_modes; i++, best++)
|
519
|
407 if (in_range(hfreq, hsf(best)) && in_range(vfreq, vsf(best)) &&
|
|
408 in_range(dotclock, dcf(best)))
|
|
409 break;
|
|
410
|
950
|
411 if (i == nr_modes)
|
519
|
412 return NULL;
|
950
|
413 if (i == nr_modes - 1)
|
519
|
414 return best;
|
393
|
415
|
950
|
416 if (verbose > 1)
|
|
417 printf(FBDEV "%dx%d\n", best->xres, best->yres);
|
|
418
|
|
419 for (curr = best + 1; i < nr_modes; i++, curr++) {
|
|
420 if (!in_range(hfreq, hsf(curr)) ||
|
|
421 !in_range(vfreq, vsf(curr)) ||
|
|
422 !in_range(dotclock, dcf(curr)))
|
519
|
423 continue;
|
|
424 if (verbose > 1)
|
|
425 printf(FBDEV "%dx%d ", curr->xres, curr->yres);
|
|
426 if ((best->xres < xres || best->yres < yres) &&
|
|
427 (curr->xres > best->xres ||
|
|
428 curr->yres > best->yres)) {
|
|
429 if (verbose > 1)
|
|
430 printf("better than %dx%d\n", best->xres,
|
|
431 best->yres);
|
|
432 best = curr;
|
|
433 } else if (curr->xres >= xres && curr->yres >= yres) {
|
393
|
434 if (curr->xres < best->xres && curr->yres < best->yres) {
|
519
|
435 if (verbose > 1)
|
|
436 printf("smaller than %dx%d\n",
|
|
437 best->xres, best->yres);
|
393
|
438 best = curr;
|
519
|
439 } else if (curr->xres == best->xres &&
|
|
440 curr->yres == best->yres &&
|
|
441 (vsf(curr) > vsf(best))) {
|
|
442 if (verbose > 1)
|
|
443 printf("faster screen refresh\n");
|
|
444 best = curr;
|
|
445 } else if (verbose > 1)
|
|
446 printf("\n");
|
|
447 } else if (verbose > 1)
|
|
448 printf("is too small\n");
|
393
|
449 }
|
|
450 return best;
|
|
451 }
|
|
452
|
418
|
453 static void set_bpp(struct fb_var_screeninfo *p, int bpp)
|
|
454 {
|
476
|
455 p->bits_per_pixel = (bpp + 1) & ~1;
|
1087
|
456 p->red.msb_right = p->green.msb_right = p->blue.msb_right = p->transp.msb_right = 0;
|
563
|
457 p->transp.offset = p->transp.length = 0;
|
950
|
458 p->blue.offset = 0;
|
418
|
459 switch (bpp) {
|
|
460 case 32:
|
563
|
461 p->transp.offset = 24;
|
|
462 p->transp.length = 8;
|
418
|
463 case 24:
|
|
464 p->red.offset = 16;
|
|
465 p->red.length = 8;
|
|
466 p->green.offset = 8;
|
|
467 p->green.length = 8;
|
550
|
468 p->blue.length = 8;
|
418
|
469 break;
|
|
470 case 16:
|
|
471 p->red.offset = 11;
|
550
|
472 p->green.length = 6;
|
418
|
473 p->red.length = 5;
|
|
474 p->green.offset = 5;
|
550
|
475 p->blue.length = 5;
|
418
|
476 break;
|
|
477 case 15:
|
|
478 p->red.offset = 10;
|
550
|
479 p->green.length = 5;
|
418
|
480 p->red.length = 5;
|
|
481 p->green.offset = 5;
|
550
|
482 p->blue.length = 5;
|
418
|
483 break;
|
|
484 }
|
|
485 }
|
|
486
|
|
487 static void fb_mode2fb_vinfo(fb_mode_t *m, struct fb_var_screeninfo *v)
|
|
488 {
|
|
489 v->xres = m->xres;
|
|
490 v->yres = m->yres;
|
|
491 v->xres_virtual = m->vxres;
|
|
492 v->yres_virtual = m->vyres;
|
|
493 set_bpp(v, m->depth);
|
|
494 v->pixclock = m->pixclock;
|
|
495 v->left_margin = m->left;
|
|
496 v->right_margin = m->right;
|
|
497 v->upper_margin = m->upper;
|
|
498 v->lower_margin = m->lower;
|
|
499 v->hsync_len = m->hslen;
|
|
500 v->vsync_len = m->vslen;
|
|
501 v->sync = m->sync;
|
|
502 v->vmode = m->vmode;
|
|
503 }
|
|
504
|
|
505 static range_t *str2range(char *s)
|
|
506 {
|
|
507 float tmp_min, tmp_max;
|
|
508 char *endptr = s; // to start the loop
|
|
509 range_t *r = NULL;
|
950
|
510 int i;
|
418
|
511
|
|
512 if (!s)
|
|
513 return NULL;
|
|
514 for (i = 0; *endptr; i++) {
|
|
515 if (*s == ',')
|
|
516 goto out_err;
|
538
|
517 if (!(r = (range_t *) realloc(r, sizeof(*r) * (i + 2)))) {
|
418
|
518 printf("can't realloc 'r'\n");
|
|
519 return NULL;
|
|
520 }
|
|
521 tmp_min = strtod(s, &endptr);
|
|
522 if (*endptr == 'k' || *endptr == 'K') {
|
|
523 tmp_min *= 1000.0;
|
|
524 endptr++;
|
|
525 } else if (*endptr == 'm' || *endptr == 'M') {
|
|
526 tmp_min *= 1000000.0;
|
|
527 endptr++;
|
|
528 }
|
|
529 if (*endptr == '-') {
|
|
530 tmp_max = strtod(endptr + 1, &endptr);
|
|
531 if (*endptr == 'k' || *endptr == 'K') {
|
|
532 tmp_max *= 1000.0;
|
|
533 endptr++;
|
|
534 } else if (*endptr == 'm' || *endptr == 'M') {
|
|
535 tmp_max *= 1000000.0;
|
|
536 endptr++;
|
|
537 }
|
|
538 if (*endptr != ',' && *endptr)
|
|
539 goto out_err;
|
|
540 } else if (*endptr == ',' || !*endptr) {
|
|
541 tmp_max = tmp_min;
|
|
542 } else
|
|
543 goto out_err;
|
|
544 r[i].min = tmp_min;
|
|
545 r[i].max = tmp_max;
|
950
|
546 if (r[i].min < 0 || r[i].max < 0)
|
|
547 goto out_err;
|
418
|
548 s = endptr + 1;
|
|
549 }
|
|
550 r[i].min = r[i].max = -1;
|
|
551 return r;
|
|
552 out_err:
|
|
553 if (r)
|
|
554 free(r);
|
|
555 return NULL;
|
|
556 }
|
|
557
|
359
|
558 /******************************
|
|
559 * vo_fbdev *
|
|
560 ******************************/
|
|
561
|
658
|
562 /* command line/config file options */
|
393
|
563 char *fb_dev_name = NULL;
|
|
564 char *fb_mode_cfgfile = "/etc/fb.modes";
|
|
565 char *fb_mode_name = NULL;
|
418
|
566 char *monitor_hfreq_str = NULL;
|
|
567 char *monitor_vfreq_str = NULL;
|
|
568 char *monitor_dotclock_str = NULL;
|
|
569
|
658
|
570 /* fb.modes related variables */
|
1087
|
571 static range_t *monitor_hfreq = NULL;
|
|
572 static range_t *monitor_vfreq = NULL;
|
|
573 static range_t *monitor_dotclock = NULL;
|
658
|
574 static fb_mode_t *fb_mode = NULL;
|
393
|
575
|
950
|
576 /* vt related variables */
|
1087
|
577 static int vt_fd;
|
|
578 static FILE *vt_fp;
|
|
579 static int vt_doit = 1;
|
950
|
580
|
658
|
581 /* vo_fbdev related variables */
|
225
|
582 static int fb_dev_fd;
|
|
583 static size_t fb_size;
|
|
584 static uint8_t *frame_buffer;
|
658
|
585 static uint8_t *L123123875; /* thx .so :) */
|
359
|
586 static struct fb_fix_screeninfo fb_finfo;
|
|
587 static struct fb_var_screeninfo fb_orig_vinfo;
|
|
588 static struct fb_var_screeninfo fb_vinfo;
|
481
|
589 static struct fb_cmap fb_oldcmap;
|
|
590 static int fb_cmap_changed = 0;
|
359
|
591 static int fb_pixel_size; // 32: 4 24: 3 16: 2 15: 2
|
|
592 static int fb_real_bpp; // 32: 24 24: 24 16: 16 15: 15
|
|
593 static int fb_bpp; // 32: 32 24: 24 16: 16 15: 15
|
393
|
594 static int fb_bpp_we_want; // 32: 32 24: 24 16: 16 15: 15
|
950
|
595 static int fb_line_len;
|
|
596 static int fb_xres;
|
|
597 static int fb_yres;
|
658
|
598 static void (*draw_alpha_p)(int w, int h, unsigned char *src,
|
|
599 unsigned char *srca, int stride, unsigned char *dst,
|
|
600 int dstride);
|
359
|
601
|
|
602 static uint8_t *next_frame;
|
225
|
603 static int in_width;
|
|
604 static int in_height;
|
|
605 static int out_width;
|
|
606 static int out_height;
|
950
|
607 static int first_row;
|
|
608 static int last_row;
|
225
|
609 static uint32_t pixel_format;
|
804
|
610 static int fs;
|
|
611 static int flip;
|
225
|
612
|
305
|
613 /*
|
|
614 * Note: this function is completely cut'n'pasted from
|
|
615 * Chris Lawrence's code.
|
311
|
616 * (modified a bit to fit in my code...)
|
305
|
617 */
|
|
618 struct fb_cmap *make_directcolor_cmap(struct fb_var_screeninfo *var)
|
|
619 {
|
|
620 /* Hopefully any DIRECTCOLOR device will have a big enough palette
|
|
621 * to handle mapping the full color depth.
|
|
622 * e.g. 8 bpp -> 256 entry palette
|
|
623 *
|
|
624 * We could handle some sort of gamma here
|
|
625 */
|
|
626 int i, cols, rcols, gcols, bcols;
|
|
627 uint16_t *red, *green, *blue;
|
|
628 struct fb_cmap *cmap;
|
|
629
|
|
630 rcols = 1 << var->red.length;
|
|
631 gcols = 1 << var->green.length;
|
|
632 bcols = 1 << var->blue.length;
|
|
633
|
|
634 /* Make our palette the length of the deepest color */
|
|
635 cols = (rcols > gcols ? rcols : gcols);
|
|
636 cols = (cols > bcols ? cols : bcols);
|
|
637
|
|
638 red = malloc(cols * sizeof(red[0]));
|
|
639 if(!red) {
|
|
640 printf("Can't allocate red palette with %d entries.\n", cols);
|
|
641 return NULL;
|
|
642 }
|
|
643 for(i=0; i< rcols; i++)
|
|
644 red[i] = (65535/(rcols-1)) * i;
|
|
645
|
|
646 green = malloc(cols * sizeof(green[0]));
|
|
647 if(!green) {
|
|
648 printf("Can't allocate green palette with %d entries.\n", cols);
|
|
649 free(red);
|
|
650 return NULL;
|
|
651 }
|
|
652 for(i=0; i< gcols; i++)
|
|
653 green[i] = (65535/(gcols-1)) * i;
|
|
654
|
|
655 blue = malloc(cols * sizeof(blue[0]));
|
|
656 if(!blue) {
|
|
657 printf("Can't allocate blue palette with %d entries.\n", cols);
|
|
658 free(red);
|
|
659 free(green);
|
|
660 return NULL;
|
|
661 }
|
|
662 for(i=0; i< bcols; i++)
|
|
663 blue[i] = (65535/(bcols-1)) * i;
|
|
664
|
|
665 cmap = malloc(sizeof(struct fb_cmap));
|
|
666 if(!cmap) {
|
|
667 printf("Can't allocate color map\n");
|
|
668 free(red);
|
|
669 free(green);
|
|
670 free(blue);
|
|
671 return NULL;
|
|
672 }
|
|
673 cmap->start = 0;
|
|
674 cmap->transp = 0;
|
|
675 cmap->len = cols;
|
|
676 cmap->red = red;
|
|
677 cmap->blue = blue;
|
|
678 cmap->green = green;
|
|
679 cmap->transp = NULL;
|
|
680
|
|
681 return cmap;
|
|
682 }
|
225
|
683
|
393
|
684 static int fb_preinit(void)
|
225
|
685 {
|
950
|
686 static int fb_preinit_done = 0;
|
|
687 static int fb_works = 0;
|
|
688
|
|
689 if (fb_preinit_done)
|
|
690 return fb_works;
|
|
691
|
393
|
692 if (!fb_dev_name && !(fb_dev_name = getenv("FRAMEBUFFER")))
|
|
693 fb_dev_name = "/dev/fb0";
|
|
694 if (verbose > 0)
|
|
695 printf(FBDEV "using %s\n", fb_dev_name);
|
225
|
696
|
393
|
697 if ((fb_dev_fd = open(fb_dev_name, O_RDWR)) == -1) {
|
|
698 printf(FBDEV "Can't open %s: %s\n", fb_dev_name, strerror(errno));
|
|
699 goto err_out;
|
|
700 }
|
|
701 if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo)) {
|
|
702 printf(FBDEV "Can't get VSCREENINFO: %s\n", strerror(errno));
|
|
703 goto err_out_fd;
|
|
704 }
|
418
|
705 fb_orig_vinfo = fb_vinfo;
|
393
|
706
|
663
|
707 fb_bpp = fb_vinfo.bits_per_pixel;
|
|
708
|
1076
|
709 if (fb_bpp == 8 && !vo_dbpp) {
|
|
710 printf(FBDEV "8 bpp output is not supported.\n");
|
|
711 goto err_out_fd;
|
|
712 }
|
|
713
|
663
|
714 /* 16 and 15 bpp is reported 16 bpp */
|
|
715 if (fb_bpp == 16)
|
|
716 fb_bpp = fb_vinfo.red.length + fb_vinfo.green.length +
|
|
717 fb_vinfo.blue.length;
|
|
718
|
418
|
719 if (vo_dbpp) {
|
|
720 if (vo_dbpp != 15 && vo_dbpp != 16 && vo_dbpp != 24 &&
|
|
721 vo_dbpp != 32) {
|
|
722 printf(FBDEV "can't switch to %d bpp\n", vo_dbpp);
|
1076
|
723 goto err_out_fd;
|
359
|
724 }
|
418
|
725 fb_bpp = vo_dbpp;
|
359
|
726 }
|
245
|
727
|
393
|
728 fb_preinit_done = 1;
|
|
729 fb_works = 1;
|
950
|
730 return 1;
|
393
|
731 err_out_fd:
|
|
732 close(fb_dev_fd);
|
|
733 fb_dev_fd = -1;
|
|
734 err_out:
|
|
735 fb_preinit_done = 1;
|
950
|
736 fb_works = 0;
|
|
737 return 0;
|
393
|
738 }
|
245
|
739
|
633
|
740 static void lots_of_printf(void)
|
|
741 {
|
|
742 if (verbose > 0) {
|
|
743 printf(FBDEV "var info:\n");
|
|
744 printf(FBDEV "xres: %u\n", fb_vinfo.xres);
|
|
745 printf(FBDEV "yres: %u\n", fb_vinfo.yres);
|
|
746 printf(FBDEV "xres_virtual: %u\n", fb_vinfo.xres_virtual);
|
|
747 printf(FBDEV "yres_virtual: %u\n", fb_vinfo.yres_virtual);
|
|
748 printf(FBDEV "xoffset: %u\n", fb_vinfo.xoffset);
|
|
749 printf(FBDEV "yoffset: %u\n", fb_vinfo.yoffset);
|
|
750 printf(FBDEV "bits_per_pixel: %u\n", fb_vinfo.bits_per_pixel);
|
|
751 printf(FBDEV "grayscale: %u\n", fb_vinfo.grayscale);
|
|
752 printf(FBDEV "red: %lu %lu %lu\n",
|
|
753 (unsigned long) fb_vinfo.red.offset,
|
|
754 (unsigned long) fb_vinfo.red.length,
|
|
755 (unsigned long) fb_vinfo.red.msb_right);
|
|
756 printf(FBDEV "green: %lu %lu %lu\n",
|
|
757 (unsigned long) fb_vinfo.green.offset,
|
|
758 (unsigned long) fb_vinfo.green.length,
|
|
759 (unsigned long) fb_vinfo.green.msb_right);
|
|
760 printf(FBDEV "blue: %lu %lu %lu\n",
|
|
761 (unsigned long) fb_vinfo.blue.offset,
|
|
762 (unsigned long) fb_vinfo.blue.length,
|
|
763 (unsigned long) fb_vinfo.blue.msb_right);
|
|
764 printf(FBDEV "transp: %lu %lu %lu\n",
|
|
765 (unsigned long) fb_vinfo.transp.offset,
|
|
766 (unsigned long) fb_vinfo.transp.length,
|
|
767 (unsigned long) fb_vinfo.transp.msb_right);
|
|
768 printf(FBDEV "nonstd: %u\n", fb_vinfo.nonstd);
|
|
769 if (verbose > 1) {
|
|
770 printf(FBDEV "activate: %u\n", fb_vinfo.activate);
|
|
771 printf(FBDEV "height: %u\n", fb_vinfo.height);
|
|
772 printf(FBDEV "width: %u\n", fb_vinfo.width);
|
|
773 printf(FBDEV "accel_flags: %u\n", fb_vinfo.accel_flags);
|
|
774 printf(FBDEV "timing:\n");
|
|
775 printf(FBDEV "pixclock: %u\n", fb_vinfo.pixclock);
|
|
776 printf(FBDEV "left_margin: %u\n", fb_vinfo.left_margin);
|
|
777 printf(FBDEV "right_margin: %u\n", fb_vinfo.right_margin);
|
|
778 printf(FBDEV "upper_margin: %u\n", fb_vinfo.upper_margin);
|
|
779 printf(FBDEV "lower_margin: %u\n", fb_vinfo.lower_margin);
|
|
780 printf(FBDEV "hsync_len: %u\n", fb_vinfo.hsync_len);
|
|
781 printf(FBDEV "vsync_len: %u\n", fb_vinfo.vsync_len);
|
|
782 printf(FBDEV "sync: %u\n", fb_vinfo.sync);
|
|
783 printf(FBDEV "vmode: %u\n", fb_vinfo.vmode);
|
|
784 }
|
|
785 printf(FBDEV "fix info:\n");
|
|
786 printf(FBDEV "framebuffer size: %d bytes\n", fb_finfo.smem_len);
|
|
787 printf(FBDEV "type: %lu\n", (unsigned long) fb_finfo.type);
|
|
788 printf(FBDEV "type_aux: %lu\n", (unsigned long) fb_finfo.type_aux);
|
|
789 printf(FBDEV "visual: %lu\n", (unsigned long) fb_finfo.visual);
|
|
790 printf(FBDEV "line_length: %lu bytes\n", (unsigned long) fb_finfo.line_length);
|
|
791 if (verbose > 1) {
|
|
792 printf(FBDEV "id: %.16s\n", fb_finfo.id);
|
|
793 printf(FBDEV "smem_start: %p\n", (void *) fb_finfo.smem_start);
|
|
794 printf(FBDEV "xpanstep: %u\n", fb_finfo.xpanstep);
|
|
795 printf(FBDEV "ypanstep: %u\n", fb_finfo.ypanstep);
|
|
796 printf(FBDEV "ywrapstep: %u\n", fb_finfo.ywrapstep);
|
|
797 printf(FBDEV "mmio_start: %p\n", (void *) fb_finfo.mmio_start);
|
|
798 printf(FBDEV "mmio_len: %u bytes\n", fb_finfo.mmio_len);
|
|
799 printf(FBDEV "accel: %u\n", fb_finfo.accel);
|
|
800 }
|
950
|
801 printf(FBDEV "fb_bpp: %d\n", fb_bpp);
|
|
802 printf(FBDEV "fb_real_bpp: %d\n", fb_real_bpp);
|
|
803 printf(FBDEV "fb_pixel_size: %d bytes\n", fb_pixel_size);
|
|
804 printf(FBDEV "other:\n");
|
|
805 printf(FBDEV "in_width: %d\n", in_width);
|
|
806 printf(FBDEV "in_height: %d\n", in_height);
|
|
807 printf(FBDEV "out_width: %d\n", out_width);
|
|
808 printf(FBDEV "out_height: %d\n", out_height);
|
|
809 printf(FBDEV "first_row: %d\n", first_row);
|
|
810 printf(FBDEV "last_row: %d\n", last_row);
|
|
811 if (verbose > 1)
|
|
812 printf(FBDEV "draw_alpha_p:%dbpp = %p\n", fb_bpp, draw_alpha_p);
|
633
|
813 }
|
|
814 }
|
658
|
815
|
950
|
816 static void vt_set_textarea(int u, int l)
|
|
817 {
|
|
818 /* how can I determine the font height?
|
|
819 * just use 16 for now
|
|
820 */
|
|
821 int urow = ((u + 15) / 16) + 1;
|
|
822 int lrow = l / 16;
|
|
823
|
|
824 if (verbose > 1)
|
|
825 printf(FBDEV "vt_set_textarea(%d,%d): %d,%d\n", u, l, urow, lrow);
|
|
826 fprintf(vt_fp, "\33[%d;%dr\33[%d;%dH", urow, lrow, lrow, 0);
|
|
827 fflush(vt_fp);
|
|
828 }
|
|
829
|
393
|
830 static uint32_t init(uint32_t width, uint32_t height, uint32_t d_width,
|
|
831 uint32_t d_height, uint32_t fullscreen, char *title,
|
|
832 uint32_t format)
|
|
833 {
|
950
|
834 struct fb_cmap *cmap;
|
|
835 int vm = fullscreen & 0x02;
|
|
836 int zoom = fullscreen & 0x04;
|
418
|
837
|
950
|
838 fs = fullscreen & 0x01;
|
|
839 flip = fullscreen & 0x08;
|
393
|
840
|
950
|
841 if (!fb_preinit())
|
393
|
842 return 1;
|
245
|
843
|
950
|
844 if (zoom) {
|
418
|
845 printf(FBDEV "-zoom is not supported\n");
|
|
846 return 1;
|
|
847 }
|
950
|
848 if (fb_mode_name && !vm) {
|
|
849 printf(FBDEV "-fbmode can only be used with -vm\n");
|
418
|
850 return 1;
|
|
851 }
|
950
|
852 if (vm && (parse_fbmode_cfg(fb_mode_cfgfile) < 0))
|
418
|
853 return 1;
|
950
|
854 if (d_width && (fs || vm)) {
|
418
|
855 out_width = d_width;
|
|
856 out_height = d_height;
|
|
857 } else {
|
|
858 out_width = width;
|
|
859 out_height = height;
|
|
860 }
|
|
861 in_width = width;
|
|
862 in_height = height;
|
|
863 pixel_format = format;
|
|
864
|
393
|
865 if (fb_mode_name) {
|
418
|
866 if (!(fb_mode = find_mode_by_name(fb_mode_name))) {
|
|
867 printf(FBDEV "can't find requested video mode\n");
|
|
868 return 1;
|
|
869 }
|
|
870 fb_mode2fb_vinfo(fb_mode, &fb_vinfo);
|
950
|
871 } else if (vm) {
|
418
|
872 monitor_hfreq = str2range(monitor_hfreq_str);
|
|
873 monitor_vfreq = str2range(monitor_vfreq_str);
|
|
874 monitor_dotclock = str2range(monitor_dotclock_str);
|
|
875 if (!monitor_hfreq || !monitor_vfreq || !monitor_dotclock) {
|
|
876 printf(FBDEV "you have to specify the capabilities of"
|
|
877 " the monitor.\n");
|
|
878 return 1;
|
|
879 }
|
|
880 if (!(fb_mode = find_best_mode(out_width, out_height,
|
|
881 monitor_hfreq, monitor_vfreq,
|
|
882 monitor_dotclock))) {
|
|
883 printf(FBDEV "can't find best video mode\n");
|
|
884 return 1;
|
|
885 }
|
519
|
886 printf(FBDEV "using mode %dx%d @ %.1fHz\n", fb_mode->xres,
|
|
887 fb_mode->yres, vsf(fb_mode));
|
418
|
888 fb_mode2fb_vinfo(fb_mode, &fb_vinfo);
|
359
|
889 }
|
418
|
890 fb_bpp_we_want = fb_bpp;
|
|
891 set_bpp(&fb_vinfo, fb_bpp);
|
359
|
892 fb_vinfo.xres_virtual = fb_vinfo.xres;
|
|
893 fb_vinfo.yres_virtual = fb_vinfo.yres;
|
245
|
894
|
359
|
895 if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_vinfo)) {
|
393
|
896 printf(FBDEV "Can't put VSCREENINFO: %s\n", strerror(errno));
|
|
897 return 1;
|
|
898 }
|
950
|
899
|
|
900 fb_pixel_size = fb_vinfo.bits_per_pixel / 8;
|
|
901 fb_real_bpp = fb_vinfo.red.length + fb_vinfo.green.length +
|
|
902 fb_vinfo.blue.length;
|
|
903 fb_bpp = (fb_pixel_size == 4) ? 32 : fb_real_bpp;
|
|
904 if (fb_bpp_we_want != fb_bpp)
|
1076
|
905 printf(FBDEV "requested %d bpp, got %d bpp!!!\n",
|
950
|
906 fb_bpp_we_want, fb_bpp);
|
|
907
|
|
908 switch (fb_bpp) {
|
|
909 case 32:
|
|
910 draw_alpha_p = vo_draw_alpha_rgb32;
|
|
911 break;
|
|
912 case 24:
|
|
913 draw_alpha_p = vo_draw_alpha_rgb24;
|
|
914 break;
|
|
915 case 16:
|
|
916 draw_alpha_p = vo_draw_alpha_rgb16;
|
|
917 break;
|
|
918 case 15:
|
|
919 draw_alpha_p = vo_draw_alpha_rgb15;
|
|
920 break;
|
|
921 }
|
|
922
|
|
923 if (flip & ((((pixel_format & 0xff) + 7) / 8) != fb_pixel_size)) {
|
|
924 printf(FBDEV "Flipped output with depth conversion is not "
|
|
925 "supported\n");
|
|
926 return 1;
|
|
927 }
|
|
928
|
|
929 fb_xres = fb_vinfo.xres;
|
|
930 fb_yres = fb_vinfo.yres;
|
|
931
|
|
932 if (vm || fs) {
|
|
933 out_width = fb_xres;
|
|
934 out_height = fb_yres;
|
|
935 }
|
|
936 if (out_width < in_width || out_height < in_height) {
|
|
937 printf(FBDEV "screensize is smaller than video size\n");
|
|
938 return 1;
|
|
939 }
|
|
940
|
|
941 first_row = (out_height - in_height) / 2;
|
|
942 last_row = (out_height + in_height) / 2;
|
|
943
|
618
|
944 if (ioctl(fb_dev_fd, FBIOGET_FSCREENINFO, &fb_finfo)) {
|
|
945 printf(FBDEV "Can't get FSCREENINFO: %s\n", strerror(errno));
|
|
946 return 1;
|
|
947 }
|
633
|
948
|
|
949 lots_of_printf();
|
245
|
950
|
633
|
951 if (fb_finfo.type != FB_TYPE_PACKED_PIXELS) {
|
|
952 printf(FBDEV "type %d not supported\n", fb_finfo.type);
|
|
953 return 1;
|
305
|
954 }
|
618
|
955
|
379
|
956 switch (fb_finfo.visual) {
|
393
|
957 case FB_VISUAL_TRUECOLOR:
|
|
958 break;
|
|
959 case FB_VISUAL_DIRECTCOLOR:
|
|
960 if (verbose > 0)
|
|
961 printf(FBDEV "creating cmap for directcolor\n");
|
481
|
962 if (ioctl(fb_dev_fd, FBIOGETCMAP, &fb_oldcmap)) {
|
393
|
963 printf(FBDEV "can't get cmap: %s\n",
|
|
964 strerror(errno));
|
|
965 return 1;
|
|
966 }
|
|
967 if (!(cmap = make_directcolor_cmap(&fb_vinfo)))
|
|
968 return 1;
|
|
969 if (ioctl(fb_dev_fd, FBIOPUTCMAP, cmap)) {
|
|
970 printf(FBDEV "can't put cmap: %s\n",
|
|
971 strerror(errno));
|
|
972 return 1;
|
|
973 }
|
481
|
974 fb_cmap_changed = 1;
|
393
|
975 free(cmap->red);
|
|
976 free(cmap->green);
|
|
977 free(cmap->blue);
|
|
978 free(cmap);
|
|
979 break;
|
|
980 default:
|
|
981 printf(FBDEV "visual: %d not yet supported\n",
|
|
982 fb_finfo.visual);
|
|
983 return 1;
|
245
|
984 }
|
618
|
985
|
950
|
986 fb_line_len = fb_finfo.line_length;
|
359
|
987 fb_size = fb_finfo.smem_len;
|
225
|
988 if ((frame_buffer = (uint8_t *) mmap(0, fb_size, PROT_READ | PROT_WRITE,
|
|
989 MAP_SHARED, fb_dev_fd, 0)) == (uint8_t *) -1) {
|
393
|
990 printf(FBDEV "Can't mmap %s: %s\n", fb_dev_name, strerror(errno));
|
|
991 return 1;
|
225
|
992 }
|
519
|
993 L123123875 = frame_buffer + (out_width - in_width) * fb_pixel_size /
|
950
|
994 2 + (out_height - in_height) * fb_line_len / 2;
|
229
|
995
|
393
|
996 if (verbose > 0) {
|
519
|
997 if (verbose > 1) {
|
393
|
998 printf(FBDEV "frame_buffer @ %p\n", frame_buffer);
|
519
|
999 printf(FBDEV "L123123875 @ %p\n", L123123875);
|
|
1000 }
|
950
|
1001 printf(FBDEV "pixel per line: %d\n", fb_line_len / fb_pixel_size);
|
379
|
1002 }
|
225
|
1003
|
278
|
1004 if (!(next_frame = (uint8_t *) malloc(in_width * in_height * fb_pixel_size))) {
|
393
|
1005 printf(FBDEV "Can't malloc next_frame: %s\n", strerror(errno));
|
225
|
1006 return 1;
|
|
1007 }
|
|
1008
|
950
|
1009 if (vt_doit && (vt_fd = open("/dev/tty", O_WRONLY)) == -1) {
|
|
1010 printf(FBDEV "can't open /dev/tty: %s\n", strerror(errno));
|
|
1011 vt_doit = 0;
|
|
1012 }
|
|
1013 if (vt_doit && !(vt_fp = fdopen(vt_fd, "w"))) {
|
|
1014 printf(FBDEV "can't fdopen /dev/tty: %s\n", strerror(errno));
|
|
1015 vt_doit = 0;
|
804
|
1016 }
|
950
|
1017
|
|
1018 if (vt_doit)
|
|
1019 vt_set_textarea(last_row, fb_yres);
|
|
1020
|
|
1021 if (fs || vm)
|
|
1022 memset(frame_buffer, '\0', fb_line_len * fb_yres);
|
|
1023
|
225
|
1024 if (format == IMGFMT_YV12)
|
359
|
1025 yuv2rgb_init(fb_bpp, MODE_RGB);
|
950
|
1026
|
225
|
1027 return 0;
|
|
1028 }
|
|
1029
|
|
1030 static uint32_t query_format(uint32_t format)
|
|
1031 {
|
658
|
1032 int ret = 0x4; /* osd/sub is supported on every bpp */
|
519
|
1033
|
950
|
1034 if (!fb_preinit())
|
305
|
1035 return 0;
|
|
1036
|
311
|
1037 if ((format & IMGFMT_BGR_MASK) == IMGFMT_BGR) {
|
|
1038 int bpp = format & 0xff;
|
519
|
1039
|
359
|
1040 if (bpp == fb_bpp)
|
519
|
1041 return ret|0x2;
|
359
|
1042 else if (bpp == 15 && fb_bpp == 16)
|
519
|
1043 return ret|0x1;
|
359
|
1044 else if (bpp == 24 && fb_bpp == 32)
|
519
|
1045 return ret|0x1;
|
311
|
1046 }
|
|
1047 if (format == IMGFMT_YV12)
|
658
|
1048 return ret|0x1;
|
311
|
1049 return 0;
|
225
|
1050 }
|
|
1051
|
|
1052 static const vo_info_t *get_info(void)
|
|
1053 {
|
|
1054 return &vo_info;
|
|
1055 }
|
|
1056
|
|
1057 static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
|
|
1058 unsigned char *srca, int stride)
|
|
1059 {
|
658
|
1060 unsigned char *dst = next_frame + (in_width * y0 + x0) * fb_pixel_size;
|
359
|
1061 int dstride = in_width * fb_pixel_size;
|
|
1062
|
658
|
1063 (*draw_alpha_p)(w, h, src, srca, stride, dst, dstride);
|
225
|
1064 }
|
|
1065
|
|
1066 static uint32_t draw_frame(uint8_t *src[])
|
|
1067 {
|
|
1068 if (pixel_format == IMGFMT_YV12) {
|
|
1069 yuv2rgb(next_frame, src[0], src[1], src[2], in_width,
|
278
|
1070 in_height, in_width * fb_pixel_size,
|
225
|
1071 in_width, in_width / 2);
|
804
|
1072 } else if (flip) {
|
|
1073 int h = in_height;
|
|
1074 int len = in_width * fb_pixel_size;
|
|
1075 char *d = next_frame + (in_height - 1) * len;
|
|
1076 char *s = src[0];
|
|
1077 while (h--) {
|
|
1078 memcpy(d, s, len);
|
|
1079 s += len;
|
|
1080 d -= len;
|
|
1081 }
|
311
|
1082 } else {
|
|
1083 int sbpp = ((pixel_format & 0xff) + 7) / 8;
|
|
1084 char *d = next_frame;
|
|
1085 char *s = src[0];
|
|
1086 if (sbpp == fb_pixel_size) {
|
359
|
1087 if (fb_real_bpp == 16 && pixel_format == (IMGFMT_BGR|15)) {
|
311
|
1088 #ifdef HAVE_MMX
|
|
1089 rgb15to16_mmx(s, d, 2 * in_width * in_height);
|
|
1090 #else
|
|
1091 unsigned short *s1 = (unsigned short *) s;
|
|
1092 unsigned short *d1 = (unsigned short *) d;
|
|
1093 unsigned short *e = s1 + in_width * in_height;
|
|
1094 while (s1<e) {
|
|
1095 register x = *(s1++);
|
|
1096 *(d1++) = (x&0x001f)|((x&0x7fe0)<<1);
|
|
1097 }
|
|
1098 #endif
|
|
1099 } else
|
|
1100 memcpy(d, s, sbpp * in_width * in_height);
|
|
1101 }
|
|
1102 }
|
225
|
1103 return 0;
|
|
1104 }
|
|
1105
|
|
1106 static uint32_t draw_slice(uint8_t *src[], int stride[], int w, int h, int x,
|
|
1107 int y)
|
|
1108 {
|
|
1109 uint8_t *dest;
|
|
1110
|
278
|
1111 dest = next_frame + (in_width * y + x) * fb_pixel_size;
|
|
1112 yuv2rgb(dest, src[0], src[1], src[2], w, h, in_width * fb_pixel_size,
|
225
|
1113 stride[0], stride[1]);
|
|
1114 return 0;
|
|
1115 }
|
|
1116
|
|
1117 static void check_events(void)
|
|
1118 {
|
|
1119 }
|
|
1120
|
519
|
1121 static void put_frame(void)
|
225
|
1122 {
|
|
1123 int i, out_offset = 0, in_offset = 0;
|
|
1124
|
|
1125 for (i = 0; i < in_height; i++) {
|
519
|
1126 memcpy(L123123875 + out_offset, next_frame + in_offset,
|
423
|
1127 in_width * fb_pixel_size);
|
950
|
1128 out_offset += fb_line_len;
|
278
|
1129 in_offset += in_width * fb_pixel_size;
|
225
|
1130 }
|
|
1131 }
|
|
1132
|
246
|
1133 static void flip_page(void)
|
|
1134 {
|
|
1135 vo_draw_text(in_width, in_height, draw_alpha);
|
|
1136 check_events();
|
519
|
1137 put_frame();
|
246
|
1138 }
|
|
1139
|
225
|
1140 static void uninit(void)
|
|
1141 {
|
379
|
1142 if (verbose > 0)
|
393
|
1143 printf(FBDEV "uninit\n");
|
481
|
1144 if (fb_cmap_changed) {
|
|
1145 if (ioctl(fb_dev_fd, FBIOPUTCMAP, &fb_oldcmap))
|
393
|
1146 printf(FBDEV "Can't restore original cmap\n");
|
481
|
1147 fb_cmap_changed = 0;
|
306
|
1148 }
|
503
|
1149 free(next_frame);
|
|
1150 if (ioctl(fb_dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo))
|
|
1151 printf(FBDEV "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno));
|
|
1152 fb_orig_vinfo.xoffset = fb_vinfo.xoffset;
|
|
1153 fb_orig_vinfo.yoffset = fb_vinfo.yoffset;
|
379
|
1154 if (ioctl(fb_dev_fd, FBIOPUT_VSCREENINFO, &fb_orig_vinfo))
|
503
|
1155 printf(FBDEV "Can't reset original fb_var_screeninfo: %s\n", strerror(errno));
|
950
|
1156 if (vt_doit)
|
|
1157 vt_set_textarea(0, fb_orig_vinfo.yres);
|
359
|
1158 close(fb_dev_fd);
|
225
|
1159 munmap(frame_buffer, fb_size);
|
|
1160 }
|