Skip to content

Commit 6b2f91f

Browse files
committed
Support Linux framebuffer as new backend
1 parent c007403 commit 6b2f91f

File tree

3 files changed

+198
-2
lines changed

3 files changed

+198
-2
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Generated
22
*.o
33
*.o.d
4-
demo-sdl
5-
.demo-sdl
4+
demo-*
5+
.demo-*
66
libtwin.a
77
.libtwin.a
88
libbackend.a

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ libtwin.a_cflags-y += $(shell sdl2-config --cflags)
9393
TARGET_LIBS += $(shell sdl2-config --libs)
9494
endif
9595

96+
ifeq ($(CONFIG_BACKEND_FBDEV), y)
97+
BACKEND = fbdev
98+
libtwin.a_files-y += backend/fbdev.c
99+
libtwin.a_cflags-y += $(shell sdl2-config --cflags)
100+
TARGET_LIBS += $(shell sdl2-config --libs)
101+
endif
102+
96103
# Standalone application
97104

98105
ifeq ($(CONFIG_DEMO_APPLICATIONS), y)

backend/fbdev.c

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2024 National Cheng Kung University, Taiwan
4+
* All rights reserved.
5+
*/
6+
7+
#include <fcntl.h>
8+
#include <linux/fb.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <sys/ioctl.h>
12+
#include <sys/mman.h>
13+
#include <twin.h>
14+
#include <unistd.h>
15+
16+
#include "twin_backend.h"
17+
18+
typedef struct {
19+
int fd;
20+
int depth;
21+
int image_y;
22+
int *pixels;
23+
int *fbdev_raw;
24+
twin_screen_t *screen;
25+
twin_coord_t width, height;
26+
} twin_fbdev_t;
27+
28+
#define FBDEV_ENVVAR "FRAMEBUFFER"
29+
#define SCREEN(x) ((twin_context_t *) x)->screen
30+
#define PRIV(x) ((twin_fbdev_t *) ((twin_context_t *) x)->priv)
31+
32+
static void _twin_fbdev_put_begin(twin_coord_t left,
33+
twin_coord_t top,
34+
twin_coord_t right,
35+
twin_coord_t bottom,
36+
void *closure)
37+
{
38+
twin_fbdev_t *tx = PRIV(closure);
39+
tx->width = right - left;
40+
tx->height = bottom - top;
41+
tx->image_y = top;
42+
}
43+
44+
static void _twin_fbdev_put_span(twin_coord_t left,
45+
twin_coord_t top,
46+
twin_coord_t right,
47+
twin_argb32_t *pixels,
48+
void *closure)
49+
{
50+
twin_screen_t *screen = SCREEN(closure);
51+
twin_fbdev_t *tx = PRIV(closure);
52+
53+
for (twin_coord_t ix = left, iy = top; ix < right; ix++) {
54+
twin_argb32_t pixel = *pixels++;
55+
tx->pixels[iy * screen->width + ix] = pixel;
56+
}
57+
if ((top + 1 - tx->image_y) == tx->height) {
58+
/* Update the pixels to the framebuffer */
59+
memcpy(tx->fbdev_raw, tx->pixels,
60+
sizeof(uint32_t) * screen->width * screen->height);
61+
}
62+
}
63+
64+
static void twin_fbdev_get_screen_size(twin_fbdev_t *tx,
65+
int *width,
66+
int *height)
67+
{
68+
struct fb_var_screeninfo info;
69+
ioctl(tx->fd, FBIOGET_VSCREENINFO, &info);
70+
*width = info.xres;
71+
*height = info.yres;
72+
}
73+
74+
static void twin_fbdev_damage(twin_screen_t *screen, twin_fbdev_t *tx)
75+
{
76+
int width, height;
77+
twin_fbdev_get_screen_size(tx, &width, &height);
78+
twin_screen_damage(tx->screen, 0, 0, width, height);
79+
}
80+
81+
static bool twin_fbdev_read_events(int file maybe_unused,
82+
twin_file_op_t ops maybe_unused,
83+
void *closure)
84+
{
85+
/* TODO: Implement events handling for mouse, keyboard, etc. */
86+
return true;
87+
}
88+
89+
static bool twin_fbdev_work(void *closure)
90+
{
91+
twin_screen_t *screen = SCREEN(closure);
92+
93+
if (twin_screen_damaged(screen))
94+
twin_screen_update(screen);
95+
return true;
96+
}
97+
98+
twin_context_t *twin_fbdev_init(int width, int height)
99+
{
100+
char *fbdev_path = getenv(FBDEV_ENVVAR);
101+
if (!fbdev_path) {
102+
printf("error : environment variable $FRAMEBUFFER not set\n");
103+
return NULL;
104+
}
105+
106+
twin_context_t *ctx = calloc(1, sizeof(twin_context_t));
107+
if (!ctx)
108+
return NULL;
109+
ctx->priv = calloc(1, sizeof(twin_fbdev_t));
110+
if (!ctx->priv)
111+
return NULL;
112+
113+
twin_fbdev_t *tx = ctx->priv;
114+
115+
/* Open the framebuffer device */
116+
tx->fd = open(fbdev_path, O_RDWR);
117+
if (tx->fd == -1) {
118+
printf("error : failed opening %s\n", fbdev_path);
119+
goto bail;
120+
}
121+
122+
/* Read framebuffer information */
123+
struct fb_var_screeninfo info;
124+
if (ioctl(tx->fd, FBIOGET_VSCREENINFO, &info) == -1) {
125+
printf("error : failed getting framebuffer information\n");
126+
goto bail_fd;
127+
}
128+
width = info.xres;
129+
height = info.yres;
130+
131+
/* Create memory mapping for accessing the framebuffer */
132+
tx->fbdev_raw = mmap(NULL, width * height * info.bits_per_pixel / 8,
133+
PROT_READ | PROT_WRITE, MAP_SHARED, tx->fd, 0);
134+
if (tx->fbdev_raw == MAP_FAILED) {
135+
printf("error : failed calling mmap()\n");
136+
goto bail_fd;
137+
}
138+
139+
/* Create buffer space for TWIN */
140+
tx->pixels = malloc(width * height * sizeof(uint32_t));
141+
if (!tx->pixels) {
142+
printf("error : failed calling malloc()\n");
143+
goto bail_fd;
144+
}
145+
memset(tx->pixels, 255, width * height * sizeof(uint32_t));
146+
147+
/* Create TWIN screen */
148+
ctx->screen = twin_screen_create(width, height, _twin_fbdev_put_begin,
149+
_twin_fbdev_put_span, ctx);
150+
151+
/* Setup file handler and work function for framebuffer backend */
152+
twin_set_file(twin_fbdev_read_events, 0, TWIN_READ, ctx);
153+
twin_set_work(twin_fbdev_work, TWIN_WORK_REDISPLAY, ctx);
154+
155+
return ctx;
156+
157+
bail_fd:
158+
close(tx->fd);
159+
bail:
160+
free(ctx->priv);
161+
free(ctx);
162+
return NULL;
163+
}
164+
165+
static void twin_fbdev_configure(twin_context_t *ctx)
166+
{
167+
int width, height;
168+
twin_fbdev_t *tx = ctx->priv;
169+
twin_fbdev_get_screen_size(tx, &width, &height);
170+
twin_screen_resize(ctx->screen, width, height);
171+
}
172+
173+
static void twin_fbdev_exit(twin_context_t *ctx)
174+
{
175+
if (!ctx)
176+
return;
177+
close(PRIV(ctx)->fd);
178+
free(PRIV(ctx)->pixels);
179+
free(ctx->priv);
180+
free(ctx);
181+
}
182+
183+
/* Register the Linux framebuffer backend */
184+
185+
const twin_backend_t g_twin_backend = {
186+
.init = twin_fbdev_init,
187+
.configure = twin_fbdev_configure,
188+
.exit = twin_fbdev_exit,
189+
};

0 commit comments

Comments
 (0)