Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support 16/24/32 bit color depth #70

Merged
merged 1 commit into from
Nov 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 */
jserv marked this conversation as resolved.
Show resolved Hide resolved
#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)
Comment on lines +44 to +57
Copy link
Contributor

@jserv jserv Nov 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Bennctu, can you review these color conversion macros and suggest any potential use of Pixman for performance? These macros handle ARGB32 to RGB565 and RGB888 conversions.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pixman API does not support color conversion.


#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