From: <you...@16...> - 2007-08-12 15:07:43
Attachments:
zhcon-0.2.6-directcolor.diff
|
[Send again, include zhc...@li...] Hi ejoy and ccpaging, I found a bug of Zhcon. When Zhcon uses framebuffer driver on direct color graphic card, it can't display color correctly, especially in 32bit mode. The reason is because Zhcon treat always colors as "true color" that are combined as R,G and B directly. However, in direct color mode, the R,G and B value send to the framebuffer driver is just the index to the color map. For example, in 32bit mode, if you want to use pure red as 0xff0000, it is correct in "true color" mode. However, for the graphic card as as ATI Radeon, they use "direct color" mechanism, the real color will be: red=red_color_map[0xff], blue=blue_color_map[0x00], green=green_color_map[0x00]. If the color_map is not correctly initialized, the real color will not be pure red. Hence there is two key steps must be taken: when initializing the framebuffer object, the 3 color maps should be correct initialized as: X_color_map[i]=i|i<<8, where X is red, green or blue. I have written a patch for 32bit direct color mode, as attachment. But the patch doesn't include the support of 16bit and 8bit direct mode. However the basic idea is the same. Please feel free to contac me if u have any question. BTW, I don't know whether this mail list can have attachment, so I list the content of the patch at the end of the email. Thanks & Regards, Hawk diff -Naur zhcon-0.2.6/src/display/fbdev.cpp zhcon-0.2.7/src/display/fbdev.cpp --- zhcon-0.2.6/src/display/fbdev.cpp 2007-06-19 09:34:37.000000000 +0800 +++ zhcon-0.2.7/src/display/fbdev.cpp 2007-08-05 00:44:33.000000000 +0800 @@ -26,6 +26,9 @@ #include <sys/ioctl.h> #include <sys/mman.h> #include <assert.h> +#include <linux/fb.h> + +#include <errno.h> #include "fbdev.h" #include "fblinear4.h" @@ -43,6 +46,10 @@ int FBDev::mpBufLen = 0; // FrameBuffer file handle int FBDev::mFd = -1; +struct fb_cmap *FBDev::cmap =NULL; +struct fb_cmap *FBDev::cmap_orig =NULL; +struct fb_fix_screeninfo FBDev::Finfo; +struct fb_var_screeninfo FBDev::Vinfo; unsigned long FBDev::mNextLine = 0; unsigned long FBDev::mNextPlane = 0; int FBDev::mCurrentMode = 0; @@ -59,7 +66,6 @@ 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff }; - #if defined(linux) #include <linux/fb.h> #define MAX_DEV_LEN 63 @@ -84,10 +90,22 @@ } rc = NORMAL; - static struct fb_fix_screeninfo Finfo; - static struct fb_var_screeninfo Vinfo; ioctl(mFd, FBIOGET_FSCREENINFO, &Finfo); ioctl(mFd, FBIOGET_VSCREENINFO, &Vinfo); + //In direct color mode, begin to create cmap, and its backup cmap_orig + if (Finfo.visual==FB_VISUAL_DIRECTCOLOR) + { + if ((cmap_orig=CreateCMAP())==(struct fb_cmap *)-1) + { + throw(runtime_error("Can't create color map")); + return FAILURE; + } + if ((cmap=CreateCMAP())==(struct fb_cmap *)-1) + { + throw(runtime_error("Can't create color map")); + return FAILURE; + } + } switch (Finfo.type) { case FB_TYPE_PACKED_PIXELS: // truecolor packed pixels rc = LinearSet(Vinfo); @@ -269,6 +287,13 @@ } FBDev::~FBDev() { + if (cmap) + fb_cmap_destroy(cmap); + if (cmap_orig) + { + ioctl(mFd,FBIOPUTCMAP, cmap_orig); + fb_cmap_destroy(cmap_orig); + } if (mpBuf != NULL) munmap(mpBuf, mpBufLen); if (mFd >= 0) @@ -292,4 +317,169 @@ #endif } +struct fb_cmap * FBDev::CreateCMAP(void) +{ + struct fb_cmap *pcmap=NULL; + int pcmaplen=256; + + /* check the existence of colormap */ + if (Finfo.visual == FB_VISUAL_MONO01 || + Finfo.visual == FB_VISUAL_MONO10 || + Finfo.visual == FB_VISUAL_TRUECOLOR) + return NULL; + + pcmap = (struct fb_cmap *)malloc(sizeof(struct fb_cmap)); + if (!pcmap) { + throw(runtime_error("pcmap malloc error\n")); + return (struct fb_cmap *)-1; + } + memset(pcmap, 0, sizeof(struct fb_cmap)); + + /* Allocates memory for a colormap */ + if (Vinfo.red.length) { + pcmap->red = (__u16 *) malloc(sizeof(__u16) * pcmaplen); + if (!pcmap->red) { + throw(runtime_error("red lut malloc error\n")); + return (struct fb_cmap *)-1; + } + } + if (Vinfo.green.length) { + pcmap->green = (__u16 *) malloc(sizeof(__u16) * pcmaplen); + if (!pcmap->green) { + if (Vinfo.red.length) + free(pcmap->red); + throw(runtime_error("green lut malloc error\n")); + return (struct fb_cmap *)-1; + } + } + if (Vinfo.blue.length) { + pcmap->blue = (__u16 *) malloc(sizeof(__u16) * pcmaplen); + if (!pcmap->blue) { + if (Vinfo.red.length) + free(pcmap->red); + if (Vinfo.green.length) + free(pcmap->green); + throw(runtime_error("blue lut malloc error\n")); + return (struct fb_cmap *)-1; + } + } + if (Vinfo.transp.length) { + pcmap->transp = (__u16 *) malloc(sizeof(__u16) * pcmaplen); + if (!pcmap->transp) { + if (Vinfo.red.length) + free(pcmap->red); + if (Vinfo.green.length) + free(pcmap->green); + if (Vinfo.blue.length) + free(pcmap->blue); + throw(runtime_error("transp lut malloc error\n")); + return (struct fb_cmap *)-1; + } + } + pcmap->len = pcmaplen; + if (ioctl(mFd, FBIOGETCMAP, pcmap)) { + throw(runtime_error(strerror(errno))); + fb_cmap_destroy(pcmap); + return (struct fb_cmap *)-1; + } + return pcmap; +} + +int FBDev::CopyCMAP(struct fb_cmap *cmap_dest, struct fb_cmap *cmap_src) +{ + int cmaplen=256; + + if ((!cmap_dest) || (!cmap_src)) + { + throw("Invalid Argument"); + return -1; + } + + if ((!cmap_src->red) && (cmap_dest->red)) + { + free(cmap_dest->red); + cmap_dest->red=NULL; + } + else if (cmap_src->red) + { + if (!cmap_dest->red) + { + if ((cmap_dest->red=(__u16 *)malloc(sizeof(__u16)*cmaplen))==NULL) + { + throw(runtime_error("Failed to malloc red lut!")); + return -1; + } + } + memcpy((__u8 *)cmap_dest->red,(__u8 *)cmap_src->red, sizeof(__u16)*cmaplen); + } + + if ((!cmap_src->green) && (cmap_dest->green)) + { + free(cmap_dest->green); + cmap_dest->green=NULL; + } + else if (cmap_src->green) + { + if (!cmap_dest->green) + { + if ((cmap_dest->green=(__u16 *)malloc(sizeof(__u16)*cmaplen))==NULL) + { + throw(runtime_error("Failed to malloc green lut!")); + return -1; + } + } + memcpy((__u8 *)cmap_dest->green,(__u8 *)cmap_src->green, sizeof(__u16)*cmaplen); + } + + if ((!cmap_src->blue) && (cmap_dest->blue)) + { + free(cmap_dest->blue); + cmap_dest->blue=NULL; + } + else if (cmap_src->blue) + { + if (!cmap_dest->blue) + { + if ((cmap_dest->blue=(__u16 *)malloc(sizeof(__u16)*cmaplen))==NULL) + { + throw(runtime_error("Failed to malloc blue lut!")); + return -1; + } + } + memcpy((__u8 *)cmap_dest->blue,(__u8 *)cmap_src->blue, sizeof(__u16)*cmaplen); + } + if ((!cmap_src->transp) && (cmap_dest->transp)) + { + free(cmap_dest->transp); + cmap_dest->transp=NULL; + } + else if (cmap_src->transp) + { + if (!cmap_dest->transp) + { + if ((cmap_dest->transp=(__u16 *)malloc(sizeof(__u16)*cmaplen))==NULL) + { + throw(runtime_error("Failed to malloc transp lut!")); + return -1; + } + } + memcpy((__u8 *)cmap_dest->transp,(__u8 *)cmap_src->transp, sizeof(__u16)*cmaplen); + } + cmap_dest->start=cmap_src->start; + cmap_dest->len=cmap_src->len; + return 0; +} + +void FBDev::fb_cmap_destroy(struct fb_cmap *cmap) +{ + if (cmap->red) + free(cmap->red); + if (cmap->green) + free(cmap->green); + if (cmap->blue) + free(cmap->blue); + if (cmap->transp) + free(cmap->transp); + free(cmap); +} diff -Naur zhcon-0.2.6/src/display/fbdev.h zhcon-0.2.7/src/display/fbdev.h --- zhcon-0.2.6/src/display/fbdev.h 2007-06-19 09:34:37.000000000 +0800 +++ zhcon-0.2.7/src/display/fbdev.h 2007-08-04 15:45:18.000000000 +0800 @@ -43,6 +43,9 @@ static OPEN_RC LinearSet( struct fb_var_screeninfo &Vinfo ); static void VGAPlaneSet( void ); static int mCurrentMode; // for FreeBSD + static struct fb_cmap * CreateCMAP(void); + static int CopyCMAP(struct fb_cmap *cmap_dest, struct fb_cmap *cmap_src); + static void fb_cmap_destroy(struct fb_cmap *cmap); protected: // mmap framebuffer address @@ -54,6 +57,10 @@ // FrameBuffer file handle static int mFd; static __u16 red16[],green16[],blue16[]; + static struct fb_fix_screeninfo Finfo; + static struct fb_var_screeninfo Vinfo; + static struct fb_cmap * cmap; + static struct fb_cmap * cmap_orig; }; #endif diff -Naur zhcon-0.2.6/src/display/fblinear32.cpp zhcon-0.2.7/src/display/fblinear32.cpp --- zhcon-0.2.6/src/display/fblinear32.cpp 2007-06-19 09:34:37.000000000 +0800 +++ zhcon-0.2.7/src/display/fblinear32.cpp 2007-08-04 16:36:23.000000000 +0800 @@ -20,6 +20,8 @@ #include <assert.h> #include "global.h" #include "fblinear32.h" +#include <linux/fb.h> +#include <sys/ioctl.h> FBLinear32::FBLinear32() { InitColorMap(); @@ -29,6 +31,20 @@ void FBLinear32::InitColorMap() { int i; __u32 red, green, blue; + + //Firstly we initialize the frame buffer's color map + if (cmap) + { + for (__u32 loop=0;loop<256;loop++) + { + cmap->red[loop]=cmap->green[loop]=cmap->blue[loop]=(loop|loop<<8); + } + if (ioctl(mFd, FBIOPUTCMAP, cmap)) + { + throw(runtime_error("Can't initialize the framebuffer's 32 bits color map.")); + } + } + // Then zhcon's color map for(i = 0; i < 16; i++) { red = red16[i]; green = green16[i]; |