X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=loader%2Fhost_fb.c;fp=loader%2Fhost_fb.c;h=8529f3675752ceb3d3ebe8fb4638ee66f21b0e20;hb=3d295a9fe6e27f6103701e8d8ae23257b43ff2dd;hp=0000000000000000000000000000000000000000;hpb=86418a845b35b2bb08b611fa1a1d1eec05b924c9;p=ginge.git diff --git a/loader/host_fb.c b/loader/host_fb.c new file mode 100644 index 0000000..8529f36 --- /dev/null +++ b/loader/host_fb.c @@ -0,0 +1,164 @@ +/* copy-paste from PD */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FBDEV_MAX_BUFFERS 3 + +static int fbdev = -1; +static void *fbdev_mem = MAP_FAILED; +static int fbdev_mem_size; +static struct fb_var_screeninfo fbvar_old; +static struct fb_var_screeninfo fbvar_new; +static int fbdev_buffer_write; + +static void *fbdev_buffers[FBDEV_MAX_BUFFERS]; +static int fbdev_buffer_count; +static void *g_screen_ptr; + +void plat_video_flip(void) +{ + int draw_buf; + + if (fbdev_buffer_count < 2) + return; + + draw_buf = fbdev_buffer_write; + fbdev_buffer_write++; + if (fbdev_buffer_write >= fbdev_buffer_count) + fbdev_buffer_write = 0; + + fbvar_new.yoffset = fbvar_old.yres * draw_buf; + g_screen_ptr = fbdev_buffers[fbdev_buffer_write]; + + ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar_new); +} + +void plat_video_wait_vsync(void) +{ + int arg = 0; + ioctl(fbdev, FBIO_WAITFORVSYNC, &arg); +} + +int vout_fbdev_init(int *w, int *h) +{ + static const char *fbdev_name = "/dev/fb0"; + int i, ret; + + fbdev = open(fbdev_name, O_RDWR); + if (fbdev == -1) { + fprintf(stderr, "%s: ", fbdev_name); + perror("open"); + return -1; + } + + ret = ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar_old); + if (ret == -1) { + perror("FBIOGET_VSCREENINFO ioctl"); + goto fail; + } + + fbvar_new = fbvar_old; + printf("%s: %ix%i@%d\n", fbdev_name, fbvar_old.xres, fbvar_old.yres, fbvar_old.bits_per_pixel); + *w = fbvar_old.xres; + *h = fbvar_old.yres; + fbdev_buffer_count = FBDEV_MAX_BUFFERS; // be optimistic + + if (fbvar_new.bits_per_pixel != 16) { + printf(" switching to 16bpp\n"); + fbvar_new.bits_per_pixel = 16; + ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar_new); + if (ret == -1) { + perror("FBIOPUT_VSCREENINFO ioctl"); + goto fail; + } + } + + if (fbvar_new.yres_virtual < fbvar_old.yres * fbdev_buffer_count) { + fbvar_new.yres_virtual = fbvar_old.yres * fbdev_buffer_count; + ret = ioctl(fbdev, FBIOPUT_VSCREENINFO, &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, 0); + if (fbdev_mem == MAP_FAILED && fbdev_buffer_count > 1) { + fbdev_mem_size = *w * *h * 2; + fbdev_buffer_count = 1; + fprintf(stderr, "Warning: can't map %d bytes, doublebuffering disabled\n", fbdev_mem_size); + fbdev_mem = mmap(0, fbdev_mem_size, PROT_WRITE|PROT_READ, MAP_SHARED, fbdev, 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; + g_screen_ptr = fbdev_buffers[0]; + + // some checks + ret = 0; + ret = ioctl(fbdev, 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; + fbvar_new.yoffset = fbvar_old.yres * (fbdev_buffer_count - 1); + ret = ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar_new); + if (ret != 0) { + fbdev_buffer_count = 1; + fprintf(stderr, "Warning: can't pan display, doublebuffering disabled\n"); + } + } + + printf("fbdev initialized.\n"); + return 0; + +fail: + close(fbdev); + return -1; +} + +void vout_fbdev_finish(void) +{ + ioctl(fbdev, FBIOPUT_VSCREENINFO, &fbvar_old); + if (fbdev_mem != MAP_FAILED) + munmap(fbdev_mem, fbdev_mem_size); + if (fbdev >= 0) + close(fbdev); + fbdev_mem = NULL; + fbdev = -1; +} + +#include "header.h" + +void *host_video_init(int *stride) +{ + int ret, w, h; + + ret = vout_fbdev_init(&w, &h); + if (ret != 0) + return NULL; + + *stride = w * 2; + return g_screen_ptr; +} + +void *host_video_flip(void) +{ + plat_video_flip(); + return g_screen_ptr; +}