RVVM
RVVM copied to clipboard
Asking for support of /dev/fb0 (or /dev/graphics/fb0) directly
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)
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
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);
}
Now this complicates VM migration even more as migrating across hosts with different stride is impossible unless we manually convert framebuffers upon rendering....