From f0922c9bafce6a565af020851012dd3cbb609888 Mon Sep 17 00:00:00 2001 From: Girish Ramakrishnan Date: Fri, 6 Jul 2012 05:40:57 +0530 Subject: linuxfb: Rework screen code Move the screen code from integration. The design philosophy is that QFbScreen takes care of generic framebuffer composition. QLinuxFbScreen is just an linux framebuffer adaptation layer. Change-Id: I8456c13826f06621037dd77fe0d0bd8873806c96 Reviewed-by: Thomas Senyk Reviewed-by: Girish Ramakrishnan --- src/plugins/platforms/linuxfb/main.cpp | 2 +- .../platforms/linuxfb/qlinuxfbintegration.cpp | 751 +-------------------- .../platforms/linuxfb/qlinuxfbintegration.h | 54 +- src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp | 400 +++++++++-- src/plugins/platforms/linuxfb/qlinuxfbscreen.h | 24 +- 5 files changed, 402 insertions(+), 829 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/linuxfb/main.cpp b/src/plugins/platforms/linuxfb/main.cpp index e0348abac4..12b68a6f2b 100644 --- a/src/plugins/platforms/linuxfb/main.cpp +++ b/src/plugins/platforms/linuxfb/main.cpp @@ -56,7 +56,7 @@ QPlatformIntegration* QLinuxFbIntegrationPlugin::create(const QString& system, c { Q_UNUSED(paramList); if (system.toLower() == "linuxfb") - return new QLinuxFbIntegration; + return new QLinuxFbIntegration(paramList); return 0; } diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index cdec49b55f..057839a96d 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -48,744 +48,25 @@ #include #include +#include #include -#include // overrides QT_OPEN -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if !defined(Q_OS_DARWIN) && !defined(Q_OS_FREEBSD) -#include - -#ifdef __i386__ -#include -#endif -#endif QT_BEGIN_NAMESPACE -class QLinuxFbIntegrationPrivate -{ -public: - QLinuxFbIntegrationPrivate(); - ~QLinuxFbIntegrationPrivate(); - - void openTty(); - void closeTty(); - - int fd; - int startupw; - int startuph; - int startupd; - bool blank; - - bool doGraphicsMode; -#ifdef QT_QWS_DEPTH_GENERIC - bool doGenericColors; -#endif - int ttyfd; - long oldKdMode; - QString ttyDevice; - QString displaySpec; -}; - -QLinuxFbIntegrationPrivate::QLinuxFbIntegrationPrivate() - : fd(-1), blank(true), doGraphicsMode(true), -#ifdef QT_QWS_DEPTH_GENERIC - doGenericColors(false), -#endif - ttyfd(-1), oldKdMode(KD_TEXT) -{ -} - -QLinuxFbIntegrationPrivate::~QLinuxFbIntegrationPrivate() -{ - closeTty(); -} - -void QLinuxFbIntegrationPrivate::openTty() -{ - const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0}; - - if (ttyDevice.isEmpty()) { - for (const char * const *dev = devs; *dev; ++dev) { - ttyfd = QT_OPEN(*dev, O_RDWR); - if (ttyfd != -1) - break; - } - } else { - ttyfd = QT_OPEN(ttyDevice.toLatin1().constData(), O_RDWR); - } - - if (ttyfd == -1) - return; - - if (doGraphicsMode) { - ioctl(ttyfd, KDGETMODE, &oldKdMode); - if (oldKdMode != KD_GRAPHICS) { - int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS); - if (ret == -1) - doGraphicsMode = false; - } - } - - // No blankin' screen, no blinkin' cursor!, no cursor! - const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c"; - QT_WRITE(ttyfd, termctl, sizeof(termctl)); -} - -void QLinuxFbIntegrationPrivate::closeTty() +QLinuxFbIntegration::QLinuxFbIntegration(const QStringList ¶mList) + : m_fontDb(new QGenericUnixFontDatabase()), + m_eventDispatcher(createUnixEventDispatcher()) { - if (ttyfd == -1) - return; - - if (doGraphicsMode) - ioctl(ttyfd, KDSETMODE, oldKdMode); - - // Blankin' screen, blinkin' cursor! - const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c"; - QT_WRITE(ttyfd, termctl, sizeof(termctl)); - - QT_CLOSE(ttyfd); - ttyfd = -1; -} - -QLinuxFbIntegration::QLinuxFbIntegration() - :fontDb(new QGenericUnixFontDatabase()) -{ - d_ptr = new QLinuxFbIntegrationPrivate(); - - // XXX - QString displaySpec = QString::fromLatin1(qgetenv("QWS_DISPLAY")); + QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); - if (!connect(displaySpec)) - qFatal("QLinuxFbIntegration: could not initialize screen"); - initDevice(); - - // Create a QImage directly on the screen's framebuffer. - // This is the blit target for copying windows to the screen. - mPrimaryScreen = new QLinuxFbScreen(data, w, h, lstep, - screenFormat); - mPrimaryScreen->setPhysicalSize(QSize(physWidth, physHeight)); - mScreens.append(mPrimaryScreen); + m_primaryScreen = new QLinuxFbScreen; + if (m_primaryScreen->initialize(paramList)) + screenAdded(m_primaryScreen); } QLinuxFbIntegration::~QLinuxFbIntegration() { - delete mPrimaryScreen; - delete d_ptr; -} - -bool QLinuxFbIntegration::connect(const QString &displaySpec) -{ - const QStringList args = displaySpec.split(QLatin1Char(':')); - - if (args.contains(QLatin1String("nographicsmodeswitch"))) - d_ptr->doGraphicsMode = false; - -#ifdef QT_QWS_DEPTH_GENERIC - if (args.contains(QLatin1String("genericcolors"))) - d_ptr->doGenericColors = true; -#endif - - QRegExp ttyRegExp(QLatin1String("tty=(.*)")); - if (args.indexOf(ttyRegExp) != -1) - d_ptr->ttyDevice = ttyRegExp.cap(1); - -#if 0 -#if Q_BYTE_ORDER == Q_BIG_ENDIAN -#ifndef QT_QWS_FRAMEBUFFER_LITTLE_ENDIAN - if (args.contains(QLatin1String("littleendian"))) -#endif - QScreen::setFrameBufferLittleEndian(true); -#endif -#endif - - // Check for explicitly specified device - const int len = 8; // "/dev/fbx" - int m = displaySpec.indexOf(QLatin1String("/dev/fb")); - - QString dev; - if (m > 0) - dev = displaySpec.mid(m, len); - else - dev = QLatin1String("/dev/fb0"); - - if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0) - d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR); - if (d_ptr->fd == -1) { - if (access(dev.toLatin1().constData(), R_OK) == 0) - d_ptr->fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY); - if (d_ptr->fd == 1) { - qWarning("Error opening framebuffer device %s", qPrintable(dev)); - return false; - } - } - - fb_fix_screeninfo finfo; - fb_var_screeninfo vinfo; - //####################### - // Shut up Valgrind - memset(&vinfo, 0, sizeof(vinfo)); - memset(&finfo, 0, sizeof(finfo)); - //####################### - - /* Get fixed screen information */ - if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) { - perror("QLinuxFbIntegration::connect"); - qWarning("Error reading fixed information"); - return false; - } - - if (finfo.type == FB_TYPE_VGA_PLANES) { - qWarning("VGA16 video mode not supported"); - return false; - } - - /* Get variable screen information */ - if (d_ptr->fd != -1 && ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) { - perror("QLinuxFbIntegration::connect"); - qWarning("Error reading variable information"); - return false; - } - - grayscale = vinfo.grayscale; - d = vinfo.bits_per_pixel; - if (d == 24) { - d = vinfo.red.length + vinfo.green.length + vinfo.blue.length; - if (d <= 0) - d = 24; // reset if color component lengths are not reported - } else if (d == 16) { - d = vinfo.red.length + vinfo.green.length + vinfo.blue.length; - if (d <= 0) - d = 16; - } - lstep = finfo.line_length; - - int xoff = vinfo.xoffset; - int yoff = vinfo.yoffset; - const char* qwssize; - if((qwssize=::getenv("QWS_SIZE")) && sscanf(qwssize,"%dx%d",&w,&h)==2) { - if (d_ptr->fd != -1) { - if ((uint)w > vinfo.xres) w = vinfo.xres; - if ((uint)h > vinfo.yres) h = vinfo.yres; - } - dw=w; - dh=h; - int xxoff, yyoff; - if (sscanf(qwssize, "%*dx%*d+%d+%d", &xxoff, &yyoff) == 2) { - if (xxoff < 0 || xxoff + w > (int)(vinfo.xres)) - xxoff = vinfo.xres - w; - if (yyoff < 0 || yyoff + h > (int)(vinfo.yres)) - yyoff = vinfo.yres - h; - xoff += xxoff; - yoff += yyoff; - } else { - xoff += (vinfo.xres - w)/2; - yoff += (vinfo.yres - h)/2; - } - } else { - dw=w=vinfo.xres; - dh=h=vinfo.yres; - } - - if (w == 0 || h == 0) { - qWarning("QLinuxFbIntegration::connect(): Unable to find screen geometry, " - "will use 320x240."); - dw = w = 320; - dh = h = 240; - } - - setPixelFormat(vinfo); - - // Handle display physical size spec. - QStringList displayArgs = displaySpec.split(QLatin1Char(':')); - QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)")); - int dimIdxW = displayArgs.indexOf(mmWidthRx); - QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)")); - int dimIdxH = displayArgs.indexOf(mmHeightRx); - if (dimIdxW >= 0) { - mmWidthRx.exactMatch(displayArgs.at(dimIdxW)); - physWidth = mmWidthRx.cap(1).toInt(); - if (dimIdxH < 0) - physHeight = dh*physWidth/dw; - } - if (dimIdxH >= 0) { - mmHeightRx.exactMatch(displayArgs.at(dimIdxH)); - physHeight = mmHeightRx.cap(1).toInt(); - if (dimIdxW < 0) - physWidth = dw*physHeight/dh; - } - if (dimIdxW < 0 && dimIdxH < 0) { - if (vinfo.width != 0 && vinfo.height != 0 - && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) { - physWidth = vinfo.width; - physHeight = vinfo.height; - } else { - const int dpi = 72; - physWidth = qRound(dw * 25.4 / dpi); - physHeight = qRound(dh * 25.4 / dpi); - } - } - - dataoffset = yoff * lstep + xoff * d / 8; - //qDebug("Using %dx%dx%d screen",w,h,d); - - /* Figure out the size of the screen in bytes */ - size = h * lstep; - - mapsize = finfo.smem_len; - - data = (unsigned char *)-1; - if (d_ptr->fd != -1) - data = (unsigned char *)mmap(0, mapsize, PROT_READ | PROT_WRITE, - MAP_SHARED, d_ptr->fd, 0); - - if ((long)data == -1) { - perror("QLinuxFbIntegration::connect"); - qWarning("Error: failed to map framebuffer device to memory."); - return false; - } else { - data += dataoffset; - } - -#if 0 - canaccel = useOffscreen(); - if(canaccel) - setupOffScreen(); -#endif - canaccel = false; - - // Now read in palette - if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) { - screencols= (vinfo.bits_per_pixel==8) ? 256 : 16; - int loopc; - fb_cmap startcmap; - startcmap.start=0; - startcmap.len=screencols; - startcmap.red=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - startcmap.green=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - startcmap.blue=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - startcmap.transp=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - if (d_ptr->fd == -1 || ioctl(d_ptr->fd, FBIOGETCMAP, &startcmap)) { - perror("QLinuxFbIntegration::connect"); - qWarning("Error reading palette from framebuffer, using default palette"); - createPalette(startcmap, vinfo, finfo); - } - int bits_used = 0; - for(loopc=0;loopc> 8, - startcmap.green[loopc] >> 8, - startcmap.blue[loopc] >> 8); - bits_used |= startcmap.red[loopc] - | startcmap.green[loopc] - | startcmap.blue[loopc]; - } - // WORKAROUND: Some framebuffer drivers only return 8 bit - // color values, so we need to not bit shift them.. - if ((bits_used & 0x00ff) && !(bits_used & 0xff00)) { - for(loopc=0;loopcopenTty(); - - // Grab current mode so we can reset it - fb_var_screeninfo vinfo; - fb_fix_screeninfo finfo; - //####################### - // Shut up Valgrind - memset(&vinfo, 0, sizeof(vinfo)); - memset(&finfo, 0, sizeof(finfo)); - //####################### - - if (ioctl(d_ptr->fd, FBIOGET_VSCREENINFO, &vinfo)) { - perror("QLinuxFbScreen::initDevice"); - qFatal("Error reading variable information in card init"); - return false; - } - -#ifdef DEBUG_VINFO - qDebug("Greyscale %d",vinfo.grayscale); - qDebug("Nonstd %d",vinfo.nonstd); - qDebug("Red %d %d %d",vinfo.red.offset,vinfo.red.length, - vinfo.red.msb_right); - qDebug("Green %d %d %d",vinfo.green.offset,vinfo.green.length, - vinfo.green.msb_right); - qDebug("Blue %d %d %d",vinfo.blue.offset,vinfo.blue.length, - vinfo.blue.msb_right); - qDebug("Transparent %d %d %d",vinfo.transp.offset,vinfo.transp.length, - vinfo.transp.msb_right); -#endif - - d_ptr->startupw=vinfo.xres; - d_ptr->startuph=vinfo.yres; - d_ptr->startupd=vinfo.bits_per_pixel; - grayscale = vinfo.grayscale; - - if (ioctl(d_ptr->fd, FBIOGET_FSCREENINFO, &finfo)) { - perror("QLinuxFbScreen::initDevice"); - qCritical("Error reading fixed information in card init"); - // It's not an /error/ as such, though definitely a bad sign - // so we return true - return true; - } - -#ifdef __i386__ - // Now init mtrr - if(!::getenv("QWS_NOMTRR")) { - int mfd=QT_OPEN("/proc/mtrr",O_WRONLY,0); - // MTRR entry goes away when file is closed - i.e. - // hopefully when QWS is killed - if(mfd != -1) { - mtrr_sentry sentry; - sentry.base=(unsigned long int)finfo.smem_start; - //qDebug("Physical framebuffer address %p",(void*)finfo.smem_start); - // Size needs to be in 4k chunks, but that's not always - // what we get thanks to graphics card registers. Write combining - // these is Not Good, so we write combine what we can - // (which is not much - 4 megs on an 8 meg card, it seems) - unsigned int size=finfo.smem_len; - size=size >> 22; - size=size << 22; - sentry.size=size; - sentry.type=MTRR_TYPE_WRCOMB; - if(ioctl(mfd,MTRRIOC_ADD_ENTRY,&sentry)==-1) { - //printf("Couldn't add mtrr entry for %lx %lx, %s\n", - //sentry.base,sentry.size,strerror(errno)); - } - } - - // Should we close mfd here? - //QT_CLOSE(mfd); - } -#endif - if ((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4) || (finfo.visual==FB_VISUAL_DIRECTCOLOR)) - { - fb_cmap cmap; - createPalette(cmap, vinfo, finfo); - if (ioctl(d_ptr->fd, FBIOPUTCMAP, &cmap)) { - perror("QLinuxFbScreen::initDevice"); - qWarning("Error writing palette to framebuffer"); - } - free(cmap.red); - free(cmap.green); - free(cmap.blue); - free(cmap.transp); - } - -#if 0 - if (canaccel) { - *entryp=0; - *lowest = mapsize; - insert_entry(*entryp, *lowest, *lowest); // dummy entry to mark start - } - - shared->fifocount = 0; - shared->buffer_offset = 0xffffffff; // 0 would be a sensible offset (screen) - shared->linestep = 0; - shared->cliptop = 0xffffffff; - shared->clipleft = 0xffffffff; - shared->clipright = 0xffffffff; - shared->clipbottom = 0xffffffff; - shared->rop = 0xffffffff; -#endif - -#ifdef QT_QWS_DEPTH_GENERIC - if (pixelFormat() == QImage::Format_Invalid && screencols == 0 - && d_ptr->doGenericColors) - { - qt_set_generic_blit(this, vinfo.bits_per_pixel, - vinfo.red.length, vinfo.green.length, - vinfo.blue.length, vinfo.transp.length, - vinfo.red.offset, vinfo.green.offset, - vinfo.blue.offset, vinfo.transp.offset); - } -#endif - -#if 0 -#ifndef QT_NO_QWS_CURSOR - QScreenCursor::initSoftwareCursor(); -#endif -#endif - blank(false); - - return true; -} - -void QLinuxFbIntegration::setPixelFormat(struct fb_var_screeninfo info) -{ - const fb_bitfield rgba[4] = { info.red, info.green, - info.blue, info.transp }; - - QImage::Format format = QImage::Format_Invalid; - - switch (d) { - case 32: { - const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0}, - {0, 8, 0}, {24, 8, 0}}; - const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0}, - {16, 8, 0}, {24, 8, 0}}; - if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_ARGB32; - } else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB32; - } else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB32; - pixeltype = BGRPixel; - } - break; - } - case 24: { - const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0}, - {0, 8, 0}, {0, 0, 0}}; - const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0}, - {16, 8, 0}, {0, 0, 0}}; - if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB888; - } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB888; - pixeltype = BGRPixel; - } - break; - } - case 18: { - const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0}, - {0, 6, 0}, {0, 0, 0}}; - if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0) - format = QImage::Format_RGB666; - break; - } - case 16: { - const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0}, - {0, 5, 0}, {0, 0, 0}}; - const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0}, - {11, 5, 0}, {0, 0, 0}}; - if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB16; - } else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB16; - pixeltype = BGRPixel; - } - break; - } - case 15: { - const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0}, - {0, 5, 0}, {15, 1, 0}}; - const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0}, - {10, 5, 0}, {15, 1, 0}}; - if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB555; - } else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) { - format = QImage::Format_RGB555; - pixeltype = BGRPixel; - } - break; - } - case 12: { - const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0}, - {0, 4, 0}, {0, 0, 0}}; - if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0) - format = QImage::Format_RGB444; - break; - } - case 8: - break; - case 1: - format = QImage::Format_Mono; //###: LSB??? - break; - default: - break; - } - - screenFormat = format; -} - -void QLinuxFbIntegration::createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo) -{ - if((vinfo.bits_per_pixel==8) || (vinfo.bits_per_pixel==4)) { - screencols= (vinfo.bits_per_pixel==8) ? 256 : 16; - cmap.start=0; - cmap.len=screencols; - cmap.red=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - cmap.green=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - cmap.blue=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - cmap.transp=(unsigned short int *) - malloc(sizeof(unsigned short int)*screencols); - - if (screencols==16) { - if (finfo.type == FB_TYPE_PACKED_PIXELS) { - // We'll setup a grayscale cmap for 4bpp linear - int val = 0; - for (int idx = 0; idx < 16; ++idx, val += 17) { - cmap.red[idx] = (val<<8)|val; - cmap.green[idx] = (val<<8)|val; - cmap.blue[idx] = (val<<8)|val; - screenclut[idx]=qRgb(val, val, val); - } - } else { - // Default 16 colour palette - // Green is now trolltech green so certain images look nicer - // black d_gray l_gray white red green blue cyan magenta yellow - unsigned char reds[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0xFF, 0xA2, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x82 }; - unsigned char greens[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0xC5, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F }; - unsigned char blues[16] = { 0x00, 0x7F, 0xBF, 0xFF, 0x00, 0x11, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00 }; - - for (int idx = 0; idx < 16; ++idx) { - cmap.red[idx] = ((reds[idx]) << 8)|reds[idx]; - cmap.green[idx] = ((greens[idx]) << 8)|greens[idx]; - cmap.blue[idx] = ((blues[idx]) << 8)|blues[idx]; - cmap.transp[idx] = 0; - screenclut[idx]=qRgb(reds[idx], greens[idx], blues[idx]); - } - } - } else { - if (grayscale) { - // Build grayscale palette - int i; - for(i=0;iblank == on) - return; - -#if defined(QT_QWS_IPAQ) - if (on) - system("apm -suspend"); -#else - if (d_ptr->fd == -1) - return; -// Some old kernel versions don't have this. These defines should go -// away eventually -#if defined(FBIOBLANK) -#if defined(VESA_POWERDOWN) && defined(VESA_NO_BLANKING) - ioctl(d_ptr->fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING); -#else - ioctl(d_ptr->fd, FBIOBLANK, on ? 1 : 0); -#endif -#endif -#endif - - d_ptr->blank = on; + delete m_primaryScreen; } bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) const @@ -796,7 +77,6 @@ bool QLinuxFbIntegration::hasCapability(QPlatformIntegration::Capability cap) co } } - QPlatformPixmap *QLinuxFbIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const { return new QRasterPlatformPixmap(type); @@ -810,18 +90,25 @@ QPlatformBackingStore *QLinuxFbIntegration::createPlatformBackingStore(QWindow * QPlatformWindow *QLinuxFbIntegration::createPlatformWindow(QWindow *window) const { QFbWindow *w = new QFbWindow(window); - mPrimaryScreen->addWindow(w); + m_primaryScreen->addWindow(w); return w; } QAbstractEventDispatcher *QLinuxFbIntegration::guiThreadEventDispatcher() const { - return createUnixEventDispatcher(); + return m_eventDispatcher; +} + +QList QLinuxFbIntegration::screens() const +{ + QList list; + list.append(m_primaryScreen); + return list; } QPlatformFontDatabase *QLinuxFbIntegration::fontDatabase() const { - return fontDb; + return m_fontDb; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h index 430375dbb6..7c67431fdb 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.h @@ -44,21 +44,16 @@ #include -#include - QT_BEGIN_NAMESPACE class QLinuxFbIntegrationPrivate; -struct fb_cmap; -struct fb_var_screeninfo; -struct fb_fix_screeninfo; class QAbstractEventDispatcher; class QLinuxFbScreen; class QLinuxFbIntegration : public QPlatformIntegration { public: - QLinuxFbIntegration(); + QLinuxFbIntegration(const QStringList ¶mList); ~QLinuxFbIntegration(); bool hasCapability(QPlatformIntegration::Capability cap) const; @@ -67,52 +62,13 @@ public: QPlatformWindow *createPlatformWindow(QWindow *window) const; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const; QAbstractEventDispatcher *guiThreadEventDispatcher() const; - - QList screens() const { return mScreens; } - + QList screens() const; QPlatformFontDatabase *fontDatabase() const; private: - QLinuxFbScreen *mPrimaryScreen; - QList mScreens; - QLinuxFbIntegrationPrivate *d_ptr; - - enum PixelType { NormalPixel, BGRPixel }; - - QRgb screenclut[256]; - int screencols; - - uchar * data; - - QImage::Format screenFormat; - int w; - int lstep; - int h; - int d; - PixelType pixeltype; - bool grayscale; - - int dw; - int dh; - - int size; // Screen size - int mapsize; // Total mapped memory - - int displayId; - - int physWidth; - int physHeight; - - bool canaccel; - int dataoffset; - int cacheStart; - - bool connect(const QString &displaySpec); - bool initDevice(); - void setPixelFormat(struct fb_var_screeninfo); - void createPalette(fb_cmap &cmap, fb_var_screeninfo &vinfo, fb_fix_screeninfo &finfo); - void blank(bool on); - QPlatformFontDatabase *fontDb; + QLinuxFbScreen *m_primaryScreen; + QPlatformFontDatabase *m_fontDb; + QAbstractEventDispatcher *m_eventDispatcher; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp index 729fd87a31..7b9eacf59f 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp @@ -43,63 +43,383 @@ #include #include +#include // overrides QT_OPEN +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + QT_BEGIN_NAMESPACE -QLinuxFbScreen::QLinuxFbScreen(uchar * d, int w, - int h, int lstep, QImage::Format screenFormat) : compositePainter(0) +static int openFramebufferDevice(const QString &dev) { - data = d; - mGeometry = QRect(0,0,w,h); - bytesPerLine = lstep; - mFormat = screenFormat; - mDepth = 16; - mScreenImage = new QImage(mGeometry.width(), mGeometry.height(), - mFormat); - mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(), - bytesPerLine, mFormat); - cursor = new QFbCursor(this); + int fd = -1; + + if (access(dev.toLatin1().constData(), R_OK|W_OK) == 0) + fd = QT_OPEN(dev.toLatin1().constData(), O_RDWR); + + if (fd == -1) { + if (access(dev.toLatin1().constData(), R_OK) == 0) + fd = QT_OPEN(dev.toLatin1().constData(), O_RDONLY); + } + + return fd; } -void QLinuxFbScreen::setGeometry(QRect rect) +static int determineDepth(const fb_var_screeninfo &vinfo) { - mGeometry = rect; - delete mFbScreenImage; - mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(), - bytesPerLine, mFormat); - delete compositePainter; - compositePainter = 0; - - delete mScreenImage; - mScreenImage = new QImage(mGeometry.width(), mGeometry.height(), - mFormat); + int depth = vinfo.bits_per_pixel; + if (depth== 24) { + depth = vinfo.red.length + vinfo.green.length + vinfo.blue.length; + if (depth <= 0) + depth = 24; // reset if color component lengths are not reported + } else if (depth == 16) { + depth = vinfo.red.length + vinfo.green.length + vinfo.blue.length; + if (depth <= 0) + depth = 16; + } + return depth; } -void QLinuxFbScreen::setFormat(QImage::Format format) +static QRect determineGeometry(const fb_var_screeninfo &vinfo, const QRect &userGeometry) { - mFormat = format; - delete mFbScreenImage; - mFbScreenImage = new QImage(data, mGeometry.width(), mGeometry.height(), - bytesPerLine, mFormat); - delete compositePainter; - compositePainter = 0; - - delete mScreenImage; - mScreenImage = new QImage(mGeometry.width(), mGeometry.height(), - mFormat); + int xoff = vinfo.xoffset; + int yoff = vinfo.yoffset; + int w, h; + if (userGeometry.isValid()) { + w = userGeometry.width(); + h = userGeometry.height(); + if ((uint)w > vinfo.xres) + w = vinfo.xres; + if ((uint)h > vinfo.yres) + h = vinfo.yres; + + int xxoff = userGeometry.x(), yyoff = userGeometry.y(); + if (xxoff != 0 || yyoff != 0) { + if (xxoff < 0 || xxoff + w > (int)(vinfo.xres)) + xxoff = vinfo.xres - w; + if (yyoff < 0 || yyoff + h > (int)(vinfo.yres)) + yyoff = vinfo.yres - h; + xoff += xxoff; + yoff += yyoff; + } else { + xoff += (vinfo.xres - w)/2; + yoff += (vinfo.yres - h)/2; + } + } else { + w = vinfo.xres; + h = vinfo.yres; + } + + if (w == 0 || h == 0) { + qWarning("Unable to find screen geometry, using 320x240"); + w = 320; + h = 240; + } + + return QRect(xoff, yoff, w, h); } -QRegion QLinuxFbScreen::doRedraw() +static QSizeF determinePhysicalSize(const fb_var_screeninfo &vinfo, const QSize &mmSize, const QSize &res) { - QRegion touched; - touched = QFbScreen::doRedraw(); + int mmWidth = mmSize.width(), mmHeight = mmSize.height(); + + if (mmWidth <= 0 && mmHeight <= 0) { + if (vinfo.width != 0 && vinfo.height != 0 + && vinfo.width != UINT_MAX && vinfo.height != UINT_MAX) { + mmWidth = vinfo.width; + mmHeight = vinfo.height; + } else { + const int dpi = 72; + mmWidth = qRound(res.width() * 25.4 / dpi); + mmHeight = qRound(res.height() * 25.4 / dpi); + } + } else if (mmWidth > 0 && mmHeight <= 0) { + mmHeight = res.height() * mmWidth/res.width(); + } else if (mmHeight > 0 && mmWidth <= 0) { + mmWidth = res.width() * mmHeight/res.height(); + } + + return QSize(mmWidth, mmHeight); +} - if (!compositePainter) { - compositePainter = new QPainter(mFbScreenImage); +static QImage::Format determineFormat(const fb_var_screeninfo &info, int depth) +{ + const fb_bitfield rgba[4] = { info.red, info.green, + info.blue, info.transp }; + + QImage::Format format = QImage::Format_Invalid; + + switch (depth) { + case 32: { + const fb_bitfield argb8888[4] = {{16, 8, 0}, {8, 8, 0}, + {0, 8, 0}, {24, 8, 0}}; + const fb_bitfield abgr8888[4] = {{0, 8, 0}, {8, 8, 0}, + {16, 8, 0}, {24, 8, 0}}; + if (memcmp(rgba, argb8888, 4 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_ARGB32; + } else if (memcmp(rgba, argb8888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB32; + } else if (memcmp(rgba, abgr8888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB32; + // pixeltype = BGRPixel; + } + break; + } + case 24: { + const fb_bitfield rgb888[4] = {{16, 8, 0}, {8, 8, 0}, + {0, 8, 0}, {0, 0, 0}}; + const fb_bitfield bgr888[4] = {{0, 8, 0}, {8, 8, 0}, + {16, 8, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB888; + } else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB888; + // pixeltype = BGRPixel; + } + break; + } + case 18: { + const fb_bitfield rgb666[4] = {{12, 6, 0}, {6, 6, 0}, + {0, 6, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb666, 3 * sizeof(fb_bitfield)) == 0) + format = QImage::Format_RGB666; + break; } + case 16: { + const fb_bitfield rgb565[4] = {{11, 5, 0}, {5, 6, 0}, + {0, 5, 0}, {0, 0, 0}}; + const fb_bitfield bgr565[4] = {{0, 5, 0}, {5, 6, 0}, + {11, 5, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb565, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB16; + } else if (memcmp(rgba, bgr565, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB16; + // pixeltype = BGRPixel; + } + break; + } + case 15: { + const fb_bitfield rgb1555[4] = {{10, 5, 0}, {5, 5, 0}, + {0, 5, 0}, {15, 1, 0}}; + const fb_bitfield bgr1555[4] = {{0, 5, 0}, {5, 5, 0}, + {10, 5, 0}, {15, 1, 0}}; + if (memcmp(rgba, rgb1555, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB555; + } else if (memcmp(rgba, bgr1555, 3 * sizeof(fb_bitfield)) == 0) { + format = QImage::Format_RGB555; + // pixeltype = BGRPixel; + } + break; + } + case 12: { + const fb_bitfield rgb444[4] = {{8, 4, 0}, {4, 4, 0}, + {0, 4, 0}, {0, 0, 0}}; + if (memcmp(rgba, rgb444, 3 * sizeof(fb_bitfield)) == 0) + format = QImage::Format_RGB444; + break; + } + case 8: + break; + case 1: + format = QImage::Format_Mono; //###: LSB??? + break; + default: + break; + } + + return format; +} + +static void debug(const fb_var_screeninfo &vinfo) +{ + qDebug("Greyscale %d", vinfo.grayscale); + qDebug("Nonstd %d", vinfo.nonstd); + qDebug("Red %d %d %d", vinfo.red.offset, vinfo.red.length, vinfo.red.msb_right); + qDebug("Green %d %d %d", vinfo.green.offset, vinfo.green.length, vinfo.green.msb_right); + qDebug("Blue %d %d %d", vinfo.blue.offset, vinfo.blue.length, vinfo.blue.msb_right); + qDebug("Transparent %d %d %d", vinfo.transp.offset, vinfo.transp.length, vinfo.transp.msb_right); +} + +static int openTtyDevice(const QString &device) +{ + const char *const devs[] = { "/dev/tty0", "/dev/tty", "/dev/console", 0 }; + + int fd = -1; + if (device.isEmpty()) { + for (const char * const *dev = devs; *dev; ++dev) { + fd = QT_OPEN(*dev, O_RDWR); + if (fd != -1) + break; + } + } else { + fd = QT_OPEN(QFile::encodeName(device).constData(), O_RDWR); + } + + return fd; +} + +static bool switchToGraphicsMode(int ttyfd, int *oldMode) +{ + ioctl(ttyfd, KDGETMODE, &oldMode); + if (*oldMode != KD_GRAPHICS) { + if (ioctl(ttyfd, KDSETMODE, KD_GRAPHICS) != 0) + return false; + } + + // No blankin' screen, no blinkin' cursor!, no cursor! + const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c"; + QT_WRITE(ttyfd, termctl, sizeof(termctl)); + return true; +} + +static void resetTty(int ttyfd, int oldMode) +{ + ioctl(ttyfd, KDSETMODE, oldMode); + + // Blankin' screen, blinkin' cursor! + const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c"; + QT_WRITE(ttyfd, termctl, sizeof(termctl)); + + QT_CLOSE(ttyfd); +} + +static void blankScreen(int fd, bool on) +{ + ioctl(fd, FBIOBLANK, on ? VESA_POWERDOWN : VESA_NO_BLANKING); +} + +QLinuxFbScreen::QLinuxFbScreen() + : mFbFd(-1), mBlitter(0) +{ +} + +QLinuxFbScreen::~QLinuxFbScreen() +{ + if (mFbFd != -1) { + munmap(mMmap.data - mMmap.offset, mMmap.size); + close(mFbFd); + } + + if (mTtyFd != -1) { + resetTty(mTtyFd, mOldTtyMode); + close(mTtyFd); + } + + delete mBlitter; +} + +bool QLinuxFbScreen::initialize(const QStringList &args) +{ + QRegExp ttyRx(QLatin1String("tty=(.*)")); + QRegExp fbRx(QLatin1String("fb=(.*)")); + QRegExp mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)")); + QRegExp sizeRx(QLatin1String("size=(\\d+)x(\\d+)")); + QRegExp offsetRx(QLatin1String("offset=(\\d+)x(\\d+)")); + + QString fbDevice, ttyDevice; + QSize userMmSize; + QRect userGeometry; + + // Parse arguments + foreach (const QString &arg, args) { + if (sizeRx.indexIn(arg) != -1) + userGeometry.setSize(QSize(sizeRx.cap(1).toInt(), sizeRx.cap(2).toInt())); + else if (offsetRx.indexIn(arg) != -1) + userGeometry.setTopLeft(QPoint(offsetRx.cap(1).toInt(), offsetRx.cap(2).toInt())); + else if (ttyRx.indexIn(arg) != -1) + ttyDevice = ttyRx.cap(1); + else if (fbRx.indexIn(arg) != -1) + fbDevice = fbRx.cap(1); + else if (mmSizeRx.indexIn(arg) != -1) + userMmSize = QSize(mmSizeRx.cap(1).toInt(), mmSizeRx.cap(2).toInt()); + } + + if (fbDevice.isEmpty()) + fbDevice = QLatin1String("/dev/fb0"); // ## auto-detect + + // Open the device + mFbFd = openFramebufferDevice(fbDevice); + if (mFbFd == -1) { + qWarning("Failed to open framebuffer %s : %s", qPrintable(fbDevice), strerror(errno)); + return false; + } + + // Read the fixed and variable screen information + fb_fix_screeninfo finfo; + fb_var_screeninfo vinfo; + memset(&vinfo, 0, sizeof(vinfo)); + memset(&finfo, 0, sizeof(finfo)); + + if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) { + qWarning("Error reading fixed information: %s", strerror(errno)); + return false; + } + + if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) { + qWarning("Error reading variable information: %s", strerror(errno)); + return false; + } + + mDepth = determineDepth(vinfo); + mBytesPerLine = finfo.line_length; + mGeometry = determineGeometry(vinfo, userGeometry); + mFormat = determineFormat(vinfo, mDepth); + mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, mGeometry.size()); + + // mmap the framebuffer + mMmap.size = finfo.smem_len; + uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0); + if ((long)data == -1) { + qWarning("Failed to mmap framebuffer: %s", strerror(errno)); + return false; + } + + mMmap.offset = mGeometry.y() * mBytesPerLine + mGeometry.x() * mDepth / 8; + mMmap.data = data + mMmap.offset; + + QFbScreen::initializeCompositor(); + mFbScreenImage = QImage(data, mGeometry.width(), mGeometry.height(), mBytesPerLine, mFormat); + mCursor = new QFbCursor(this); + + mTtyFd = openTtyDevice(ttyDevice); + if (mTtyFd == -1) + qWarning() << "Failed to open tty" << strerror(errno); + + if (!switchToGraphicsMode(mTtyFd, &mOldTtyMode)) + qWarning() << "Failed to set graphics mode" << strerror(errno); + + blankScreen(mFbFd, false); + + return true; +} + +QRegion QLinuxFbScreen::doRedraw() +{ + QRegion touched = QFbScreen::doRedraw(); + + if (touched.isEmpty()) + return touched; + + if (!mBlitter) + mBlitter = new QPainter(&mFbScreenImage); QVector rects = touched.rects(); for (int i = 0; i < rects.size(); i++) - compositePainter->drawImage(rects[i], *mScreenImage, rects[i]); + mBlitter->drawImage(rects[i], *mScreenImage, rects[i]); return touched; } diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h index 6181ee964b..69b8d5c79a 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.h +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.h @@ -47,24 +47,34 @@ QT_BEGIN_NAMESPACE class QPainter; +class QFbCursor; class QLinuxFbScreen : public QFbScreen { Q_OBJECT public: - QLinuxFbScreen(uchar * d, int w, int h, int lstep, QImage::Format screenFormat); - void setGeometry(QRect rect); - void setFormat(QImage::Format format); + QLinuxFbScreen(); + ~QLinuxFbScreen(); + + bool initialize(const QStringList &args); public slots: QRegion doRedraw(); private: - QImage *mFbScreenImage; - uchar *data; - int bytesPerLine; + int mFbFd; + int mTtyFd; + + QImage mFbScreenImage; + int mBytesPerLine; + int mOldTtyMode; + + struct { + uchar *data; + int offset, size; + } mMmap; - QPainter *compositePainter; + QPainter *mBlitter; }; QT_END_NAMESPACE -- cgit v1.2.3