Initial support for 24bit fbdev
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.
This commit is contained in:
parent
3f8b688221
commit
662884a4c8
@ -55,6 +55,7 @@ struct fbdev_display {
|
||||
unsigned int stride;
|
||||
|
||||
bool xrgb32;
|
||||
bool rgb24;
|
||||
bool rgb16;
|
||||
unsigned int Bpp;
|
||||
unsigned int off_r;
|
||||
|
@ -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)
|
||||
@ -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) {
|
||||
@ -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) {
|
||||
@ -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)
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
@ -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);
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user