Skip to content

Commit 9caaa25

Browse files
committed
Support Linux framebuffer as new backend
1 parent 07b3bf8 commit 9caaa25

File tree

8 files changed

+209
-10
lines changed

8 files changed

+209
-10
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 = fb
98+
libtwin.a_files-y += backend/fb.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)

apps/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ static void sigint_handler(int sig)
8787
exit(1);
8888
}
8989

90-
int main(void)
90+
int main(int argc, char *argv[])
9191
{
92-
tx = twin_create(WIDTH, HEIGHT);
92+
tx = twin_create(WIDTH, HEIGHT, argc, argv);
9393
if (!tx)
9494
return 1;
9595

backend/fb.c

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
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 *fb_raw;
24+
twin_screen_t *screen;
25+
twin_coord_t width, height;
26+
} twin_fb_t;
27+
28+
#define SCREEN(x) ((twin_context_t *) x)->screen
29+
#define PRIV(x) ((twin_fb_t *) ((twin_context_t *) x)->priv)
30+
31+
static void _twin_fb_put_begin(twin_coord_t left,
32+
twin_coord_t top,
33+
twin_coord_t right,
34+
twin_coord_t bottom,
35+
void *closure)
36+
{
37+
twin_fb_t *tx = PRIV(closure);
38+
tx->width = right - left;
39+
tx->height = bottom - top;
40+
tx->image_y = top;
41+
}
42+
43+
static void _twin_fb_put_span(twin_coord_t left,
44+
twin_coord_t top,
45+
twin_coord_t right,
46+
twin_argb32_t *pixels,
47+
void *closure)
48+
{
49+
twin_screen_t *screen = SCREEN(closure);
50+
twin_fb_t *tx = PRIV(closure);
51+
52+
for (twin_coord_t ix = left, iy = top; ix < right; ix++) {
53+
twin_argb32_t pixel = *pixels++;
54+
tx->pixels[iy * screen->width + ix] = pixel;
55+
}
56+
if ((top + 1 - tx->image_y) == tx->height) {
57+
/* Update the pixels to the framebuffer */
58+
memcpy(tx->fb_raw, tx->pixels,
59+
sizeof(uint32_t) * screen->width * screen->height);
60+
}
61+
}
62+
63+
static void twin_fb_get_screen_size(twin_fb_t *tx, int *width, int *height)
64+
{
65+
struct fb_var_screeninfo info;
66+
ioctl(tx->fd, FBIOGET_VSCREENINFO, &info);
67+
*width = info.xres;
68+
*height = info.yres;
69+
}
70+
71+
static void twin_fb_damage(twin_screen_t *screen, twin_fb_t *tx)
72+
{
73+
int width, height;
74+
twin_fb_get_screen_size(tx, &width, &height);
75+
twin_screen_damage(tx->screen, 0, 0, width, height);
76+
}
77+
78+
static bool twin_fb_read_events(int file maybe_unused,
79+
twin_file_op_t ops maybe_unused,
80+
void *closure)
81+
{
82+
/* TODO: Implement events handling for mouse, keyboard, etc. */
83+
return true;
84+
}
85+
86+
static bool twin_fb_work(void *closure)
87+
{
88+
twin_screen_t *screen = SCREEN(closure);
89+
90+
if (twin_screen_damaged(screen))
91+
twin_screen_update(screen);
92+
return true;
93+
}
94+
95+
twin_context_t *twin_fb_init(int width, int height, int optc, char *optv[])
96+
{
97+
if (optc < 2) {
98+
printf("error : no framebuffer device path is given\n");
99+
return NULL;
100+
} else if (optc > 2) {
101+
printf(
102+
"error : too many options for initializing the Framebuffer "
103+
"backend\n");
104+
return NULL;
105+
}
106+
107+
char *fb_path = optv[1];
108+
109+
twin_context_t *ctx = calloc(1, sizeof(twin_context_t));
110+
if (!ctx)
111+
return NULL;
112+
ctx->priv = calloc(1, sizeof(twin_fb_t));
113+
if (!ctx->priv)
114+
return NULL;
115+
116+
twin_fb_t *tx = ctx->priv;
117+
118+
/* Open the framebuffer device */
119+
tx->fd = open(fb_path, O_RDWR);
120+
if (tx->fd == -1) {
121+
printf("error : failed opening %s\n", fb_path);
122+
goto bail;
123+
}
124+
125+
/* Read framebuffer information */
126+
struct fb_var_screeninfo info;
127+
if (ioctl(tx->fd, FBIOGET_VSCREENINFO, &info) == -1) {
128+
printf("error : failed getting framebuffer information\n");
129+
goto bail_fd;
130+
}
131+
width = info.xres;
132+
height = info.yres;
133+
134+
/* Create memory mapping for accessing the framebuffer */
135+
tx->fb_raw = mmap(NULL, width * height * info.bits_per_pixel / 8,
136+
PROT_READ | PROT_WRITE, MAP_SHARED, tx->fd, 0);
137+
if (tx->fb_raw == MAP_FAILED) {
138+
printf("error : failed calling mmap()\n");
139+
goto bail_fd;
140+
}
141+
142+
/* Create buffer space for TWIN */
143+
tx->pixels = malloc(width * height * sizeof(uint32_t));
144+
if (!tx->pixels) {
145+
printf("error : failed calling malloc()\n");
146+
goto bail_fd;
147+
}
148+
memset(tx->pixels, 255, width * height * sizeof(uint32_t));
149+
150+
/* Create TWIN screen */
151+
ctx->screen = twin_screen_create(width, height, _twin_fb_put_begin,
152+
_twin_fb_put_span, ctx);
153+
154+
/* Setup file handler and work function for framebuffer backend */
155+
twin_set_file(twin_fb_read_events, 0, TWIN_READ, ctx);
156+
twin_set_work(twin_fb_work, TWIN_WORK_REDISPLAY, ctx);
157+
158+
return ctx;
159+
160+
bail_fd:
161+
close(tx->fd);
162+
bail:
163+
free(ctx->priv);
164+
free(ctx);
165+
return NULL;
166+
}
167+
168+
static void twin_fb_configure(twin_context_t *ctx)
169+
{
170+
int width, height;
171+
twin_fb_t *tx = ctx->priv;
172+
twin_fb_get_screen_size(tx, &width, &height);
173+
twin_screen_resize(ctx->screen, width, height);
174+
}
175+
176+
static void twin_fb_exit(twin_context_t *ctx)
177+
{
178+
if (!ctx)
179+
return;
180+
close(PRIV(ctx)->fd);
181+
free(PRIV(ctx)->pixels);
182+
free(ctx->priv);
183+
free(ctx);
184+
}
185+
186+
/* Register the Linux framebuffer backend */
187+
188+
const twin_backend_t g_twin_backend = {
189+
.init = twin_fb_init,
190+
.configure = twin_fb_configure,
191+
.exit = twin_fb_exit,
192+
};

backend/sdl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,14 @@ static bool twin_sdl_read_events(int file maybe_unused,
124124

125125
static bool twin_sdl_work(void *closure)
126126
{
127-
twin_screen_t *screen = SCREEN(closure);
127+
twin_screen_t *screen = SCREEN(closure);:
128128

129129
if (twin_screen_damaged(screen))
130130
twin_screen_update(screen);
131131
return true;
132132
}
133133

134-
twin_context_t *twin_sdl_init(int width, int height)
134+
twin_context_t *twin_sdl_init(int width, int height, int optc, char *optv[])
135135
{
136136
twin_context_t *ctx = calloc(1, sizeof(twin_context_t));
137137
if (!ctx)

include/twin.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,7 +1119,7 @@ typedef struct _twin_context {
11191119
void *priv;
11201120
} twin_context_t;
11211121

1122-
twin_context_t *twin_create(int width, int height);
1122+
twin_context_t *twin_create(int width, int height, int optc, char *optv[]);
11231123

11241124
void twin_destroy(twin_context_t *ctx);
11251125

src/api.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313

1414
extern twin_backend_t g_twin_backend;
1515

16-
twin_context_t *twin_create(int width, int height)
16+
twin_context_t *twin_create(int width, int height, int optc, char *optv[])
1717
{
18-
return g_twin_backend.init(width, height);
18+
return g_twin_backend.init(width, height, optc, optv);
1919
}
2020

2121
void twin_destroy(twin_context_t *ctx)

src/twin_backend.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
typedef struct twin_backend {
1515
/* Initialize the backend */
16-
twin_context_t *(*init)(int width, int height);
16+
twin_context_t *(*init)(int width, int height, int optc, char *optv[]);
1717

1818
/* Configure the device */
1919
/* FIXME: Refine the parameter list */

0 commit comments

Comments
 (0)