Skip to content

Commit fc00614

Browse files
committed
Support Linux framebuffer as new backend
1 parent 2d85c45 commit fc00614

File tree

4 files changed

+345
-1
lines changed

4 files changed

+345
-1
lines changed

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# FIXME: make these entries configurable
22
CONFIG_BACKEND_SDL := y
3+
CONFIG_BACKEND_FB := y
34
CONFIG_LOADER_JPEG := y
45
CONFIG_LOADER_PNG := y
56

@@ -88,14 +89,18 @@ libbackend.a_cflags-y += $(shell sdl2-config --cflags)
8889
TARGET_LIBS += $(shell sdl2-config --libs)
8990
endif
9091

92+
ifeq ($(CONFIG_BACKEND_SDL), y)
93+
libbackend.a_files-y += backend/fb.c
94+
endif
95+
9196
# Platform-specific executables
9297

9398
ifeq ($(CONFIG_BACKEND_SDL), y)
9499
target-y += demo-sdl
95100

96101
demo-sdl_depends-y += $(target.a-y)
97102
demo-sdl_files-y = \
98-
apps/twin-sdl.c
103+
apps/twin-apps-main.c
99104

100105
demo-sdl_includes-y := include
101106
demo-sdl_includes-y += backend

apps/twin-apps-main.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2004 Keith Packard <keithp@keithp.com>
4+
* All rights reserved.
5+
*/
6+
7+
#include <assert.h>
8+
#include <getopt.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <sys/time.h>
13+
#include <time.h>
14+
#include <twin.h>
15+
#include <unistd.h>
16+
17+
#include "twin_fb.h"
18+
#include "twin_sdl.h"
19+
20+
#include "apps_calc.h"
21+
#include "apps_clock.h"
22+
#include "apps_demo.h"
23+
#include "apps_hello.h"
24+
#include "apps_line.h"
25+
#include "apps_spline.h"
26+
27+
#define WIDTH 640
28+
#define HEIGHT 480
29+
30+
#define ASSET_PATH "assets/"
31+
32+
/**
33+
* Load the background pixmap from storage.
34+
* @filename: File name of a PNG background.
35+
*
36+
* Return a default pattern if the load of @filename fails.
37+
*/
38+
static twin_pixmap_t *load_background(twin_screen_t *screen,
39+
const char *filename)
40+
{
41+
twin_pixmap_t *raw_background = twin_png_to_pixmap(filename, TWIN_ARGB32);
42+
if (!raw_background) /* Fallback to a default pattern */
43+
return twin_make_pattern();
44+
45+
if (screen->height == raw_background->height &&
46+
screen->width == raw_background->width)
47+
return raw_background;
48+
49+
/* Scale as needed. */
50+
twin_pixmap_t *scaled_background =
51+
twin_pixmap_create(TWIN_ARGB32, screen->width, screen->height);
52+
if (!scaled_background) {
53+
twin_pixmap_destroy(raw_background);
54+
return twin_make_pattern();
55+
}
56+
twin_fixed_t sx, sy;
57+
sx = twin_fixed_div(twin_int_to_fixed(raw_background->width),
58+
twin_int_to_fixed(screen->width));
59+
sy = twin_fixed_div(twin_int_to_fixed(raw_background->height),
60+
twin_int_to_fixed(screen->height));
61+
62+
twin_matrix_scale(&raw_background->transform, sx, sy);
63+
twin_operand_t srcop = {
64+
.source_kind = TWIN_PIXMAP,
65+
.u.pixmap = raw_background,
66+
};
67+
twin_composite(scaled_background, 0, 0, &srcop, 0, 0, NULL, 0, 0,
68+
TWIN_SOURCE, screen->width, screen->height);
69+
70+
twin_pixmap_destroy(raw_background);
71+
72+
return scaled_background;
73+
}
74+
75+
static void usage(const char *execpath)
76+
{
77+
fprintf(stderr, "Usage: %s -b backend [-p fb-path]\n", execpath);
78+
}
79+
80+
static void handle_options(int argc,
81+
char **argv,
82+
char **backend,
83+
char **fb_path)
84+
{
85+
*backend = *fb_path = NULL;
86+
87+
int optidx = 0;
88+
struct option opts[] = {
89+
{"backend", 1, NULL, 'b'},
90+
{"fb-path", 1, NULL, 'p'},
91+
{"help", 0, NULL, 'h'},
92+
};
93+
94+
int c;
95+
while ((c = getopt_long(argc, argv, "b:p:h", opts, &optidx)) != -1) {
96+
switch (c) {
97+
case 'b':
98+
*backend = optarg;
99+
break;
100+
case 'p':
101+
*fb_path = optarg;
102+
break;
103+
case 'h':
104+
usage(argv[0]);
105+
exit(0);
106+
default:
107+
break;
108+
}
109+
}
110+
111+
if (!*backend) {
112+
fprintf(stderr, "Must assign a backend via -b option.\n");
113+
usage(argv[0]);
114+
exit(2);
115+
}
116+
}
117+
118+
int main(int argc, char **argv)
119+
{
120+
char *backend, *fb_path;
121+
handle_options(argc, argv, &backend, &fb_path);
122+
123+
twin_sdl_t *sdl;
124+
twin_fb_t *fb;
125+
twin_screen_t *screen;
126+
127+
if (!strcmp(backend, "sdl")) {
128+
/* Select SDL as backend */
129+
sdl = twin_sdl_create(WIDTH, HEIGHT);
130+
screen = sdl->screen;
131+
} else if (!strcmp(backend, "fb")) {
132+
if (!fb_path) {
133+
fprintf(
134+
stderr,
135+
"Must assign the path to framebuffer device via -p option.\n");
136+
usage(argv[0]);
137+
exit(2);
138+
}
139+
140+
/* Select Linux framebuffer as backend */
141+
fb = twin_fb_create(fb_path);
142+
screen = fb->screen;
143+
} else {
144+
/* Unknown backend */
145+
fprintf(stderr,
146+
"Unknown backend: %s\n"
147+
"Must be 'sdl' or 'fb'.\n",
148+
backend);
149+
exit(2);
150+
}
151+
152+
twin_screen_set_background(screen,
153+
load_background(screen, ASSET_PATH "/tux.png"));
154+
155+
apps_demo_start(screen, "Demo", 100, 100, 400, 400);
156+
apps_hello_start(screen, "Hello, World", 0, 0, 200, 200);
157+
apps_clock_start(screen, "Clock", 10, 10, 200, 200);
158+
apps_calc_start(screen, "Calculator", 100, 100, 200, 200);
159+
apps_line_start(screen, "Line", 0, 0, 200, 200);
160+
apps_spline_start(screen, "Spline", 20, 20, 400, 400);
161+
162+
twin_dispatch();
163+
return 0;
164+
}

backend/fb.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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 <unistd.h>
14+
15+
#include "twin_fb.h"
16+
#include "twin_private.h"
17+
18+
static void _twin_fb_put_begin(twin_coord_t left,
19+
twin_coord_t top,
20+
twin_coord_t right,
21+
twin_coord_t bottom,
22+
void *closure)
23+
{
24+
twin_fb_t *tx = closure;
25+
tx->width = right - left;
26+
tx->height = bottom - top;
27+
tx->image_y = top;
28+
}
29+
30+
static void _twin_fb_put_span(twin_coord_t left,
31+
twin_coord_t top,
32+
twin_coord_t right,
33+
twin_argb32_t *pixels,
34+
void *closure)
35+
{
36+
twin_fb_t *tx = closure;
37+
twin_coord_t ix;
38+
twin_coord_t iy = top;
39+
40+
for (ix = left; ix < right; ix++) {
41+
twin_argb32_t pixel = *pixels++;
42+
43+
if (tx->depth == 16)
44+
pixel = twin_argb32_to_rgb16(pixel);
45+
46+
tx->pixels[iy * tx->screen->width + ix] = pixel;
47+
}
48+
if ((top + 1 - tx->image_y) == tx->height) {
49+
/* Update the pixels to the framebuffer */
50+
memcpy(tx->fb_raw, tx->pixels,
51+
sizeof(uint32_t) * tx->width * tx->height);
52+
}
53+
}
54+
55+
static bool twin_fb_read_events(int maybe_unused file,
56+
twin_file_op_t maybe_unused ops,
57+
void *closure)
58+
{
59+
/* TODO: Implement events handling for mouse, keyboard, etc. */
60+
return true;
61+
}
62+
63+
static bool twin_fb_work(void *closure)
64+
{
65+
twin_fb_t *tx = closure;
66+
67+
if (twin_screen_damaged(tx->screen))
68+
twin_fb_update(tx);
69+
return true;
70+
}
71+
72+
twin_fb_t *twin_fb_create(char *fb_path)
73+
{
74+
/* Allocate TWIN framebuffer object */
75+
twin_fb_t *tx = malloc(sizeof(twin_fb_t));
76+
if (!tx) {
77+
fprintf(stderr, "Error in malloc.\n");
78+
exit(2);
79+
}
80+
81+
/* Open the framebuffer device */
82+
tx->fd = open(fb_path, O_RDWR);
83+
if (tx->fd == -1) {
84+
fprintf(stderr, "Error opening %s\n", fb_path);
85+
exit(2);
86+
}
87+
88+
/* Read framebuffer information */
89+
struct fb_var_screeninfo info;
90+
if (ioctl(tx->fd, FBIOGET_VSCREENINFO, &info) == -1) {
91+
fprintf(stderr, "Error reading framebuffer information from %s\n",
92+
fb_path);
93+
close(tx->fd);
94+
exit(2);
95+
}
96+
tx->width = info.xres;
97+
tx->height = info.yres;
98+
99+
/* Create memory mapping for accessing the framebuffer */
100+
tx->fb_raw = mmap(NULL, tx->width * tx->height * info.bits_per_pixel / 8,
101+
PROT_READ | PROT_WRITE, MAP_SHARED, tx->fd, 0);
102+
if (tx->fb_raw == MAP_FAILED) {
103+
fprintf(stderr, "Error in mmap\n");
104+
close(tx->fd);
105+
exit(2);
106+
}
107+
108+
/* Create buffer space for TWIN */
109+
tx->pixels = malloc(tx->width * tx->height * sizeof(uint32_t));
110+
memset(tx->pixels, 255, tx->width * tx->height * sizeof(uint32_t));
111+
112+
/* Create TWIN screen */
113+
tx->screen = twin_screen_create(tx->width, tx->height, _twin_fb_put_begin,
114+
_twin_fb_put_span, tx);
115+
116+
/* Set up framebuffer work functions */
117+
twin_set_file(twin_fb_read_events, 0, TWIN_READ, tx);
118+
twin_set_work(twin_fb_work, TWIN_WORK_REDISPLAY, tx);
119+
120+
return tx;
121+
}
122+
123+
void twin_fb_destroy(twin_fb_t *tx)
124+
{
125+
twin_screen_destroy(tx->screen);
126+
close(tx->fd);
127+
}
128+
129+
void twin_fb_damage(twin_fb_t *tx)
130+
{
131+
int width, height;
132+
struct fb_var_screeninfo info;
133+
134+
/* Read screan width and height */
135+
ioctl(tx->fd, FBIOGET_VSCREENINFO, &info);
136+
width = info.xres;
137+
height = info.yres;
138+
139+
twin_screen_damage(tx->screen, 0, 0, width, height);
140+
}
141+
142+
void twin_fb_update(twin_fb_t *tx)
143+
{
144+
twin_screen_update(tx->screen);
145+
}

backend/twin_fb.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2024 National Cheng Kung University, Taiwan
4+
* All rights reserved.
5+
*/
6+
7+
#ifndef _TWIN_FB_H_
8+
#define _TWIN_FB_H_
9+
10+
#include <twin.h>
11+
12+
typedef struct _twin_fb {
13+
int fd;
14+
twin_screen_t *screen;
15+
int depth;
16+
int *pixels;
17+
int *fb_raw;
18+
twin_coord_t width, height;
19+
int image_y;
20+
} twin_fb_t;
21+
22+
twin_fb_t *twin_fb_create(char *fb_path);
23+
24+
void twin_fb_destroy(twin_fb_t *tx);
25+
26+
void twin_fb_damage(twin_fb_t *tx);
27+
28+
void twin_fb_update(twin_fb_t *tx);
29+
30+
#endif /* _TWIN_FB_H_ */

0 commit comments

Comments
 (0)