/* Neutrino-GUI - DBoxII-Project Copyright (C) 2001 Steffen Hehn 'McClean' 2003 thegoodguy mute icon handling from tuxbox project Copyright (C) 2009 Stefan Seyfried mute icon & info clock handling Copyright (C) 2013 M. Liebmann (micha-bbg) License: GPL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_COOL_HARDWARE #include #endif extern cVideo * videoDecoder; extern CPictureViewer * g_PicViewer; #define ICON_CACHE_SIZE 1024*1024*2 // 2mb #define BACKGROUNDIMAGEWIDTH 720 #ifdef BOXMODEL_APOLLO #ifndef FB_HW_ACCELERATION #define FB_HW_ACCELERATION #endif #endif #if defined(FB_HW_ACCELERATION) && defined(USE_NEVIS_GXA) #error #endif //#undef USE_NEVIS_GXA //FIXME /*******************************************************************************/ #ifdef USE_NEVIS_GXA #ifdef GXA_FG_COLOR_REG #undef GXA_FG_COLOR_REG #endif #ifdef GXA_BG_COLOR_REG #undef GXA_BG_COLOR_REG #endif #ifdef GXA_LINE_CONTROL_REG #undef GXA_LINE_CONTROL_REG #endif #ifdef GXA_DEPTH_REG #undef GXA_DEPTH_REG #endif #ifdef GXA_CONTENT_ID_REG #undef GXA_CONTENT_ID_REG #endif #define GXA_POINT(x, y) (((y) & 0x0FFF) << 16) | ((x) & 0x0FFF) #define GXA_SRC_BMP_SEL(x) (x << 8) #define GXA_DST_BMP_SEL(x) (x << 5) #define GXA_PARAM_COUNT(x) (x << 2) #define GXA_CMD_REG 0x001C #define GXA_FG_COLOR_REG 0x0020 #define GXA_BG_COLOR_REG 0x0024 #define GXA_LINE_CONTROL_REG 0x0038 #define GXA_BMP2_TYPE_REG 0x0050 #define GXA_BMP2_ADDR_REG 0x0054 #define GXA_DEPTH_REG 0x00F4 #define GXA_CONTENT_ID_REG 0x0144 #define GXA_BLT_CONTROL_REG 0x0034 #define GXA_CMD_BLT 0x00010800 #define GXA_CMD_NOT_ALPHA 0x00011000 #define GXA_CMD_NOT_TEXT 0x00018000 #define GXA_CMD_QMARK 0x00001000 #define GXA_BMP1_TYPE_REG 0x0048 #define GXA_BMP1_ADDR_REG 0x004C #define GXA_BMP7_TYPE_REG 0x0078 #define GXA_BLEND_CFG_REG 0x003C #define GXA_CFG_REG 0x0030 #define GXA_CFG2_REG 0x00FC /* static unsigned int _read_gxa(volatile unsigned char *base_addr, unsigned int offset) { return *(volatile unsigned int *)(base_addr + offset); } */ static unsigned int _mark = 0; static void _write_gxa(volatile unsigned char *base_addr, unsigned int offset, unsigned int value) { while( (*(volatile unsigned int *)(base_addr + GXA_DEPTH_REG)) & 0x40000000) {}; *(volatile unsigned int *)(base_addr + offset) = value; } /* this adds a tagged marker into the GXA queue. Once this comes out of the other end of the queue, all commands before it are finished */ void CFrameBuffer::add_gxa_sync_marker(void) { unsigned int cmd = GXA_CMD_QMARK | GXA_PARAM_COUNT(1); // TODO: locking? _mark++; _mark &= 0x0000001F; /* bit 0x20 crashes the kernel, if set */ _write_gxa(gxa_base, cmd, _mark); //fprintf(stderr, "%s: wrote %02x\n", __FUNCTION__, _mark); } /* wait until the current marker comes out of the GXA command queue */ void CFrameBuffer::waitForIdle(const char* func) { unsigned int cfg, count = 0; do { cfg = *(volatile unsigned int *)(gxa_base + GXA_CMD_REG); cfg >>= 24; /* the token is stored in bits 31...24 */ if (cfg == _mark) break; /* usleep is too coarse, because of CONFIG_HZ=100 in kernel so use sched_yield to at least give other threads a chance to run */ sched_yield(); //fprintf(stderr, "%s: read %02x, expected %02x\n", __FUNCTION__, cfg, _mark); } while(++count < 2048); /* don't deadlock here if there is an error */ if (count > 1024) /* more than 100 are unlikely, */{ //NI if (func != NULL) fprintf(stderr, "CFrameBuffer::waitForIdle: count is big (%04u) [%s]!\n", count, func); else fprintf(stderr, "CFrameBuffer::waitForIdle: count is big (%u)!\n", count); } } #endif /* USE_NEVIS_GXA */ /*******************************************************************************/ static uint8_t * virtual_fb = NULL; inline unsigned int make16color(uint16_t r, uint16_t g, uint16_t b, uint16_t t, uint32_t /*rl*/ = 0, uint32_t /*ro*/ = 0, uint32_t /*gl*/ = 0, uint32_t /*go*/ = 0, uint32_t /*bl*/ = 0, uint32_t /*bo*/ = 0, uint32_t /*tl*/ = 0, uint32_t /*to*/ = 0) { return ((t << 24) & 0xFF000000) | ((r << 8) & 0xFF0000) | ((g << 0) & 0xFF00) | (b >> 8 & 0xFF); } CFrameBuffer::CFrameBuffer() : active ( true ) { iconBasePath = ""; available = 0; cmap.start = 0; cmap.len = 256; cmap.red = red; cmap.green = green; cmap.blue = blue; cmap.transp = trans; backgroundColor = 0; useBackgroundPaint = false; background = NULL; backupBackground = NULL; backgroundFilename = ""; fd = 0; tty = 0; locked = false; //NI m_transparent_default = CFrameBuffer::TM_BLACK; // TM_BLACK: Transparency when black content ('pseudo' transparency) // TM_NONE: No 'pseudo' transparency // TM_INI: Transparency depends on g_settings.infobar_alpha ??? m_transparent = m_transparent_default; q_circle = NULL; initQCircle(); corner_tl = false; corner_tr = false; corner_bl = false; corner_br = false; //FIXME: test memset(red, 0, 256*sizeof(__u16)); memset(green, 0, 256*sizeof(__u16)); memset(blue, 0, 256*sizeof(__u16)); memset(trans, 0, 256*sizeof(__u16)); fbAreaActiv = false; fb_no_check = false; do_paint_mute_icon = true; } CFrameBuffer* CFrameBuffer::getInstance() { static CFrameBuffer* frameBuffer = NULL; if(!frameBuffer) { frameBuffer = new CFrameBuffer(); printf("[neutrino] frameBuffer Instance created\n"); } else { //printf("[neutrino] frameBuffer Instace requested\n"); } return frameBuffer; } #ifdef USE_NEVIS_GXA void CFrameBuffer::setupGXA(void) { // We (re)store the GXA regs here in case DFB override them and was not // able to restore them. _write_gxa(gxa_base, GXA_BMP2_TYPE_REG, (3 << 16) | screeninfo.xres); _write_gxa(gxa_base, GXA_BMP2_ADDR_REG, (unsigned int) fix.smem_start); _write_gxa(gxa_base, GXA_BLEND_CFG_REG, 0x00089064); // TODO check mono-flip, bit 8 _write_gxa(gxa_base, GXA_CFG_REG, 0x100 | (1 << 12) | (1 << 29)); _write_gxa(gxa_base, GXA_CFG2_REG, 0x1FF); _write_gxa(gxa_base, GXA_BG_COLOR_REG, (unsigned int) backgroundColor); _write_gxa(gxa_base, GXA_BMP7_TYPE_REG, (3 << 16) | screeninfo.xres | (1 << 27)); } #endif void CFrameBuffer::init(const char * const fbDevice) { int tr = 0xFF; fd = open(fbDevice, O_RDWR); if(!fd) fd = open(fbDevice, O_RDWR); if (fd<0) { perror(fbDevice); goto nolfb; } if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo)<0) { perror("FBIOGET_VSCREENINFO"); goto nolfb; } memmove(&oldscreen, &screeninfo, sizeof(screeninfo)); if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0) { perror("FBIOGET_FSCREENINFO"); goto nolfb; } available=fix.smem_len; printf("%dk video mem\n", available/1024); lfb=(fb_pixel_t*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); if (!lfb) { perror("mmap"); goto nolfb; } #ifdef USE_NEVIS_GXA /* Open /dev/mem for HW-register access */ devmem_fd = open("/dev/mem", O_RDWR | O_SYNC); if (devmem_fd < 0) { perror("Unable to open /dev/mem"); goto nolfb; } /* mmap the GXA's base address */ gxa_base = (volatile unsigned char*) mmap(0, 0x00040000, PROT_READ | PROT_WRITE, MAP_SHARED, devmem_fd, 0xE0600000); if (gxa_base == (void*) -1){ perror("Unable to mmap /dev/mem"); goto nolfb; } /* tell the GXA where the framebuffer to draw on starts */ smem_start = (unsigned int) fix.smem_start; printf("smem_start %x\n", smem_start); setupGXA(); #endif cache_size = 0; /* Windows Colors */ paletteSetColor(0x1, 0x010101, tr); paletteSetColor(0x2, 0x800000, tr); paletteSetColor(0x3, 0x008000, tr); paletteSetColor(0x4, 0x808000, tr); paletteSetColor(0x5, 0x000080, tr); paletteSetColor(0x6, 0x800080, tr); paletteSetColor(0x7, 0x008080, tr); paletteSetColor(0x8, 0xA0A0A0, tr); paletteSetColor(0x9, 0x505050, tr); paletteSetColor(0xA, 0xFF0000, tr); paletteSetColor(0xB, 0x00FF00, tr); paletteSetColor(0xC, 0xFFFF00, tr); paletteSetColor(0xD, 0x0000FF, tr); paletteSetColor(0xE, 0xFF00FF, tr); paletteSetColor(0xF, 0x00FFFF, tr); paletteSetColor(0x10, 0xFFFFFF, tr); paletteSetColor(0x11, 0x000000, tr); paletteSetColor(COL_BACKGROUND, 0x000000, 0x0); paletteSet(); useBackground(false); m_transparent = m_transparent_default; #if 0 if ((tty=open("/dev/vc/0", O_RDWR))<0) { perror("open (tty)"); goto nolfb; } struct sigaction act; memset(&act,0,sizeof(act)); act.sa_handler = switch_signal; sigemptyset(&act.sa_mask); sigaction(SIGUSR1,&act,NULL); sigaction(SIGUSR2,&act,NULL); struct vt_mode mode; if (-1 == ioctl(tty,KDGETMODE, &kd_mode)) { perror("ioctl KDGETMODE"); goto nolfb; } if (-1 == ioctl(tty,VT_GETMODE, &vt_mode)) { perror("ioctl VT_GETMODE"); goto nolfb; } if (-1 == ioctl(tty,VT_GETMODE, &mode)) { perror("ioctl VT_GETMODE"); goto nolfb; } mode.mode = VT_PROCESS; mode.waitv = 0; mode.relsig = SIGUSR1; mode.acqsig = SIGUSR2; if (-1 == ioctl(tty,VT_SETMODE, &mode)) { perror("ioctl VT_SETMODE"); goto nolfb; } if (-1 == ioctl(tty,KDSETMODE, KD_GRAPHICS)) { perror("ioctl KDSETMODE"); goto nolfb; } #endif return; nolfb: printf("framebuffer not available.\n"); lfb=0; } //NI void CFrameBuffer::clearIconCache() { std::map::iterator it; for(it = icon_cache.begin(); it != icon_cache.end(); ++it) { /* printf("FB: delete cached icon %s: %x\n", it->first.c_str(), (int) it->second.data); */ cs_free_uncached(it->second.data); } icon_cache.clear(); } CFrameBuffer::~CFrameBuffer() { clearIconCache(); //NI if (background) { delete[] background; background = NULL; } if (backupBackground) { delete[] backupBackground; backupBackground = NULL; } if (q_circle) { delete[] q_circle; q_circle = NULL; } #if 0 #ifdef RETURN_FROM_GRAPHICS_MODE if (-1 == ioctl(tty,KDSETMODE, kd_mode)) perror("ioctl KDSETMODE"); #endif if (-1 == ioctl(tty,VT_SETMODE, &vt_mode)) perror("ioctl VT_SETMODE"); if (available) ioctl(fd, FBIOPUT_VSCREENINFO, &oldscreen); #endif if (lfb) munmap(lfb, available); if (virtual_fb){ delete[] virtual_fb; virtual_fb = NULL; } close(fd); close(tty); v_fbarea.clear(); } int CFrameBuffer::getFileHandle() const { return fd; } unsigned int CFrameBuffer::getStride() const { return stride; } unsigned int CFrameBuffer::getScreenWidth(bool real) { if(real) return xRes; else return g_settings.screen_EndX - g_settings.screen_StartX; } unsigned int CFrameBuffer::getScreenHeight(bool real) { if(real) return yRes; else return g_settings.screen_EndY - g_settings.screen_StartY; } unsigned int CFrameBuffer::getScreenWidthRel(bool force_small) { int percent = force_small ? WINDOW_SIZE_MIN_FORCED : g_settings.window_width; // always reduce a possible detailline return (g_settings.screen_EndX - g_settings.screen_StartX - 2*ConnectLineBox_Width) * percent / 100; } unsigned int CFrameBuffer::getScreenHeightRel(bool force_small) { int percent = force_small ? WINDOW_SIZE_MIN_FORCED : g_settings.window_height; return (g_settings.screen_EndY - g_settings.screen_StartY) * percent / 100; } unsigned int CFrameBuffer::getScreenX() { return g_settings.screen_StartX; } unsigned int CFrameBuffer::getScreenY() { return g_settings.screen_StartY; } fb_pixel_t * CFrameBuffer::getFrameBufferPointer() const { if (active || (virtual_fb == NULL)) return lfb; else return (fb_pixel_t *) virtual_fb; } bool CFrameBuffer::getActive() const { return (active || (virtual_fb != NULL)); } void CFrameBuffer::setActive(bool enable) { active = enable; } t_fb_var_screeninfo *CFrameBuffer::getScreenInfo() { return &screeninfo; } int CFrameBuffer::setMode(unsigned int /*nxRes*/, unsigned int /*nyRes*/, unsigned int /*nbpp*/) { if (!available&&!active) return -1; #if 0 screeninfo.xres_virtual=screeninfo.xres=nxRes; screeninfo.yres_virtual=screeninfo.yres=nyRes; screeninfo.height=0; screeninfo.width=0; screeninfo.xoffset=screeninfo.yoffset=0; screeninfo.bits_per_pixel=nbpp; if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0) { perror("FBIOPUT_VSCREENINFO"); } if(1) { printf("SetMode: %dbits, red %d:%d green %d:%d blue %d:%d transp %d:%d\n", screeninfo.bits_per_pixel, screeninfo.red.length, screeninfo.red.offset, screeninfo.green.length, screeninfo.green.offset, screeninfo.blue.length, screeninfo.blue.offset, screeninfo.transp.length, screeninfo.transp.offset); } if ((screeninfo.xres!=nxRes) && (screeninfo.yres!=nyRes) && (screeninfo.bits_per_pixel!=nbpp)) { printf("SetMode failed: wanted: %dx%dx%d, got %dx%dx%d\n", nxRes, nyRes, nbpp, screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel); return -1; } #endif xRes = screeninfo.xres; yRes = screeninfo.yres; bpp = screeninfo.bits_per_pixel; fb_fix_screeninfo _fix; if (ioctl(fd, FBIOGET_FSCREENINFO, &_fix)<0) { perror("FBIOGET_FSCREENINFO"); return -1; } stride = _fix.line_length; printf("FB: %dx%dx%d line length %d. %s accelerator.\n", xRes, yRes, bpp, stride, #if defined(USE_NEVIS_GXA) "Using nevis GXA" #elif defined(FB_HW_ACCELERATION) "Using fb hw graphics" #else "Not using graphics" #endif ); //memset(getFrameBufferPointer(), 0, stride * yRes); paintBackground(); if (ioctl(fd, FBIOBLANK, FB_BLANK_UNBLANK) < 0) { printf("screen unblanking failed\n"); } return 0; } #if 0 //never used void CFrameBuffer::setTransparency( int /*tr*/ ) { } #endif void CFrameBuffer::setBlendMode(uint8_t mode) { #ifdef HAVE_COOL_HARDWARE if (ioctl(fd, FBIO_SETBLENDMODE, mode)) printf("FBIO_SETBLENDMODE failed.\n"); #endif } void CFrameBuffer::setBlendLevel(int level) { #ifdef HAVE_COOL_HARDWARE //printf("CFrameBuffer::setBlendLevel %d\n", level); unsigned char value = 0xFF; if((level >= 0) && (level <= 100)) value = convertSetupAlpha2Alpha(level); if (ioctl(fd, FBIO_SETOPACITY, value)) printf("FBIO_SETOPACITY failed.\n"); #ifndef BOXMODEL_APOLLO if(level == 100) // TODO: sucks. usleep(20000); #endif #endif } #if 0 //never used void CFrameBuffer::setAlphaFade(int in, int num, int tr) { for (int i=0; i>16)*level; *g= ((rgb2&0x00FF00)>>8 )*level; *b= ((rgb2&0x0000FF) )*level; *r+=((rgb1&0xFF0000)>>16)*(255-level); *g+=((rgb1&0x00FF00)>>8 )*(255-level); *b+=((rgb1&0x0000FF) )*(255-level); } void CFrameBuffer::paletteGenFade(int in, __u32 rgb1, __u32 rgb2, int num, int tr) { for (int i=0; i>8; cmap.green[i] =(rgb&0x00FF00) ; cmap.blue[i] =(rgb&0x0000FF)<<8; cmap.transp[i] = tr; } void CFrameBuffer::paletteSet(struct fb_cmap *map) { if (!active) return; if(map == NULL) map = &cmap; if(bpp == 8) { //printf("Set palette for %dbit\n", bpp); ioctl(fd, FBIOPUTCMAP, map); } uint32_t rl, ro, gl, go, bl, bo, tl, to; rl = screeninfo.red.length; ro = screeninfo.red.offset; gl = screeninfo.green.length; go = screeninfo.green.offset; bl = screeninfo.blue.length; bo = screeninfo.blue.offset; tl = screeninfo.transp.length; to = screeninfo.transp.offset; for (int i = 0; i < 256; i++) { realcolor[i] = make16color(cmap.red[i], cmap.green[i], cmap.blue[i], cmap.transp[i], rl, ro, gl, go, bl, bo, tl, to); } OnAfterSetPallette(); } void CFrameBuffer::paintHLineRelInternal2Buf(const int& x, const int& dx, const int& y, const int& box_dx, const fb_pixel_t& col, fb_pixel_t* buf) { uint8_t * pos = ((uint8_t *)buf) + x * sizeof(fb_pixel_t) + box_dx * sizeof(fb_pixel_t) * y; fb_pixel_t * dest = (fb_pixel_t *)pos; for (int i = 0; i < dx; i++) *(dest++) = col; } fb_pixel_t* CFrameBuffer::paintBoxRel2Buf(const int dx, const int dy, const int w_align, const int offs_align, const fb_pixel_t col, fb_pixel_t* buf/* = NULL*/, int radius/* = 0*/, int type/* = CORNER_ALL*/) { if (!getActive()) return buf; if (dx == 0 || dy == 0) { dprintf(DEBUG_INFO, "[CFrameBuffer] [%s - %d]: radius %d, dx %d dy %d\n", __func__, __LINE__, radius, dx, dy); return buf; } fb_pixel_t* pixBuf = buf; if (pixBuf == NULL) { pixBuf = (fb_pixel_t*) cs_malloc_uncached(w_align*dy*sizeof(fb_pixel_t)); if (pixBuf == NULL) { dprintf(DEBUG_NORMAL, "[%s #%d] Error cs_malloc_uncached\n", __func__, __LINE__); return NULL; } } memset((void*)pixBuf, '\0', w_align*dy*sizeof(fb_pixel_t)); if (type && radius) { setCornerFlags(type); radius = limitRadius(dx, dy, radius); int line = 0; while (line < dy) { int ofl, ofr; calcCorners(NULL, &ofl, &ofr, dy, line, radius, type); if (dx-ofr-ofl < 1) { if (dx-ofr-ofl == 0) { dprintf(DEBUG_INFO, "[%s - %d]: radius %d, end x %d y %d\n", __func__, __LINE__, radius, dx-ofr-ofl, line); } else { dprintf(DEBUG_INFO, "[%s - %04d]: Calculated width: %d\n (radius %d, dx %d, offsetLeft %d, offsetRight %d).\n Width can not be less than 0, abort.\n", __func__, __LINE__, dx-ofr-ofl, radius, dx, ofl, ofr); } line++; continue; } paintHLineRelInternal2Buf(ofl+offs_align, dx-ofl-ofr, line, w_align, col, pixBuf); line++; } } else { fb_pixel_t *bp = pixBuf; int line = 0; while (line < dy) { for (int pos = offs_align; pos < dx+offs_align; pos++) *(bp + pos) = col; bp += w_align; line++; } } return pixBuf; } fb_pixel_t* CFrameBuffer::paintBoxRel(const int x, const int y, const int dx, const int dy, const fb_pixel_t /*col*/, gradientData_t *gradientData, int radius, int type) { if (!getActive()) return NULL; checkFbArea(x, y, dx, dy, true); fb_pixel_t MASK = 0xFFFFFFFF; int _dx = dx; int w_align; int offs_align; #ifdef BOXMODEL_APOLLO if (_dx%4 != 0) { w_align = GetWidth4FB_HW_ACC(x, _dx, true); if (w_align < _dx) _dx = w_align; offs_align = w_align - _dx; if ((x - offs_align) < 0) offs_align = 0; } else { w_align = _dx; offs_align = 0; } #else w_align = _dx; offs_align = 0; #endif fb_pixel_t* boxBuf = paintBoxRel2Buf(_dx, dy, w_align, offs_align, MASK, NULL, radius, type); if (boxBuf == NULL) { checkFbArea(x, y, dx, dy, false); return NULL; } fb_pixel_t *bp = boxBuf; fb_pixel_t *gra = gradientData->gradientBuf; gradientData->boxBuf = boxBuf; gradientData->x = x - offs_align; gradientData->dx = w_align; if (gradientData->direction == gradientVertical) { // vertical for (int pos = offs_align; pos < _dx+offs_align; pos++) { for(int count = 0; count < dy; count++) { if (*(bp + pos) == MASK) *(bp + pos) = (fb_pixel_t)(*(gra + count)); bp += w_align; } bp = boxBuf; } } else { // horizontal for (int line = 0; line < dy; line++) { int gra_pos = 0; for (int pos = 0; pos < w_align; pos++) { if ((*(bp + pos) == MASK) && (pos >= offs_align) && (gra_pos < _dx)) { *(bp + pos) = (fb_pixel_t)(*(gra + gra_pos)); gra_pos++; } } bp += w_align; } } if ((gradientData->mode & pbrg_noPaint) == pbrg_noPaint) { checkFbArea(x, y, dx, dy, false); return boxBuf; } blitBox2FB(boxBuf, w_align, dy, x-offs_align, y); if ((gradientData->mode & pbrg_noFree) == pbrg_noFree) { checkFbArea(x, y, dx, dy, false); return boxBuf; } cs_free_uncached(boxBuf); checkFbArea(x, y, dx, dy, false); return NULL; } void CFrameBuffer::paintBoxRel(const int x, const int y, const int dx, const int dy, const fb_pixel_t col, int radius, int type) { /* draw a filled rectangle (with additional round corners) */ if (!getActive()) return; if (dx == 0 || dy == 0) { dprintf(DEBUG_DEBUG, "[CFrameBuffer] [%s - %d]: radius %d, start x %d y %d end x %d y %d\n", __func__, __LINE__, radius, x, y, x+dx, y+dy); return; } if (radius < 0) dprintf(DEBUG_NORMAL, "[CFrameBuffer] [%s - %d]: WARNING! radius < 0 [%d] FIXME\n", __func__, __LINE__, radius); checkFbArea(x, y, dx, dy, true); #if defined(FB_HW_ACCELERATION) fb_fillrect fillrect; fillrect.color = col; fillrect.rop = ROP_COPY; #elif defined(USE_NEVIS_GXA) if (!fb_no_check) OpenThreads::ScopedLock m_lock(mutex); /* solid fill with background color */ unsigned int cmd = GXA_CMD_BLT | GXA_CMD_NOT_TEXT | GXA_SRC_BMP_SEL(7) | GXA_DST_BMP_SEL(2) | GXA_PARAM_COUNT(2) | GXA_CMD_NOT_ALPHA; _write_gxa(gxa_base, GXA_BG_COLOR_REG, (unsigned int) col); /* setup the drawing color */ #endif if (type && radius) { setCornerFlags(type); radius = limitRadius(dx, dy, radius); int line = 0; while (line < dy) { int ofl, ofr; if (calcCorners(NULL, &ofl, &ofr, dy, line, radius, type)) { //printf("3: x %d y %d dx %d dy %d rad %d line %d\n", x, y, dx, dy, radius, line); #if defined(FB_HW_ACCELERATION) || defined(USE_NEVIS_GXA) int rect_height_mult = ((type & CORNER_TOP) && (type & CORNER_BOTTOM)) ? 2 : 1; #if defined(FB_HW_ACCELERATION) fillrect.dx = x; fillrect.dy = y + line; fillrect.width = dx; fillrect.height = dy - (radius * rect_height_mult); ioctl(fd, FBIO_FILL_RECT, &fillrect); #elif defined(USE_NEVIS_GXA) _write_gxa(gxa_base, GXA_BLT_CONTROL_REG, 0); _write_gxa(gxa_base, cmd, GXA_POINT(x, y + line)); /* destination x/y */ _write_gxa(gxa_base, cmd, GXA_POINT(dx, dy - (radius * rect_height_mult))); /* width/height */ #endif line += dy - (radius * rect_height_mult); continue; #endif } if (dx-ofr-ofl < 1) { if (dx-ofr-ofl == 0){ dprintf(DEBUG_INFO, "[CFrameBuffer] [%s - %d]: radius %d, start x %d y %d end x %d y %d\n", __func__, __LINE__, radius, x, y, x+dx-ofr-ofl, y+line); }else{ dprintf(DEBUG_INFO, "[CFrameBuffer] [%s - %04d]: Calculated width: %d\n (radius %d, dx %d, offsetLeft %d, offsetRight %d).\n Width can not be less than 0, abort.\n", __func__, __LINE__, dx-ofr-ofl, radius, dx, ofl, ofr); } line++; continue; } #ifdef USE_NEVIS_GXA _write_gxa(gxa_base, GXA_BLT_CONTROL_REG, 0); _write_gxa(gxa_base, cmd, GXA_POINT(x + ofl, y + line)); /* destination x/y */ _write_gxa(gxa_base, cmd, GXA_POINT(dx-ofl-ofr, 1)); /* width/height */ #else paintHLineRelInternal(x+ofl, dx-ofl-ofr, y+line, col); #endif line++; } } else { #if defined(FB_HW_ACCELERATION) /* FIXME small size faster to do by software */ if (dx > 10 || dy > 10) { fillrect.dx = x; fillrect.dy = y; fillrect.width = dx; fillrect.height = dy; ioctl(fd, FBIO_FILL_RECT, &fillrect); checkFbArea(x, y, dx, dy, false); return; } #endif #if defined(USE_NEVIS_GXA) _write_gxa(gxa_base, GXA_BLT_CONTROL_REG, 0); _write_gxa(gxa_base, cmd, GXA_POINT(x, y)); /* destination x/y */ _write_gxa(gxa_base, cmd, GXA_POINT(dx, dy)); /* width/height */ #else int swidth = stride / sizeof(fb_pixel_t); fb_pixel_t *fbp = getFrameBufferPointer() + (swidth * y); int line = 0; while (line < dy) { for (int pos = x; pos < x + dx; pos++) *(fbp + pos) = col; fbp += swidth; line++; } #endif } #ifdef USE_NEVIS_GXA _write_gxa(gxa_base, GXA_BG_COLOR_REG, (unsigned int) backgroundColor); //FIXME needed ? /* the GXA seems to do asynchronous rendering, so we add a sync marker * to which the fontrenderer code can synchronize */ add_gxa_sync_marker(); #endif checkFbArea(x, y, dx, dy, false); } void CFrameBuffer::paintVLineRelInternal(int x, int y, int dy, const fb_pixel_t col) { #if defined(FB_HW_ACCELERATION) fb_fillrect fillrect; fillrect.dx = x; fillrect.dy = y; fillrect.width = 1; fillrect.height = dy; fillrect.color = col; fillrect.rop = ROP_COPY; ioctl(fd, FBIO_FILL_RECT, &fillrect); #elif defined(USE_NEVIS_GXA) /* draw a single vertical line from point x/y with hight dx */ unsigned int cmd = GXA_CMD_NOT_TEXT | GXA_SRC_BMP_SEL(2) | GXA_DST_BMP_SEL(2) | GXA_PARAM_COUNT(2) | GXA_CMD_NOT_ALPHA; _write_gxa(gxa_base, GXA_FG_COLOR_REG, (unsigned int) col); /* setup the drawing color */ _write_gxa(gxa_base, GXA_LINE_CONTROL_REG, 0x00000404); /* X is major axis, skip last pixel */ _write_gxa(gxa_base, cmd, GXA_POINT(x, y + dy)); /* end point */ _write_gxa(gxa_base, cmd, GXA_POINT(x, y)); /* start point */ #else /* USE_NEVIS_GXA */ uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; for(int count=0;count m_lock(mutex); #endif paintVLineRelInternal(x, y, dy, col); } void CFrameBuffer::paintHLineRelInternal(int x, int dx, int y, const fb_pixel_t col) { #if defined(FB_HW_ACCELERATION) if (dx >= 10) { fb_fillrect fillrect; fillrect.dx = x; fillrect.dy = y; fillrect.width = dx; fillrect.height = 1; fillrect.color = col; fillrect.rop = ROP_COPY; ioctl(fd, FBIO_FILL_RECT, &fillrect); return; } #endif #if defined(USE_NEVIS_GXA) /* draw a single horizontal line from point x/y with width dx */ unsigned int cmd = GXA_CMD_NOT_TEXT | GXA_SRC_BMP_SEL(2) | GXA_DST_BMP_SEL(2) | GXA_PARAM_COUNT(2) | GXA_CMD_NOT_ALPHA; _write_gxa(gxa_base, GXA_FG_COLOR_REG, (unsigned int) col); /* setup the drawing color */ _write_gxa(gxa_base, GXA_LINE_CONTROL_REG, 0x00000404); /* X is major axis, skip last pixel */ _write_gxa(gxa_base, cmd, GXA_POINT(x + dx, y)); /* end point */ _write_gxa(gxa_base, cmd, GXA_POINT(x, y)); /* start point */ #else /* USE_NEVIS_GXA */ uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * dest = (fb_pixel_t *)pos; for (int i = 0; i < dx; i++) *(dest++) = col; #endif /* USE_NEVIS_GXA */ } void CFrameBuffer::paintHLineRel(int x, int dx, int y, const fb_pixel_t col) { if (!getActive()) return; #if defined(USE_NEVIS_GXA) OpenThreads::ScopedLock m_lock(mutex); #endif paintHLineRelInternal(x, dx, y, col); } void CFrameBuffer::setIconBasePath(const std::string & iconPath) { iconBasePath = iconPath; } std::string CFrameBuffer::getIconPath(std::string icon_name, std::string file_type) { std::string path, filetype; filetype = "." + file_type; path = std::string(ICONSDIR_VAR) + "/" + icon_name + filetype; if (access(path.c_str(), F_OK)) path = iconBasePath + "/" + icon_name + filetype; if (icon_name.find("/", 0) != std::string::npos) path = icon_name; return path; } void CFrameBuffer::getIconSize(const char * const filename, int* width, int *height) { *width = 0; *height = 0; if(filename == NULL) return; //check for full path, icon don't have full path, or ? if (filename[0]== '/'){ return; } std::map::iterator it; /* if code ask for size, lets cache it. assume we have enough ram for cache */ /* FIXME offset seems never used in code, always default = 1 ? */ it = icon_cache.find(filename); if(it == icon_cache.end()) { if(paintIcon(filename, 0, 0, 0, 1, false)) { it = icon_cache.find(filename); } } if(it != icon_cache.end()) { *width = it->second.width; *height = it->second.height; } } bool CFrameBuffer::paintIcon8(const std::string & filename, const int x, const int y, const unsigned char offset) { if (!getActive()) return false; //printf("%s(file, %d, %d, %d)\n", __FUNCTION__, x, y, offset); struct rawHeader header; uint16_t width, height; int lfd; lfd = open((iconBasePath + "/" + filename).c_str(), O_RDONLY); if (lfd == -1) { printf("paintIcon8: error while loading icon: %s/%s\n", iconBasePath.c_str(), filename.c_str()); return false; } read(lfd, &header, sizeof(struct rawHeader)); width = (header.width_hi << 8) | header.width_lo; height = (header.height_hi << 8) | header.height_lo; unsigned char pixbuf[768]; uint8_t * d = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * d2; for (int count=0; count::iterator it; if (!getActive()) return false; int yy = y; //printf("CFrameBuffer::paintIcon: load %s\n", filename.c_str());fflush(stdout); /* we cache and check original name */ it = icon_cache.find(filename); if(it == icon_cache.end()) { std::string newname = getIconPath(filename); //printf("CFrameBuffer::paintIcon: check for %s\n", newname.c_str());fflush(stdout); data = g_PicViewer->getIcon(newname, &width, &height); if(data) { //TODO: intercepting of possible full icon cache, that could cause strange behavior while painting of uncached icons int dsize = width*height*sizeof(fb_pixel_t); //printf("CFrameBuffer::paintIcon: %s found, data %x size %d x %d\n", newname.c_str(), data, width, height);fflush(stdout); if(cache_size+dsize < ICON_CACHE_SIZE) { cache_size += dsize; tmpIcon.width = width; tmpIcon.height = height; tmpIcon.data = data; icon_cache.insert(std::pair (filename, tmpIcon)); //printf("Cached %s, cache size %d\n", newname.c_str(), cache_size); } goto _display; } newname = getIconPath(filename, "raw"); int lfd = open(newname.c_str(), O_RDONLY); if (lfd == -1) { //printf("paintIcon: error while loading icon: %s\n", newname.c_str()); return false; } ssize_t s = read(lfd, &header, sizeof(struct rawHeader)); if (s < 0) { perror("read"); return false; } if (s < (ssize_t) sizeof(rawHeader)){ printf("paintIcon: error while loading icon: %s, header too small\n", newname.c_str()); return false; } tmpIcon.width = width = (header.width_hi << 8) | header.width_lo; tmpIcon.height = height = (header.height_hi << 8) | header.height_lo; if (!width || !height) { printf("paintIcon: error while loading icon: %s, wrong dimensions (%dHx%dW)\n", newname.c_str(), height, width); return false; } int dsize = width*height*sizeof(fb_pixel_t); tmpIcon.data = (fb_pixel_t*) cs_malloc_uncached(dsize); data = tmpIcon.data; unsigned char pixbuf[768]; for (int count = 0; count < height; count ++ ) { read(lfd, &pixbuf[0], width >> 1 ); unsigned char *pixpos = &pixbuf[0]; for (int count2 = 0; count2 < width >> 1; count2 ++ ) { unsigned char compressed = *pixpos; unsigned char pix1 = (compressed & 0xf0) >> 4; unsigned char pix2 = (compressed & 0x0f); if (pix1 != header.transp) *data++ = realcolor[pix1+offset]; else *data++ = 0; if (pix2 != header.transp) *data++ = realcolor[pix2+offset]; else *data++ = 0; pixpos++; } } close(lfd); data = tmpIcon.data; if(cache_size+dsize < ICON_CACHE_SIZE) { cache_size += dsize; icon_cache.insert(std::pair (filename, tmpIcon)); //printf("Cached %s, cache size %d\n", newname.c_str(), cache_size); } } else { data = it->second.data; width = it->second.width; height = it->second.height; //printf("paintIcon: already cached %s %d x %d\n", newname.c_str(), width, height); } _display: if(!paint) return true; if (h != 0) yy += (h - height) / 2; checkFbArea(x, yy, width, height, true); if (paintBg) paintBoxRel(x, yy, width, height, colBg); blit2FB(data, width, height, x, yy, 0, 0, true); checkFbArea(x, yy, width, height, false); return true; } void CFrameBuffer::loadPal(const std::string & filename, const unsigned char offset, const unsigned char endidx) { if (!getActive()) return; //printf("%s()\n", __FUNCTION__); struct rgbData rgbdata; int lfd; lfd = open((iconBasePath + "/" + filename).c_str(), O_RDONLY); if (lfd == -1) { printf("error while loading palette: %s/%s\n", iconBasePath.c_str(), filename.c_str()); return; } int pos = 0; int readb = read(lfd, &rgbdata, sizeof(rgbdata) ); while(readb) { __u32 rgb = (rgbdata.r<<16) | (rgbdata.g<<8) | (rgbdata.b); int colpos = offset+pos; if( colpos>endidx) break; paletteSetColor(colpos, rgb, 0xFF); readb = read(lfd, &rgbdata, sizeof(rgbdata) ); pos++; } paletteSet(&cmap); close(lfd); } void CFrameBuffer::paintPixel(const int x, const int y, const fb_pixel_t col) { if (!getActive()) return; #ifdef USE_NEVIS_GXA paintHLineRel(x, 1, y, col); #else fb_pixel_t * pos = getFrameBufferPointer(); pos += (stride / sizeof(fb_pixel_t)) * y; pos += x; *pos = col; #endif } void CFrameBuffer::paintShortHLineRelInternal(const int& x, const int& dx, const int& y, const fb_pixel_t& col) { uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * dest = (fb_pixel_t *)pos; for (int i = 0; i < dx; i++) *(dest++) = col; } int CFrameBuffer::limitRadius(const int& dx, const int& dy, int& radius) { if (radius > dx) return dx; if (radius > dy) return dy; if (radius > 540) return 540; return radius; } void CFrameBuffer::setCornerFlags(const int& type) { corner_tl = (type & CORNER_TOP_LEFT) == CORNER_TOP_LEFT; corner_tr = (type & CORNER_TOP_RIGHT) == CORNER_TOP_RIGHT; corner_bl = (type & CORNER_BOTTOM_LEFT) == CORNER_BOTTOM_LEFT; corner_br = (type & CORNER_BOTTOM_RIGHT) == CORNER_BOTTOM_RIGHT; } void CFrameBuffer::initQCircle() { /* this table contains the x coordinates for a quarter circle (the bottom right quarter) with fixed radius of 540 px which is the half of the max HD graphics size of 1080 px. So with that table we ca draw boxes with round corners and als circles by just setting dx = dy = radius (max 540). */ static const int _q_circle[541] = { 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 539, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 537, 537, 537, 537, 537, 537, 537, 537, 537, 536, 536, 536, 536, 536, 536, 536, 536, 535, 535, 535, 535, 535, 535, 535, 535, 534, 534, 534, 534, 534, 534, 533, 533, 533, 533, 533, 533, 532, 532, 532, 532, 532, 532, 531, 531, 531, 531, 531, 531, 530, 530, 530, 530, 529, 529, 529, 529, 529, 529, 528, 528, 528, 528, 527, 527, 527, 527, 527, 526, 526, 526, 526, 525, 525, 525, 525, 524, 524, 524, 524, 523, 523, 523, 523, 522, 522, 522, 522, 521, 521, 521, 521, 520, 520, 520, 519, 519, 519, 518, 518, 518, 518, 517, 517, 517, 516, 516, 516, 515, 515, 515, 515, 514, 514, 514, 513, 513, 513, 512, 512, 512, 511, 511, 511, 510, 510, 510, 509, 509, 508, 508, 508, 507, 507, 507, 506, 506, 506, 505, 505, 504, 504, 504, 503, 503, 502, 502, 502, 501, 501, 500, 500, 499, 499, 499, 498, 498, 498, 497, 497, 496, 496, 496, 495, 495, 494, 494, 493, 493, 492, 492, 491, 491, 490, 490, 490, 489, 489, 488, 488, 487, 487, 486, 486, 485, 485, 484, 484, 483, 483, 482, 482, 481, 481, 480, 480, 479, 479, 478, 478, 477, 477, 476, 476, 475, 475, 474, 473, 473, 472, 472, 471, 471, 470, 470, 469, 468, 468, 467, 466, 466, 465, 465, 464, 464, 463, 462, 462, 461, 460, 460, 459, 459, 458, 458, 457, 456, 455, 455, 454, 454, 453, 452, 452, 451, 450, 450, 449, 449, 448, 447, 446, 446, 445, 445, 444, 443, 442, 441, 441, 440, 440, 439, 438, 437, 436, 436, 435, 435, 434, 433, 432, 431, 431, 430, 429, 428, 427, 427, 426, 425, 425, 424, 423, 422, 421, 421, 420, 419, 418, 417, 416, 416, 415, 414, 413, 412, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 403, 402, 401, 400, 399, 398, 397, 397, 395, 394, 393, 393, 392, 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 369, 368, 367, 367, 365, 364, 363, 362, 361, 360, 358, 357, 356, 355, 354, 353, 352, 351, 350, 348, 347, 346, 345, 343, 342, 341, 340, 339, 337, 336, 335, 334, 332, 331, 329, 328, 327, 326, 324, 323, 322, 321, 319, 317, 316, 315, 314, 312, 310, 309, 308, 307, 305, 303, 302, 301, 299, 297, 296, 294, 293, 291, 289, 288, 287, 285, 283, 281, 280, 278, 277, 275, 273, 271, 270, 268, 267, 265, 263, 261, 259, 258, 256, 254, 252, 250, 248, 246, 244, 242, 240, 238, 236, 234, 232, 230, 228, 225, 223, 221, 219, 217, 215, 212, 210, 207, 204, 202, 200, 197, 195, 192, 190, 187, 184, 181, 179, 176, 173, 170, 167, 164, 160, 157, 154, 150, 147, 144, 140, 136, 132, 128, 124, 120, 115, 111, 105, 101, 95, 89, 83, 77, 69, 61, 52, 40, 23}; if (q_circle == NULL) q_circle = new int[sizeof(_q_circle) / sizeof(int)]; memcpy(q_circle, _q_circle, sizeof(_q_circle)); } bool CFrameBuffer::calcCorners(int *ofs, int *ofl, int *ofr, const int& dy, const int& line, const int& radius, const int& type) { /* just an multiplicator for all math to reduce rounding errors */ #define MUL 32768 int scl, _ofs = 0; bool ret = false; if (ofl != NULL) *ofl = 0; if (ofr != NULL) *ofr = 0; int scf = (540 * MUL) / ((radius < 1) ? 1 : radius); /* one of the top corners */ if (line < radius && (type & CORNER_TOP)) { /* uper round corners */ scl = scf * (radius - line) / MUL; if ((scf * (radius - line) % MUL) >= (MUL / 2)) /* round up */ scl++; _ofs = radius - (q_circle[scl] * MUL / scf); if (ofl != NULL) *ofl = corner_tl ? _ofs : 0; if (ofr != NULL) *ofr = corner_tr ? _ofs : 0; } /* one of the bottom corners */ else if ((line >= dy - radius) && (type & CORNER_BOTTOM)) { /* lower round corners */ scl = scf * (radius - (dy - (line + 1))) / MUL; if ((scf * (radius - (dy - (line + 1))) % MUL) >= (MUL / 2)) /* round up */ scl++; _ofs = radius - (q_circle[scl] * MUL / scf); if (ofl != NULL) *ofl = corner_bl ? _ofs : 0; if (ofr != NULL) *ofr = corner_br ? _ofs : 0; } else ret = true; if (ofs != NULL) *ofs = _ofs; return ret; } void CFrameBuffer::paintBoxFrame(const int x, const int y, const int dx, const int dy, const int px, const fb_pixel_t col, int radius, int type) { if (!getActive()) return; if (dx == 0 || dy == 0) { dprintf(DEBUG_NORMAL, "[CFrameBuffer] [%s - %d]: radius %d, start x %d y %d end x %d y %d\n", __func__, __LINE__, radius, x, y, x+dx, y+dy); return; } if (radius < 0) dprintf(DEBUG_NORMAL, "[CFrameBuffer] [%s - %d]: WARNING! radius < 0 [%d] FIXIT\n", __func__, __LINE__, radius); setCornerFlags(type); int rad_tl = 0, rad_tr = 0, rad_bl = 0, rad_br = 0; if (type && radius) { int x_rad = radius - 1; if (corner_tl) rad_tl = x_rad; if (corner_tr) rad_tr = x_rad; if (corner_bl) rad_bl = x_rad; if (corner_br) rad_br = x_rad; } paintBoxRel(x + rad_tl , y , dx - rad_tl - rad_tr, px , col); // top horizontal paintBoxRel(x + rad_bl , y + dy - px, dx - rad_bl - rad_br, px , col); // bottom horizontal paintBoxRel(x , y + rad_tl , px , dy - rad_tl - rad_bl, col); // left vertical paintBoxRel(x + dx - px, y + rad_tr , px , dy - rad_tr - rad_br, col); // right vertical if (type && radius) { radius = limitRadius(dx, dy, radius); int line = 0; waitForIdle("CFrameBuffer::paintBoxFrame"); while (line < dy) { int ofs = 0, ofs_i = 0; // inner box if ((line >= px) && (line < (dy - px))) ofs_i = calcCornersOffset(dy - 2*px, line-px, radius-px, type); // outer box ofs = calcCornersOffset(dy, line, radius, type); int _x = x + ofs; int _x_end = x + dx; int _y = y + line; if ((line < px) || (line >= (dy - px))) { // left if (((corner_tl) && (line < radius)) || ((corner_bl) && (line >= dy - radius))) paintShortHLineRelInternal(_x, radius - ofs, _y, col); // right if (((corner_tr) && (line < radius)) || ((corner_br) && (line >= dy - radius))) paintShortHLineRelInternal(_x_end - radius, radius - ofs, _y, col); } else if (line < (dy - px)) { int _dx = (ofs_i-ofs) + px; // left if (((corner_tl) && (line < radius)) || ((corner_bl) && (line >= dy - radius))) paintShortHLineRelInternal(_x, _dx, _y, col); // right if (((corner_tr) && (line < radius)) || ((corner_br) && (line >= dy - radius))) paintShortHLineRelInternal(_x_end - ofs_i - px, _dx, _y, col); } if ((line == radius) && (dy > 2*radius)) // line outside the rounded corners line = dy - radius; else line++; } } } void CFrameBuffer::paintLine(int xa, int ya, int xb, int yb, const fb_pixel_t col) { if (!getActive()) return; //printf("%s(%d, %d, %d, %d, %.8X)\n", __FUNCTION__, xa, ya, xb, yb, col); int dx = abs (xa - xb); int dy = abs (ya - yb); int x; int y; int End; int step; if ( dx > dy ) { int p = 2 * dy - dx; int twoDy = 2 * dy; int twoDyDx = 2 * (dy-dx); if ( xa > xb ) { x = xb; y = yb; End = xa; step = ya < yb ? -1 : 1; } else { x = xa; y = ya; End = xb; step = yb < ya ? -1 : 1; } paintPixel (x, y, col); while( x < End ) { x++; if ( p < 0 ) p += twoDy; else { y += step; p += twoDyDx; } paintPixel (x, y, col); } } else { int p = 2 * dx - dy; int twoDx = 2 * dx; int twoDxDy = 2 * (dx-dy); if ( ya > yb ) { x = xb; y = yb; End = ya; step = xa < xb ? -1 : 1; } else { x = xa; y = ya; End = yb; step = xb < xa ? -1 : 1; } paintPixel (x, y, col); while( y < End ) { y++; if ( p < 0 ) p += twoDx; else { x += step; p += twoDxDy; } paintPixel (x, y, col); } } } #if 0 //never used void CFrameBuffer::setBackgroundColor(const fb_pixel_t color) { backgroundColor = color; } bool CFrameBuffer::loadPictureToMem(const std::string & filename, const uint16_t width, const uint16_t height, const uint16_t pstride, fb_pixel_t * memp) { struct rawHeader header; int lfd; //printf("%s(%d, %d, memp)\n", __FUNCTION__, width, height); lfd = open((iconBasePath + "/" + filename).c_str(), O_RDONLY ); if (lfd == -1) { printf("error while loading icon: %s/%s\n", iconBasePath.c_str(), filename.c_str()); return false; } read(lfd, &header, sizeof(struct rawHeader)); if ((width != ((header.width_hi << 8) | header.width_lo)) || (height != ((header.height_hi << 8) | header.height_lo))) { printf("error while loading icon: %s - invalid resolution = %hux%hu\n", filename.c_str(), width, height); close(lfd); return false; } if ((pstride == 0) || (pstride == width * sizeof(fb_pixel_t))) read(lfd, memp, height * width * sizeof(fb_pixel_t)); else for (int i = 0; i < height; i++) read(lfd, ((uint8_t *)memp) + i * pstride, width * sizeof(fb_pixel_t)); close(lfd); return true; } bool CFrameBuffer::loadPicture2Mem(const std::string & filename, fb_pixel_t * memp) { return loadPictureToMem(filename, BACKGROUNDIMAGEWIDTH, 576, 0, memp); } bool CFrameBuffer::loadPicture2FrameBuffer(const std::string & filename) { if (!getActive()) return false; return loadPictureToMem(filename, BACKGROUNDIMAGEWIDTH, 576, getStride(), getFrameBufferPointer()); } bool CFrameBuffer::savePictureFromMem(const std::string & filename, const fb_pixel_t * const memp) { struct rawHeader header; uint16_t width, height; int lfd; width = BACKGROUNDIMAGEWIDTH; height = 576; header.width_lo = width & 0xFF; header.width_hi = width >> 8; header.height_lo = height & 0xFF; header.height_hi = height >> 8; header.transp = 0; lfd = open((iconBasePath + "/" + filename).c_str(), O_WRONLY | O_CREAT, 0644); if (lfd==-1) { printf("error while saving icon: %s/%s", iconBasePath.c_str(), filename.c_str() ); return false; } write(lfd, &header, sizeof(struct rawHeader)); write(lfd, memp, width * height * sizeof(fb_pixel_t)); close(lfd); return true; } bool CFrameBuffer::loadBackground(const std::string & filename, const unsigned char offset) { if ((backgroundFilename == filename) && (background)) return true; if (background) delete[] background; background = new fb_pixel_t[BACKGROUNDIMAGEWIDTH * 576]; if (!loadPictureToMem(filename, BACKGROUNDIMAGEWIDTH, 576, 0, background)) { delete[] background; background=0; return false; } if (offset != 0)//pic-offset { fb_pixel_t * bpos = background; int pos = BACKGROUNDIMAGEWIDTH * 576; while (pos > 0) { *bpos += offset; bpos++; pos--; } } fb_pixel_t * dest = background + BACKGROUNDIMAGEWIDTH * 576; uint8_t * src = ((uint8_t * )background)+ BACKGROUNDIMAGEWIDTH * 576; for (int i = 576 - 1; i >= 0; i--) for (int j = BACKGROUNDIMAGEWIDTH - 1; j >= 0; j--) { dest--; src--; paintPixel(dest, *src); } backgroundFilename = filename; return true; } bool CFrameBuffer::loadBackgroundPic(const std::string & filename, bool show) { if ((backgroundFilename == filename) && (background)) return true; //printf("loadBackgroundPic: %s\n", filename.c_str()); if (background){ delete[] background; background = NULL; } background = g_PicViewer->getImage(iconBasePath + "/" + filename, BACKGROUNDIMAGEWIDTH, 576); if (background == NULL) { background=0; return false; } backgroundFilename = filename; if(show) { useBackgroundPaint = true; paintBackground(); } return true; } #endif void CFrameBuffer::useBackground(bool ub) { useBackgroundPaint = ub; if(!useBackgroundPaint) { delete[] background; background=0; } } bool CFrameBuffer::getuseBackground(void) { return useBackgroundPaint; } void CFrameBuffer::saveBackgroundImage(void) { if (backupBackground != NULL){ delete[] backupBackground; backupBackground = NULL; } backupBackground = background; //useBackground(false); // <- necessary since no background is available useBackgroundPaint = false; background = NULL; } void CFrameBuffer::restoreBackgroundImage(void) { fb_pixel_t * tmp = background; if (backupBackground != NULL) { background = backupBackground; backupBackground = NULL; } else useBackground(false); // <- necessary since no background is available if (tmp != NULL){ delete[] tmp; tmp = NULL; } } void CFrameBuffer::paintBackgroundBoxRel(int x, int y, int dx, int dy) { if (!getActive()) return; checkFbArea(x, y, dx, dy, true); if(!useBackgroundPaint) { paintBoxRel(x, y, dx, dy, backgroundColor); } else { uint8_t * fbpos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * bkpos = background + x + BACKGROUNDIMAGEWIDTH * y; for(int count = 0;count < dy; count++) { memmove(fbpos, bkpos, dx * sizeof(fb_pixel_t)); fbpos += stride; bkpos += BACKGROUNDIMAGEWIDTH; } } checkFbArea(x, y, dx, dy, false); } void CFrameBuffer::paintBackground() { if (!getActive()) return; checkFbArea(0, 0, xRes, yRes, true); if (useBackgroundPaint && (background != NULL)) { for (int i = 0; i < 576; i++) memmove(((uint8_t *)getFrameBufferPointer()) + i * stride, (background + i * BACKGROUNDIMAGEWIDTH), BACKGROUNDIMAGEWIDTH * sizeof(fb_pixel_t)); } else { paintBoxRel(0, 0, xRes, yRes, backgroundColor); } checkFbArea(0, 0, xRes, yRes, false); } void CFrameBuffer::SaveScreen(int x, int y, int dx, int dy, fb_pixel_t * const memp) { if (!getActive()) return; checkFbArea(x, y, dx, dy, true); uint8_t * pos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * bkpos = memp; for (int count = 0; count < dy; count++) { fb_pixel_t * dest = (fb_pixel_t *)pos; for (int i = 0; i < dx; i++) //*(dest++) = col; *(bkpos++) = *(dest++); pos += stride; } #if 0 //FIXME test to flush cache if (ioctl(fd, 1, FB_BLANK_UNBLANK) < 0); #endif //RestoreScreen(x, y, dx, dy, memp); //FIXME #if 0 uint8_t * fbpos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * bkpos = memp; for (int count = 0; count < dy; count++) { memmove(bkpos, fbpos, dx * sizeof(fb_pixel_t)); fbpos += stride; bkpos += dx; } #endif checkFbArea(x, y, dx, dy, false); } void CFrameBuffer::RestoreScreen(int x, int y, int dx, int dy, fb_pixel_t * const memp) { if (!getActive()) return; checkFbArea(x, y, dx, dy, true); uint8_t * fbpos = ((uint8_t *)getFrameBufferPointer()) + x * sizeof(fb_pixel_t) + stride * y; fb_pixel_t * bkpos = memp; for (int count = 0; count < dy; count++) { memmove(fbpos, bkpos, dx * sizeof(fb_pixel_t)); fbpos += stride; bkpos += dx; } checkFbArea(x, y, dx, dy, false); } #if 0 //never used void CFrameBuffer::switch_signal (int signal) { CFrameBuffer * thiz = CFrameBuffer::getInstance(); if (signal == SIGUSR1) { if (virtual_fb != NULL) delete[] virtual_fb; virtual_fb = new uint8_t[thiz->stride * thiz->yRes]; thiz->active = false; if (virtual_fb != NULL) memmove(virtual_fb, thiz->lfb, thiz->stride * thiz->yRes); ioctl(thiz->tty, VT_RELDISP, 1); printf ("release display\n"); } else if (signal == SIGUSR2) { ioctl(thiz->tty, VT_RELDISP, VT_ACKACQ); thiz->active = true; printf ("acquire display\n"); thiz->paletteSet(NULL); if (virtual_fb != NULL) memmove(thiz->lfb, virtual_fb, thiz->stride * thiz->yRes); else memset(thiz->lfb, 0, thiz->stride * thiz->yRes); } } #endif void CFrameBuffer::Clear() { paintBackground(); //memset(getFrameBufferPointer(), 0, stride * yRes); } void CFrameBuffer::showFrame(const std::string & filename) { std::string picture = std::string(ICONSDIR_VAR) + "/" + filename; if (access(picture.c_str(), F_OK)) picture = iconBasePath + "/" + filename; if (filename.find("/", 0) != std::string::npos) picture = filename; videoDecoder->ShowPicture(picture.c_str()); } void CFrameBuffer::stopFrame() { videoDecoder->StopPicture(); } bool CFrameBuffer::Lock() { if(locked) return false; locked = true; return true; } void CFrameBuffer::Unlock() { locked = false; } void * CFrameBuffer::int_convertRGB2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y, int transp, bool alpha) { unsigned long i; unsigned int *fbbuff; unsigned long count; if (!x || !y) { printf("convertRGB2FB%s: Error: invalid dimensions (%luX x %luY)\n", ((alpha) ? " (Alpha)" : ""), x, y); return NULL; } count = x * y; fbbuff = (unsigned int *) cs_malloc_uncached(count * sizeof(unsigned int)); if(fbbuff == NULL) { printf("convertRGB2FB%s: Error: cs_malloc_uncached\n", ((alpha) ? " (Alpha)" : "")); return NULL; } if (alpha) { for(i = 0; i < count ; i++) fbbuff[i] = ((rgbbuff[i*4+3] << 24) & 0xFF000000) | ((rgbbuff[i*4] << 16) & 0x00FF0000) | ((rgbbuff[i*4+1] << 8) & 0x0000FF00) | ((rgbbuff[i*4+2]) & 0x000000FF); } else { switch (m_transparent) { case CFrameBuffer::TM_BLACK: for(i = 0; i < count ; i++) { transp = 0; if(rgbbuff[i*3] || rgbbuff[i*3+1] || rgbbuff[i*3+2]) transp = 0xFF; fbbuff[i] = (transp << 24) | ((rgbbuff[i*3] << 16) & 0xFF0000) | ((rgbbuff[i*3+1] << 8) & 0xFF00) | (rgbbuff[i*3+2] & 0xFF); } break; case CFrameBuffer::TM_INI: for(i = 0; i < count ; i++) fbbuff[i] = (transp << 24) | ((rgbbuff[i*3] << 16) & 0xFF0000) | ((rgbbuff[i*3+1] << 8) & 0xFF00) | (rgbbuff[i*3+2] & 0xFF); break; case CFrameBuffer::TM_NONE: default: for(i = 0; i < count ; i++) fbbuff[i] = 0xFF000000 | ((rgbbuff[i*3] << 16) & 0xFF0000) | ((rgbbuff[i*3+1] << 8) & 0xFF00) | (rgbbuff[i*3+2] & 0xFF); break; } } return (void *) fbbuff; } void * CFrameBuffer::convertRGB2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y, int transp) { return int_convertRGB2FB(rgbbuff, x, y, transp, false); } void * CFrameBuffer::convertRGBA2FB(unsigned char *rgbbuff, unsigned long x, unsigned long y) { return int_convertRGB2FB(rgbbuff, x, y, 0, true); } //NI void CFrameBuffer::blit2FB_unscaled(void *fbbuff, uint32_t width, uint32_t height, uint32_t xoff, uint32_t yoff, uint32_t unscaled_w, uint32_t unscaled_h, uint32_t xp, uint32_t yp, bool transp) { return blit2FB(fbbuff, width, height, xoff, yoff, xp, yp, transp, unscaled_w, unscaled_h); } //NI void CFrameBuffer::blit2FB(void *fbbuff, uint32_t width, uint32_t height, uint32_t xoff, uint32_t yoff, uint32_t xp, uint32_t yp, bool /*transp*/, uint32_t unscaled_w, uint32_t unscaled_h) { int xc, yc; xc = (width > xRes) ? xRes : width; yc = (height > yRes) ? yRes : height; //NI if(unscaled_w != 0 && (int)unscaled_w < xc) xc = unscaled_w; if(unscaled_h != 0 && (int)unscaled_h < yc) yc = unscaled_h; #if defined(FB_HW_ACCELERATION) if(!(width%4)) { fb_image image; image.dx = xoff; image.dy = yoff; image.width = xc; image.height = yc; image.cmap.len = 0; image.depth = 32; if(unscaled_w == 0 && unscaled_h == 0) { //NI #if 1 image.data = (const char*)fbbuff; ioctl(fd, FBIO_IMAGE_BLT, &image); } else { //NI #else for (int count = 0; count < yc; count++ ) { fb_pixel_t* data = (fb_pixel_t *) fbbuff; fb_pixel_t *pixpos = &data[(count + yp) * width]; image.data = (const char*) pixpos; //fbbuff +(count + yp)*width; image.dy = yoff+count; image.height = 1; ioctl(fd, FBIO_IMAGE_BLT, &image); } } //NI #endif //printf("\033[34m>>>>\033[0m [%s:%s:%d] FB_HW_ACCELERATION (image) x: %d, y: %d, w: %d, h: %d\n", __file__, __func__, __LINE__, xoff, yoff, xc, yc); return; } #elif defined(USE_NEVIS_GXA) u32 cmd; void * uKva; uKva = cs_phys_addr(fbbuff); //printf("CFrameBuffer::blit2FB: data %x Kva %x\n", (int) fbbuff, (int) uKva); if(uKva != NULL) { OpenThreads::ScopedLock m_lock(mutex); cmd = GXA_CMD_BLT | GXA_CMD_NOT_TEXT | GXA_SRC_BMP_SEL(1) | GXA_DST_BMP_SEL(2) | GXA_PARAM_COUNT(3); _write_gxa(gxa_base, GXA_BMP1_TYPE_REG, (3 << 16) | width); _write_gxa(gxa_base, GXA_BMP1_ADDR_REG, (unsigned int) uKva); _write_gxa(gxa_base, cmd, GXA_POINT(xoff, yoff)); /* destination pos */ _write_gxa(gxa_base, cmd, GXA_POINT(xc, yc)); /* source width, FIXME real or adjusted xc, yc ? */ _write_gxa(gxa_base, cmd, GXA_POINT(xp, yp)); /* source pos */ return; } #endif fb_pixel_t* data = (fb_pixel_t *) fbbuff; uint8_t * d = ((uint8_t *)getFrameBufferPointer()) + xoff * sizeof(fb_pixel_t) + stride * yoff; fb_pixel_t * d2; for (int count = 0; count < yc; count++ ) { fb_pixel_t *pixpos = &data[(count + yp) * width]; d2 = (fb_pixel_t *) d; for (int count2 = 0; count2 < xc; count2++ ) { fb_pixel_t pix = *(pixpos + xp); if ((pix & 0xff000000) == 0xff000000) *d2 = pix; else { uint8_t *in = (uint8_t *)(pixpos + xp); uint8_t *out = (uint8_t *)d2; int a = in[3]; /* TODO: big/little endian */ *out = (*out + ((*in - *out) * a) / 256); in++; out++; *out = (*out + ((*in - *out) * a) / 256); in++; out++; *out = (*out + ((*in - *out) * a) / 256); } d2++; pixpos++; } d += stride; } } void CFrameBuffer::blitBox2FB(const fb_pixel_t* boxBuf, uint32_t width, uint32_t height, uint32_t xoff, uint32_t yoff) { uint32_t xc = (width > xRes) ? (uint32_t)xRes : width; uint32_t yc = (height > yRes) ? (uint32_t)yRes : height; #if defined(FB_HW_ACCELERATION) if (!(width%4)) { fb_image image; image.dx = xoff; image.dy = yoff; image.width = xc; image.height = yc; image.cmap.len = 0; image.depth = 32; image.data = (const char*)boxBuf; ioctl(fd, FBIO_IMAGE_BLT, &image); //printf("\033[33m>>>>\033[0m [%s:%s:%d] FB_HW_ACCELERATION x: %d, y: %d, w: %d, h: %d\n", __file__, __func__, __LINE__, xoff, yoff, xc, yc); return; } printf("\033[31m>>>>\033[0m [%s:%s:%d] Not use FB_HW_ACCELERATION x: %d, y: %d, w: %d, h: %d\n", __file__, __func__, __LINE__, xoff, yoff, xc, yc); #elif defined(USE_NEVIS_GXA) void* uKva = cs_phys_addr((void*)boxBuf); if(uKva != NULL) { OpenThreads::ScopedLock m_lock(mutex); u32 cmd = GXA_CMD_BLT | GXA_CMD_NOT_TEXT | GXA_SRC_BMP_SEL(1) | GXA_DST_BMP_SEL(2) | GXA_PARAM_COUNT(3); _write_gxa(gxa_base, GXA_BMP1_TYPE_REG, (3 << 16) | width); _write_gxa(gxa_base, GXA_BMP1_ADDR_REG, (unsigned int) uKva); _write_gxa(gxa_base, cmd, GXA_POINT(xoff, yoff)); _write_gxa(gxa_base, cmd, GXA_POINT(xc, yc)); _write_gxa(gxa_base, cmd, GXA_POINT(0, 0)); //printf("\033[33m>>>>\033[0m [%s:%s:%d] USE_NEVIS_GXA x: %d, y: %d, w: %d, h: %d\n", __file__, __func__, __LINE__, xoff, yoff, xc, yc); add_gxa_sync_marker(); return; } printf("\033[31m>>>>\033[0m [%s:%s:%d] Not use USE_NEVIS_GXA x: %d, y: %d, w: %d, h: %d\n", __file__, __func__, __LINE__, xoff, yoff, xc, yc); #endif uint32_t swidth = stride / sizeof(fb_pixel_t); fb_pixel_t *fbp = getFrameBufferPointer() + (swidth * yoff); fb_pixel_t* data = (fb_pixel_t*)boxBuf; uint32_t line = 0; while (line < yc) { fb_pixel_t *pixpos = &data[line * xc]; for (uint32_t pos = xoff; pos < xoff + xc; pos++) { //don't paint backgroundcolor (*pixpos = 0x00000000) if (*pixpos) *(fbp + pos) = *pixpos; pixpos++; } fbp += swidth; line++; } } void CFrameBuffer::displayRGB(unsigned char *rgbbuff, int x_size, int y_size, int x_pan, int y_pan, int x_offs, int y_offs, bool clearfb, int transp) { void *fbbuff = NULL; if(rgbbuff == NULL) return; /* correct panning */ if(x_pan > x_size - (int)xRes) x_pan = 0; if(y_pan > y_size - (int)yRes) y_pan = 0; /* correct offset */ if(x_offs + x_size > (int)xRes) x_offs = 0; if(y_offs + y_size > (int)yRes) y_offs = 0; /* blit buffer 2 fb */ fbbuff = convertRGB2FB(rgbbuff, x_size, y_size, transp); if(fbbuff==NULL) return; /* ClearFB if image is smaller */ /* if(x_size < (int)xRes || y_size < (int)yRes) */ if(clearfb) CFrameBuffer::getInstance()->Clear(); blit2FB(fbbuff, x_size, y_size, x_offs, y_offs, x_pan, y_pan); cs_free_uncached(fbbuff); } // ## AudioMute / Clock ###################################### void CFrameBuffer::setFbArea(int element, int _x, int _y, int _dx, int _dy) { if (_x == 0 && _y == 0 && _dx == 0 && _dy == 0) { // delete area for (fbarea_iterator_t it = v_fbarea.begin(); it != v_fbarea.end(); ++it) { if (it->element == element) { v_fbarea.erase(it); break; } } if (v_fbarea.empty()) { fbAreaActiv = false; } } else { // change area bool found = false; for (unsigned int i = 0; i < v_fbarea.size(); i++) { if (v_fbarea[i].element == element) { v_fbarea[i].x = _x; v_fbarea[i].y = _y; v_fbarea[i].dx = _dx; v_fbarea[i].dy = _dy; found = true; break; } } // set new area if (!found) { fb_area_t area; area.x = _x; area.y = _y; area.dx = _dx; area.dy = _dy; area.element = element; v_fbarea.push_back(area); } fbAreaActiv = true; } } int CFrameBuffer::checkFbAreaElement(int _x, int _y, int _dx, int _dy, fb_area_t *area) { if (fb_no_check) return FB_PAINTAREA_MATCH_NO; if (_y > area->y + area->dy) return FB_PAINTAREA_MATCH_NO; if (_x + _dx < area->x) return FB_PAINTAREA_MATCH_NO; if (_x > area->x + area->dx) return FB_PAINTAREA_MATCH_NO; if (_y + _dy < area->y) return FB_PAINTAREA_MATCH_NO; return FB_PAINTAREA_MATCH_OK; } bool CFrameBuffer::_checkFbArea(int _x, int _y, int _dx, int _dy, bool prev) { if (v_fbarea.empty()) return true; static bool firstMutePaint = true; for (unsigned int i = 0; i < v_fbarea.size(); i++) { int ret = checkFbAreaElement(_x, _y, _dx, _dy, &v_fbarea[i]); if (ret == FB_PAINTAREA_MATCH_OK) { switch (v_fbarea[i].element) { case FB_PAINTAREA_MUTEICON1: if (!do_paint_mute_icon) break; // waitForIdle(); fb_no_check = true; if (prev) { firstMutePaint = false; CAudioMute::getInstance()->hide(); } else { if (!firstMutePaint) CAudioMute::getInstance()->paint(); } fb_no_check = false; break; default: break; } } } return true; }