Skip to content

Commit 777f3a5

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. Additionally, a color format conversion for 24-bit per pixel environments has been implemented, but it requires further validation to ensure its correctness. 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 e4e0e70 commit 777f3a5

File tree

1 file changed

+93
-24
lines changed

1 file changed

+93
-24
lines changed

backend/fbdev.c

+93-24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@
2222
#define SCREEN(x) ((twin_context_t *) x)->screen
2323
#define PRIV(x) ((twin_fbdev_t *) ((twin_context_t *) x)->priv)
2424

25+
/* color conversion */
26+
#define ARGB32_TO_RGB565_PERLINE(dest, pixels, width) \
27+
do { \
28+
for (int i = 0; i < width; i++) \
29+
dest[i] = ((pixels[i] & 0x00f80000) >> 8) | \
30+
((pixels[i] & 0x0000fc00) >> 5) | \
31+
((pixels[i] & 0x000000f8) >> 3); \
32+
} while (0)
33+
34+
/* Requires validation in 24-bit per pixel environments */
35+
#define ARGB32_TO_RGB888_PERLINE(dest, pixels, width) \
36+
do { \
37+
for (int i = 0; i < width; i++) \
38+
dest[i] = 0xff000000 | pixels[i]; \
39+
} while (0)
40+
41+
#define ARGB32_TO_ARGB32_PERLINE(dest, pixels, width) \
42+
memcpy(dest, pixels, width * sizeof(*dest))
43+
2544
typedef struct {
2645
twin_screen_t *screen;
2746

@@ -40,24 +59,23 @@ typedef struct {
4059
size_t fb_len;
4160
} twin_fbdev_t;
4261

43-
static void _twin_fbdev_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_fbdev_t *tx = PRIV(closure);
62+
#define FBDEV_PUT_SPAN_IMPL(bpp, op) \
63+
static void _twin_fbdev_put_span##bpp( \
64+
twin_coord_t left, twin_coord_t top, twin_coord_t right, \
65+
twin_argb32_t *pixels, void *closure) \
66+
{ \
67+
uint32_t *dest; \
68+
twin_screen_t *screen = SCREEN(closure); \
69+
twin_fbdev_t *tx = PRIV(closure); \
70+
off_t off = sizeof(*dest) * left + top * tx->fb_fix.line_length; \
71+
dest = (uint32_t *) ((uintptr_t) tx->fb_base + off); \
72+
twin_coord_t width = right - left; \
73+
op(dest, pixels, width); \
74+
}
5175

52-
if (tx->fb_base == MAP_FAILED)
53-
return;
54-
55-
twin_coord_t width = right - left;
56-
uint32_t *dest;
57-
off_t off = sizeof(*dest) * left + top * tx->fb_fix.line_length;
58-
dest = (uint32_t *) ((uintptr_t) tx->fb_base + off);
59-
memcpy(dest, pixels, width * sizeof(*dest));
60-
}
76+
FBDEV_PUT_SPAN_IMPL(16, ARGB32_TO_RGB565_PERLINE)
77+
FBDEV_PUT_SPAN_IMPL(24, ARGB32_TO_RGB888_PERLINE)
78+
FBDEV_PUT_SPAN_IMPL(32, ARGB32_TO_ARGB32_PERLINE)
6179

6280
static void twin_fbdev_get_screen_size(twin_fbdev_t *tx,
6381
int *width,
@@ -85,6 +103,27 @@ static bool twin_fbdev_work(void *closure)
85103
return true;
86104
}
87105

106+
static inline bool twin_fbdev_is_rgb565(twin_fbdev_t *tx)
107+
{
108+
return tx->fb_var.red.offset == 11 && tx->fb_var.red.length == 5 &&
109+
tx->fb_var.green.offset == 5 && tx->fb_var.green.length == 6 &&
110+
tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 5;
111+
}
112+
113+
static inline bool twin_fbdev_is_rgb888(twin_fbdev_t *tx)
114+
{
115+
return tx->fb_var.red.offset == 16 && tx->fb_var.red.length == 8 &&
116+
tx->fb_var.green.offset == 8 && tx->fb_var.green.length == 8 &&
117+
tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 8;
118+
}
119+
120+
static inline bool twin_fbdev_is_argb32(twin_fbdev_t *tx)
121+
{
122+
return tx->fb_var.red.offset == 16 && tx->fb_var.red.length == 8 &&
123+
tx->fb_var.green.offset == 8 && tx->fb_var.green.length == 8 &&
124+
tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 8;
125+
}
126+
88127
static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
89128
{
90129
/* Read changable information of the framebuffer */
@@ -96,7 +135,6 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
96135
/* Set the virtual screen size to be the same as the physical screen */
97136
tx->fb_var.xres_virtual = tx->fb_var.xres;
98137
tx->fb_var.yres_virtual = tx->fb_var.yres;
99-
tx->fb_var.bits_per_pixel = 32;
100138
if (ioctl(tx->fb_fd, FBIOPUT_VSCREENINFO, &tx->fb_var) < 0) {
101139
log_error("Failed to set framebuffer mode");
102140
return false;
@@ -108,10 +146,29 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
108146
return false;
109147
}
110148

111-
/* Check bits per pixel */
112-
if (tx->fb_var.bits_per_pixel != 32) {
113-
log_error("Failed to set framebuffer bpp to 32");
114-
return false;
149+
/* Examine the framebuffer format */
150+
switch (tx->fb_var.bits_per_pixel) {
151+
case 16: /* RGB565 */
152+
if (!twin_fbdev_is_rgb565(tx)) {
153+
log_error("Invalid framebuffer format for 16 bpp");
154+
return false;
155+
}
156+
break;
157+
case 24: /* RGB888 */
158+
if (!twin_fbdev_is_rgb888(tx)) {
159+
log_error("Invalid framebuffer format for 24 bpp");
160+
return false;
161+
}
162+
break;
163+
case 32: /* ARGB32 */
164+
if (!twin_fbdev_is_argb32(tx)) {
165+
log_error("Invalid framebuffer format for 32 bpp");
166+
return false;
167+
}
168+
break;
169+
default:
170+
log_error("Unsupported bits per pixel: %d", tx->fb_var.bits_per_pixel);
171+
break;
115172
}
116173

117174
/* Read unchangable information of the framebuffer */
@@ -172,9 +229,21 @@ twin_context_t *twin_fbdev_init(int width, int height)
172229
goto bail_vt_fd;
173230
}
174231

232+
/* Examine if framebuffer mapping is valid */
233+
if (tx->fb_base == MAP_FAILED) {
234+
log_error("Failed to map framebuffer memory");
235+
return;
236+
}
237+
238+
const twin_put_span_t fbdev_put_spans[] = {
239+
_twin_fbdev_put_span16,
240+
_twin_fbdev_put_span24,
241+
_twin_fbdev_put_span32,
242+
};
175243
/* Create TWIN screen */
176-
ctx->screen =
177-
twin_screen_create(width, height, NULL, _twin_fbdev_put_span, ctx);
244+
ctx->screen = twin_screen_create(
245+
width, height, NULL, fbdev_put_spans[tx->fb_var.bits_per_pixel / 8 - 2],
246+
ctx);
178247

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

0 commit comments

Comments
 (0)