Skip to content

Commit 8f5b338

Browse files
committed
Support 16/32 bit color depth
Mado currently supports 32-bit color depth for desktop and laptop display devices. To enhance its compatibility across diverse Linux framebuffer environments, I have made the following changes to support both 16-bit and 32-bit color depths: - Distinguish the color format and perform color format conversion. - Examine the correctness of the framebuffer format based on the color format. These updates improve Mado's compatibility, enabling it to be used on devices with low memory overhead, such as the Raspberry Pi, in addition to desktop display devices.
1 parent b6a91e5 commit 8f5b338

File tree

1 file changed

+109
-14
lines changed

1 file changed

+109
-14
lines changed

backend/fbdev.c

Lines changed: 109 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@
2222
#define FBDEV_DEFAULT "/dev/fb0"
2323
#define SCREEN(x) ((twin_context_t *) x)->screen
2424
#define PRIV(x) ((twin_fbdev_t *) ((twin_context_t *) x)->priv)
25+
#define ARGB32_TO_RGB565(pixel) \
26+
(((pixel & 0x00f80000) >> 8) | ((pixel & 0x0000fc00) >> 5) | \
27+
((pixel & 0x000000f8) >> 3))
28+
29+
/* Requires validation in 24-bit per pixel environments. */
30+
#define ARGB32_TO_RGB888(pixel) (0xff000000 | (pixel))
31+
#define GET_TWIN_FBDEV(left, top, closure, dest) \
32+
do { \
33+
twin_screen_t *screen = SCREEN(closure); \
34+
twin_fbdev_t *tx = PRIV(closure); \
35+
off_t off = (top) * (screen->width) + (left); \
36+
*(dest) = \
37+
(uint32_t *) ((uintptr_t) tx->fb_base + (off * sizeof(uint32_t))); \
38+
} while (0)
2539

2640
typedef struct {
2741
twin_screen_t *screen;
@@ -43,22 +57,43 @@ typedef struct {
4357
size_t fb_len;
4458
} twin_fbdev_t;
4559

46-
static void _twin_fbdev_put_span(twin_coord_t left,
47-
twin_coord_t top,
48-
twin_coord_t right,
49-
twin_argb32_t *pixels,
50-
void *closure)
60+
static void _twin_fbdev_put_span16(twin_coord_t left,
61+
twin_coord_t top,
62+
twin_coord_t right,
63+
twin_argb32_t *pixels,
64+
void *closure)
5165
{
52-
twin_screen_t *screen = SCREEN(closure);
53-
twin_fbdev_t *tx = PRIV(closure);
66+
uint32_t *dest;
67+
GET_TWIN_FBDEV(left, top, closure, &dest);
68+
twin_coord_t width = right - left;
69+
for (int i = 0; i < width; i++) {
70+
dest[i] = ARGB32_TO_RGB565(pixels[i]);
71+
}
72+
}
5473

55-
if (tx->fb_base == MAP_FAILED)
56-
return;
74+
static void _twin_fbdev_put_span24(twin_coord_t left,
75+
twin_coord_t top,
76+
twin_coord_t right,
77+
twin_argb32_t *pixels,
78+
void *closure)
79+
{
80+
uint32_t *dest;
81+
GET_TWIN_FBDEV(left, top, closure, &dest);
82+
twin_coord_t width = right - left;
83+
for (int i = 0; i < width; i++) {
84+
dest[i] = ARGB32_TO_RGB888(pixels[i]);
85+
}
86+
}
5787

88+
static void _twin_fbdev_put_span32(twin_coord_t left,
89+
twin_coord_t top,
90+
twin_coord_t right,
91+
twin_argb32_t *pixels,
92+
void *closure)
93+
{
94+
uint32_t *dest;
95+
GET_TWIN_FBDEV(left, top, closure, &dest);
5896
twin_coord_t width = right - left;
59-
off_t off = top * screen->width + left;
60-
uint32_t *dest =
61-
(uint32_t *) ((uintptr_t) tx->fb_base + (off * sizeof(*dest)));
6297
memcpy(dest, pixels, width * sizeof(*dest));
6398
}
6499

@@ -88,6 +123,27 @@ static bool twin_fbdev_work(void *closure)
88123
return true;
89124
}
90125

126+
static bool twin_fbdev_is_rgb565(twin_fbdev_t *tx)
127+
{
128+
return tx->fb_var.red.offset == 11 && tx->fb_var.red.length == 5 &&
129+
tx->fb_var.green.offset == 5 && tx->fb_var.green.length == 6 &&
130+
tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 5;
131+
}
132+
133+
static bool twin_fbdev_is_rgb888(twin_fbdev_t *tx)
134+
{
135+
return tx->fb_var.red.offset == 16 && tx->fb_var.red.length == 8 &&
136+
tx->fb_var.green.offset == 8 && tx->fb_var.green.length == 8 &&
137+
tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 8;
138+
}
139+
140+
static bool twin_fbdev_is_argb32(twin_fbdev_t *tx)
141+
{
142+
return tx->fb_var.red.offset == 16 && tx->fb_var.red.length == 8 &&
143+
tx->fb_var.green.offset == 8 && tx->fb_var.green.length == 8 &&
144+
tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 8;
145+
}
146+
91147
static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
92148
{
93149
/* Read changable information of the framebuffer */
@@ -110,6 +166,34 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
110166
return false;
111167
}
112168

169+
<<<<<<< HEAD
170+
=======
171+
/* Examine the framebuffer format */
172+
switch (tx->fb_var.bits_per_pixel) {
173+
case 16: // RGB565
174+
if (!twin_fbdev_is_rgb565(tx)) {
175+
log_error("Invalid framebuffer format for 16 bpp");
176+
return false;
177+
}
178+
break;
179+
case 24: // RGB888
180+
if (!twin_fbdev_is_rgb888(tx)) {
181+
log_error("Invalid framebuffer format for 24 bpp");
182+
return false;
183+
}
184+
break;
185+
case 32: // ARGB32
186+
if (!twin_fbdev_is_argb32(tx)) {
187+
log_error("Invalid framebuffer format for 32 bpp");
188+
return false;
189+
}
190+
break;
191+
default:
192+
log_error("Unsupported bits per pixel: %d", tx->fb_var.bits_per_pixel);
193+
break;
194+
}
195+
196+
>>>>>>> f56a638 (Support 16/32 bit color depth)
113197
/* Read unchangable information of the framebuffer */
114198
ioctl(tx->fb_fd, FBIOGET_FSCREENINFO, &tx->fb_fix);
115199

@@ -213,9 +297,20 @@ twin_context_t *twin_fbdev_init(int width, int height)
213297
goto bail_vt_fd;
214298
}
215299

300+
/* Examine if framebuffer mapping is valid */
301+
if (tx->fb_base == MAP_FAILED) {
302+
log_error("Failed to map framebuffer memory");
303+
return;
304+
}
305+
216306
/* Create TWIN screen */
217-
ctx->screen =
218-
twin_screen_create(width, height, NULL, _twin_fbdev_put_span, ctx);
307+
ctx->screen = twin_screen_create(
308+
width, height, NULL,
309+
(tx->fb_var.bits_per_pixel == 16) ? _twin_fbdev_put_span16
310+
: (tx->fb_var.bits_per_pixel == 24) ? _twin_fbdev_put_span24
311+
: (tx->fb_var.bits_per_pixel == 32) ? _twin_fbdev_put_span32
312+
: NULL,
313+
ctx);
219314

220315
/* Create Linux input system object */
221316
tx->input = twin_linux_input_create(ctx->screen);

0 commit comments

Comments
 (0)