Skip to content

Commit

Permalink
Merge pull request #70 from p96114175/main
Browse files Browse the repository at this point in the history
Support 16/24/32 bit color depth
  • Loading branch information
jserv authored Nov 23, 2024
2 parents e4e0e70 + 2cc4b56 commit 35ddf50
Showing 1 changed file with 92 additions and 24 deletions.
116 changes: 92 additions & 24 deletions backend/fbdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,41 @@ typedef struct {
size_t fb_len;
} twin_fbdev_t;

static void _twin_fbdev_put_span(twin_coord_t left,
twin_coord_t top,
twin_coord_t right,
twin_argb32_t *pixels,
void *closure)
{
twin_screen_t *screen = SCREEN(closure);
twin_fbdev_t *tx = PRIV(closure);

if (tx->fb_base == MAP_FAILED)
return;
/* 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); \
} while (0)

/* Requires validation in 24-bit per pixel environments */
#define ARGB32_TO_RGB888_PERLINE(dest, pixels, width) \
do { \
for (int i = 0; i < width; 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); \
}

twin_coord_t width = right - left;
uint32_t *dest;
off_t off = sizeof(*dest) * left + top * tx->fb_fix.line_length;
dest = (uint32_t *) ((uintptr_t) tx->fb_base + off);
memcpy(dest, pixels, width * sizeof(*dest));
}
FBDEV_PUT_SPAN_IMPL(16, ARGB32_TO_RGB565_PERLINE)
FBDEV_PUT_SPAN_IMPL(24, ARGB32_TO_RGB888_PERLINE)
FBDEV_PUT_SPAN_IMPL(32, ARGB32_TO_ARGB32_PERLINE)

static void twin_fbdev_get_screen_size(twin_fbdev_t *tx,
int *width,
Expand Down Expand Up @@ -85,6 +102,27 @@ static bool twin_fbdev_work(void *closure)
return true;
}

static inline bool twin_fbdev_is_rgb565(twin_fbdev_t *tx)
{
return tx->fb_var.red.offset == 11 && tx->fb_var.red.length == 5 &&
tx->fb_var.green.offset == 5 && tx->fb_var.green.length == 6 &&
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)
{
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 bool twin_fbdev_apply_config(twin_fbdev_t *tx)
{
/* Read changable information of the framebuffer */
Expand All @@ -96,7 +134,6 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
/* Set the virtual screen size to be the same as the physical screen */
tx->fb_var.xres_virtual = tx->fb_var.xres;
tx->fb_var.yres_virtual = tx->fb_var.yres;
tx->fb_var.bits_per_pixel = 32;
if (ioctl(tx->fb_fd, FBIOPUT_VSCREENINFO, &tx->fb_var) < 0) {
log_error("Failed to set framebuffer mode");
return false;
Expand All @@ -108,10 +145,29 @@ static bool twin_fbdev_apply_config(twin_fbdev_t *tx)
return false;
}

/* Check bits per pixel */
if (tx->fb_var.bits_per_pixel != 32) {
log_error("Failed to set framebuffer bpp to 32");
return false;
/* Examine the framebuffer format */
switch (tx->fb_var.bits_per_pixel) {
case 16: /* RGB565 */
if (!twin_fbdev_is_rgb565(tx)) {
log_error("Invalid framebuffer format for 16 bpp");
return false;
}
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");
return false;
}
break;
default:
log_error("Unsupported bits per pixel: %d", tx->fb_var.bits_per_pixel);
break;
}

/* Read unchangable information of the framebuffer */
Expand Down Expand Up @@ -172,9 +228,21 @@ twin_context_t *twin_fbdev_init(int width, int height)
goto bail_vt_fd;
}

/* Examine if framebuffer mapping is valid */
if (tx->fb_base == MAP_FAILED) {
log_error("Failed to map framebuffer memory");
return;
}

const twin_put_span_t fbdev_put_spans[] = {
_twin_fbdev_put_span16,
_twin_fbdev_put_span24,
_twin_fbdev_put_span32,
};
/* Create TWIN screen */
ctx->screen =
twin_screen_create(width, height, NULL, _twin_fbdev_put_span, ctx);
ctx->screen = twin_screen_create(
width, height, NULL, fbdev_put_spans[tx->fb_var.bits_per_pixel / 8 - 2],
ctx);

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

0 comments on commit 35ddf50

Please sign in to comment.