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;
|
unsigned int stride;
|
||||||
|
|
||||||
bool xrgb32;
|
bool xrgb32;
|
||||||
|
bool rgb24;
|
||||||
bool rgb16;
|
bool rgb16;
|
||||||
unsigned int Bpp;
|
unsigned int Bpp;
|
||||||
unsigned int off_r;
|
unsigned int off_r;
|
||||||
|
@ -100,6 +100,21 @@ static uint_fast32_t xrgb32_to_device(struct uterm_display *disp,
|
|||||||
return res;
|
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,
|
int uterm_fbdev_display_blit(struct uterm_display *disp,
|
||||||
const struct uterm_video_buffer *buf,
|
const struct uterm_video_buffer *buf,
|
||||||
unsigned int x, unsigned int y)
|
unsigned int x, unsigned int y)
|
||||||
@ -151,6 +166,16 @@ int uterm_fbdev_display_blit(struct uterm_display *disp,
|
|||||||
dst += fbdev->stride;
|
dst += fbdev->stride;
|
||||||
src += buf->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) {
|
} else if (fbdev->Bpp == 4) {
|
||||||
while (height--) {
|
while (height--) {
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
@ -272,6 +297,35 @@ int uterm_fbdev_display_fake_blendv(struct uterm_display *disp,
|
|||||||
dst += fbdev->stride;
|
dst += fbdev->stride;
|
||||||
src += req->buf->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) {
|
} else if (fbdev->Bpp == 4) {
|
||||||
while (height--) {
|
while (height--) {
|
||||||
for (i = 0; i < width; ++i) {
|
for (i = 0; i < width; ++i) {
|
||||||
@ -358,6 +412,13 @@ int uterm_fbdev_display_fill(struct uterm_display *disp,
|
|||||||
dst += fbdev->stride;
|
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) {
|
} else if (fbdev->Bpp == 4) {
|
||||||
while (height--) {
|
while (height--) {
|
||||||
for (i = 0; i < width; ++i)
|
for (i = 0; i < width; ++i)
|
||||||
|
@ -132,9 +132,7 @@ static int display_activate_force(struct uterm_display *disp,
|
|||||||
struct uterm_mode *mode,
|
struct uterm_mode *mode,
|
||||||
bool force)
|
bool force)
|
||||||
{
|
{
|
||||||
/* TODO: Add support for 24-bpp. However, we need to check how 3-bytes
|
static const char depths[] = { 32, 24, 16, 0 };
|
||||||
* integers are assembled in big/little/mixed endian systems. */
|
|
||||||
static const char depths[] = { 32, 16, 0 };
|
|
||||||
struct fbdev_display *dfb = disp->data;
|
struct fbdev_display *dfb = disp->data;
|
||||||
struct uterm_mode *m;
|
struct uterm_mode *m;
|
||||||
struct fbdev_mode *mfb;
|
struct fbdev_mode *mfb;
|
||||||
@ -217,14 +215,19 @@ static int display_activate_force(struct uterm_display *disp,
|
|||||||
if (finfo->visual != FB_VISUAL_TRUECOLOR ||
|
if (finfo->visual != FB_VISUAL_TRUECOLOR ||
|
||||||
vinfo->bits_per_pixel != 32) {
|
vinfo->bits_per_pixel != 32) {
|
||||||
for (i = 0; depths[i]; ++i) {
|
for (i = 0; depths[i]; ++i) {
|
||||||
vinfo->bits_per_pixel = depths[i];
|
/* Try to set a new mode and if it's successful... */
|
||||||
vinfo->activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE;
|
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,
|
ret = ioctl(dfb->fd, FBIOPUT_VSCREENINFO,
|
||||||
vinfo);
|
&vinfo_new);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* ... keep it. */
|
||||||
|
*vinfo = vinfo_new;
|
||||||
|
|
||||||
ret = refresh_info(disp);
|
ret = refresh_info(disp);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_close;
|
goto err_close;
|
||||||
@ -235,6 +238,7 @@ static int display_activate_force(struct uterm_display *disp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vinfo->bits_per_pixel != 32 &&
|
if (vinfo->bits_per_pixel != 32 &&
|
||||||
|
vinfo->bits_per_pixel != 24 &&
|
||||||
vinfo->bits_per_pixel != 16) {
|
vinfo->bits_per_pixel != 16) {
|
||||||
log_error("device %s does not support 16/32 bpp but: %u",
|
log_error("device %s does not support 16/32 bpp but: %u",
|
||||||
dfb->node, vinfo->bits_per_pixel);
|
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->off_r == 11 && dfb->off_g == 5 && dfb->off_b == 0 &&
|
||||||
dfb->Bpp == 2)
|
dfb->Bpp == 2)
|
||||||
dfb->rgb16 = true;
|
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 */
|
/* TODO: make dithering configurable */
|
||||||
disp->flags |= DISPLAY_DITHERING;
|
disp->flags |= DISPLAY_DITHERING;
|
||||||
@ -455,6 +463,8 @@ static int display_get_buffers(struct uterm_display *disp,
|
|||||||
f = UTERM_FORMAT_XRGB32;
|
f = UTERM_FORMAT_XRGB32;
|
||||||
else if (dfb->rgb16)
|
else if (dfb->rgb16)
|
||||||
f = UTERM_FORMAT_RGB16;
|
f = UTERM_FORMAT_RGB16;
|
||||||
|
else if (dfb->rgb24)
|
||||||
|
f = UTERM_FORMAT_RGB24;
|
||||||
|
|
||||||
if (!(formats & f))
|
if (!(formats & f))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
@ -100,6 +100,7 @@ enum uterm_video_format {
|
|||||||
UTERM_FORMAT_GREY = 0x01,
|
UTERM_FORMAT_GREY = 0x01,
|
||||||
UTERM_FORMAT_XRGB32 = 0x02,
|
UTERM_FORMAT_XRGB32 = 0x02,
|
||||||
UTERM_FORMAT_RGB16 = 0x04,
|
UTERM_FORMAT_RGB16 = 0x04,
|
||||||
|
UTERM_FORMAT_RGB24 = 0x08,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct uterm_video_buffer {
|
struct uterm_video_buffer {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user