Allow two GL primitives to be combined to one HW primitive
[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 #define DEFAULT_DEPTH 8
27
28 static struct fb_fix_screeninfo FixedInfo;
29 static struct fb_var_screeninfo VarInfo, OrigVarInfo;
30 static int DesiredDepth = 0;
31 static int OriginalVT = -1;
32 static int ConsoleFD = -1;
33 static int FrameBufferFD = -1;
34 static caddr_t FrameBuffer = (caddr_t) -1;
35 static caddr_t MMIOAddress = (caddr_t) -1;
36
37
38 static void
39 print_fixed_info(const struct fb_fix_screeninfo *fixed, const char *s)
40 {
41 static const char *visuals[] = {
42 "MONO01", "MONO10", "TRUECOLOR", "PSEUDOCOLOR",
43 "DIRECTCOLOR", "STATIC_PSEUDOCOLOR"
44 };
45
46 printf("%s info -----------------------\n", s);
47 printf("id = %16s\n", fixed->id);
48 printf("smem_start = 0x%lx\n", fixed->smem_start);
49 printf("smem_len = %d (0x%x)\n", fixed->smem_len, fixed->smem_len);
50 printf("type = 0x%x\n", fixed->type);
51 printf("type_aux = 0x%x\n", fixed->type_aux);
52 printf("visual = 0x%x (%s)\n", fixed->visual, visuals[fixed->visual]);
53 printf("xpanstep = %d\n", fixed->xpanstep);
54 printf("ypanstep = %d\n", fixed->ypanstep);
55 printf("ywrapstep = %d\n", fixed->ywrapstep);
56 printf("line_length = %d\n", fixed->line_length);
57 printf("mmio_start = 0x%lx\n", fixed->mmio_start);
58 printf("mmio_len = %d (0x%x)\n", fixed->mmio_len, fixed->mmio_len);
59 printf("accel = 0x%x\n", fixed->accel);
60 }
61
62
63 static void
64 print_var_info(const struct fb_var_screeninfo *var, const char *s)
65 {
66 printf("%s info -----------------------\n", s);
67 printf("xres = %d\n", var->xres);
68 printf("yres = %d\n", var->yres);
69 printf("xres_virtual = %d\n", var->xres_virtual);
70 printf("yres_virtual = %d\n", var->yres_virtual);
71 printf("xoffset = %d\n", var->xoffset);
72 printf("yoffset = %d\n", var->yoffset);
73 printf("bits_per_pixel = %d\n", var->bits_per_pixel);
74 printf("grayscale = %d\n", var->grayscale);
75
76 printf("red.offset = %d length = %d msb_right = %d\n",
77 var->red.offset, var->red.length, var->red.msb_right);
78 printf("green.offset = %d length = %d msb_right = %d\n",
79 var->green.offset, var->green.length, var->green.msb_right);
80 printf("blue.offset = %d length = %d msb_right = %d\n",
81 var->blue.offset, var->blue.length, var->blue.msb_right);
82 printf("transp.offset = %d length = %d msb_right = %d\n",
83 var->transp.offset, var->transp.length, var->transp.msb_right);
84
85 printf("nonstd = %d\n", var->nonstd);
86 printf("activate = %d\n", var->activate);
87 printf("height = %d mm\n", var->height);
88 printf("width = %d mm\n", var->width);
89 printf("accel_flags = 0x%x\n", var->accel_flags);
90 printf("pixclock = %d\n", var->pixclock);
91 printf("left_margin = %d\n", var->left_margin);
92 printf("right_margin = %d\n", var->right_margin);
93 printf("upper_margin = %d\n", var->upper_margin);
94 printf("lower_margin = %d\n", var->lower_margin);
95 printf("hsync_len = %d\n", var->hsync_len);
96 printf("vsync_len = %d\n", var->vsync_len);
97 printf("sync = %d\n", var->sync);
98 printf("vmode = %d\n", var->vmode);
99 }
100
101
102 static void
103 signal_handler(int signumber)
104 {
105 signal(signumber, SIG_IGN); /* prevent recursion! */
106 fprintf(stderr, "error: got signal %d (exiting)\n", signumber);
107 exit(1);
108 }
109
110
111 static void
112 initialize_fbdev( void )
113 {
114 char ttystr[1000];
115 int fd, vtnumber, ttyfd;
116 int sz;
117
118 (void) sz;
119
120 if (geteuid()) {
121 fprintf(stderr, "error: you need to be root\n");
122 exit(1);
123 }
124
125 #if 1
126 /* open the framebuffer device */
127 FrameBufferFD = open("/dev/fb0", O_RDWR);
128 if (FrameBufferFD < 0) {
129 fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno));
130 exit(1);
131 }
132 #endif
133
134 /* open /dev/tty0 and get the vt number */
135 if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) {
136 fprintf(stderr, "error opening /dev/tty0\n");
137 exit(1);
138 }
139 if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
140 fprintf(stderr, "error: couldn't get a free vt\n");
141 exit(1);
142 }
143 close(fd);
144
145 /* open the console tty */
146 sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */
147 ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
148 if (ConsoleFD < 0) {
149 fprintf(stderr, "error couldn't open console fd\n");
150 exit(1);
151 }
152
153 /* save current vt number */
154 {
155 struct vt_stat vts;
156 if (ioctl(ConsoleFD, VT_GETSTATE, &vts) == 0)
157 OriginalVT = vts.v_active;
158 }
159
160 /* disconnect from controlling tty */
161 ttyfd = open("/dev/tty", O_RDWR);
162 if (ttyfd >= 0) {
163 ioctl(ttyfd, TIOCNOTTY, 0);
164 close(ttyfd);
165 }
166
167 /* some magic to restore the vt when we exit */
168 {
169 struct vt_mode vt;
170 if (ioctl(ConsoleFD, VT_ACTIVATE, vtnumber) != 0)
171 printf("ioctl VT_ACTIVATE: %s\n", strerror(errno));
172 if (ioctl(ConsoleFD, VT_WAITACTIVE, vtnumber) != 0)
173 printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno));
174
175 if (ioctl(ConsoleFD, VT_GETMODE, &vt) < 0) {
176 fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
177 exit(1);
178 }
179
180 vt.mode = VT_PROCESS;
181 vt.relsig = SIGUSR1;
182 vt.acqsig = SIGUSR1;
183 if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) {
184 fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
185 strerror(errno));
186 exit(1);
187 }
188 }
189
190 /* go into graphics mode */
191 if (ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
192 fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
193 strerror(errno));
194 exit(1);
195 }
196
197
198 #if 0
199 /* open the framebuffer device */
200 FrameBufferFD = open("/dev/fb0", O_RDWR);
201 if (FrameBufferFD < 0) {
202 fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno));
203 exit(1);
204 }
205 #endif
206
207 /* Get the fixed screen info */
208 if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
209 fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
210 strerror(errno));
211 exit(1);
212 }
213
214 print_fixed_info(&FixedInfo, "Fixed");
215
216
217 /* get the variable screen info */
218 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
219 fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
220 strerror(errno));
221 exit(1);
222 }
223
224 print_var_info(&OrigVarInfo, "Orig Var");
225
226 /* operate on a copy */
227 VarInfo = OrigVarInfo;
228
229 /* set the depth, resolution, etc */
230 DesiredDepth = 32;
231 if (DesiredDepth)
232 VarInfo.bits_per_pixel = DesiredDepth;
233
234 if (VarInfo.bits_per_pixel == 16) {
235 VarInfo.red.offset = 11;
236 VarInfo.green.offset = 5;
237 VarInfo.blue.offset = 0;
238 VarInfo.red.length = 5;
239 VarInfo.green.length = 6;
240 VarInfo.blue.length = 5;
241 VarInfo.transp.offset = 0;
242 VarInfo.transp.length = 0;
243 }
244 else if (VarInfo.bits_per_pixel == 32) {
245 VarInfo.red.offset = 16;
246 VarInfo.green.offset = 8;
247 VarInfo.blue.offset = 0;
248 VarInfo.transp.offset = 24;
249 VarInfo.red.length = 8;
250 VarInfo.green.length = 8;
251 VarInfo.blue.length = 8;
252 VarInfo.transp.length = 8;
253 }
254 /* timing values taken from /etc/fb.modes (1280x1024 @ 75Hz) */
255 VarInfo.xres_virtual = VarInfo.xres = 1280;
256 VarInfo.yres_virtual = VarInfo.yres = 1024;
257 VarInfo.pixclock = 7408;
258 VarInfo.left_margin = 248;
259 VarInfo.right_margin = 16;
260 VarInfo.upper_margin = 38;
261 VarInfo.lower_margin = 1;
262 VarInfo.hsync_len = 144;
263 VarInfo.vsync_len = 3;
264
265 VarInfo.xoffset = 0;
266 VarInfo.yoffset = 0;
267 VarInfo.nonstd = 0;
268 VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
269
270 /* set new variable screen info */
271 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
272 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
273 strerror(errno));
274 exit(1);
275 }
276
277 print_var_info(&VarInfo, "New Var");
278
279 if (FixedInfo.visual != FB_VISUAL_TRUECOLOR &&
280 FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
281 fprintf(stderr, "non-TRUE/DIRECT-COLOR visuals (0x%x) not supported by this demo.\n", FixedInfo.visual);
282 exit(1);
283 }
284
285 /* initialize colormap */
286 if (FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
287 struct fb_cmap cmap;
288 unsigned short red[256], green[256], blue[256];
289 int i;
290
291 /* we're assuming 256 entries here */
292 printf("initializing directcolor colormap\n");
293 cmap.start = 0;
294 cmap.len = 256;
295 cmap.red = red;
296 cmap.green = green;
297 cmap.blue = blue;
298 cmap.transp = NULL;
299 for (i = 0; i < cmap.len; i++) {
300 red[i] = green[i] = blue[i] = (i << 8) | i;
301 }
302 if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
303 fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
304 }
305 }
306
307 /*
308 * fbdev says the frame buffer is at offset zero, and the mmio region
309 * is immediately after.
310 */
311
312 /* mmap the framebuffer into our address space */
313 FrameBuffer = (caddr_t) mmap(0, /* start */
314 FixedInfo.smem_len, /* bytes */
315 PROT_READ | PROT_WRITE, /* prot */
316 MAP_SHARED, /* flags */
317 FrameBufferFD, /* fd */
318 0 /* offset */);
319 if (FrameBuffer == (caddr_t) - 1) {
320 fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
321 strerror(errno));
322 exit(1);
323 }
324 printf("FrameBuffer = %p\n", FrameBuffer);
325
326 #if 1
327 /* mmap the MMIO region into our address space */
328 MMIOAddress = (caddr_t) mmap(0, /* start */
329 FixedInfo.mmio_len, /* bytes */
330 PROT_READ | PROT_WRITE, /* prot */
331 MAP_SHARED, /* flags */
332 FrameBufferFD, /* fd */
333 FixedInfo.smem_len /* offset */);
334 if (MMIOAddress == (caddr_t) - 1) {
335 fprintf(stderr, "error: unable to mmap mmio region: %s\n",
336 strerror(errno));
337 }
338 printf("MMIOAddress = %p\n", MMIOAddress);
339
340 /* try out some simple MMIO register reads */
341 if (1)
342 {
343 typedef unsigned int CARD32;
344 typedef unsigned char CARD8;
345 #define RADEON_CONFIG_MEMSIZE 0x00f8
346 #define RADEON_MEM_SDRAM_MODE_REG 0x0158
347 #define MMIO_IN32(base, offset) \
348 *(volatile CARD32 *)(void *)(((CARD8*)(base)) + (offset))
349 #define INREG(addr) MMIO_IN32(MMIOAddress, addr)
350 int sz, type;
351 const char *typeStr[] = {"SDR", "DDR", "64-bit SDR"};
352 sz = INREG(RADEON_CONFIG_MEMSIZE);
353 type = INREG(RADEON_MEM_SDRAM_MODE_REG);
354 printf("RADEON_CONFIG_MEMSIZE = %d (%d MB)\n", sz, sz / 1024 / 1024);
355 printf("RADEON_MEM_SDRAM_MODE_REG >> 30 = %d (%s)\n",
356 type >> 30, typeStr[type>>30]);
357 }
358 #endif
359
360 }
361
362
363 static void
364 shutdown_fbdev( void )
365 {
366 struct vt_mode VT;
367
368 printf("cleaning up...\n");
369 /* restore original variable screen info */
370 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo)) {
371 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
372 strerror(errno));
373 exit(1);
374 }
375
376 munmap(MMIOAddress, FixedInfo.mmio_len);
377 munmap(FrameBuffer, FixedInfo.smem_len);
378 close(FrameBufferFD);
379
380 /* restore text mode */
381 ioctl(ConsoleFD, KDSETMODE, KD_TEXT);
382
383 /* set vt */
384 if (ioctl(ConsoleFD, VT_GETMODE, &VT) != -1) {
385 VT.mode = VT_AUTO;
386 ioctl(ConsoleFD, VT_SETMODE, &VT);
387 }
388
389 /* restore original vt */
390 if (OriginalVT >= 0) {
391 ioctl(ConsoleFD, VT_ACTIVATE, OriginalVT);
392 OriginalVT = -1;
393 }
394
395 close(ConsoleFD);
396 }
397
398
399 /* Borrowed from GLUT */
400 static void
401 doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
402 {
403 int i, j;
404 GLfloat theta, phi, theta1;
405 GLfloat cosTheta, sinTheta;
406 GLfloat cosTheta1, sinTheta1;
407 GLfloat ringDelta, sideDelta;
408
409 ringDelta = 2.0 * M_PI / rings;
410 sideDelta = 2.0 * M_PI / nsides;
411
412 theta = 0.0;
413 cosTheta = 1.0;
414 sinTheta = 0.0;
415 for (i = rings - 1; i >= 0; i--) {
416 theta1 = theta + ringDelta;
417 cosTheta1 = cos(theta1);
418 sinTheta1 = sin(theta1);
419 glBegin(GL_QUAD_STRIP);
420 phi = 0.0;
421 for (j = nsides; j >= 0; j--) {
422 GLfloat cosPhi, sinPhi, dist;
423
424 phi += sideDelta;
425 cosPhi = cos(phi);
426 sinPhi = sin(phi);
427 dist = R + r * cosPhi;
428
429 glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
430 glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
431 glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
432 glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
433 }
434 glEnd();
435 theta = theta1;
436 cosTheta = cosTheta1;
437 sinTheta = sinTheta1;
438 }
439 }
440
441
442 static void
443 gltest( void )
444 {
445 static const int attribs[] = {
446 GLFBDEV_DOUBLE_BUFFER,
447 GLFBDEV_DEPTH_SIZE, 16,
448 GLFBDEV_NONE
449 };
450 GLFBDevContextPtr ctx;
451 GLFBDevBufferPtr buf;
452 GLFBDevVisualPtr vis;
453 int bytes, r, g, b, a;
454 float ang;
455
456 printf("GLFBDEV_VENDOR = %s\n", glFBDevGetString(GLFBDEV_VENDOR));
457 printf("GLFBDEV_VERSION = %s\n", glFBDevGetString(GLFBDEV_VERSION));
458
459 /* framebuffer size */
460 bytes = VarInfo.xres_virtual * VarInfo.yres_virtual * VarInfo.bits_per_pixel / 8;
461
462 vis = glFBDevCreateVisual( &FixedInfo, &VarInfo, attribs );
463 assert(vis);
464
465 buf = glFBDevCreateBuffer( &FixedInfo, &VarInfo, vis, FrameBuffer, NULL, bytes );
466 assert(buf);
467
468 ctx = glFBDevCreateContext( vis, NULL );
469 assert(buf);
470
471 b = glFBDevMakeCurrent( ctx, buf, buf );
472 assert(b);
473
474 /*printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));*/
475 glGetIntegerv(GL_RED_BITS, &r);
476 glGetIntegerv(GL_GREEN_BITS, &g);
477 glGetIntegerv(GL_BLUE_BITS, &b);
478 glGetIntegerv(GL_ALPHA_BITS, &a);
479 printf("RED_BITS=%d GREEN_BITS=%d BLUE_BITS=%d ALPHA_BITS=%d\n",
480 r, g, b, a);
481
482 glClearColor(0.5, 0.5, 1.0, 0);
483 glMatrixMode(GL_PROJECTION);
484 glLoadIdentity();
485 glFrustum(-1, 1, -1, 1, 2, 30);
486 glMatrixMode(GL_MODELVIEW);
487 glLoadIdentity();
488 glTranslatef(0, 0, -15);
489 glViewport(0, 0, VarInfo.xres_virtual, VarInfo.yres_virtual);
490 glEnable(GL_LIGHTING);
491 glEnable(GL_LIGHT0);
492 glEnable(GL_DEPTH_TEST);
493
494 for (ang = 0; ang <= 180; ang += 15) {
495 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
496 glPushMatrix();
497 glRotatef(ang, 1, 0, 0);
498 doughnut(1, 3, 40, 20);
499 glPopMatrix();
500 glFBDevSwapBuffers(buf);
501 }
502
503 /* clean up */
504 b = glFBDevMakeCurrent( NULL, NULL, NULL);
505 assert(b);
506
507 glFBDevDestroyContext(ctx);
508 glFBDevDestroyBuffer(buf);
509 glFBDevDestroyVisual(vis);
510 }
511
512
513 int
514 main( int argc, char *argv[] )
515 {
516 signal(SIGUSR1, signal_handler); /* exit if someone tries a vt switch */
517 signal(SIGSEGV, signal_handler); /* catch segfaults */
518
519 initialize_fbdev();
520 gltest();
521 shutdown_fbdev();
522
523 return 0;
524 }