diff options
Diffstat (limited to 'progs/fbdev')
-rw-r--r-- | progs/fbdev/glfbdevtest.c | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/progs/fbdev/glfbdevtest.c b/progs/fbdev/glfbdevtest.c new file mode 100644 index 0000000000..a461c55e2f --- /dev/null +++ b/progs/fbdev/glfbdevtest.c @@ -0,0 +1,524 @@ +/* + * Test the GLFBDev interface. Only tested with radeonfb driver!!!! + * + * Written by Brian Paul + */ + + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <linux/fb.h> +#include <linux/kd.h> +#include <linux/vt.h> +#include <GL/gl.h> +#include <GL/glfbdev.h> +#include <math.h> + +#define DEFAULT_DEPTH 8 + +static struct fb_fix_screeninfo FixedInfo; +static struct fb_var_screeninfo VarInfo, OrigVarInfo; +static int DesiredDepth = 0; +static int OriginalVT = -1; +static int ConsoleFD = -1; +static int FrameBufferFD = -1; +static caddr_t FrameBuffer = (caddr_t) -1; +static caddr_t MMIOAddress = (caddr_t) -1; + + +static void +print_fixed_info(const struct fb_fix_screeninfo *fixed, const char *s) +{ + static const char *visuals[] = { + "MONO01", "MONO10", "TRUECOLOR", "PSEUDOCOLOR", + "DIRECTCOLOR", "STATIC_PSEUDOCOLOR" + }; + + printf("%s info -----------------------\n", s); + printf("id = %16s\n", fixed->id); + printf("smem_start = 0x%lx\n", fixed->smem_start); + printf("smem_len = %d (0x%x)\n", fixed->smem_len, fixed->smem_len); + printf("type = 0x%x\n", fixed->type); + printf("type_aux = 0x%x\n", fixed->type_aux); + printf("visual = 0x%x (%s)\n", fixed->visual, visuals[fixed->visual]); + printf("xpanstep = %d\n", fixed->xpanstep); + printf("ypanstep = %d\n", fixed->ypanstep); + printf("ywrapstep = %d\n", fixed->ywrapstep); + printf("line_length = %d\n", fixed->line_length); + printf("mmio_start = 0x%lx\n", fixed->mmio_start); + printf("mmio_len = %d (0x%x)\n", fixed->mmio_len, fixed->mmio_len); + printf("accel = 0x%x\n", fixed->accel); +} + + +static void +print_var_info(const struct fb_var_screeninfo *var, const char *s) +{ + printf("%s info -----------------------\n", s); + printf("xres = %d\n", var->xres); + printf("yres = %d\n", var->yres); + printf("xres_virtual = %d\n", var->xres_virtual); + printf("yres_virtual = %d\n", var->yres_virtual); + printf("xoffset = %d\n", var->xoffset); + printf("yoffset = %d\n", var->yoffset); + printf("bits_per_pixel = %d\n", var->bits_per_pixel); + printf("grayscale = %d\n", var->grayscale); + + printf("red.offset = %d length = %d msb_right = %d\n", + var->red.offset, var->red.length, var->red.msb_right); + printf("green.offset = %d length = %d msb_right = %d\n", + var->green.offset, var->green.length, var->green.msb_right); + printf("blue.offset = %d length = %d msb_right = %d\n", + var->blue.offset, var->blue.length, var->blue.msb_right); + printf("transp.offset = %d length = %d msb_right = %d\n", + var->transp.offset, var->transp.length, var->transp.msb_right); + + printf("nonstd = %d\n", var->nonstd); + printf("activate = %d\n", var->activate); + printf("height = %d mm\n", var->height); + printf("width = %d mm\n", var->width); + printf("accel_flags = 0x%x\n", var->accel_flags); + printf("pixclock = %d\n", var->pixclock); + printf("left_margin = %d\n", var->left_margin); + printf("right_margin = %d\n", var->right_margin); + printf("upper_margin = %d\n", var->upper_margin); + printf("lower_margin = %d\n", var->lower_margin); + printf("hsync_len = %d\n", var->hsync_len); + printf("vsync_len = %d\n", var->vsync_len); + printf("sync = %d\n", var->sync); + printf("vmode = %d\n", var->vmode); +} + + +static void +signal_handler(int signumber) +{ + signal(signumber, SIG_IGN); /* prevent recursion! */ + fprintf(stderr, "error: got signal %d (exiting)\n", signumber); + exit(1); +} + + +static void +initialize_fbdev( void ) +{ + char ttystr[1000]; + int fd, vtnumber, ttyfd; + int sz; + + (void) sz; + + if (geteuid()) { + fprintf(stderr, "error: you need to be root\n"); + exit(1); + } + +#if 1 + /* open the framebuffer device */ + FrameBufferFD = open("/dev/fb0", O_RDWR); + if (FrameBufferFD < 0) { + fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno)); + exit(1); + } +#endif + + /* open /dev/tty0 and get the vt number */ + if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) { + fprintf(stderr, "error opening /dev/tty0\n"); + exit(1); + } + if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) { + fprintf(stderr, "error: couldn't get a free vt\n"); + exit(1); + } + close(fd); + + /* open the console tty */ + sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */ + ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0); + if (ConsoleFD < 0) { + fprintf(stderr, "error couldn't open console fd\n"); + exit(1); + } + + /* save current vt number */ + { + struct vt_stat vts; + if (ioctl(ConsoleFD, VT_GETSTATE, &vts) == 0) + OriginalVT = vts.v_active; + } + + /* disconnect from controlling tty */ + ttyfd = open("/dev/tty", O_RDWR); + if (ttyfd >= 0) { + ioctl(ttyfd, TIOCNOTTY, 0); + close(ttyfd); + } + + /* some magic to restore the vt when we exit */ + { + struct vt_mode vt; + if (ioctl(ConsoleFD, VT_ACTIVATE, vtnumber) != 0) + printf("ioctl VT_ACTIVATE: %s\n", strerror(errno)); + if (ioctl(ConsoleFD, VT_WAITACTIVE, vtnumber) != 0) + printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno)); + + if (ioctl(ConsoleFD, VT_GETMODE, &vt) < 0) { + fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno)); + exit(1); + } + + vt.mode = VT_PROCESS; + vt.relsig = SIGUSR1; + vt.acqsig = SIGUSR1; + if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) { + fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n", + strerror(errno)); + exit(1); + } + } + + /* go into graphics mode */ + if (ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) { + fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n", + strerror(errno)); + exit(1); + } + + +#if 0 + /* open the framebuffer device */ + FrameBufferFD = open("/dev/fb0", O_RDWR); + if (FrameBufferFD < 0) { + fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno)); + exit(1); + } +#endif + + /* Get the fixed screen info */ + if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) { + fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n", + strerror(errno)); + exit(1); + } + + print_fixed_info(&FixedInfo, "Fixed"); + + + /* get the variable screen info */ + if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) { + fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n", + strerror(errno)); + exit(1); + } + + print_var_info(&OrigVarInfo, "Orig Var"); + + /* operate on a copy */ + VarInfo = OrigVarInfo; + + /* set the depth, resolution, etc */ + DesiredDepth = 32; + if (DesiredDepth) + VarInfo.bits_per_pixel = DesiredDepth; + + if (VarInfo.bits_per_pixel == 16) { + VarInfo.red.offset = 11; + VarInfo.green.offset = 5; + VarInfo.blue.offset = 0; + VarInfo.red.length = 5; + VarInfo.green.length = 6; + VarInfo.blue.length = 5; + VarInfo.transp.offset = 0; + VarInfo.transp.length = 0; + } + else if (VarInfo.bits_per_pixel == 32) { + VarInfo.red.offset = 16; + VarInfo.green.offset = 8; + VarInfo.blue.offset = 0; + VarInfo.transp.offset = 24; + VarInfo.red.length = 8; + VarInfo.green.length = 8; + VarInfo.blue.length = 8; + VarInfo.transp.length = 8; + } + /* timing values taken from /etc/fb.modes (1280x1024 @ 75Hz) */ + VarInfo.xres_virtual = VarInfo.xres = 1280; + VarInfo.yres_virtual = VarInfo.yres = 1024; + VarInfo.pixclock = 7408; + VarInfo.left_margin = 248; + VarInfo.right_margin = 16; + VarInfo.upper_margin = 38; + VarInfo.lower_margin = 1; + VarInfo.hsync_len = 144; + VarInfo.vsync_len = 3; + + VarInfo.xoffset = 0; + VarInfo.yoffset = 0; + VarInfo.nonstd = 0; + VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */ + + /* set new variable screen info */ + if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) { + fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n", + strerror(errno)); + exit(1); + } + + print_var_info(&VarInfo, "New Var"); + + if (FixedInfo.visual != FB_VISUAL_TRUECOLOR && + FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) { + fprintf(stderr, "non-TRUE/DIRECT-COLOR visuals (0x%x) not supported by this demo.\n", FixedInfo.visual); + exit(1); + } + + /* initialize colormap */ + if (FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) { + struct fb_cmap cmap; + unsigned short red[256], green[256], blue[256]; + int i; + + /* we're assuming 256 entries here */ + printf("initializing directcolor colormap\n"); + cmap.start = 0; + cmap.len = 256; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = NULL; + for (i = 0; i < cmap.len; i++) { + red[i] = green[i] = blue[i] = (i << 8) | i; + } + if (ioctl(FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) { + fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i); + } + } + + /* + * fbdev says the frame buffer is at offset zero, and the mmio region + * is immediately after. + */ + + /* mmap the framebuffer into our address space */ + FrameBuffer = (caddr_t) mmap(0, /* start */ + FixedInfo.smem_len, /* bytes */ + PROT_READ | PROT_WRITE, /* prot */ + MAP_SHARED, /* flags */ + FrameBufferFD, /* fd */ + 0 /* offset */); + if (FrameBuffer == (caddr_t) - 1) { + fprintf(stderr, "error: unable to mmap framebuffer: %s\n", + strerror(errno)); + exit(1); + } + printf("FrameBuffer = %p\n", FrameBuffer); + +#if 1 + /* mmap the MMIO region into our address space */ + MMIOAddress = (caddr_t) mmap(0, /* start */ + FixedInfo.mmio_len, /* bytes */ + PROT_READ | PROT_WRITE, /* prot */ + MAP_SHARED, /* flags */ + FrameBufferFD, /* fd */ + FixedInfo.smem_len /* offset */); + if (MMIOAddress == (caddr_t) - 1) { + fprintf(stderr, "error: unable to mmap mmio region: %s\n", + strerror(errno)); + } + printf("MMIOAddress = %p\n", MMIOAddress); + + /* try out some simple MMIO register reads */ + if (1) + { + typedef unsigned int CARD32; + typedef unsigned char CARD8; +#define RADEON_CONFIG_MEMSIZE 0x00f8 +#define RADEON_MEM_SDRAM_MODE_REG 0x0158 +#define MMIO_IN32(base, offset) \ + *(volatile CARD32 *)(void *)(((CARD8*)(base)) + (offset)) +#define INREG(addr) MMIO_IN32(MMIOAddress, addr) + int sz, type; + const char *typeStr[] = {"SDR", "DDR", "64-bit SDR"}; + sz = INREG(RADEON_CONFIG_MEMSIZE); + type = INREG(RADEON_MEM_SDRAM_MODE_REG); + printf("RADEON_CONFIG_MEMSIZE = %d (%d MB)\n", sz, sz / 1024 / 1024); + printf("RADEON_MEM_SDRAM_MODE_REG >> 30 = %d (%s)\n", + type >> 30, typeStr[type>>30]); + } +#endif + +} + + +static void +shutdown_fbdev( void ) +{ + struct vt_mode VT; + + printf("cleaning up...\n"); + /* restore original variable screen info */ + if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo)) { + fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n", + strerror(errno)); + exit(1); + } + + munmap(MMIOAddress, FixedInfo.mmio_len); + munmap(FrameBuffer, FixedInfo.smem_len); + close(FrameBufferFD); + + /* restore text mode */ + ioctl(ConsoleFD, KDSETMODE, KD_TEXT); + + /* set vt */ + if (ioctl(ConsoleFD, VT_GETMODE, &VT) != -1) { + VT.mode = VT_AUTO; + ioctl(ConsoleFD, VT_SETMODE, &VT); + } + + /* restore original vt */ + if (OriginalVT >= 0) { + ioctl(ConsoleFD, VT_ACTIVATE, OriginalVT); + OriginalVT = -1; + } + + close(ConsoleFD); +} + + +/* Borrowed from GLUT */ +static void +doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings) +{ + int i, j; + GLfloat theta, phi, theta1; + GLfloat cosTheta, sinTheta; + GLfloat cosTheta1, sinTheta1; + GLfloat ringDelta, sideDelta; + + ringDelta = 2.0 * M_PI / rings; + sideDelta = 2.0 * M_PI / nsides; + + theta = 0.0; + cosTheta = 1.0; + sinTheta = 0.0; + for (i = rings - 1; i >= 0; i--) { + theta1 = theta + ringDelta; + cosTheta1 = cos(theta1); + sinTheta1 = sin(theta1); + glBegin(GL_QUAD_STRIP); + phi = 0.0; + for (j = nsides; j >= 0; j--) { + GLfloat cosPhi, sinPhi, dist; + + phi += sideDelta; + cosPhi = cos(phi); + sinPhi = sin(phi); + dist = R + r * cosPhi; + + glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi); + glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi); + glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi); + glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi); + } + glEnd(); + theta = theta1; + cosTheta = cosTheta1; + sinTheta = sinTheta1; + } +} + + +static void +gltest( void ) +{ + static const int attribs[] = { + GLFBDEV_DOUBLE_BUFFER, + GLFBDEV_DEPTH_SIZE, 16, + GLFBDEV_NONE + }; + GLFBDevContextPtr ctx; + GLFBDevBufferPtr buf; + GLFBDevVisualPtr vis; + int bytes, r, g, b, a; + float ang; + + printf("GLFBDEV_VENDOR = %s\n", glFBDevGetString(GLFBDEV_VENDOR)); + printf("GLFBDEV_VERSION = %s\n", glFBDevGetString(GLFBDEV_VERSION)); + + /* framebuffer size */ + bytes = VarInfo.xres_virtual * VarInfo.yres_virtual * VarInfo.bits_per_pixel / 8; + + vis = glFBDevCreateVisual( &FixedInfo, &VarInfo, attribs ); + assert(vis); + + buf = glFBDevCreateBuffer( &FixedInfo, &VarInfo, vis, FrameBuffer, NULL, bytes ); + assert(buf); + + ctx = glFBDevCreateContext( vis, NULL ); + assert(buf); + + b = glFBDevMakeCurrent( ctx, buf, buf ); + assert(b); + + /*printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS));*/ + glGetIntegerv(GL_RED_BITS, &r); + glGetIntegerv(GL_GREEN_BITS, &g); + glGetIntegerv(GL_BLUE_BITS, &b); + glGetIntegerv(GL_ALPHA_BITS, &a); + printf("RED_BITS=%d GREEN_BITS=%d BLUE_BITS=%d ALPHA_BITS=%d\n", + r, g, b, a); + + glClearColor(0.5, 0.5, 1.0, 0); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-1, 1, -1, 1, 2, 30); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -15); + glViewport(0, 0, VarInfo.xres_virtual, VarInfo.yres_virtual); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_DEPTH_TEST); + + for (ang = 0; ang <= 180; ang += 15) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPushMatrix(); + glRotatef(ang, 1, 0, 0); + doughnut(1, 3, 40, 20); + glPopMatrix(); + glFBDevSwapBuffers(buf); + } + + /* clean up */ + b = glFBDevMakeCurrent( NULL, NULL, NULL); + assert(b); + + glFBDevDestroyContext(ctx); + glFBDevDestroyBuffer(buf); + glFBDevDestroyVisual(vis); +} + + +int +main( int argc, char *argv[] ) +{ + signal(SIGUSR1, signal_handler); /* exit if someone tries a vt switch */ + signal(SIGSEGV, signal_handler); /* catch segfaults */ + + initialize_fbdev(); + gltest(); + shutdown_fbdev(); + + return 0; +} |