-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix mismatch screen width and height and buffer synchronization when using Linux framebuffer backend #62
Comments
Hi, I can help fixing the problem but it is a little harder for me to duplicate the problem. |
Yes, I am interested in this problem, but I am not familiar with Linux framebuffer. This will take a while. |
Consider to call twin_set_work(twin_fbdev_work, TWIN_WORK_REDISPLAY, ctx);
/* Enable immediate refresh */
twin_screen_register_damaged(ctx->screen, twin_fbdev_damaged, ctx);
... And the callback static void twin_fbdev_damaged(void *closure)
{
twin_screen_t *screen = SCREEN(closure);
twin_fbdev_t *tx = PRIV(closure);
if (tx->vt_active /* VT switch is ready */ && twin_screen_damaged(screen))
twin_screen_update(screen);
} However, the current fbdev backend lacks of VT switch operations. That is, consider the following: static void twin_fbdev_switch(twin_fbdev_t *tf, int activate)
{
tx->vt_active = activate;
/* Upon activation */
if (activate) {
/* Switch complete */
ioctl(tx->vt_fd, VT_RELDISP, VT_ACKACQ);
/* Restore fbdev settings */
if (twin_fbdev_apply_config(tf)) {
tx->vt_active = true;
/* Mark entire screen for refresh */
if (tx->screen)
twin_screen_damage(tx->screen, 0, 0, tx->screen->width,
tx->screen->height);
}
} else {
/* FIXME: should expose some option to disallow them */
ioctl(tx->vt_fd, VT_RELDISP, 1);
tx->vt_active = 0;
if (tx->fb_base != MAP_FAILED)
munmap(tx->fb_base, tx->fb_len);
tx->fb_base = MAP_FAILED;
}
}
static bool vt_switch_pending;
static bool twin_fbdev_work(void *closure)
{
twin_fbdev_t *tx = PRIV(closure);
if (vt_switch_pending) {
twin_fbdev_switch(tf, !tx->vt_active);
vt_switch_pending = false;
}
return true;
}
static void twin_fbdev_vtswitch(int sig)
{
signal(sig, twin_fbdev_vtswitch);
vt_switch_pending = true;
}
static bool twin_fbdev_setup_vt(twin_fbdev_t *tx, int switch_sig)
{
struct vt_mode vtm;
struct termios tio;
if (ioctl(tx->vt_fd, VT_GETMODE, &vtm) < 0) {
SERROR("can't get VT mode");
return 0;
}
vtm.mode = VT_PROCESS;
vtm.relsig = switch_sig;
vtm.acqsig = switch_sig;
signal(switch_sig, twin_fbdev_vtswitch);
tx->vt_swsig = switch_sig;
if (ioctl(tx->vt_fd, VT_SETMODE, &vtm) < 0) {
SERROR("can't set VT mode");
signal(switch_sig, SIG_IGN);
return 0;
}
tcgetattr(tx->vt_fd, &tx->old_tio);
ioctl(tx->vt_fd, KDGKBMODE, &tx->old_kbmode);
ioctl(tx->vt_fd, KDSKBMODE, K_MEDIUMRAW);
tio = tx->old_tio;
tio.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP);
tio.c_oflag = 0;
tio.c_cflag = CREAD | CS8;
tio.c_lflag = 0;
tio.c_cc[VTIME] = 0;
tio.c_cc[VMIN] = 1;
cfsetispeed(&tio, 9600);
cfsetospeed(&tio, 9600);
tcsetattr(tx->vt_fd, TCSANOW, &tio);
ioctl(tx->vx_fd, KDSETMODE, KD_GRAPHICS);
return true;
} Check the following implementations:
|
Another problem I found is visible resolution and virtual resolution are different on Virtualbox, and miscalculates the memory region to be rendered. Use Run
On my laptop is gives:
Solution: static void _twin_fbdev_put_span(twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_argb32_t *pixels,
void *closure)
{
twin_screen_t *screen = SCREEN(closure);
twin_fbdev_t *tx = PRIV(closure);
if (tx->fb_base == MAP_FAILED)
return;
twin_coord_t width = right - left;
- off_t off = top * screen->width + left;
- uint32_t *dest =
- (uint32_t *) ((uintptr_t) tx->fb_base + (off * sizeof(uint32_t)));
+ unsigned char *dest =
+ (unsigned char *) tx->fb_base + tx->fb_fix.line_length * top + 4 * left;
memcpy(dest, pixels, width * sizeof(uint32_t));
} |
Can you submit a pull request for testing and reviewing purpose? |
There are two test cases and are being tested on my Ubuntu laptop and VirtualBox.
Case 2 works fine. In case 1, I find out another way to make it not lagging is updating the cache, the code below is from sys_cache.c, but I am not sure whether it is an appropriate way. #define FBIO_CACHE_SYNC 0x4630
unsigned int args[2];
args[0] = tx->fb_base;
args[1] = tx->fb_base + tx->fb_var.yres_virtual * tx->fb_fix.line_length;
ioctl(tx->fb_fd, FBIO_CACHE_SYNC, args); mado with framebuffer can start from different terminals like The pull request: #65 static void _twin_fbdev_put_span(twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_argb32_t *pixels,
void *closure)
{
twin_screen_t *screen = SCREEN(closure);
twin_fbdev_t *tx = PRIV(closure);
if (tx->fb_base == MAP_FAILED)
return;
twin_coord_t width = right - left;
- off_t off = top * screen->width + left;
- uint32_t *dest =
- (uint32_t *) ((uintptr_t) tx->fb_base + (off * sizeof(uint32_t)));
+ off_t off = tx->fb_fix.line_length * top + 4 * left;
+ unsigned char *dest = (unsigned char *) tx->fb_base + off;
memcpy(dest, pixels, width * sizeof(uint32_t));
} |
@huaxinliao, Please install VirtualBox as @a1091150 suggested, and see if the above issue still occurs in the latest |
In Case 2, when I attempted to gradually move the cursor to the right by shifting my finger to the right, I observed that the cursor on the screen moved to the right in fixed increments rather than in a smooth, continuous motion. At this time, the cursor was unable to move upward or in any other direction. Case2.mp4 |
I attempted to reproduce Case 1. However, after launching Case1.mp4 |
Same happened on Virtualbox with Ubuntu 22.04 as a guest OS and Windows as a host OS. No same problem on a real hardware.
Start a terminal (i.e. by clicking a terminal icon in gnome desktop). In this terminal, run Originally, this issue wants to fix framebuffer region which cause #62 (comment) and the screenshot presented. The lastest main branch fixs this and supports more different bits of a pixel. |
I conducted the experiment based on @a1091150's suggestion. During the process, I discovered that the framebuffer backend simultaneously exists on multiple TTYs. Initially, only part of the window is displayed on the screen. However, when I move the cursor within the window area, the full window becomes visible on the screen. Case_1.mp4 |
You can check how DirectFB2 deals with virtual terminal. See |
The commit 980bd4c supports Linux framebuffer backend, but the behavior is weird on my machine.
The root case is that some hardware require a cache synchronization when using the framebuffer.
Problem:
twin_screen_damage
to mark the field to be updated) are not apply immediately on computer screen.One possible fix is in a1091150/mado@fbe9e00, the code is copied from FOSDEM 2020 - Back to the Linux Framebuffer! and sync_cache.c
After the below commit, another problem appeared is that the whole screen is not rendered when startup. To fix this, simply use
twin_screen_damage
to mark the whole scrreen to be damaged, shown in the following code(a1091150/mado@977463a).The text was updated successfully, but these errors were encountered: