From 473b0e205d372bc4663c868f9691f93a4e5a88f6 Mon Sep 17 00:00:00 2001 From: Chisheng Chen Date: Sun, 26 Apr 2026 10:21:56 +0800 Subject: [PATCH 1/3] Correct pixel size for RGB565 mode For RGB565, 2 bytes should be used to store one pixel in the destination frame buffer. However, the _twin_fbdev_put_span16 use 4 bytes to store it, causing the render result exceeds the boundary and some black lines between columns. This corrects it. --- backend/fbdev.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/backend/fbdev.c b/backend/fbdev.c index ad5050a..6da9471 100644 --- a/backend/fbdev.c +++ b/backend/fbdev.c @@ -45,35 +45,37 @@ typedef struct { } twin_fbdev_t; /* color conversion */ -#define ARGB32_TO_RGB565_PERLINE(dest, pixels, width) \ - do { \ - for (int i = 0; i < width; i++) \ - dest[i] = ((pixels[i] & 0x00f80000) >> 8) | \ - ((pixels[i] & 0x0000fc00) >> 5) | \ - ((pixels[i] & 0x000000f8) >> 3); \ +#define ARGB32_TO_RGB565_PERLINE(dest, pixels, width) \ + do { \ + uint16_t *_dest = (uint16_t *) dest; \ + for (int i = 0; i < width; i++) \ + _dest[i] = ((pixels[i] & 0x00f80000) >> 8) | \ + ((pixels[i] & 0x0000fc00) >> 5) | \ + ((pixels[i] & 0x000000f8) >> 3); \ } while (0) /* Requires validation in 24-bit per pixel environments */ #define ARGB32_TO_RGB888_PERLINE(dest, pixels, width) \ do { \ + uint32_t *_dest = (uint32_t *) dest; \ for (int i = 0; i < width; i++) \ - dest[i] = 0xff000000 | pixels[i]; \ + _dest[i] = 0xff000000 | pixels[i]; \ } while (0) #define ARGB32_TO_ARGB32_PERLINE(dest, pixels, width) \ - memcpy(dest, pixels, width * sizeof(*dest)) - -#define FBDEV_PUT_SPAN_IMPL(bpp, op) \ - static void _twin_fbdev_put_span##bpp( \ - twin_coord_t left, twin_coord_t top, twin_coord_t right, \ - twin_argb32_t *pixels, void *closure) \ - { \ - uint32_t *dest; \ - twin_fbdev_t *tx = PRIV(closure); \ - off_t off = sizeof(*dest) * left + top * tx->fb_fix.line_length; \ - dest = (uint32_t *) ((uintptr_t) tx->fb_base + off); \ - twin_coord_t width = right - left; \ - op(dest, pixels, width); \ + memcpy((uint32_t *) dest, pixels, width * 4) + +#define FBDEV_PUT_SPAN_IMPL(bpp, op) \ + static void _twin_fbdev_put_span##bpp( \ + twin_coord_t left, twin_coord_t top, twin_coord_t right, \ + twin_argb32_t *pixels, void *closure) \ + { \ + uintptr_t dest; \ + twin_fbdev_t *tx = PRIV(closure); \ + off_t off = (bpp / 8) * left + top * tx->fb_fix.line_length; \ + dest = (uintptr_t) tx->fb_base + off; \ + twin_coord_t width = right - left; \ + op(dest, pixels, width); \ } FBDEV_PUT_SPAN_IMPL(16, ARGB32_TO_RGB565_PERLINE) From 6ec4c6319668bb06ec3e33e1fdcf44423d38a917 Mon Sep 17 00:00:00 2001 From: Chisheng Chen Date: Sun, 26 Apr 2026 12:46:49 +0800 Subject: [PATCH 2/3] Correct pixel size for RGB888 For RGB888, 3 bytes should be used to store one pixel instead of the original 4 bytes. This corrects it. --- backend/fbdev.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/backend/fbdev.c b/backend/fbdev.c index 6da9471..8cc91bd 100644 --- a/backend/fbdev.c +++ b/backend/fbdev.c @@ -55,11 +55,14 @@ typedef struct { } while (0) /* Requires validation in 24-bit per pixel environments */ -#define ARGB32_TO_RGB888_PERLINE(dest, pixels, width) \ - do { \ - uint32_t *_dest = (uint32_t *) dest; \ - for (int i = 0; i < width; i++) \ - _dest[i] = 0xff000000 | pixels[i]; \ +#define ARGB32_TO_RGB888_PERLINE(dest, pixels, width) \ + do { \ + uint8_t *_dest = (uint8_t *) dest; \ + for (int i = 0; i < width; i++) { \ + _dest[i * 3] = pixels[i] & 0xFF; \ + _dest[i * 3 + 1] = ((pixels[i] & 0x0000FF00) >> 8); \ + _dest[i * 3 + 2] = ((pixels[i] & 0x00FF0000) >> 16); \ + } \ } while (0) #define ARGB32_TO_ARGB32_PERLINE(dest, pixels, width) \ From b08122897734fe5ed6c239bfb7aa6fd67ecbcb62 Mon Sep 17 00:00:00 2001 From: Chisheng Chen Date: Sun, 26 Apr 2026 12:58:20 +0800 Subject: [PATCH 3/3] Drop duplicated is_argb32 and is_rgb888 The twin_fbdev_is_rgb888 and twin_fb_dev_is_argb32 are exactly the same. This merges them to a single function. --- backend/fbdev.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/backend/fbdev.c b/backend/fbdev.c index 8cc91bd..4f754cf 100644 --- a/backend/fbdev.c +++ b/backend/fbdev.c @@ -102,14 +102,7 @@ static inline bool twin_fbdev_is_rgb565(twin_fbdev_t *tx) tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 5; } -static inline bool twin_fbdev_is_rgb888(twin_fbdev_t *tx) -{ - return tx->fb_var.red.offset == 16 && tx->fb_var.red.length == 8 && - tx->fb_var.green.offset == 8 && tx->fb_var.green.length == 8 && - tx->fb_var.blue.offset == 0 && tx->fb_var.blue.length == 8; -} - -static inline bool twin_fbdev_is_argb32(twin_fbdev_t *tx) +static inline bool twin_fbdev_is_rgb888_or_argb32(twin_fbdev_t *tx) { return tx->fb_var.red.offset == 16 && tx->fb_var.red.length == 8 && tx->fb_var.green.offset == 8 && tx->fb_var.green.length == 8 && @@ -147,14 +140,10 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx) } break; case 24: /* RGB888 */ - if (!twin_fbdev_is_rgb888(tx)) { - log_error("Invalid framebuffer format for 24 bpp"); - return false; - } - break; case 32: /* ARGB32 */ - if (!twin_fbdev_is_argb32(tx)) { - log_error("Invalid framebuffer format for 32 bpp"); + if (!twin_fbdev_is_rgb888_or_argb32(tx)) { + log_error("Invalid framebuffer format for %u bpp", + tx->fb_var.bits_per_pixel); return false; } break;