Skip to content

Commit

Permalink
Initial support for 24bit fbdev
Browse files Browse the repository at this point in the history
This is necessary to provide output for cirrus.
While there is some DRM support available, it's too limited for kmscon's drm2d
and even then only supports 24bit out of the box.
  • Loading branch information
Vogtinator committed Jul 25, 2018
1 parent 3f8b688 commit 662884a
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/uterm_fbdev_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct fbdev_display {
unsigned int stride;

bool xrgb32;
bool rgb24;
bool rgb16;
unsigned int Bpp;
unsigned int off_r;
Expand Down
61 changes: 61 additions & 0 deletions src/uterm_fbdev_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ static uint_fast32_t xrgb32_to_device(struct uterm_display *disp,
return res;
}

static void write_24bit(uint8_t *dst, uint_fast32_t value)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
dst[0] = value;
dst[1] = value >> 8;
dst[2] = value >> 16;
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
dst[0] = value >> 16;
dst[1] = value >> 8;
dst[2] = value;
#else
#error "Unknown endianness"
#endif
}

int uterm_fbdev_display_blit(struct uterm_display *disp,
const struct uterm_video_buffer *buf,
unsigned int x, unsigned int y)
Expand Down Expand Up @@ -151,6 +166,16 @@ int uterm_fbdev_display_blit(struct uterm_display *disp,
dst += fbdev->stride;
src += buf->stride;
}
} else if (fbdev->Bpp == 3) {
while (height--) {
for (i = 0; i < width; ++i) {
val = ((uint32_t*)src)[i];
uint_fast32_t full = xrgb32_to_device(disp, val);
write_24bit(&dst[i * 3], full);
}
dst += fbdev->stride;
src += buf->stride;
}
} else if (fbdev->Bpp == 4) {
while (height--) {
for (i = 0; i < width; ++i) {
Expand Down Expand Up @@ -272,6 +297,35 @@ int uterm_fbdev_display_fake_blendv(struct uterm_display *disp,
dst += fbdev->stride;
src += req->buf->stride;
}
} else if (fbdev->Bpp == 3) {
while (height--) {
for (i = 0; i < width; ++i) {
if (src[i] == 0) {
r = req->br;
g = req->bg;
b = req->bb;
} else if (src[i] == 255) {
r = req->fr;
g = req->fg;
b = req->fb;
} else {
r = req->fr * src[i] +
req->br * (255 - src[i]);
r /= 256;
g = req->fg * src[i] +
req->bg * (255 - src[i]);
g /= 256;
b = req->fb * src[i] +
req->bb * (255 - src[i]);
b /= 256;
}
val = (r << 16) | (g << 8) | b;
uint_fast32_t full = xrgb32_to_device(disp, val);
write_24bit(&dst[i * 3], full);
}
dst += fbdev->stride;
src += req->buf->stride;
}
} else if (fbdev->Bpp == 4) {
while (height--) {
for (i = 0; i < width; ++i) {
Expand Down Expand Up @@ -358,6 +412,13 @@ int uterm_fbdev_display_fill(struct uterm_display *disp,
dst += fbdev->stride;
}
}
} else if (fbdev->Bpp == 3) {
while (height--) {
for (i = 0; i < width * 3; i += 3) {
write_24bit(&dst[i], full_val);
}
dst += fbdev->stride;
}
} else if (fbdev->Bpp == 4) {
while (height--) {
for (i = 0; i < width; ++i)
Expand Down
22 changes: 16 additions & 6 deletions src/uterm_fbdev_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,7 @@ static int display_activate_force(struct uterm_display *disp,
struct uterm_mode *mode,
bool force)
{
/* TODO: Add support for 24-bpp. However, we need to check how 3-bytes
* integers are assembled in big/little/mixed endian systems. */
static const char depths[] = { 32, 16, 0 };
static const char depths[] = { 32, 24, 16, 0 };
struct fbdev_display *dfb = disp->data;
struct uterm_mode *m;
struct fbdev_mode *mfb;
Expand Down Expand Up @@ -217,14 +215,19 @@ static int display_activate_force(struct uterm_display *disp,
if (finfo->visual != FB_VISUAL_TRUECOLOR ||
vinfo->bits_per_pixel != 32) {
for (i = 0; depths[i]; ++i) {
vinfo->bits_per_pixel = depths[i];
vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
/* Try to set a new mode and if it's successful... */
struct fb_var_screeninfo vinfo_new = *vinfo;
vinfo_new.bits_per_pixel = depths[i];
vinfo_new.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;

ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO,
vinfo);
&vinfo_new);
if (ret < 0)
continue;

/* ... keep it. */
*vinfo = vinfo_new;

ret = refresh_info(disp);
if (ret)
goto err_close;
Expand All @@ -235,6 +238,7 @@ static int display_activate_force(struct uterm_display *disp,
}

if (vinfo->bits_per_pixel != 32 &&
vinfo->bits_per_pixel != 24 &&
vinfo->bits_per_pixel != 16) {
log_error("device %s does not support 16/32 bpp but: %u",
dfb->node, vinfo->bits_per_pixel);
Expand Down Expand Up @@ -333,6 +337,10 @@ static int display_activate_force(struct uterm_display *disp,
dfb->off_r == 11 && dfb->off_g == 5 && dfb->off_b == 0 &&
dfb->Bpp == 2)
dfb->rgb16 = true;
else if (dfb->len_r == 8 && dfb->len_g == 8 && dfb->len_b == 8 &&
dfb->off_r == 16 && dfb->off_g == 8 && dfb->off_b == 0 &&
dfb->Bpp == 3)
dfb->rgb24 = true;

/* TODO: make dithering configurable */
disp->flags |= DISPLAY_DITHERING;
Expand Down Expand Up @@ -455,6 +463,8 @@ static int display_get_buffers(struct uterm_display *disp,
f = UTERM_FORMAT_XRGB32;
else if (dfb->rgb16)
f = UTERM_FORMAT_RGB16;
else if (dfb->rgb24)
f = UTERM_FORMAT_RGB24;

if (!(formats & f))
return -EOPNOTSUPP;
Expand Down
1 change: 1 addition & 0 deletions src/uterm_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ enum uterm_video_format {
UTERM_FORMAT_GREY = 0x01,
UTERM_FORMAT_XRGB32 = 0x02,
UTERM_FORMAT_RGB16 = 0x04,
UTERM_FORMAT_RGB24 = 0x08,
};

struct uterm_video_buffer {
Expand Down

0 comments on commit 662884a

Please sign in to comment.