diff options
author | mrwastl <mrwastl@users.sourceforge.net> | 2011-10-21 00:50:56 +0200 |
---|---|---|
committer | mrwastl <mrwastl@users.sourceforge.net> | 2011-10-21 00:50:56 +0200 |
commit | d14d492732a84e1bda42b0a4a249c83a7d99b93c (patch) | |
tree | 004993f4a9fe5a2da7af4410c3cf70b7de365479 /glcddrivers | |
parent | a3916e6c29491024c7204e6a994e156241c5ff42 (diff) | |
download | graphlcd-base-d14d492732a84e1bda42b0a4a249c83a7d99b93c.tar.gz graphlcd-base-d14d492732a84e1bda42b0a4a249c83a7d99b93c.tar.bz2 |
framebuffer: now with colour support (depths 8, 16, 24, 32), damage reporting, selectable framebuffer device
Diffstat (limited to 'glcddrivers')
-rw-r--r-- | glcddrivers/framebuffer.c | 296 | ||||
-rw-r--r-- | glcddrivers/framebuffer.h | 9 |
2 files changed, 254 insertions, 51 deletions
diff --git a/glcddrivers/framebuffer.c b/glcddrivers/framebuffer.c index a77900d..254f487 100644 --- a/glcddrivers/framebuffer.c +++ b/glcddrivers/framebuffer.c @@ -37,6 +37,7 @@ cDriverFramebuffer::cDriverFramebuffer(cDriverConfig * config) int cDriverFramebuffer::Init() { +#if 0 // default values width = config->width; if (width <= 0) @@ -44,7 +45,10 @@ int cDriverFramebuffer::Init() height = config->height; if (height <= 0) height = 240; +#endif zoom = 1; + damage = 0; + depth = 1; for (unsigned int i = 0; i < config->options.size(); i++) { @@ -57,11 +61,34 @@ int cDriverFramebuffer::Init() syslog(LOG_ERR, "%s error: zoom %d not supported, using default (%d)!\n", config->name.c_str(), z, zoom); } + else if (config->options[i].name == "ReportDamage" || config->options[i].name == "Damage" ) + { + if (config->options[i].value == "none") { + damage = 0; + } else if (config->options[i].value == "ugly") { + damage = 1; + } else if (config->options[i].value == "udlfb") { + damage = 2; + } else if (config->options[i].value == "auto") { + damage = -1; + } + else + syslog(LOG_ERR, "%s error: ReportDamage='%s' not supported, continuing w/o damage reporting!\n", + config->name.c_str(), config->options[i].value.c_str()); + } } - // Open the file for reading and writing - fbfd = open("/dev/fb0", O_RDWR); - if (1 == fbfd) + if (config->device == "") + { + fbfd = open("/dev/fb0", O_RDWR); + } + else + { + fbfd = open(config->device.c_str(), O_RDWR); + } + + //fbfd = open("/dev/fb0", O_RDWR); + if (fbfd < 0) { syslog(LOG_ERR, "%s: cannot open framebuffer device.\n", config->name.c_str()); return -1; @@ -82,11 +109,78 @@ int cDriverFramebuffer::Init() return -1; } + if ( ! ( vinfo.bits_per_pixel == 8 || vinfo.bits_per_pixel == 16 || vinfo.bits_per_pixel == 24 || vinfo.bits_per_pixel == 32 ) ) + { + syslog(LOG_ERR, "%s: bpp %d not supported.\n", config->name.c_str(), vinfo.bits_per_pixel); + return -1; + } + + // get colour info + if (vinfo.bits_per_pixel > 8) { + rlen = vinfo.red.length; + glen = vinfo.green.length; + blen = vinfo.blue.length; + alen = vinfo.transp.length; + + roff = vinfo.red.offset; + goff = vinfo.green.offset; + boff = vinfo.blue.offset; + aoff = vinfo.transp.offset; + } else { + // init colour map + struct fb_cmap cmap; + uint16_t r[256], g[256], b[256]; + int i; + + // RGB332 code from fbsplash-project taken as guideline + for ( i = 0; i < 256; i ++ ) { + r[i] = (( i & 0xe0) << 8) + ((i & 0x20) ? 0x1fff : 0); + g[i] = (( i & 0x1c) << 11) + ((i & 0x04) ? 0x1fff : 0); + b[i] = (( i & 0x03) << 14) + ((i & 0x01) ? 0x3fff : 0); + } + cmap.start = 0; + cmap.len = 256; + cmap.red = r; + cmap.green = g; + cmap.blue = b; + cmap.transp = 0; + if (ioctl(fbfd, FBIOPUTCMAP, &cmap)) { + syslog(LOG_ERR, "%s: Error setting colour map for bpp=8.\n", config->name.c_str()); + return -1; + } + } + // Figure out the size of the screen in bytes screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; syslog(LOG_INFO, "%s: V01: xres: %d, yres %d, vyres: %d, bpp: %d, linelenght: %d\n", config->name.c_str(),vinfo.xres,vinfo.yres,vinfo.yres_virtual,vinfo.bits_per_pixel,finfo.line_length); + // auto calc w/h depending on zoom + if (zoom == 1) { + width = vinfo.xres >> 1; + height = vinfo.yres >> 1; + } else { + width = vinfo.xres; + height = vinfo.yres; + } + depth = vinfo.bits_per_pixel; + + // init bounding box + bbox[0] = width - 1; // x top + bbox[1] = height - 1; // y top + bbox[2] = 0; // x bottom + bbox[3] = 0; // y bottom + + + // damage reporting == auto: detect framebuffer driver + if (damage == -1) { + if (strncasecmp(finfo.id, "udlfb", 16) == 0) { + damage = 2; // udlfb + } else { /* not supported / not detected */ + damage = 0; // not detected -> no damage reporting + } + } + // reserve another memory to draw into offbuff = new char[screensize]; if (!offbuff) @@ -148,7 +242,9 @@ int cDriverFramebuffer::CheckSetup() void cDriverFramebuffer::SetPixel(int x, int y, uint32_t data) { int location; - int outcol; + unsigned char col1, col2, col3, alpha = 0; + uint32_t colraw; + int changed = 0; if (x >= width || y >= height) return; @@ -161,70 +257,107 @@ void cDriverFramebuffer::SetPixel(int x, int y, uint32_t data) // Figure out where in memory to put the pixel - location = (x*(1+zoom)+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + - (y*(1+zoom)+vinfo.yoffset) * finfo.line_length; - - if (data == GRAPHLCD_White) { - if (vinfo.bits_per_pixel <= 8) { - outcol = 15; - } else { - outcol = 255; - } - } else { - outcol = 0; - } + location = ( (x << zoom) + vinfo.xoffset) * (vinfo.bits_per_pixel >> 3) + + ( (y << zoom) + vinfo.yoffset) * finfo.line_length; if (vinfo.bits_per_pixel <= 8) { - *(offbuff + location) = outcol; - if (zoom == 1) - { - *(offbuff + location + 1) = outcol; - *(offbuff + location + finfo.line_length) = outcol; - *(offbuff + location + finfo.line_length + 1) = outcol; + col1 = ((data & 0x00FF0000) >> (16 + 5) << 5) | // RRRg ggbb + ((data & 0x0000FF00) >> ( 8 + 5) << 2) | // rrrG GGbb + ((data & 0x000000FF) >> ( 6) ); // rrrg ggBB + if ( *(offbuff + location) != col1) { + changed = 1; + *(offbuff + location) = col1; + if (zoom == 1) + { + *(offbuff + location + 1) = col1; + *(offbuff + location + finfo.line_length) = col1; + *(offbuff + location + finfo.line_length + 1) = col1; + } } } else if (vinfo.bits_per_pixel <= 16) { - *(offbuff + location) = outcol; - *(offbuff + location + 1) = outcol; - if (zoom == 1) - { - *(offbuff + location + 2) = outcol; - *(offbuff + location + 3) = outcol; - *(offbuff + location + finfo.line_length) = outcol; - *(offbuff + location + finfo.line_length + 1) = outcol; - *(offbuff + location + finfo.line_length + 2) = outcol; - *(offbuff + location + finfo.line_length + 3) = outcol; + + + colraw = ((data & 0x00FF0000) >> (16 + 8 - rlen) << roff) | // red + ((data & 0x0000FF00) >> ( 8 + 8 - glen) << goff) | // green + ((data & 0x000000FF) >> ( 0 + 8 - blen) << boff); // blue + col1 = colraw & 0x0000FF; + col2 = (colraw & 0x00FF00) >> 8; + if ( *(offbuff + location) != col1 || *(offbuff + location + 1) != col2 ) { + changed = 1; + *(offbuff + location) = col1; + *(offbuff + location + 1) = col2; + if (zoom == 1) + { + *(offbuff + location + 2) = col1; + *(offbuff + location + 3) = col2; + *(offbuff + location + finfo.line_length) = col1; + *(offbuff + location + finfo.line_length + 1) = col2; + *(offbuff + location + finfo.line_length + 2) = col1; + *(offbuff + location + finfo.line_length + 3) = col2; + } } } else { - *(offbuff + location) = outcol; - *(offbuff + location + 1) = outcol; - *(offbuff + location + 2) = outcol; - *(offbuff + location + 3) = 0; /* should be transparency */ - if (zoom == 1) - { - *(offbuff + location + 4) = outcol; - *(offbuff + location + 5) = outcol; - *(offbuff + location + 6) = outcol; - *(offbuff + location + 7) = 0; - *(offbuff + location + finfo.line_length) = outcol; - *(offbuff + location + finfo.line_length + 1) = outcol; - *(offbuff + location + finfo.line_length + 2) = outcol; - *(offbuff + location + finfo.line_length + 3) = 0; - *(offbuff + location + finfo.line_length + 4) = outcol; - *(offbuff + location + finfo.line_length + 5) = outcol; - *(offbuff + location + finfo.line_length + 6) = outcol; - *(offbuff + location + finfo.line_length + 7) = 0; + // remap graphlcd colour representation to framebuffer rep. + colraw = ((data & 0x00FF0000) >> (16 + 8 - rlen) << roff) | // red + ((data & 0x0000FF00) >> ( 8 + 8 - glen) << goff) | // green + ((data & 0x000000FF) >> ( 0 + 8 - blen) << boff); // blue + col1 = (colraw & 0x000000FF); + col2 = (colraw & 0x0000FF00) >> 8; + col3 = (colraw & 0x00FF0000) >> 16; + + if (vinfo.bits_per_pixel == 32) { + colraw |= ((data & 0xFF000000) >> (24 + 8 - alen) << aoff); // transp. + alpha = (colraw & 0xFF000000) >> 24; + } + + if ( *(offbuff + location) != col1 || *(offbuff + location + 1) != col2 || *(offbuff + location + 2) != col3 ) { + int pos = 0; + changed = 1; + *(offbuff + location + pos++) = col1; + *(offbuff + location + pos++) = col2; + *(offbuff + location + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + pos++) = alpha; /* should be transparency */ + if (zoom == 1) + { + *(offbuff + location + pos++) = col1; + *(offbuff + location + pos++) = col2; + *(offbuff + location + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + pos++) = alpha; + pos = 0; + *(offbuff + location + finfo.line_length + pos++) = col1; + *(offbuff + location + finfo.line_length + pos++) = col2; + *(offbuff + location + finfo.line_length + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + finfo.line_length + pos++) = alpha; + *(offbuff + location + finfo.line_length + pos++) = col1; + *(offbuff + location + finfo.line_length + pos++) = col2; + *(offbuff + location + finfo.line_length + pos++) = col3; + if (vinfo.bits_per_pixel > 24) + *(offbuff + location + finfo.line_length + pos++) = alpha; + } } } + + if (changed) { + // bounding box changed? + if (x < bbox[0]) bbox[0] = x; + if (y < bbox[1]) bbox[1] = y; + if (x > bbox[2]) bbox[2] = x; + if (y > bbox[3]) bbox[3] = y; + } } void cDriverFramebuffer::Clear() { memset(offbuff, 0, screensize); + processDamage(); } #if 0 @@ -245,6 +378,69 @@ void cDriverFramebuffer::Set8Pixels(int x, int y, unsigned char data) void cDriverFramebuffer::Refresh(bool refreshAll) { memcpy(fbp, offbuff, screensize); + processDamage(); +} + +bool cDriverFramebuffer::GetDriverFeature (const std::string & Feature, int & value) { + if (offbuff) { + if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = depth; + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = 0; + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = 0; + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = 1; + return true; +#if 0 + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + if (...) { + value = (...) ? 1 : 0; + } + return true; +#endif + } + } + value = 0; + return false; +} + + +/* defines for different damage processing calls needed by _update() */ +#define DLFB_IOCTL_REPORT_DAMAGE 0xAA +void cDriverFramebuffer::processDamage (void) { + switch (damage) { + case 1: // ugly + { + unsigned char buf[3] = "\n"; + write(fbfd,buf,2); + } + break; + case 2: // udlfb + { + struct fb_rect { + int x; int y; int w; int h; + } damage = {0, 0, 0, 0}; + damage.x = bbox[0] << zoom; + damage.y = bbox[1] << zoom; + damage.w = (bbox[2] - bbox[0] + 1) << zoom; + damage.h = (bbox[3] - bbox[1] + 1) << zoom; + + ioctl(fbfd, DLFB_IOCTL_REPORT_DAMAGE, &damage); + } + break; + default: // no damage reporting + break; + } + + /* reset bounding box */ + bbox[0] = width - 1; + bbox[1] = height - 1; + bbox[2] = 0; + bbox[3] = 0; } } // end of namespace diff --git a/glcddrivers/framebuffer.h b/glcddrivers/framebuffer.h index 0d94562..328b0c9 100644 --- a/glcddrivers/framebuffer.h +++ b/glcddrivers/framebuffer.h @@ -34,9 +34,16 @@ private: long int screensize; void *fbp; int zoom; + int damage; + int bbox[4]; + int depth; + uint32_t roff, boff, goff, aoff; + uint32_t rlen, blen, glen, alen; int CheckSetup(); - + void processDamage (void); +protected: + virtual bool GetDriverFeature (const std::string & Feature, int & value); public: cDriverFramebuffer(cDriverConfig * config); |