Never fail `make clean'
[mesa.git] / progs / fbdev / glfbdevtest.c
1 /*
2 * Test the GLFBDev interface. Only tested with radeonfb driver!!!!
3 *
4 * Written by Brian Paul
5 */
6
7
8 #include <assert.h>
9 #include <errno.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 #include <sys/mman.h>
18 #include <sys/types.h>
19 #include <linux/fb.h>
20 #include <linux/kd.h>
21 #include <linux/vt.h>
22 #include <GL/gl.h>
23 #include <GL/glfbdev.h>
24 #include <math.h>
25
26
27 /**
28 * Choose one of these modes
29 */
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;
34
35 static int DesiredDepth = 32;
36
37 static int NumFrames = 100;
38
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;
46
47
48 static void
49 print_fixed_info(const struct fb_fix_screeninfo *fixed, const char *s)
50 {
51 static const char *visuals[] = {
52 "MONO01", "MONO10", "TRUECOLOR", "PSEUDOCOLOR",
53 "DIRECTCOLOR", "STATIC_PSEUDOCOLOR"
54 };
55
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);
70 }
71
72
73 static void
74 print_var_info(const struct fb_var_screeninfo *var, const char *s)
75 {
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);
85
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);
94
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);
109 }
110
111
112 static void
113 signal_handler(int signumber)
114 {
115 signal(signumber, SIG_IGN); /* prevent recursion! */
116 fprintf(stderr, "error: got signal %d (exiting)\n", signumber);
117 exit(1);
118 }
119
120
121 static void
122 initialize_fbdev( void )
123 {
124 char ttystr[1000];
125 int fd, vtnumber, ttyfd;
126 int sz;
127
128 (void) sz;
129
130 if (geteuid()) {
131 fprintf(stderr, "error: you need to be root\n");
132 exit(1);
133 }
134
135 #if 1
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));
140 exit(1);
141 }
142 #endif
143
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");
147 exit(1);
148 }
149 if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
150 fprintf(stderr, "error: couldn't get a free vt\n");
151 exit(1);
152 }
153 close(fd);
154
155 /* open the console tty */
156 sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */
157 ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
158 if (ConsoleFD < 0) {
159 fprintf(stderr, "error couldn't open console fd\n");
160 exit(1);
161 }
162
163 /* save current vt number */
164 {
165 struct vt_stat vts;
166 if (ioctl(ConsoleFD, VT_GETSTATE, &vts) == 0)
167 OriginalVT = vts.v_active;
168 }
169
170 /* disconnect from controlling tty */
171 ttyfd = open("/dev/tty", O_RDWR);
172 if (ttyfd >= 0) {
173 ioctl(ttyfd, TIOCNOTTY, 0);
174 close(ttyfd);
175 }
176
177 /* some magic to restore the vt when we exit */
178 {
179 struct vt_mode vt;
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));
184
185 if (ioctl(ConsoleFD, VT_GETMODE, &vt) < 0) {
186 fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
187 exit(1);
188 }
189
190 vt.mode = VT_PROCESS;
191 vt.relsig = SIGUSR1;
192 vt.acqsig = SIGUSR1;
193 if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) {
194 fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
195 strerror(errno));
196 exit(1);
197 }
198 }
199
200 /* go into graphics mode */
201 if (ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
202 fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
203 strerror(errno));
204 exit(1);
205 }
206
207
208 #if 0
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));
213 exit(1);
214 }
215 #endif
216
217 /* Get the fixed screen info */
218 if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
219 fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
220 strerror(errno));
221 exit(1);
222 }
223
224 print_fixed_info(&FixedInfo, "Fixed");
225
226
227 /* get the variable screen info */
228 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
229 fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
230 strerror(errno));
231 exit(1);
232 }
233
234 print_var_info(&OrigVarInfo, "Orig Var");
235
236 /* operate on a copy */
237 VarInfo = OrigVarInfo;
238
239 /* set the depth, resolution, etc */
240 if (DesiredDepth)
241 VarInfo.bits_per_pixel = DesiredDepth;
242
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;
252 }
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;
262 }
263
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;
268 if (Hz == 75) {
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;
276 }
277 else if (Hz == 70) {
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;
285 }
286 else if (Hz == 60) {
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;
294 }
295 else {
296 fprintf(stderr, "invalid rate for 1280x1024\n");
297 exit(1);
298 }
299 }
300 else if (XRes == 1024 && YRes == 768 && Hz == 70) {
301 VarInfo.xres_virtual = VarInfo.xres = XRes;
302 VarInfo.yres_virtual = VarInfo.yres = YRes;
303 if (Hz == 70) {
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;
311 }
312 else {
313 fprintf(stderr, "invalid rate for 1024x768\n");
314 exit(1);
315 }
316 }
317
318 VarInfo.xoffset = 0;
319 VarInfo.yoffset = 0;
320 VarInfo.nonstd = 0;
321 VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
322
323 /* set new variable screen info */
324 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
325 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
326 strerror(errno));
327 exit(1);
328 }
329
330 print_var_info(&VarInfo, "New Var");
331
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);
335 exit(1);
336 }
337
338 /* initialize colormap */
339 if (FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
340 struct fb_cmap cmap;
341 unsigned short red[256], green[256], blue[256];
342 int i;
343
344 /* we're assuming 256 entries here */
345 printf("initializing directcolor colormap\n");
346 cmap.start = 0;
347 cmap.len = 256;
348 cmap.red = red;
349 cmap.green = green;
350 cmap.blue = blue;
351 cmap.transp = NULL;
352 for (i = 0; i < cmap.len; i++) {
353 red[i] = green[i] = blue[i] = (i << 8) | i;
354 }
355 if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
356 fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
357 }
358 }
359
360 /*
361 * fbdev says the frame buffer is at offset zero, and the mmio region
362 * is immediately after.
363 */
364
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 */
371 0 /* offset */);
372 if (FrameBuffer == (caddr_t) - 1) {
373 fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
374 strerror(errno));
375 exit(1);
376 }
377 printf("FrameBuffer = %p\n", FrameBuffer);
378
379 #if 1
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",
389 strerror(errno));
390 }
391 printf("MMIOAddress = %p\n", MMIOAddress);
392
393 /* try out some simple MMIO register reads */
394 if (0)
395 {
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)
403 int sz, type;
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]);
410 }
411 #endif
412
413 }
414
415
416 static void
417 shutdown_fbdev( void )
418 {
419 struct vt_mode VT;
420
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",
425 strerror(errno));
426 exit(1);
427 }
428
429 munmap(MMIOAddress, FixedInfo.mmio_len);
430 munmap(FrameBuffer, FixedInfo.smem_len);
431 close(FrameBufferFD);
432
433 /* restore text mode */
434 ioctl(ConsoleFD, KDSETMODE, KD_TEXT);
435
436 /* set vt */
437 if (ioctl(ConsoleFD, VT_GETMODE, &VT) != -1) {
438 VT.mode = VT_AUTO;
439 ioctl(ConsoleFD, VT_SETMODE, &VT);
440 }
441
442 /* restore original vt */
443 if (OriginalVT >= 0) {
444 ioctl(ConsoleFD, VT_ACTIVATE, OriginalVT);
445 OriginalVT = -1;
446 }
447
448 close(ConsoleFD);
449 }
450
451
452 /* Borrowed from GLUT */
453 static void
454 doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
455 {
456 int i, j;
457 GLfloat theta, phi, theta1;
458 GLfloat cosTheta, sinTheta;
459 GLfloat cosTheta1, sinTheta1;
460 GLfloat ringDelta, sideDelta;
461
462 ringDelta = 2.0 * M_PI / rings;
463 sideDelta = 2.0 * M_PI / nsides;
464
465 theta = 0.0;
466 cosTheta = 1.0;
467 sinTheta = 0.0;
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);
473 phi = 0.0;
474 for (j = nsides; j >= 0; j--) {
475 GLfloat cosPhi, sinPhi, dist;
476
477 phi += sideDelta;
478 cosPhi = cos(phi);
479 sinPhi = sin(phi);
480 dist = R + r * cosPhi;
481
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);
486 }
487 glEnd();
488 theta = theta1;
489 cosTheta = cosTheta1;
490 sinTheta = sinTheta1;
491 }
492 }
493
494
495 static void
496 gltest( void )
497 {
498 static const int attribs[] = {
499 GLFBDEV_DOUBLE_BUFFER,
500 GLFBDEV_DEPTH_SIZE, 16,
501 GLFBDEV_NONE
502 };
503 GLFBDevContextPtr ctx;
504 GLFBDevBufferPtr buf;
505 GLFBDevVisualPtr vis;
506 int bytes, r, g, b, a;
507 float ang;
508 int i;
509
510 printf("GLFBDEV_VENDOR = %s\n", glFBDevGetString(GLFBDEV_VENDOR));
511 printf("GLFBDEV_VERSION = %s\n", glFBDevGetString(GLFBDEV_VERSION));
512
513 /* framebuffer size */
514 bytes = VarInfo.xres_virtual * VarInfo.yres_virtual * VarInfo.bits_per_pixel / 8;
515
516 vis = glFBDevCreateVisual( &FixedInfo, &VarInfo, attribs );
517 assert(vis);
518
519 buf = glFBDevCreateBuffer( &FixedInfo, &VarInfo, vis, FrameBuffer, NULL, bytes );
520 assert(buf);
521
522 ctx = glFBDevCreateContext( vis, NULL );
523 assert(buf);
524
525 b = glFBDevMakeCurrent( ctx, buf, buf );
526 assert(b);
527
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",
534 r, g, b, a);
535
536 glClearColor(0.5, 0.5, 1.0, 0);
537 glMatrixMode(GL_PROJECTION);
538 glLoadIdentity();
539 glFrustum(-1, 1, -1, 1, 2, 30);
540 glMatrixMode(GL_MODELVIEW);
541 glLoadIdentity();
542 glTranslatef(0, 0, -15);
543 glViewport(0, 0, VarInfo.xres_virtual, VarInfo.yres_virtual);
544 glEnable(GL_LIGHTING);
545 glEnable(GL_LIGHT0);
546 glEnable(GL_DEPTH_TEST);
547
548 printf("Drawing %d frames...\n", NumFrames);
549
550 ang = 0.0;
551 for (i = 0; i < NumFrames; i++) {
552 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
553 glPushMatrix();
554 glRotatef(ang, 1, 0, 0);
555 doughnut(1, 3, 40, 20);
556 glPopMatrix();
557 glFBDevSwapBuffers(buf);
558 ang += 15.0;
559 }
560
561 /* clean up */
562 b = glFBDevMakeCurrent( NULL, NULL, NULL);
563 assert(b);
564
565 glFBDevDestroyContext(ctx);
566 glFBDevDestroyBuffer(buf);
567 glFBDevDestroyVisual(vis);
568 }
569
570
571 static void
572 parse_args(int argc, char *argv[])
573 {
574 int i;
575
576 for (i = 1; i < argc; i++) {
577 if (strcmp(argv[i], "-f") == 0) {
578 NumFrames = atoi(argv[i+1]);
579 i++;
580 }
581 }
582 }
583
584
585 int
586 main( int argc, char *argv[] )
587 {
588 signal(SIGUSR1, signal_handler); /* exit if someone tries a vt switch */
589 signal(SIGSEGV, signal_handler); /* catch segfaults */
590
591 parse_args(argc, argv);
592
593 printf("Setting mode to %d x %d @ %d Hz, %d bpp\n", XRes, YRes, Hz, DesiredDepth);
594 initialize_fbdev();
595 gltest();
596 shutdown_fbdev();
597
598 return 0;
599 }