RVVM icon indicating copy to clipboard operation
RVVM copied to clipboard

Asking for support of /dev/fb0 (or /dev/graphics/fb0) directly

Open fish4terrisa-MSDSM opened this issue 2 years ago • 3 comments

In some embedded linux platforms, both sdl and x11 just doest exist. Maybe a support of /dev/fb0` can help to run rvvm on these platforms. We can also handle the keyboard, mouse or touchscreen events directly. Maybe this feature can also be used in some BSDs and can reduce the performance cost of SDL or X11.( And also, remove these depends, which will definitely help us in porting RVVM to SONY walkmans and some other platforms with limited gui libs)

fish4terrisa-MSDSM avatar Oct 20 '23 06:10 fish4terrisa-MSDSM

It is already possible to run SDL/SDL2 on top of the kernel framebuffer / DRM (DRM is more modern) instead of running atop X/Wayland server. It is also possible to compile SDL manually for those platforms.

However I am willing to provide some help in implementing a lowlevel framebuffer driver. The basic principle (On Linux) is:

  • Allocate/claim a VT and switch it into a graphical mode using ioctl(KDSETMODE, KD_GRAPHICS...)
  • Open /dev/fb0
  • Query some info via ioctl() like resolution and pixel format
  • mmap() it into the process space and then attach that memory region to the VM

Now the remaining issue is to implement mouse/keyboard input, which is handled by /dev/uinput or /dev/input/, I have no idea how to work with them.

I have made a minimal framebuffer implementation (Doesn't claim the VT so it is a bit glitchy for now) - see lower comment

LekKit avatar Oct 21 '23 10:10 LekKit

UPD: Turns out some Linux framebuffers have non-canonical stride (I.e. bytes per row != width * bytes per pixel), so the above implementation would skew the guest framebuffer and make it unusable on such occasions. Added non-canonical framebuffer stride support in a01b956, here is updated framebuffer driver code:

#include "fb_window.h"
#include "blk_io.h"
#include "utils.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 <linux/kd.h>
#include <linux/vt.h>

bool fb_window_create(fb_window_t* window)
{
    // In future it would be preferred to support mmap
    // atop builtin blk_io/vma_ops abstractions
    int fd = open("/dev/fb0", O_RDWR);
    if (fd < 0) {
        rvvm_error("Failed to open /dev/fb0: %s", strerror(errno));
        return false;
    }

    struct fb_fix_screeninfo fix_info;
    struct fb_var_screeninfo var_info;
    if (ioctl(fd, FBIOGET_FSCREENINFO, &fix_info)
     || ioctl(fd, FBIOGET_VSCREENINFO, &var_info)) {
        rvvm_error("Failed to determine fb size");
        close(fd);
        return false;
    }
    // Determine pixel format, resolution, stride
    window->fb.format = rgb_format_from_bpp(var_info.bits_per_pixel);
    window->fb.width = var_info.xres;
    window->fb.height = var_info.yres;
    window->fb.stride = fix_info.line_length;
    window->fb.buffer = mmap(NULL, framebuffer_size(&window->fb),
                             PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    if (window->fb.buffer == MAP_FAILED) {
        rvvm_error("Failed to mmap() framebuffer: %s", strerror(errno));
        return false;
    }

    return true;
}

void fb_window_close(fb_window_t* window)
{
    munmap(window->fb.buffer, framebuffer_size(&window->fb));
}

void fb_window_update(fb_window_t* window)
{
    UNUSED(window);
}

LekKit avatar Oct 21 '23 13:10 LekKit

Now this complicates VM migration even more as migrating across hosts with different stride is impossible unless we manually convert framebuffers upon rendering....

LekKit avatar Oct 21 '23 14:10 LekKit