1 /******************************************************************************
3 * test program for the tuxbox-framebuffer device
4 * tests all GTX/eNX supported modes
6 * (c) 2003 Carsten Juttner (carjay@gmx.net)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * The Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 ******************************************************************************
23 * $Id: fbtest.c,v 1.5 2005/01/14 23:14:41 carjay Exp $
24 ******************************************************************************/
26 // TODO: - should restore the colour map and mode to what it was before
27 // - is colour map handled correctly?
34 #include <sys/types.h>
36 #include <sys/ioctl.h>
44 #define FBDEV "/dev/fb0"
51 const struct vidsize vidsizetable
[]={ // all supported sizes
52 {720,576},{720,480},{720,288},{720,240},
53 {640,576},{640,480},{640,288},{640,240},
54 {360,576},{360,480},{360,288},{360,240},
55 {320,576},{320,480},{320,288},{320,240}
57 #define VIDSIZENUM (sizeof(vidsizetable)/sizeof(struct vidsize))
59 enum pixenum
{ // keep in sync with pixname !
66 const char *pixname
[] = {
76 struct fb_bitfield red
;
77 struct fb_bitfield green
;
78 struct fb_bitfield blue
;
79 struct fb_bitfield transp
;
84 static // so far these are all modes supported by the eNX (only partially by GTX)
85 const struct pixelformat pixelformattable
[] = {
86 { .name
= "CLUT4 ARGB8888", // CLUT4 (ARGB8888)
87 .bpp
= 4, .pixenum
= CLUT4
,
88 .red
= { .offset
= 0, .length
=8, .msb_right
=0 },
89 .green
= { .offset
= 0, .length
=8, .msb_right
=0 },
90 .blue
= { .offset
= 0, .length
=8, .msb_right
=0 },
91 .transp
= { .offset
= 0, .length
=8, .msb_right
=0 }
93 { .name
= "CLUT4 ARGB1555", // CLUT4 (ARGB1555)
94 .bpp
= 4, .pixenum
= CLUT4
,
95 .red
= { .offset
= 0, .length
=5, .msb_right
=0 },
96 .green
= { .offset
= 0, .length
=5, .msb_right
=0 },
97 .blue
= { .offset
= 0, .length
=5, .msb_right
=0 },
98 .transp
= { .offset
= 0, .length
=1, .msb_right
=0 }
100 { .name
= "CLUT8 ARGB8888", // CLUT8 (ARGB8888)
101 .bpp
= 8, .pixenum
= CLUT8
,
102 .red
= { .offset
= 0, .length
=8, .msb_right
=0 },
103 .green
= { .offset
= 0, .length
=8, .msb_right
=0 },
104 .blue
= { .offset
= 0, .length
=8, .msb_right
=0 },
105 .transp
= { .offset
= 0, .length
=8, .msb_right
=0 }
107 { .name
= "CLUT8 ARGB1555", // CLUT8 (ARGB1555)
108 .bpp
= 8, .pixenum
= CLUT8
,
109 .red
= { .offset
= 0, .length
=5, .msb_right
=0 },
110 .green
= { .offset
= 0, .length
=5, .msb_right
=0 },
111 .blue
= { .offset
= 0, .length
=5, .msb_right
=0 },
112 .transp
= { .offset
= 0, .length
=1, .msb_right
=0 }
114 { .name
= "ARGB1555", // ARGB1555
115 .bpp
= 16, .pixenum
= ARGB1555
,
116 .red
= { .offset
= 10, .length
=5, .msb_right
=0 },
117 .green
= { .offset
= 5, .length
=5, .msb_right
=0 },
118 .blue
= { .offset
= 0, .length
=5, .msb_right
=0 },
119 .transp
= { .offset
= 15, .length
=1, .msb_right
=0 }
121 { .name
= "RGB565", // RGB565
122 .bpp
= 16, .pixenum
= RGB565
,
123 .red
= { .offset
= 11, .length
=5, .msb_right
=0 },
124 .green
= { .offset
= 5, .length
=6, .msb_right
=0 },
125 .blue
= { .offset
= 0, .length
=5, .msb_right
=0 },
126 .transp
= { .offset
= 0, .length
=0, .msb_right
=0 }
128 { .name
= "ARGB", // 32 f*cking bits, the real McCoy :)
129 .bpp
= 32, .pixenum
= ARGB
,
130 .red
= { .offset
= 16, .length
=8, .msb_right
=0 },
131 .green
= { .offset
= 8, .length
=8, .msb_right
=0 },
132 .blue
= { .offset
= 0, .length
=8, .msb_right
=0 },
133 .transp
= { .offset
= 24, .length
=8, .msb_right
=0 }
136 #define PIXELFORMATNUM (sizeof(pixelformattable)/sizeof(struct pixelformat))
145 struct colour colourtable
[] = {
146 {.r
=0xffff, .g
= 0xffff, .b
=0xffff, .a
=0xffff}, // fully transparent white
147 {.r
=0xffff, .g
= 0x0000, .b
=0x0000, .a
=0x0000}, // red
148 {.r
=0x0000, .g
= 0xffff, .b
=0x0000, .a
=0x0000}, // green
149 {.r
=0x0000, .g
= 0x0000, .b
=0xffff, .a
=0x0000}, // blue
150 {.r
=0x0000, .g
= 0x0000, .b
=0x0000, .a
=0x0000} // black
152 #define COLOURNUM (sizeof(colourtable)/sizeof(struct colour))
159 const struct colour
*col
;
161 struct pixel
{ // up to 32 bits of pixel information
165 void col2pixel (struct pixel
*pix
, const struct pixelformat
*pixf
, const struct colour
*col
){
166 switch (pixf
->pixenum
){
168 pix
->byte
[0]=(col
->r
&0xf8)|(col
->g
&0xfc)>>5;
169 pix
->byte
[1]=(col
->g
&0xfc)<<3|(col
->b
&0xf8)>>3;
172 pix
->byte
[0]=(col
->a
&0x80)|(col
->r
&0xf8)>>1|(col
->g
&0xf8)>>6;
173 pix
->byte
[1]=(col
->g
&0xf8)<<2|(col
->b
&0xf8)>>3;
182 printf ("unknown pixelformat\n");
187 int setmode(int fbd
, const struct pixelformat
*pixf
,const struct vidsize
*vids
){
188 struct fb_var_screeninfo var
;
190 stat
= ioctl (fbd
, FBIOGET_VSCREENINFO
,&var
);
191 if (stat
<0) return -2;
193 var
.xres
= vids
->width
;
194 var
.xres_virtual
= vids
->width
;
195 var
.yres
= vids
->height
;
196 var
.yres_virtual
= vids
->height
;
198 var
.bits_per_pixel
= pixf
->bpp
;
200 var
.green
= pixf
->green
;
201 var
.blue
= pixf
->blue
;
202 var
.transp
= pixf
->transp
;
204 stat
= ioctl (fbd
, FBIOPUT_VSCREENINFO
,&var
);
205 if (stat
<0) return -1;
209 // unefficient implementation, do NOT use it for your next ego shooter, please :)
210 // for 4-Bit only rectangles with even width are supported
211 // CLUT-modes use value of red component as index
212 void drawrect(void *videoram
, struct rect
*r
, const struct pixelformat
*pixf
, const struct vidsize
*vids
){
213 int x
,y
,corwidth
, bpp
= 0, tocopy
= 1;
215 unsigned char *pmem
= videoram
;
216 corwidth
= r
->width
; // actually only "corrected" for 4 Bit
218 if (pixf
->pixenum
!=CLUT4
&&pixf
->pixenum
!=CLUT8
){
219 switch (pixf
->pixenum
){
230 printf ("drawrect: unknown pixelformat(%d) bpp:%d\n",pixf
->pixenum
,pixf
->bpp
);
233 col2pixel(&pix
,pixf
,r
->col
);
235 switch (pixf
->pixenum
){ // CLUT = Colour LookUp Table (palette)
236 case CLUT4
: // take red value as index in this case
237 pix
.byte
[0]=(r
->col
->r
)<<4|(r
->col
->r
&0xf); // slightly cryptic... "rect->colour->red"
238 corwidth
>>=1; // we copy bytes
243 pix
.byte
[0]=(r
->col
->r
&0xff);
249 pmem
=videoram
+((((r
->y
*vids
->width
)+r
->x
)*bpp
)>>3);
250 for (y
=0;y
<r
->height
;y
++){
252 for (x
=0;x
<corwidth
;x
++){
253 memcpy (pmem
+offset
,pix
.byte
,tocopy
);
256 pmem
+=((vids
->width
*bpp
)>>3); // skip one whole line, actually should be taken from "fix-info"
260 // create quick little test image, 4 colours from table
261 void draw4field(void *videoram
, const struct pixelformat
*pixf
, const struct vidsize
*vids
){
265 c
.r
= 1; // only used for the indexed modes, r is taken as index
266 height
= vids
->height
;
269 r
.height
= height
>>1;
272 if (pixf
->pixenum
==CLUT4
||pixf
->pixenum
==CLUT8
) r
.col
= &c
;
273 else r
.col
= &colourtable
[1];
274 drawrect (videoram
, &r
, pixf
, vids
);
276 r
.x
= width
/2; r
.y
= 0;
277 if (pixf
->pixenum
==CLUT4
||pixf
->pixenum
==CLUT8
) c
.r
= 2;
278 else r
.col
= &colourtable
[2];
279 drawrect (videoram
, &r
, pixf
, vids
);
281 r
.x
= 0; r
.y
= height
/2;
282 if (pixf
->pixenum
==CLUT4
||pixf
->pixenum
==CLUT8
) c
.r
= 3;
283 else r
.col
= &colourtable
[3];
284 drawrect (videoram
, &r
, pixf
, vids
);
286 r
.x
= width
/2; r
.y
= height
/2;
287 if (pixf
->pixenum
==CLUT4
||pixf
->pixenum
==CLUT8
) c
.r
= 0;
288 else r
.col
= &colourtable
[0];
289 drawrect (videoram
, &r
, pixf
, vids
);
292 void usage(char *name
){
293 printf ("Usage: %s [options]\n"
294 "Options: -f<pixelformat>\n"
295 " where format is one of:\n"
296 " CLUT4,CLUT8,ARGB1555,RGB565,ARGB\n"
297 " -s<width>x<heigth>\n"
298 " where width is either 720,640,360,320\n"
299 " and height is either 288,240,480,576\n"
301 " disables clearing the framebuffer after drawing\n"
302 " the testimage. This can be useful to keep the last\n"
303 " drawn image onscreen.\n"
304 "\nExample: %s -fRGB322\n",name
,name
);
308 int main (int argc
,char **argv
){
309 struct fb_fix_screeninfo fix
;
310 struct fb_var_screeninfo var
;
316 int optchar
,fmode
=-1,smode
=-1,clear
=1;
317 int i_cmap
,i_size
,i_pix
;
320 if (argc
!=0&&argc
>4) usage(argv
[0]);
321 while ( (optchar
= getopt (argc
,argv
,"f:s:n"))!= -1){
325 for (i
=0;i
<(sizeof(pixname
)/sizeof(char*));i
++){
326 if (!strncmp (optarg
,pixname
[i
],strlen(pixname
[i
]))){
328 printf ("displaying only %s-modes\n",pixname
[i
]);
333 printf ("unknown pixelformat\n");
338 if (sscanf (optarg
,"%dx%d",&width
,&height
)!=2){
339 printf ("parsing size failed\n");
342 printf ("requested size %dx%d\n",width
,height
);
343 for (i
=0;i
<VIDSIZENUM
;i
++){
344 if (vidsizetable
[i
].width
== width
&&
345 vidsizetable
[i
].height
== height
){
351 printf ("this size is not supported\n");
358 printf ("clearing framebuffer after drawing is disabled\n");
365 fbd
= open (FBDEV
, O_RDWR
);
367 perror ("Error opening framebuffer device");
370 stat
= ioctl (fbd
, FBIOGET_FSCREENINFO
,&fix
);
372 perror ("Error getting fix screeninfo");
375 stat
= ioctl (fbd
, FBIOGET_VSCREENINFO
,&var
);
377 perror ("Error getting var screeninfo");
380 stat
= ioctl (fbd
, FBIOPUT_VSCREENINFO
,&var
);
382 perror ("Error setting mode");
385 pfb
= mmap (0, fix
.smem_len
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fbd
, 0);
386 if (pfb
== MAP_FAILED
){
387 perror ("Error mmap'ing framebuffer device");
391 // iterate over all modes
392 for (i_pix
=0;i_pix
<PIXELFORMATNUM
;i_pix
++){
393 if (fmode
!=-1 && pixelformattable
[i_pix
].pixenum
!= fmode
) continue;
394 printf ("testing: %s",pixelformattable
[i_pix
].name
);
395 printf (" for sizes: \n");
396 for (i_size
=0;i_size
<VIDSIZENUM
;i_size
++){
397 if (smode
!=-1 && i_size
!=smode
) continue;
398 printf ("%dx%d ",vidsizetable
[i_size
].width
,vidsizetable
[i_size
].height
);
400 if ((i_size
%4)==3) printf ("\n");
403 stat
= setmode(fbd
,&pixelformattable
[i_pix
],&vidsizetable
[i_size
]);
404 if (stat
==-2) perror ("fbtest: could not get fb_var-screeninfo from fb-device");
406 printf ("\nCould not set mode %s (%dx%d), possible reasons:\n"
407 "- you have a GTX (soz m8)\n"
408 "- your configuration does not have enough graphics RAM\n"
409 "- you found a bug\n"
410 "choose your poison accordingly...\n",
411 pixelformattable
[i_pix
].name
,vidsizetable
[i_size
].width
,vidsizetable
[i_size
].height
);
416 if ((pixelformattable
[i_pix
].bpp
==4)||
417 ((pixelformattable
[i_pix
].bpp
==8)&&(pixelformattable
[i_pix
].red
.length
!=3))){
418 for (i_cmap
=0;i_cmap
<COLOURNUM
;i_cmap
++){
420 cmap
.red
=&colourtable
[i_cmap
].r
;
421 cmap
.green
=&colourtable
[i_cmap
].g
;
422 cmap
.blue
=&colourtable
[i_cmap
].b
;
423 cmap
.transp
=&colourtable
[i_cmap
].a
;
424 stat
= ioctl (fbd
, FBIOPUTCMAP
, &cmap
);
425 if (stat
<0) printf ("setting colourmap failed\n");
428 // create the test image
429 draw4field(pfb
,&pixelformattable
[i_pix
],&vidsizetable
[i_size
]);
433 r
.x
=r
.y
=0;r
.width
= vidsizetable
[i_size
].width
; r
.height
= vidsizetable
[i_size
].height
;
434 r
.col
= &colourtable
[4];
435 drawrect(pfb
,&r
,&pixelformattable
[i_pix
],&vidsizetable
[i_size
]);
441 stat
= munmap (pfb
,fix
.smem_len
);
443 perror ("Error munmap'ing framebuffer device");