From d8ebee6f2b14d72b69bd37f1ea7e64e936a24695 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Thu, 28 May 2009 22:13:33 +0000 Subject: [PATCH] psplash: Fix so the code honours whatever bit order the display reports with fast paths for the most common cases. --- ChangeLog | 8 +++++ psplash-fb.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++----------- psplash-fb.h | 16 +++++++++ psplash.h | 5 +-- 4 files changed, 116 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 29539c0..8cf2156 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2009-05-28 Richard Purdie + + * psplash-fb.c: + * psplash-fb.h: + * psplash.h: + Fix so the code honours whatever bit order the display reports with + fast paths for the most common cases. + 2009-05-19 Richard Purdie * psplash-fb.c: diff --git a/psplash-fb.c b/psplash-fb.c index 6fdba6a..71740cd 100644 --- a/psplash-fb.c +++ b/psplash-fb.c @@ -142,6 +142,12 @@ psplash_fb_new (int angle) goto fail; } + if (ioctl (fb->fd, FBIOGET_VSCREENINFO, &fb_var) == -1) + { + perror ("Error getting variable framebuffer info (2)"); + goto fail; + } + /* NB: It looks like the fbdev concept of fixed vs variable screen info is * broken. The line_length is part of the fixed info but it can be changed * if you set a new pixel format. */ @@ -158,6 +164,33 @@ psplash_fb_new (int angle) fb->type = fb_fix.type; fb->visual = fb_fix.visual; + fb->red_offset = fb_var.red.offset; + fb->red_length = fb_var.red.length; + fb->green_offset = fb_var.green.offset; + fb->green_length = fb_var.green.length; + fb->blue_offset = fb_var.blue.offset; + fb->blue_length = fb_var.blue.length; + + if (fb->red_offset == 11 && fb->red_length == 5 && + fb->green_offset == 5 && fb->green_length == 6 && + fb->blue_offset == 0 && fb->blue_length == 5) { + fb->rgbmode = RGB565; + } else if (fb->red_offset == 0 && fb->red_length == 5 && + fb->green_offset == 5 && fb->green_length == 6 && + fb->blue_offset == 11 && fb->blue_length == 5) { + fb->rgbmode = BGR565; + } else if (fb->red_offset == 16 && fb->red_length == 8 && + fb->green_offset == 8 && fb->green_length == 8 && + fb->blue_offset == 0 && fb->blue_length == 8) { + fb->rgbmode = RGB888; + } else if (fb->red_offset == 0 && fb->red_length == 8 && + fb->green_offset == 8 && fb->green_length == 8 && + fb->blue_offset == 8 && fb->blue_length == 8) { + fb->rgbmode = BGR888; + } else { + fb->rgbmode = GENERIC; + } + DBG("width: %i, height: %i, bpp: %i, stride: %i", fb->width, fb->height, fb->bpp, fb->stride); @@ -257,24 +290,60 @@ psplash_fb_plot_pixel (PSplashFB *fb, break; } - /* FIXME: handle no RGB orderings */ - switch (fb->bpp) - { - case 24: - case 32: - *(fb->data + off) = red; - *(fb->data + off + 1) = green; - *(fb->data + off + 2) = blue; - break; - case 16: - *(volatile uint16 *) (fb->data + off) - = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); - break; - default: - /* depth not supported yet */ - break; - } - + if (fb->rgbmode == RGB565 || fb->rgbmode == RGB888) { + switch (fb->bpp) + { + case 24: + case 32: + *(fb->data + off) = blue; + *(fb->data + off + 1) = green; + *(fb->data + off + 2) = red; + break; + case 16: + *(volatile uint16_t *) (fb->data + off) + = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); + break; + default: + /* depth not supported yet */ + break; + } + } else if (fb->rgbmode == BGR565 || fb->rgbmode == BGR888) { + switch (fb->bpp) + { + case 24: + case 32: + *(fb->data + off) = red; + *(fb->data + off + 1) = green; + *(fb->data + off + 2) = blue; + break; + case 16: + *(volatile uint16_t *) (fb->data + off) + = ((blue >> 3) << 11) | ((green >> 2) << 5) | (red >> 3); + break; + default: + /* depth not supported yet */ + break; + } + } else { + switch (fb->bpp) + { + case 32: + *(volatile uint32_t *) (fb->data + off) + = ((red >> (8 - fb->red_length)) << fb->red_offset) + | ((green >> (8 - fb->green_length)) << fb->green_offset) + | ((blue >> (8 - fb->blue_length)) << fb->blue_offset); + break; + case 16: + *(volatile uint16_t *) (fb->data + off) + = ((red >> (8 - fb->red_length)) << fb->red_offset) + | ((green >> (8 - fb->green_length)) << fb->green_offset) + | ((blue >> (8 - fb->blue_length)) << fb->blue_offset); + break; + default: + /* depth not supported yet */ + break; + } + } } void @@ -323,7 +392,7 @@ psplash_fb_draw_image (PSplashFB *fb, do { if (img_bytes_per_pixel < 4 || *(p+3)) - psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p+2), *(p+1), *(p)); + psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2)); if (++dx >= img_width) { dx=0; dy++; } } while (--len && (p - rle_data) < total_len); @@ -337,7 +406,7 @@ psplash_fb_draw_image (PSplashFB *fb, do { if (img_bytes_per_pixel < 4 || *(p+3)) - psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p+2), *(p+1), *(p)); + psplash_fb_plot_pixel (fb, x+dx, y+dy, *(p), *(p+1), *(p+2)); if (++dx >= img_width) { dx=0; dy++; } p += img_bytes_per_pixel; } diff --git a/psplash-fb.h b/psplash-fb.h index 6c661f9..ef5b39e 100644 --- a/psplash-fb.h +++ b/psplash-fb.h @@ -18,6 +18,14 @@ #ifndef _HAVE_PSPLASH_FB_H #define _HAVE_PSPLASH_FB_H +enum RGBMode { + RGB565, + BGR565, + RGB888, + BGR888, + GENERIC, +}; + typedef struct PSplashFB { int fd; @@ -32,6 +40,14 @@ typedef struct PSplashFB int angle; int real_width, real_height; + + enum RGBMode rgbmode; + int red_offset; + int red_length; + int green_offset; + int green_length; + int blue_offset; + int blue_length; } PSplashFB; diff --git a/psplash.h b/psplash.h index 36d63c5..22d73a3 100644 --- a/psplash.h +++ b/psplash.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #if defined(__i386__) || defined(__alpha__) @@ -42,8 +43,8 @@ #include #include -typedef unsigned char uint8; -typedef unsigned short uint16; +typedef uint8_t uint8; +typedef uint16_t uint16; typedef int bool; #ifndef FALSE -- 2.7.4