source: trunk/examples/qws/framebuffer/main.c@ 563

Last change on this file since 563 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 16.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the examples of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <stdlib.h>
43#include <unistd.h>
44#include <stdio.h>
45#include <fcntl.h>
46#include <linux/fb.h>
47#include <linux/kd.h>
48#include <sys/mman.h>
49#include <sys/ioctl.h>
50#include <sys/time.h>
51#include <string.h>
52#include <errno.h>
53
54struct fb_var_screeninfo vinfo;
55struct fb_fix_screeninfo finfo;
56char *frameBuffer = 0;
57int fbFd = 0;
58int ttyFd = 0;
59
60void printFixedInfo()
61{
62 printf("Fixed screen info:\n"
63 "\tid: %s\n"
64 "\tsmem_start: 0x%lx\n"
65 "\tsmem_len: %d\n"
66 "\ttype: %d\n"
67 "\ttype_aux: %d\n"
68 "\tvisual: %d\n"
69 "\txpanstep: %d\n"
70 "\typanstep: %d\n"
71 "\tywrapstep: %d\n"
72 "\tline_length: %d\n"
73 "\tmmio_start: 0x%lx\n"
74 "\tmmio_len: %d\n"
75 "\taccel: %d\n"
76 "\n",
77 finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
78 finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
79 finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
80 finfo.mmio_len, finfo.accel);
81}
82
83void printVariableInfo()
84{
85 printf("Variable screen info:\n"
86 "\txres: %d\n"
87 "\tyres: %d\n"
88 "\txres_virtual: %d\n"
89 "\tyres_virtual: %d\n"
90 "\tyoffset: %d\n"
91 "\txoffset: %d\n"
92 "\tbits_per_pixel: %d\n"
93 "\tgrayscale: %d\n"
94 "\tred: offset: %2d, length: %2d, msb_right: %2d\n"
95 "\tgreen: offset: %2d, length: %2d, msb_right: %2d\n"
96 "\tblue: offset: %2d, length: %2d, msb_right: %2d\n"
97 "\ttransp: offset: %2d, length: %2d, msb_right: %2d\n"
98 "\tnonstd: %d\n"
99 "\tactivate: %d\n"
100 "\theight: %d\n"
101 "\twidth: %d\n"
102 "\taccel_flags: 0x%x\n"
103 "\tpixclock: %d\n"
104 "\tleft_margin: %d\n"
105 "\tright_margin: %d\n"
106 "\tupper_margin: %d\n"
107 "\tlower_margin: %d\n"
108 "\thsync_len: %d\n"
109 "\tvsync_len: %d\n"
110 "\tsync: %d\n"
111 "\tvmode: %d\n"
112 "\n",
113 vinfo.xres, vinfo.yres, vinfo.xres_virtual, vinfo.yres_virtual,
114 vinfo.xoffset, vinfo.yoffset, vinfo.bits_per_pixel, vinfo.grayscale,
115 vinfo.red.offset, vinfo.red.length, vinfo.red.msb_right,
116 vinfo.green.offset, vinfo.green.length, vinfo.green.msb_right,
117 vinfo.blue.offset, vinfo.blue.length, vinfo.blue.msb_right,
118 vinfo.transp.offset, vinfo.transp.length, vinfo.transp.msb_right,
119 vinfo.nonstd, vinfo.activate, vinfo.height, vinfo.width,
120 vinfo.accel_flags, vinfo.pixclock, vinfo.left_margin,
121 vinfo.right_margin, vinfo.upper_margin, vinfo.lower_margin,
122 vinfo.hsync_len, vinfo.vsync_len, vinfo.sync, vinfo.vmode);
123}
124
125long switchToGraphicsMode()
126{
127 const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
128 const char * const *dev;
129 long oldMode = KD_TEXT;
130
131 for (dev = devs; *dev; ++dev) {
132 ttyFd = open(*dev, O_RDWR);
133 if (ttyFd != -1)
134 break;
135 printf("Opening tty device %s failed: %s\n", *dev, strerror(errno));
136 }
137
138 ioctl(ttyFd, KDGETMODE, &oldMode);
139 if (oldMode == KD_GRAPHICS) {
140 printf("Was in graphics mode already. Skipping\n");
141 return oldMode;
142 }
143 int ret = ioctl(ttyFd, KDSETMODE, KD_GRAPHICS);
144 if (ret == -1) {
145 printf("Switch to graphics mode failed: %s\n", strerror(errno));
146 return oldMode;
147 }
148
149 printf("Successfully switched to graphics mode.\n\n");
150
151 return oldMode;
152}
153
154void restoreTextMode(long oldMode)
155{
156 if (ttyFd == -1)
157 return;
158
159 ioctl(ttyFd, KDSETMODE, oldMode);
160 close(ttyFd);
161}
162
163struct fb_cmap oldPalette;
164struct fb_cmap palette;
165int paletteSize = 0;
166
167void initPalette_16()
168{
169 if (finfo.type == FB_TYPE_PACKED_PIXELS) {
170 // We'll setup a grayscale map for 4bpp linear
171 int val = 0;
172 int i;
173 for (i = 0; i < 16; ++i) {
174 palette.red[i] = (val << 8) | val;
175 palette.green[i] = (val << 8) | val;
176 palette.blue[i] = (val << 8) | val;
177 val += 17;
178 }
179 return;
180 }
181
182 // Default 16 colour palette
183 unsigned char reds[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0xFF, 0xA2,
184 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F,
185 0x00, 0x00, 0x00, 0x82 };
186 unsigned char greens[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0xC5,
187 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00,
188 0x00, 0x7F, 0x7F, 0x7F };
189 unsigned char blues[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0x11,
190 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F,
191 0x7F, 0x7F, 0x00, 0x00 };
192
193 int i;
194 for (i = 0; i < 16; ++i) {
195 palette.red[i] = ((reds[i]) << 8) | reds[i];
196 palette.green[i] = ((greens[i]) << 8) | greens[i];
197 palette.blue[i] = ((blues[i]) << 8) | blues[i];
198 palette.transp[i] = 0;
199 }
200}
201
202void initPalette_256()
203{
204 if (vinfo.grayscale) {
205 int i;
206 for (i = 0; i < 256; ++i) {
207 unsigned short c = (i << 8) | i;
208 palette.red[i] = c;
209 palette.green[i] = c;
210 palette.blue[i] = c;
211 palette.transp[i] = 0;
212 }
213 return;
214 }
215
216 // 6x6x6 216 color cube
217 int i = 0;
218 int ir, ig, ib;
219 for (ir = 0x0; ir <= 0xff; ir += 0x33) {
220 for (ig = 0x0; ig <= 0xff; ig += 0x33) {
221 for (ib = 0x0; ib <= 0xff; ib += 0x33) {
222 palette.red[i] = (ir << 8)|ir;
223 palette.green[i] = (ig << 8)|ig;
224 palette.blue[i] = (ib << 8)|ib;
225 palette.transp[i] = 0;
226 ++i;
227 }
228 }
229 }
230}
231
232void initPalette()
233{
234 switch (vinfo.bits_per_pixel) {
235 case 8: paletteSize = 256; break;
236 case 4: paletteSize = 16; break;
237 default: break;
238 }
239
240 if (!paletteSize)
241 return; /* not using a palette */
242
243 /* read old palette */
244 oldPalette.start = 0;
245 oldPalette.len = paletteSize;
246 oldPalette.red = (unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
247 oldPalette.green = (unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
248 oldPalette.blue=(unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
249 oldPalette.transp=(unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
250 if (ioctl(ttyFd, FBIOGETCMAP, &oldPalette) == -1)
251 perror("initPalette: error reading palette");
252
253 /* create new palette */
254 palette.start = 0;
255 palette.len = paletteSize;
256 palette.red = (unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
257 palette.green = (unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
258 palette.blue = (unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
259 palette.transp = (unsigned short*)malloc(sizeof(unsigned short)*paletteSize);
260 switch (paletteSize) {
261 case 16: initPalette_16(); break;
262 case 256: initPalette_256(); break;
263 default: break;
264 }
265
266 /* set new palette */
267 if (ioctl(ttyFd, FBIOPUTCMAP, &palette) == -1)
268 perror("initPalette: error setting palette");
269}
270
271void resetPalette()
272{
273 if (paletteSize == 0)
274 return;
275
276 if (ioctl(ttyFd, FBIOPUTCMAP, &oldPalette) == -1)
277 perror("resetPalette");
278
279 free(oldPalette.red);
280 free(oldPalette.green);
281 free(oldPalette.blue);
282 free(oldPalette.transp);
283
284 free(palette.red);
285 free(palette.green);
286 free(palette.blue);
287 free(palette.transp);
288}
289
290void drawRect_rgb32(int x0, int y0, int width, int height, int color)
291{
292 const int bytesPerPixel = 4;
293 const int stride = finfo.line_length / bytesPerPixel;
294
295 int *dest = (int*)(frameBuffer)
296 + (y0 + vinfo.yoffset) * stride
297 + (x0 + vinfo.xoffset);
298
299 int x, y;
300 for (y = 0; y < height; ++y) {
301 for (x = 0; x < width; ++x) {
302 dest[x] = color;
303 }
304 dest += stride;
305 }
306}
307
308void drawRect_rgb18(int x0, int y0, int width, int height, int color)
309{
310 const int bytesPerPixel = 3;
311 const int stride = finfo.line_length - width * bytesPerPixel;
312 const int red = (color & 0xff0000) >> 16;
313 const int green = (color & 0xff00) >> 8;
314 const int blue = (color & 0xff);
315 const unsigned int packed = (blue >> 2) |
316 ((green >> 2) << 6) |
317 ((red >> 2) << 12);
318 const char color18[3] = { packed & 0xff,
319 (packed & 0xff00) >> 8,
320 (packed & 0xff0000) >> 16 };
321
322 char *dest = (char*)(frameBuffer)
323 + (y0 + vinfo.yoffset) * stride
324 + (x0 + vinfo.xoffset);
325
326 int x, y;
327 for (y = 0; y < height; ++y) {
328 for (x = 0; x < width; ++x) {
329 *dest++ = color18[0];
330 *dest++ = color18[1];
331 *dest++ = color18[2];
332 }
333 dest += stride;
334 }
335}
336
337void drawRect_rgb16(int x0, int y0, int width, int height, int color)
338{
339 const int bytesPerPixel = 2;
340 const int stride = finfo.line_length / bytesPerPixel;
341 const int red = (color & 0xff0000) >> (16 + 3);
342 const int green = (color & 0xff00) >> (8 + 2);
343 const int blue = (color & 0xff) >> 3;
344 const short color16 = blue | (green << 5) | (red << (5 + 6));
345
346 short *dest = (short*)(frameBuffer)
347 + (y0 + vinfo.yoffset) * stride
348 + (x0 + vinfo.xoffset);
349
350 int x, y;
351 for (y = 0; y < height; ++y) {
352 for (x = 0; x < width; ++x) {
353 dest[x] = color16;
354 }
355 dest += stride;
356 }
357}
358
359void drawRect_rgb15(int x0, int y0, int width, int height, int color)
360{
361 const int bytesPerPixel = 2;
362 const int stride = finfo.line_length / bytesPerPixel;
363 const int red = (color & 0xff0000) >> (16 + 3);
364 const int green = (color & 0xff00) >> (8 + 3);
365 const int blue = (color & 0xff) >> 3;
366 const short color15 = blue | (green << 5) | (red << (5 + 5));
367
368 short *dest = (short*)(frameBuffer)
369 + (y0 + vinfo.yoffset) * stride
370 + (x0 + vinfo.xoffset);
371
372 int x, y;
373 for (y = 0; y < height; ++y) {
374 for (x = 0; x < width; ++x) {
375 dest[x] = color15;
376 }
377 dest += stride;
378 }
379}
380
381void drawRect_palette(int x0, int y0, int width, int height, int color)
382{
383 const int bytesPerPixel = 1;
384 const int stride = finfo.line_length / bytesPerPixel;
385 const unsigned char color8 = color;
386
387 unsigned char *dest = (unsigned char*)(frameBuffer)
388 + (y0 + vinfo.yoffset) * stride
389 + (x0 + vinfo.xoffset);
390
391 int x, y;
392 for (y = 0; y < height; ++y) {
393 for (x = 0; x < width; ++x) {
394 dest[x] = color8;
395 }
396 dest += stride;
397 }
398}
399
400void drawRect(int x0, int y0, int width, int height, int color)
401{
402 switch (vinfo.bits_per_pixel) {
403 case 32:
404 drawRect_rgb32(x0, y0, width, height, color);
405 break;
406 case 18:
407 drawRect_rgb18(x0, y0, width, height, color);
408 break;
409 case 16:
410 drawRect_rgb16(x0, y0, width, height, color);
411 break;
412 case 15:
413 drawRect_rgb15(x0, y0, width, height, color);
414 break;
415 case 8:
416 drawRect_palette(x0, y0, width, height, color);
417 break;
418 case 4:
419 drawRect_palette(x0, y0, width, height, color);
420 break;
421 default:
422 printf("Warning: drawRect() not implemented for color depth %i\n",
423 vinfo.bits_per_pixel);
424 break;
425 }
426}
427
428#define PERFORMANCE_RUN_COUNT 5
429void performSpeedTest(void* fb, int fbSize)
430{
431 int i, j, run;
432
433 struct timeval startTime, endTime;
434 unsigned long long results[PERFORMANCE_RUN_COUNT];
435 unsigned long long average;
436
437 unsigned int* testImage;
438
439 unsigned int randData[17] = {
440 0x3A428472, 0x724B84D3, 0x26B898AB, 0x7D980E3C, 0x5345A084,
441 0x6779B66B, 0x791EE4B4, 0x6E8EE3CC, 0x63AF504A, 0x18A21B33,
442 0x0E26EB73, 0x022F708E, 0x1740F3B0, 0x7E2C699D, 0x0E8A570B,
443 0x5F2C22FB, 0x6A742130
444 };
445
446 printf("Frame Buffer Performance test...\n");
447
448 for (run=0; run<PERFORMANCE_RUN_COUNT; ++run) {
449
450 /* Generate test image with random(ish) data: */
451 testImage = (unsigned int*) malloc(fbSize);
452 j = run;
453 for (i=0; i < (int)(fbSize / sizeof(int)); ++i) {
454 testImage[i] = randData[j];
455 j++;
456 if (j >= 17)
457 j = 0;
458 }
459
460 gettimeofday(&startTime, NULL);
461 memcpy(fb, testImage, fbSize);
462 gettimeofday(&endTime, NULL);
463
464 long secsDiff = endTime.tv_sec - startTime.tv_sec;
465 results[run] = secsDiff * 1000000 + (endTime.tv_usec - startTime.tv_usec);
466
467 free(testImage);
468 }
469
470
471 average = 0;
472 for (i=0; i<PERFORMANCE_RUN_COUNT; ++i)
473 average += results[i];
474 average = average / PERFORMANCE_RUN_COUNT;
475
476 printf(" Average: %llu usecs\n", average);
477 printf(" Bandwidth: %.03f MByte/Sec\n", (fbSize / 1048576.0) / ((double)average / 1000000.0));
478 printf(" Max. FPS: %.03f fps\n\n", 1000000.0 / (double)average);
479
480 /* Clear the framebuffer back to black again: */
481 memset(fb, 0, fbSize);
482}
483
484int main(int argc, char **argv)
485{
486 long int screensize = 0;
487 int doGraphicsMode = 1;
488 long oldKdMode = KD_TEXT;
489 const char *devfile = "/dev/fb0";
490 int nextArg = 1;
491
492 if (nextArg < argc) {
493 if (strncmp("nographicsmodeswitch", argv[nextArg],
494 strlen("nographicsmodeswitch")) == 0)
495 {
496 ++nextArg;
497 doGraphicsMode = 0;
498 }
499 }
500 if (nextArg < argc)
501 devfile = argv[nextArg++];
502
503 /* Open the file for reading and writing */
504 fbFd = open(devfile, O_RDWR);
505 if (fbFd == -1) {
506 perror("Error: cannot open framebuffer device");
507 exit(1);
508 }
509 printf("The framebuffer device was opened successfully.\n\n");
510
511 /* Get fixed screen information */
512 if (ioctl(fbFd, FBIOGET_FSCREENINFO, &finfo) == -1) {
513 perror("Error reading fixed information");
514 exit(2);
515 }
516
517 printFixedInfo();
518
519 /* Figure out the size of the screen in bytes */
520 screensize = finfo.smem_len;
521
522 /* Map the device to memory */
523 frameBuffer = (char *)mmap(0, screensize,
524 PROT_READ | PROT_WRITE, MAP_SHARED,
525 fbFd, 0);
526 if (frameBuffer == MAP_FAILED) {
527 perror("Error: Failed to map framebuffer device to memory");
528 exit(4);
529 }
530 printf("The framebuffer device was mapped to memory successfully.\n"
531 "\n");
532
533 if (doGraphicsMode)
534 oldKdMode = switchToGraphicsMode();
535
536 /* Get variable screen information */
537 if (ioctl(fbFd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
538 perror("Error reading variable information");
539 exit(3);
540 }
541
542 printVariableInfo();
543
544 performSpeedTest(frameBuffer, screensize);
545
546 initPalette();
547
548 if (paletteSize == 0) {
549 printf("Will draw 3 rectangles on the screen,\n"
550 "they should be colored red, green and blue (in that order).\n");
551 drawRect(vinfo.xres / 8, vinfo.yres / 8,
552 vinfo.xres / 4, vinfo.yres / 4,
553 0xffff0000);
554 drawRect(vinfo.xres * 3 / 8, vinfo.yres * 3 / 8,
555 vinfo.xres / 4, vinfo.yres / 4,
556 0xff00ff00);
557 drawRect(vinfo.xres * 5 / 8, vinfo.yres * 5 / 8,
558 vinfo.xres / 4, vinfo.yres / 4,
559 0xff0000ff);
560 } else {
561 printf("Will rectangles from the 16 first entries in the color palette"
562 " on the screen\n");
563 int y;
564 int x;
565 for (y = 0; y < 4; ++y) {
566 for (x = 0; x < 4; ++x) {
567 drawRect(vinfo.xres / 4 * x, vinfo.yres / 4 * y,
568 vinfo.xres / 4, vinfo.yres / 4,
569 4 * y + x);
570 }
571 }
572 }
573
574 sleep(5);
575
576 resetPalette();
577
578 printf(" Done.\n");
579
580 if (doGraphicsMode)
581 restoreTextMode(oldKdMode);
582
583 munmap(frameBuffer, screensize);
584 close(fbFd);
585 return 0;
586}
Note: See TracBrowser for help on using the repository browser.