fbdev backend works
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 19 May 2021 03:01:40 +0000 (06:01 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 19 May 2021 03:01:40 +0000 (06:01 +0300)
src/fbdev/fbevents.c [new file with mode: 0644]
src/fbdev/fbevents.h [new file with mode: 0644]
src/fbdev/fbgfx.c [new file with mode: 0644]
src/fbdev/fbgfx.h [new file with mode: 0644]
src/fbdev/main.c

diff --git a/src/fbdev/fbevents.c b/src/fbdev/fbevents.c
new file mode 100644 (file)
index 0000000..ec0af45
--- /dev/null
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include "fbevents.h"
+
+static struct termios orig_state;
+static int term_fd = -1;       /* tty file descriptor */
+
+static void (*keyb_func)(int, int, void*);
+static void *keyb_cls;
+static void (*mbutton_func)(int, int, int, int, void*);
+static void *mbutton_cls;
+static void (*mmotion_func)(int, int, void*);
+static void *mmotion_cls;
+
+
+int fbev_init(void)
+{
+       struct termios tstate;
+
+       if((term_fd = open("/dev/tty", O_RDWR)) == -1) {
+               perror("failed to open tty");
+               return -1;
+       }
+       fcntl(term_fd, F_SETFL, fcntl(term_fd, F_GETFL) | O_NONBLOCK);
+
+       if(tcgetattr(term_fd, &tstate) == -1) {
+               perror("failed to retrieve tty attribs");
+               close(term_fd);
+               return -1;
+       }
+       orig_state = tstate;
+
+       cfmakeraw(&tstate);
+       /* keep output flags as they where, since we'll be drawing directly to fbdev */
+       tstate.c_oflag = orig_state.c_oflag;
+       if(tcsetattr(term_fd, TCSANOW, &tstate) == -1) {
+               perror("failed put terminal into raw mode");
+               close(term_fd);
+               return -1;
+       }
+       return 0;
+}
+
+void fbev_shutdown(void)
+{
+       if(term_fd >= 0) {
+               tcsetattr(term_fd, TCSANOW, &orig_state);
+               close(term_fd);
+               term_fd = -1;
+       }
+}
+
+void fbev_update(void)
+{
+       char buf[64];
+       int i, sz;
+       assert(term_fd >= 0);
+
+       while((sz = read(term_fd, buf, 64)) > 0) {
+               if(keyb_func) {
+                       for(i=0; i<sz; i++) {
+                               keyb_func(buf[i], 1, keyb_cls);
+                       }
+               }
+       }
+}
+
+void fbev_keyboard(void (*func)(int, int, void*), void *cls)
+{
+       keyb_func = func;
+       keyb_cls = cls;
+}
+
+void fbev_mbutton(void (*func)(int, int, int, int, void*), void *cls)
+{
+       mbutton_func = func;
+       mbutton_cls = cls;
+}
+
+void fbev_mmotion(void (*func)(int, int, void*), void *cls)
+{
+       mmotion_func = func;
+       mmotion_cls = cls;
+}
diff --git a/src/fbdev/fbevents.h b/src/fbdev/fbevents.h
new file mode 100644 (file)
index 0000000..5feecbe
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef FBEVENTS_H_
+#define FBEVENTS_H_
+
+int fbev_init(void);
+void fbev_shutdown(void);
+
+void fbev_update(void);
+
+void fbev_keyboard(void (*func)(int, int, void*), void *cls);
+void fbev_mbutton(void (*func)(int, int, int, int, void*), void *cls);
+void fbev_mmotion(void (*func)(int, int, void*), void *cls);
+
+#endif /* FBEVENTS_H_ */
diff --git a/src/fbdev/fbgfx.c b/src/fbdev/fbgfx.c
new file mode 100644 (file)
index 0000000..1d403d8
--- /dev/null
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/fb.h>
+#include "fbgfx.h"
+
+static void cleanup(void);
+
+static int fd = -1;
+static void *vmem;
+static int vmem_size;
+static struct fb_fix_screeninfo finfo;
+static struct fb_var_screeninfo vinfo;
+static struct fb_var_screeninfo saved_vinfo;
+static int saved_vinfo_valid;
+static struct fbgfx_vmode curvm;
+
+static int init(void)
+{
+       if(fd >= 0) return 0;
+
+       if((fd = open("/dev/fb0", O_RDWR)) == -1) {
+               fprintf(stderr, "failed to open framebuffer device\n");
+               return -1;
+       }
+
+       ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
+
+       curvm.pitch = finfo.line_length;
+
+       atexit(cleanup);
+       return 0;
+}
+
+static void cleanup(void)
+{
+       if(vmem) {
+               munmap(vmem, vmem_size);
+       }
+       if(fd != -1) {
+               close(fd);
+       }
+}
+
+void *fbgfx_set_video_mode(int x, int y, int depth)
+{
+       struct fb_var_screeninfo new_vinfo;
+
+       if(init() == -1) {
+               return 0;
+       }
+
+       ioctl(fd, FBIOGET_VSCREENINFO, &new_vinfo);
+       new_vinfo.xres = x;
+       new_vinfo.yres = y;
+       new_vinfo.bits_per_pixel = depth;
+
+       if(ioctl(fd, FBIOPUT_VSCREENINFO, &new_vinfo) == -1) {
+               fprintf(stderr, "failed to set video mode %dx%d %dbpp: %s\n", x, y, depth, strerror(errno));
+               return 0;
+       }
+
+       if(vmem) {
+               munmap(vmem, vmem_size);
+               vmem = 0;
+               vmem_size = 0;
+       }
+
+       return fbgfx_get_video_mode(0, 0, 0);
+}
+
+void *fbgfx_get_video_mode(int *xptr, int *yptr, int *depthptr)
+{
+       if(init() == -1) {
+               return 0;
+       }
+
+       ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
+       /*vmem_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;*/
+       vmem_size = finfo.smem_len;
+
+       curvm.width = vinfo.xres;
+       curvm.height = vinfo.yres;
+       curvm.bpp = vinfo.bits_per_pixel;
+       curvm.fbsize = vmem_size;
+       curvm.rshift = vinfo.red.offset;
+       curvm.gshift = vinfo.green.offset;
+       curvm.bshift = vinfo.blue.offset;
+       curvm.rmask = (0xffffffff >> (32 - vinfo.red.length)) << curvm.rshift;
+       curvm.gmask = (0xffffffff >> (32 - vinfo.green.length)) << curvm.gshift;
+       curvm.bmask = (0xffffffff >> (32 - vinfo.blue.length)) << curvm.bshift;
+
+       if(!vmem) {
+               if((vmem = mmap(0, vmem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) {
+                       fprintf(stderr, "failed to map video memory\n");
+                       vmem = 0;
+                       return 0;
+               }
+       }
+       if(xptr) *xptr = vinfo.xres;
+       if(yptr) *yptr = vinfo.yres;
+       if(depthptr) *depthptr = vinfo.bits_per_pixel;
+       return vmem;
+}
+
+void fbgfx_save_video_mode(void)
+{
+       if(init() == -1) {
+               return;
+       }
+
+       if(ioctl(fd, FBIOGET_VSCREENINFO, &saved_vinfo) == -1) {
+               return;
+       }
+       saved_vinfo_valid = 1;
+}
+
+void fbgfx_restore_video_mode(void)
+{
+       if(init() == -1 || !saved_vinfo_valid) {
+               return;
+       }
+       ioctl(fd, FBIOPUT_VSCREENINFO, &saved_vinfo);
+}
+
+struct fbgfx_vmode *fbgfx_video_mode_info(void)
+{
+       return &curvm;
+}
diff --git a/src/fbdev/fbgfx.h b/src/fbdev/fbgfx.h
new file mode 100644 (file)
index 0000000..882d883
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef FBGFX_H_
+#define FBGFX_H_
+
+struct fbgfx_vmode {
+       int width, height, bpp;
+       int pitch;
+       unsigned int rmask, gmask, bmask;
+       int rshift, gshift, bshift;
+       int fbsize;
+};
+
+void *fbgfx_set_video_mode(int x, int y, int depth);
+void *fbgfx_get_video_mode(int *xptr, int *yptr, int *depthptr);
+
+void fbgfx_save_video_mode(void);
+void fbgfx_restore_video_mode(void);
+
+struct fbgfx_vmode *fbgfx_video_mode_info(void);
+
+
+#endif /* FBGFX_H_ */
index 3c5def6..88c4638 100644 (file)
@@ -7,23 +7,22 @@
 #include <fcntl.h>
 #include <sys/time.h>
 #include <sys/mman.h>
+#include "fbgfx.h"
+#include "fbevents.h"
 #include "rbench.h"
 #include "util.h"
 
-
-static int init_fbdev(int xsz, int ysz, int bpp);
-static void close_fbdev(void);
+static void keyb(int key, int pressed, void *cls);
 static int parse_args(int argc, char **argv);
 
-static int fbfd = -1;
-static int fbsz;
+static int quit;
 static void *fbmem;
 
-
 int main(int argc, char **argv)
 {
        int num_frames = 0;
        struct timeval tv, tv0;
+       struct fbgfx_vmode *vm;
 
        read_config("rbench.cfg");
 
@@ -31,52 +30,58 @@ int main(int argc, char **argv)
                return 1;
        }
 
-       if(init_fbdev(opt.width, opt.height, opt.bpp) == -1) {
+       fbgfx_save_video_mode();
+       if(!(fbmem = fbgfx_set_video_mode(opt.width, opt.height, opt.bpp))) {
+               fprintf(stderr, "failed to set video mode: %dx%d %dbpp\n", opt.width,
+                               opt.height, opt.bpp);
                return 1;
        }
-
-       fb_width = opt.width;
-       fb_height = opt.height;
-       fb_bpp = opt.bpp;
-       fb_pitch = opt.width * opt.bpp / 8;
+       vm = fbgfx_video_mode_info();
+
+       fb_width = vm->width;
+       fb_height = vm->height;
+       fb_bpp = vm->bpp;
+       fb_pitch = vm->pitch;
+       fb_rmask = vm->rmask;
+       fb_gmask = vm->gmask;
+       fb_bmask = vm->bmask;
+       fb_rshift = vm->rshift;
+       fb_gshift = vm->gshift;
+       fb_bshift = vm->bshift;
 
        if(!(framebuf = malloc(fb_pitch * fb_height))) {
                fprintf(stderr, "failed to allocate %dx%d (%d bpp) framebuffer\n",
                                fb_width, fb_height, fb_bpp);
                return 1;
        }
-       /*
-       fb_rmask = ximg->red_mask;
-       fb_gmask = ximg->green_mask;
-       fb_bmask = ximg->blue_mask;
-       fb_rshift = mask_to_shift(fb_rmask);
-       fb_gshift = mask_to_shift(fb_gmask);
-       fb_bshift = mask_to_shift(fb_bmask);
-       */
 
-       if(init() == -1) {
+       if(fbev_init() == -1) {
                goto end;
        }
+       fbev_keyboard(keyb, 0);
 
-       /* TODO: set terminal raw and disable cursor */
+       if(init() == -1) {
+               goto end;
+       }
 
        gettimeofday(&tv0, 0);
 
        for(;;) {
-               /* TODO read input */
+               fbev_update();
+               if(quit) break;
 
                gettimeofday(&tv, 0);
                time_msec = (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
                num_frames++;
 
                redraw();
-
-               /* TODO copy to fb */
+               memcpy(fbmem, framebuf, fb_pitch * fb_height);
        }
 
 end:
        cleanup();
-       close_fbdev();
+       fbev_shutdown();
+       fbgfx_restore_video_mode();
 
        if(num_frames) {
                printf("avg framerate: %.1f fps\n", (10000 * num_frames / time_msec) / 10.0f);
@@ -84,34 +89,15 @@ end:
        return 0;
 }
 
-int init_fbdev(int xsz, int ysz, int bpp)
+static void keyb(int key, int pressed, void *cls)
 {
-       if((fbfd = open("/dev/fb0", O_RDWR)) == -1) {
-               perror("failed to open framebuffer device");
-               return -1;
-       }
+       if(!pressed) return;
 
-       /* TODO modeset ioctl */
-
-       fbsz = xsz * ysz * bpp / 8;     /* XXX */
-
-       if((fbmem = mmap(0, fbsz, PROT_WRITE, MAP_SHARED, fbfd, 0)) == (void*)-1) {
-               perror("failed to map framebuffer");
-               return -1;
+       if(key == 27 || key == 'q' || key == 'Q') {
+               quit = 1;
        }
-
-       return 0;
 }
 
-void close_fbdev(void)
-{
-       if(fbmem) {
-               munmap(fbmem, fbsz);
-       }
-       if(fbfd >= 0) {
-               close(fbfd);
-       }
-}
 
 static const char *usage_str =
        "Usage: %s [options]\n"