X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=ginge.git;a=blobdiff_plain;f=common%2Ffbdev.c;fp=common%2Ffbdev.c;h=069dc6e9c81129159ef383d90ea7ce5d65eef906;hp=0000000000000000000000000000000000000000;hb=3adc9ccb6566130bde29eeaf5c126f28c57c57d5;hpb=2ce69bdff40e40fb1c1954e0883d95de271cecc7 diff --git a/common/fbdev.c b/common/fbdev.c new file mode 100644 index 0000000..069dc6e --- /dev/null +++ b/common/fbdev.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fbdev.h" + +#define FBDEV_MAX_BUFFERS 3 + +struct vout_fbdev { + int fd; + void *mem; + size_t mem_size; + struct fb_var_screeninfo fbvar_old; + struct fb_var_screeninfo fbvar_new; + int buffer_write; + void *buffers[FBDEV_MAX_BUFFERS]; + int buffer_count; +}; + +void *vout_fbdev_flip(struct vout_fbdev *fbdev) +{ + int draw_buf; + + if (fbdev->buffer_count < 2) + return fbdev->mem; + + draw_buf = fbdev->buffer_write; + fbdev->buffer_write++; + if (fbdev->buffer_write >= fbdev->buffer_count) + fbdev->buffer_write = 0; + + fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * draw_buf; + + ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new); + + return fbdev->buffers[fbdev->buffer_write]; +} + +void vout_fbdev_wait_vsync(struct vout_fbdev *fbdev) +{ + int arg = 0; + ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &arg); +} + +void vout_fbdev_clear(struct vout_fbdev *fbdev) +{ + memset(fbdev->mem, 0, fbdev->mem_size); +} + +struct vout_fbdev *vout_fbdev_init(const char *fbdev_name, int *w, int *h, int no_dblbuf) +{ + struct vout_fbdev *fbdev; + int i, ret; + + fbdev = calloc(1, sizeof(*fbdev)); + if (fbdev == NULL) + return NULL; + + fbdev->fd = open(fbdev_name, O_RDWR, 0); + if (fbdev->fd == -1) { + fprintf(stderr, "%s: ", fbdev_name); + perror("open"); + goto fail_open; + } + + ret = ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->fbvar_old); + if (ret == -1) { + perror("FBIOGET_VSCREENINFO ioctl"); + goto fail; + } + + fbdev->fbvar_new = fbdev->fbvar_old; + printf("%s: %ix%i@%d\n", fbdev_name, fbdev->fbvar_old.xres, fbdev->fbvar_old.yres, + fbdev->fbvar_old.bits_per_pixel); + *w = fbdev->fbvar_old.xres; + *h = fbdev->fbvar_old.yres; + fbdev->buffer_count = FBDEV_MAX_BUFFERS; // be optimistic + if (no_dblbuf) + fbdev->buffer_count = 1; + + if (fbdev->fbvar_new.bits_per_pixel != 16) { + printf(" switching to 16bpp\n"); + fbdev->fbvar_new.bits_per_pixel = 16; + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + perror("FBIOPUT_VSCREENINFO ioctl"); + goto fail; + } + } + + if (fbdev->fbvar_new.yres_virtual < fbdev->fbvar_old.yres * fbdev->buffer_count) { + fbdev->fbvar_new.yres_virtual = fbdev->fbvar_old.yres * fbdev->buffer_count; + ret = ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_new); + if (ret == -1) { + fbdev->buffer_count = 1; + fprintf(stderr, "Warning: failed to increase virtual resolution, " + "doublebuffering disabled\n"); + } + } + + fbdev->mem_size = *w * *h * 2 * fbdev->buffer_count; + fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0); + if (fbdev->mem == MAP_FAILED && fbdev->buffer_count > 1) { + fprintf(stderr, "Warning: can't map %zd bytes, doublebuffering disabled\n", fbdev->mem_size); + fbdev->mem_size = *w * *h * 2; + fbdev->buffer_count = 1; + fbdev->mem = mmap(0, fbdev->mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev->fd, 0); + } + if (fbdev->mem == MAP_FAILED) { + perror("mmap framebuffer"); + goto fail; + } + memset(fbdev->mem, 0, fbdev->mem_size); + for (i = 0; i < fbdev->buffer_count; i++) + fbdev->buffers[i] = (char *)fbdev->mem + i * *w * *h * 2; + + // some checks + ret = 0; + ret = ioctl(fbdev->fd, FBIO_WAITFORVSYNC, &ret); + if (ret != 0) + fprintf(stderr, "Warning: vsync doesn't seem to be supported\n"); + + if (fbdev->buffer_count > 1) { + fbdev->buffer_write = 0; + fbdev->fbvar_new.yoffset = fbdev->fbvar_old.yres * (fbdev->buffer_count - 1); + ret = ioctl(fbdev->fd, FBIOPAN_DISPLAY, &fbdev->fbvar_new); + if (ret != 0) { + fbdev->buffer_count = 1; + fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n"); + } + } + + printf("fbdev initialized.\n"); + return fbdev; + +fail: + close(fbdev->fd); +fail_open: + free(fbdev); + return NULL; +} + +void vout_fbdev_finish(struct vout_fbdev *fbdev) +{ + ioctl(fbdev->fd, FBIOPUT_VSCREENINFO, &fbdev->fbvar_old); + if (fbdev->mem != MAP_FAILED) + munmap(fbdev->mem, fbdev->mem_size); + if (fbdev->fd >= 0) + close(fbdev->fd); + fbdev->mem = NULL; + fbdev->fd = -1; + free(fbdev); +} + +#if 0 +void *g_screen_ptr; +int main() +{ + int w, h; + vout_fbdev_init(&w, &h); + //while (1) + { + memset(g_screen_ptr, 0xff, fbdev_mem_size / 2); + plat_video_wait_vsync(); + plat_video_flip(); + memset(g_screen_ptr, 0x00, fbdev_mem_size / 2); + usleep(8000); +// plat_video_wait_vsync(); + plat_video_flip(); + } +} +#endif