2 * Test the GLFBDev interface. Only tested with radeonfb driver!!!!
4 * Written by Brian Paul
16 #include <sys/ioctl.h>
18 #include <sys/types.h>
23 #include <GL/glfbdev.h>
28 * Choose one of these modes
30 /*static const int XRes = 1280, YRes = 1024, Hz = 75;*/
31 /*static const int XRes = 1280, YRes = 1024, Hz = 70;*/
32 /*static const int XRes = 1280, YRes = 1024, Hz = 60;*/
33 static const int XRes
= 1024, YRes
= 768, Hz
= 70;
35 static int DesiredDepth
= 32;
37 static int NumFrames
= 100;
39 static struct fb_fix_screeninfo FixedInfo
;
40 static struct fb_var_screeninfo VarInfo
, OrigVarInfo
;
41 static int OriginalVT
= -1;
42 static int ConsoleFD
= -1;
43 static int FrameBufferFD
= -1;
44 static caddr_t FrameBuffer
= (caddr_t
) -1;
45 static caddr_t MMIOAddress
= (caddr_t
) -1;
49 print_fixed_info(const struct fb_fix_screeninfo
*fixed
, const char *s
)
51 static const char *visuals
[] = {
52 "MONO01", "MONO10", "TRUECOLOR", "PSEUDOCOLOR",
53 "DIRECTCOLOR", "STATIC_PSEUDOCOLOR"
56 printf("%s info -----------------------\n", s
);
57 printf("id = %16s\n", fixed
->id
);
58 printf("smem_start = 0x%lx\n", fixed
->smem_start
);
59 printf("smem_len = %d (0x%x)\n", fixed
->smem_len
, fixed
->smem_len
);
60 printf("type = 0x%x\n", fixed
->type
);
61 printf("type_aux = 0x%x\n", fixed
->type_aux
);
62 printf("visual = 0x%x (%s)\n", fixed
->visual
, visuals
[fixed
->visual
]);
63 printf("xpanstep = %d\n", fixed
->xpanstep
);
64 printf("ypanstep = %d\n", fixed
->ypanstep
);
65 printf("ywrapstep = %d\n", fixed
->ywrapstep
);
66 printf("line_length = %d\n", fixed
->line_length
);
67 printf("mmio_start = 0x%lx\n", fixed
->mmio_start
);
68 printf("mmio_len = %d (0x%x)\n", fixed
->mmio_len
, fixed
->mmio_len
);
69 printf("accel = 0x%x\n", fixed
->accel
);
74 print_var_info(const struct fb_var_screeninfo
*var
, const char *s
)
76 printf("%s info -----------------------\n", s
);
77 printf("xres = %d\n", var
->xres
);
78 printf("yres = %d\n", var
->yres
);
79 printf("xres_virtual = %d\n", var
->xres_virtual
);
80 printf("yres_virtual = %d\n", var
->yres_virtual
);
81 printf("xoffset = %d\n", var
->xoffset
);
82 printf("yoffset = %d\n", var
->yoffset
);
83 printf("bits_per_pixel = %d\n", var
->bits_per_pixel
);
84 printf("grayscale = %d\n", var
->grayscale
);
86 printf("red.offset = %d length = %d msb_right = %d\n",
87 var
->red
.offset
, var
->red
.length
, var
->red
.msb_right
);
88 printf("green.offset = %d length = %d msb_right = %d\n",
89 var
->green
.offset
, var
->green
.length
, var
->green
.msb_right
);
90 printf("blue.offset = %d length = %d msb_right = %d\n",
91 var
->blue
.offset
, var
->blue
.length
, var
->blue
.msb_right
);
92 printf("transp.offset = %d length = %d msb_right = %d\n",
93 var
->transp
.offset
, var
->transp
.length
, var
->transp
.msb_right
);
95 printf("nonstd = %d\n", var
->nonstd
);
96 printf("activate = %d\n", var
->activate
);
97 printf("height = %d mm\n", var
->height
);
98 printf("width = %d mm\n", var
->width
);
99 printf("accel_flags = 0x%x\n", var
->accel_flags
);
100 printf("pixclock = %d\n", var
->pixclock
);
101 printf("left_margin = %d\n", var
->left_margin
);
102 printf("right_margin = %d\n", var
->right_margin
);
103 printf("upper_margin = %d\n", var
->upper_margin
);
104 printf("lower_margin = %d\n", var
->lower_margin
);
105 printf("hsync_len = %d\n", var
->hsync_len
);
106 printf("vsync_len = %d\n", var
->vsync_len
);
107 printf("sync = %d\n", var
->sync
);
108 printf("vmode = %d\n", var
->vmode
);
113 signal_handler(int signumber
)
115 signal(signumber
, SIG_IGN
); /* prevent recursion! */
116 fprintf(stderr
, "error: got signal %d (exiting)\n", signumber
);
122 initialize_fbdev( void )
125 int fd
, vtnumber
, ttyfd
;
131 fprintf(stderr
, "error: you need to be root\n");
136 /* open the framebuffer device */
137 FrameBufferFD
= open("/dev/fb0", O_RDWR
);
138 if (FrameBufferFD
< 0) {
139 fprintf(stderr
, "Error opening /dev/fb0: %s\n", strerror(errno
));
144 /* open /dev/tty0 and get the vt number */
145 if ((fd
= open("/dev/tty0", O_WRONLY
, 0)) < 0) {
146 fprintf(stderr
, "error opening /dev/tty0\n");
149 if (ioctl(fd
, VT_OPENQRY
, &vtnumber
) < 0 || vtnumber
< 0) {
150 fprintf(stderr
, "error: couldn't get a free vt\n");
155 /* open the console tty */
156 sprintf(ttystr
, "/dev/tty%d", vtnumber
); /* /dev/tty1-64 */
157 ConsoleFD
= open(ttystr
, O_RDWR
| O_NDELAY
, 0);
159 fprintf(stderr
, "error couldn't open console fd\n");
163 /* save current vt number */
166 if (ioctl(ConsoleFD
, VT_GETSTATE
, &vts
) == 0)
167 OriginalVT
= vts
.v_active
;
170 /* disconnect from controlling tty */
171 ttyfd
= open("/dev/tty", O_RDWR
);
173 ioctl(ttyfd
, TIOCNOTTY
, 0);
177 /* some magic to restore the vt when we exit */
180 if (ioctl(ConsoleFD
, VT_ACTIVATE
, vtnumber
) != 0)
181 printf("ioctl VT_ACTIVATE: %s\n", strerror(errno
));
182 if (ioctl(ConsoleFD
, VT_WAITACTIVE
, vtnumber
) != 0)
183 printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno
));
185 if (ioctl(ConsoleFD
, VT_GETMODE
, &vt
) < 0) {
186 fprintf(stderr
, "error: ioctl VT_GETMODE: %s\n", strerror(errno
));
190 vt
.mode
= VT_PROCESS
;
193 if (ioctl(ConsoleFD
, VT_SETMODE
, &vt
) < 0) {
194 fprintf(stderr
, "error: ioctl(VT_SETMODE) failed: %s\n",
200 /* go into graphics mode */
201 if (ioctl(ConsoleFD
, KDSETMODE
, KD_GRAPHICS
) < 0) {
202 fprintf(stderr
, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
209 /* open the framebuffer device */
210 FrameBufferFD
= open("/dev/fb0", O_RDWR
);
211 if (FrameBufferFD
< 0) {
212 fprintf(stderr
, "Error opening /dev/fb0: %s\n", strerror(errno
));
217 /* Get the fixed screen info */
218 if (ioctl(FrameBufferFD
, FBIOGET_FSCREENINFO
, &FixedInfo
)) {
219 fprintf(stderr
, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
224 print_fixed_info(&FixedInfo
, "Fixed");
227 /* get the variable screen info */
228 if (ioctl(FrameBufferFD
, FBIOGET_VSCREENINFO
, &OrigVarInfo
)) {
229 fprintf(stderr
, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
234 print_var_info(&OrigVarInfo
, "Orig Var");
236 /* operate on a copy */
237 VarInfo
= OrigVarInfo
;
239 /* set the depth, resolution, etc */
241 VarInfo
.bits_per_pixel
= DesiredDepth
;
243 if (VarInfo
.bits_per_pixel
== 16) {
244 VarInfo
.red
.offset
= 11;
245 VarInfo
.green
.offset
= 5;
246 VarInfo
.blue
.offset
= 0;
247 VarInfo
.red
.length
= 5;
248 VarInfo
.green
.length
= 6;
249 VarInfo
.blue
.length
= 5;
250 VarInfo
.transp
.offset
= 0;
251 VarInfo
.transp
.length
= 0;
253 else if (VarInfo
.bits_per_pixel
== 32) {
254 VarInfo
.red
.offset
= 16;
255 VarInfo
.green
.offset
= 8;
256 VarInfo
.blue
.offset
= 0;
257 VarInfo
.transp
.offset
= 24;
258 VarInfo
.red
.length
= 8;
259 VarInfo
.green
.length
= 8;
260 VarInfo
.blue
.length
= 8;
261 VarInfo
.transp
.length
= 8;
264 /* timing values taken from /etc/fb.modes */
265 if (XRes
== 1280 && YRes
== 1024) {
266 VarInfo
.xres_virtual
= VarInfo
.xres
= XRes
;
267 VarInfo
.yres_virtual
= VarInfo
.yres
= YRes
;
269 VarInfo
.pixclock
= 7408;
270 VarInfo
.left_margin
= 248;
271 VarInfo
.right_margin
= 16;
272 VarInfo
.upper_margin
= 38;
273 VarInfo
.lower_margin
= 1;
274 VarInfo
.hsync_len
= 144;
275 VarInfo
.vsync_len
= 3;
278 VarInfo
.pixclock
= 7937;
279 VarInfo
.left_margin
= 216;
280 VarInfo
.right_margin
= 80;
281 VarInfo
.upper_margin
= 36;
282 VarInfo
.lower_margin
= 1;
283 VarInfo
.hsync_len
= 112;
284 VarInfo
.vsync_len
= 5;
287 VarInfo
.pixclock
= 9260;
288 VarInfo
.left_margin
= 248;
289 VarInfo
.right_margin
= 48;
290 VarInfo
.upper_margin
= 38;
291 VarInfo
.lower_margin
= 1;
292 VarInfo
.hsync_len
= 112;
293 VarInfo
.vsync_len
= 3;
296 fprintf(stderr
, "invalid rate for 1280x1024\n");
300 else if (XRes
== 1024 && YRes
== 768 && Hz
== 70) {
301 VarInfo
.xres_virtual
= VarInfo
.xres
= XRes
;
302 VarInfo
.yres_virtual
= VarInfo
.yres
= YRes
;
304 VarInfo
.pixclock
= 13334;
305 VarInfo
.left_margin
= 144;
306 VarInfo
.right_margin
= 24;
307 VarInfo
.upper_margin
= 29;
308 VarInfo
.lower_margin
= 3;
309 VarInfo
.hsync_len
= 136;
310 VarInfo
.vsync_len
= 6;
313 fprintf(stderr
, "invalid rate for 1024x768\n");
321 VarInfo
.vmode
&= ~FB_VMODE_YWRAP
; /* turn off scrolling */
323 /* set new variable screen info */
324 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &VarInfo
)) {
325 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
330 print_var_info(&VarInfo
, "New Var");
332 if (FixedInfo
.visual
!= FB_VISUAL_TRUECOLOR
&&
333 FixedInfo
.visual
!= FB_VISUAL_DIRECTCOLOR
) {
334 fprintf(stderr
, "non-TRUE/DIRECT-COLOR visuals (0x%x) not supported by this demo.\n", FixedInfo
.visual
);
338 /* initialize colormap */
339 if (FixedInfo
.visual
== FB_VISUAL_DIRECTCOLOR
) {
341 unsigned short red
[256], green
[256], blue
[256];
344 /* we're assuming 256 entries here */
345 printf("initializing directcolor colormap\n");
352 for (i
= 0; i
< cmap
.len
; i
++) {
353 red
[i
] = green
[i
] = blue
[i
] = (i
<< 8) | i
;
355 if (ioctl(FrameBufferFD
, FBIOPUTCMAP
, (void *) &cmap
) < 0) {
356 fprintf(stderr
, "ioctl(FBIOPUTCMAP) failed [%d]\n", i
);
361 * fbdev says the frame buffer is at offset zero, and the mmio region
362 * is immediately after.
365 /* mmap the framebuffer into our address space */
366 FrameBuffer
= (caddr_t
) mmap(0, /* start */
367 FixedInfo
.smem_len
, /* bytes */
368 PROT_READ
| PROT_WRITE
, /* prot */
369 MAP_SHARED
, /* flags */
370 FrameBufferFD
, /* fd */
372 if (FrameBuffer
== (caddr_t
) - 1) {
373 fprintf(stderr
, "error: unable to mmap framebuffer: %s\n",
377 printf("FrameBuffer = %p\n", FrameBuffer
);
380 /* mmap the MMIO region into our address space */
381 MMIOAddress
= (caddr_t
) mmap(0, /* start */
382 FixedInfo
.mmio_len
, /* bytes */
383 PROT_READ
| PROT_WRITE
, /* prot */
384 MAP_SHARED
, /* flags */
385 FrameBufferFD
, /* fd */
386 FixedInfo
.smem_len
/* offset */);
387 if (MMIOAddress
== (caddr_t
) - 1) {
388 fprintf(stderr
, "error: unable to mmap mmio region: %s\n",
391 printf("MMIOAddress = %p\n", MMIOAddress
);
393 /* try out some simple MMIO register reads */
396 typedef unsigned int CARD32
;
397 typedef unsigned char CARD8
;
398 #define RADEON_CONFIG_MEMSIZE 0x00f8
399 #define RADEON_MEM_SDRAM_MODE_REG 0x0158
400 #define MMIO_IN32(base, offset) \
401 *(volatile CARD32 *)(void *)(((CARD8*)(base)) + (offset))
402 #define INREG(addr) MMIO_IN32(MMIOAddress, addr)
404 const char *typeStr
[] = {"SDR", "DDR", "64-bit SDR"};
405 sz
= INREG(RADEON_CONFIG_MEMSIZE
);
406 type
= INREG(RADEON_MEM_SDRAM_MODE_REG
);
407 printf("RADEON_CONFIG_MEMSIZE = %d (%d MB)\n", sz
, sz
/ 1024 / 1024);
408 printf("RADEON_MEM_SDRAM_MODE_REG >> 30 = %d (%s)\n",
409 type
>> 30, typeStr
[type
>>30]);
417 shutdown_fbdev( void )
421 printf("cleaning up...\n");
422 /* restore original variable screen info */
423 if (ioctl(FrameBufferFD
, FBIOPUT_VSCREENINFO
, &OrigVarInfo
)) {
424 fprintf(stderr
, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
429 munmap(MMIOAddress
, FixedInfo
.mmio_len
);
430 munmap(FrameBuffer
, FixedInfo
.smem_len
);
431 close(FrameBufferFD
);
433 /* restore text mode */
434 ioctl(ConsoleFD
, KDSETMODE
, KD_TEXT
);
437 if (ioctl(ConsoleFD
, VT_GETMODE
, &VT
) != -1) {
439 ioctl(ConsoleFD
, VT_SETMODE
, &VT
);
442 /* restore original vt */
443 if (OriginalVT
>= 0) {
444 ioctl(ConsoleFD
, VT_ACTIVATE
, OriginalVT
);
452 /* Borrowed from GLUT */
454 doughnut(GLfloat r
, GLfloat R
, GLint nsides
, GLint rings
)
457 GLfloat theta
, phi
, theta1
;
458 GLfloat cosTheta
, sinTheta
;
459 GLfloat cosTheta1
, sinTheta1
;
460 GLfloat ringDelta
, sideDelta
;
462 ringDelta
= 2.0 * M_PI
/ rings
;
463 sideDelta
= 2.0 * M_PI
/ nsides
;
468 for (i
= rings
- 1; i
>= 0; i
--) {
469 theta1
= theta
+ ringDelta
;
470 cosTheta1
= cos(theta1
);
471 sinTheta1
= sin(theta1
);
472 glBegin(GL_QUAD_STRIP
);
474 for (j
= nsides
; j
>= 0; j
--) {
475 GLfloat cosPhi
, sinPhi
, dist
;
480 dist
= R
+ r
* cosPhi
;
482 glNormal3f(cosTheta1
* cosPhi
, -sinTheta1
* cosPhi
, sinPhi
);
483 glVertex3f(cosTheta1
* dist
, -sinTheta1
* dist
, r
* sinPhi
);
484 glNormal3f(cosTheta
* cosPhi
, -sinTheta
* cosPhi
, sinPhi
);
485 glVertex3f(cosTheta
* dist
, -sinTheta
* dist
, r
* sinPhi
);
489 cosTheta
= cosTheta1
;
490 sinTheta
= sinTheta1
;
498 static const int attribs
[] = {
499 GLFBDEV_DOUBLE_BUFFER
,
500 GLFBDEV_DEPTH_SIZE
, 16,
503 GLFBDevContextPtr ctx
;
504 GLFBDevBufferPtr buf
;
505 GLFBDevVisualPtr vis
;
506 int bytes
, r
, g
, b
, a
;
510 printf("GLFBDEV_VENDOR = %s\n", glFBDevGetString(GLFBDEV_VENDOR
));
511 printf("GLFBDEV_VERSION = %s\n", glFBDevGetString(GLFBDEV_VERSION
));
513 /* framebuffer size */
514 bytes
= VarInfo
.xres_virtual
* VarInfo
.yres_virtual
* VarInfo
.bits_per_pixel
/ 8;
516 vis
= glFBDevCreateVisual( &FixedInfo
, &VarInfo
, attribs
);
519 buf
= glFBDevCreateBuffer( &FixedInfo
, &VarInfo
, vis
, FrameBuffer
, NULL
, bytes
);
522 ctx
= glFBDevCreateContext( vis
, NULL
);
525 b
= glFBDevMakeCurrent( ctx
, buf
, buf
);
528 /*printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));*/
529 glGetIntegerv(GL_RED_BITS
, &r
);
530 glGetIntegerv(GL_GREEN_BITS
, &g
);
531 glGetIntegerv(GL_BLUE_BITS
, &b
);
532 glGetIntegerv(GL_ALPHA_BITS
, &a
);
533 printf("RED_BITS=%d GREEN_BITS=%d BLUE_BITS=%d ALPHA_BITS=%d\n",
536 glClearColor(0.5, 0.5, 1.0, 0);
537 glMatrixMode(GL_PROJECTION
);
539 glFrustum(-1, 1, -1, 1, 2, 30);
540 glMatrixMode(GL_MODELVIEW
);
542 glTranslatef(0, 0, -15);
543 glViewport(0, 0, VarInfo
.xres_virtual
, VarInfo
.yres_virtual
);
544 glEnable(GL_LIGHTING
);
546 glEnable(GL_DEPTH_TEST
);
548 printf("Drawing %d frames...\n", NumFrames
);
551 for (i
= 0; i
< NumFrames
; i
++) {
552 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
554 glRotatef(ang
, 1, 0, 0);
555 doughnut(1, 3, 40, 20);
557 glFBDevSwapBuffers(buf
);
562 b
= glFBDevMakeCurrent( NULL
, NULL
, NULL
);
565 glFBDevDestroyContext(ctx
);
566 glFBDevDestroyBuffer(buf
);
567 glFBDevDestroyVisual(vis
);
572 parse_args(int argc
, char *argv
[])
576 for (i
= 1; i
< argc
; i
++) {
577 if (strcmp(argv
[i
], "-f") == 0) {
578 NumFrames
= atoi(argv
[i
+1]);
586 main( int argc
, char *argv
[] )
588 signal(SIGUSR1
, signal_handler
); /* exit if someone tries a vt switch */
589 signal(SIGSEGV
, signal_handler
); /* catch segfaults */
591 parse_args(argc
, argv
);
593 printf("Setting mode to %d x %d @ %d Hz, %d bpp\n", XRes
, YRes
, Hz
, DesiredDepth
);