src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/gfxdrivers/ahi/qscreenahi_qws.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,598 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qscreenahi_qws.h"
+
+#ifndef QT_NO_QWS_AHI
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qapplication.h>
+#include <QtCore/qvector.h>
+#include <QtCore/qvarlengtharray.h>
+#include <private/qwssignalhandler_p.h>
+
+#include <ahi.h>
+
+//#define QAHISCREEN_DEBUG
+
+static int depthForPixelFormat(const AhiPixelFormat_t format)
+{
+    switch (format) {
+    case AhiPix1bpp:
+        return 1;
+    case AhiPix2bpp:
+        return 2;
+    case AhiPix4bpp:
+        return 4;
+    case AhiPix8bpp_332RGB:
+    case AhiPix8bpp:
+        return 8;
+    case AhiPix16bpp_444RGB:
+        return 12;
+    case AhiPix16bpp_555RGB:
+        return 15;
+    case AhiPix16bpp_565RGB:
+        return 16;
+    case AhiPix32bpp_8888ARGB:
+    case AhiPix32bpp_8888BGRA:
+        return 32;
+    default:
+        return 0;
+    }
+}
+
+static AhiPixelFormat_t pixelFormatForImageFormat(const QImage::Format format)
+{
+    switch (format) {
+    case QImage::Format_Mono:
+    case QImage::Format_MonoLSB:
+        return AhiPix1bpp;
+    case QImage::Format_Indexed8:
+        return AhiPix8bpp;
+    case QImage::Format_RGB32:
+    case QImage::Format_ARGB32:
+    case QImage::Format_ARGB32_Premultiplied:
+        return AhiPix32bpp_8888ARGB;
+    case QImage::Format_RGB16:
+        return AhiPix16bpp_565RGB;
+    case QImage::Format_RGB555:
+        return AhiPix16bpp_555RGB;
+    case QImage::Format_ARGB4444_Premultiplied:
+    case QImage::Format_RGB444:
+        return AhiPix16bpp_444RGB;
+    default:
+        return AhiPixelFormatMax;
+    }
+}
+
+class QAhiScreenCursor : public QScreenCursor
+{
+public:
+    QAhiScreenCursor(QScreen *screen, AhiDevCtx_t context);
+
+    void set(const QImage &image, int hotx, int hoty);
+    void move(int x, int y);
+    void show();
+    void hide();
+
+private:
+    QScreen *screen;
+    AhiDevCtx_t context;
+};
+
+QAhiScreenCursor::QAhiScreenCursor(QScreen *s, AhiDevCtx_t c)
+    : QScreenCursor(), screen(s), context(c)
+{
+    hwaccel = true;
+    supportsAlpha = true;
+
+    if (enable)
+        show();
+    else
+        hide();
+}
+
+void QAhiScreenCursor::set(const QImage &image, int hotx, int hoty)
+{
+    if (image.isNull()) {
+        QScreenCursor::set(image, hotx, hoty);
+        return;
+    }
+
+    if (image.format() != QImage::Format_MonoLSB) {
+        set(image.convertToFormat(QImage::Format_MonoLSB), hotx, hoty);
+        return;
+    }
+
+    AhiPixelFormat_t pixFmt = pixelFormatForImageFormat(image.format());
+
+    if (pixFmt >= AhiPixelFormatMax) { // generic fallback
+        QImage::Format toFormat = screen->pixelFormat();
+        if (toFormat == QImage::Format_Invalid)
+            toFormat = QImage::Format_ARGB32;
+        set(image.convertToFormat(toFormat), hotx, hoty);
+        return;
+    }
+
+    AhiPoint_t hotSpot = { hotx, hoty };
+    AhiSize_t bitmapSize = { image.width(), image.height() };
+    AhiBitmap_t bitmap = { bitmapSize, (void*)(image.bits()),
+                           image.bytesPerLine(), pixFmt };
+
+    AhiSts_t status;
+    status = AhiDispCursorSet(context, AhiCursor1, &bitmap, &hotSpot,
+                              image.serialNumber(), 0);
+    if (status != AhiStsOk)
+        qWarning("QAhiScreenCursor::set(): AhiDispCursorSet failed: %x",
+                 status);
+
+    QScreenCursor::set(image, hotx, hoty);
+}
+
+void QAhiScreenCursor::move(int x, int y)
+{
+    AhiPoint_t pos = { x, y };
+    AhiSts_t status = AhiDispCursorPos(context, AhiCursor1, &pos, 0);
+    if (status != AhiStsOk)
+        qWarning("QAhiScreenCursor::move(): error setting mouse position: %x",
+                 status);
+    QScreenCursor::move(x, y);
+}
+
+void QAhiScreenCursor::show()
+{
+    AhiSts_t status;
+    status = AhiDispCursorState(context, AhiCursor1, AhiCursorStateOn, 0);
+    if (status != AhiStsOk)
+        qWarning("QAhiScreenCursor::show(): error setting state: %x", status);
+    QScreenCursor::show();
+}
+
+void QAhiScreenCursor::hide()
+{
+    AhiDispCursorState(context, AhiCursor1, AhiCursorStateOff, 0);
+    QScreenCursor::hide();
+}
+
+class QAhiScreenPrivate : public QObject
+{
+public:
+    QAhiScreenPrivate();
+    ~QAhiScreenPrivate();
+
+    bool setMode(AhiDispMode_t mode);
+
+    AhiDevCtx_t context;
+    AhiSurf_t surface;
+    QAhiScreenCursor *cursor;
+};
+
+QT_BEGIN_NAMESPACE
+
+QAhiScreenPrivate::QAhiScreenPrivate()
+    : context(0), surface(0), cursor(0)
+{
+#ifndef QT_NO_QWS_SIGNALHANDLER
+    QWSSignalHandler::instance()->addObject(this);
+#endif
+}
+
+QAhiScreenPrivate::~QAhiScreenPrivate()
+{
+    delete cursor;
+
+    if (surface) {
+        AhiSurfFree(context, surface);
+        surface = 0;
+    }
+    if (context) {
+        AhiDevClose(context);
+        context = 0;
+    }
+    AhiTerm();
+}
+
+bool QAhiScreenPrivate::setMode(AhiDispMode_t mode)
+{
+    AhiSts_t status;
+
+    status = AhiDispModeSet(context, &mode, 0);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreenPrivate::setMode(): AhiDispModeSet failed: %x",
+                  status);
+        return false;
+    }
+
+    if (surface) {
+        AhiSurfFree(context, surface);
+        surface = 0;
+    }
+    status = AhiSurfAlloc(context, &surface, &mode.size, mode.pixFmt,
+                          AHIFLAG_SURFFIXED);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreenPrivate::setMode(): AhisurfAlloc failed: %x",
+                  status);
+        return false;
+    }
+
+    status = AhiDispSurfSet(context, surface, 0);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreenPrivate::setMode(): AhiDispSurfSet failed: %x",
+                  status);
+        return false;
+    }
+
+    return true;
+}
+
+QAhiScreen::QAhiScreen(int displayId)
+    : QScreen(displayId), d_ptr(new QAhiScreenPrivate)
+{
+}
+
+QAhiScreen::~QAhiScreen()
+{
+    delete d_ptr;
+}
+
+bool QAhiScreen::configure()
+{
+    AhiSurfInfo_t surfaceInfo;
+    AhiSts_t status;
+
+    status = AhiSurfInfo(d_ptr->context, d_ptr->surface, &surfaceInfo);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreen::configure(): AhiSurfInfo failed: %x", status);
+        return false;
+    }
+
+    QScreen::data = 0;
+    QScreen::w = QScreen::dw = surfaceInfo.size.cx;
+    QScreen::h = QScreen::dh = surfaceInfo.size.cy;
+    QScreen::lstep = surfaceInfo.stride;
+    QScreen::size = surfaceInfo.sizeInBytes;
+
+    switch (surfaceInfo.pixFmt) {
+    case AhiPix1bpp:
+        setPixelFormat(QImage::Format_Mono);
+        QScreen::d = 1;
+        break;
+    case AhiPix4bpp:
+        QScreen::d = 4;
+        break;
+    case AhiPix8bpp_332RGB:
+    case AhiPix8bpp:
+        QScreen::d = 8;
+        break;
+    case AhiPix16bpp_444RGB:
+        setPixelFormat(QImage::Format_RGB444);
+        QScreen::d = 12;
+        break;
+    case AhiPix16bpp_555RGB:
+        setPixelFormat(QImage::Format_RGB555);
+        QScreen::d = 15;
+        break;
+    case AhiPix16bpp_565RGB:
+        setPixelFormat(QImage::Format_RGB16);
+        QScreen::d = 16;
+        break;
+    case AhiPix2bpp:
+        QScreen::d = 2;
+        break;
+    case AhiPix32bpp_8888ARGB:
+        setPixelFormat(QImage::Format_ARGB32);
+        // fallthrough
+    case AhiPix32bpp_8888BGRA:
+        QScreen::d = 32;
+        break;
+    default:
+        qCritical("QAhiScreen::configure(): Unknown pixel format: %x",
+                  surfaceInfo.pixFmt);
+        return false;
+    }
+
+    const int dpi = 72;
+    QScreen::physWidth = qRound(QScreen::dw * 25.4 / dpi);
+    QScreen::physHeight = qRound(QScreen::dh * 25.4 / dpi);
+
+    return true;
+}
+
+bool QAhiScreen::connect(const QString &displaySpec)
+{
+    Q_UNUSED(displaySpec);
+
+    AhiSts_t status;
+
+    status = AhiInit(0);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreen::connect(): AhiInit failed: %x", status);
+        return false;
+    }
+
+    AhiDev_t device;
+    AhiDevInfo_t info;
+
+    status = AhiDevEnum(&device, &info, 0);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreen::connect(): AhiDevEnum failed: %x", status);
+        return false;
+    }
+#ifdef QAHISCREEN_DEBUG
+    {
+        int displayNo = 0;
+        AhiDevInfo_t dispInfo = info;
+        qDebug("AHI supported devices:");
+        do {
+            qDebug("  %2i: %s, sw version: %s (rev %u)\n"
+                   "       chip: 0x%x (rev %u), mem: %i (%i/%i), bus: 0x%x",
+                   displayNo, dispInfo.name,
+                   dispInfo.swVersion, uint(dispInfo.swRevision),
+                   uint(dispInfo.chipId), uint(dispInfo.revisionId),
+                   uint(dispInfo.totalMemory),
+                   uint(dispInfo.internalMemSize),
+                   uint(dispInfo.externalMemSize),
+                   uint(dispInfo.cpuBusInterfaceMode));
+            status = AhiDevEnum(&device, &info, ++displayNo);
+        } while (status == AhiStsOk);
+    }
+#endif
+
+    status = AhiDevOpen(&d_ptr->context, device, "qscreenahi",
+                        AHIFLAG_USERLEVEL);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreen::connect(): AhiDevOpen failed: %x", status);
+        return false;
+    }
+
+    AhiDispMode_t mode;
+
+    status = AhiDispModeEnum(d_ptr->context, &mode, 0);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreen::connect(): AhiDispModeEnum failed: %x", status);
+        return false;
+    }
+
+#ifdef QAHISCREEN_DEBUG
+    {
+        int modeNo = 0;
+        AhiDispMode_t modeInfo = mode;
+        qDebug("AHI supported modes:");
+        do {
+            qDebug("  %2i: %ux%u, fmt: %i, %u Hz, rot: %i, mirror: %i",
+                   modeNo, uint(modeInfo.size.cx), uint(modeInfo.size.cy),
+                   modeInfo.pixFmt, uint(modeInfo.frequency),
+                   modeInfo.rotation, modeInfo.mirror);
+            status = AhiDispModeEnum(d_ptr->context, &modeInfo, ++modeNo);
+        } while (status == AhiStsOk);
+    }
+#endif
+
+    if (QApplication::type() == QApplication::GuiServer) {
+        if (!d_ptr->setMode(mode))
+            return false;
+    } else {
+        status = AhiDispSurfGet(d_ptr->context, &d_ptr->surface);
+        if (status != AhiStsOk) {
+            qCritical("QAhiScreen::connect(): AhiDispSurfGet failed: %x",
+                      status);
+            return false;
+        }
+
+        status = AhiDispModeGet(d_ptr->context, &mode);
+        if (status != AhiStsOk) {
+            qCritical("QAhiScreen::context(): AhiDispModeGet failed: %x",
+                      status);
+            return false;
+        }
+    }
+
+    return configure();
+}
+
+void QAhiScreen::disconnect()
+{
+    AhiSurfFree(d_ptr->context, d_ptr->surface);
+    d_ptr->surface = 0;
+    AhiDevClose(d_ptr->context);
+    d_ptr->context = 0;
+    AhiTerm();
+}
+
+bool QAhiScreen::initDevice()
+{
+    QScreenCursor::initSoftwareCursor();
+
+    AhiSts_t status = AhiDispState(d_ptr->context, AhiDispStateOn, 0);
+    if (status != AhiStsOk) {
+        qCritical("QAhiScreen::connect(): AhiDispState failed: %x", status);
+        return false;
+    }
+
+    return true;
+}
+
+void QAhiScreen::shutdownDevice()
+{
+    AhiDispState(d_ptr->context, AhiDispStateOff, 0);
+}
+
+void QAhiScreen::setMode(int width, int height, int depth)
+{
+    int modeNo = 0;
+    AhiDispMode_t mode;
+    AhiSts_t status = AhiStsOk;
+
+    while (status == AhiStsOk) {
+        status = AhiDispModeEnum(d_ptr->context, &mode, modeNo);
+        if (mode.size.cx == uint(width) &&
+            mode.size.cy == uint(height) &&
+            depthForPixelFormat(mode.pixFmt) == depth)
+        {
+            d_ptr->setMode(mode);
+            configure();
+            return;
+        }
+    }
+}
+
+void QAhiScreen::blit(const QImage &image, const QPoint &topLeft,
+                      const QRegion &reg)
+{
+    AhiPixelFormat_t pixFmt = pixelFormatForImageFormat(image.format());
+
+    if (pixFmt >= AhiPixelFormatMax) { // generic fallback
+        QImage::Format toFormat = pixelFormat();
+        if (toFormat == QImage::Format_Invalid)
+            toFormat = QImage::Format_ARGB32;
+        blit(image.convertToFormat(toFormat), topLeft, reg);
+        return;
+    }
+
+    AhiSts_t status;
+
+    status = AhiDrawSurfDstSet(d_ptr->context, d_ptr->surface, 0);
+    if (status != AhiStsOk) {
+        qWarning("QAhiScreen::blit(): AhiDrawSurfDstSet failed: %x", status);
+        return;
+    }
+
+    const QVector<QRect> rects = (reg & region()).rects();
+    const int numRects = rects.size();
+    QVarLengthArray<AhiPoint_t, 8> src(numRects);
+    QVarLengthArray<AhiRect_t, 8> dest(numRects);
+
+    for (int i = 0; i < numRects; ++i) {
+        const QRect rect = rects.at(i);
+
+        src[i].x = rect.x() - topLeft.x();
+        src[i].y = rect.y() - topLeft.y();
+        dest[i].left = rect.left();
+        dest[i].top = rect.top();
+        dest[i].right = rect.x() + rect.width();
+        dest[i].bottom = rect.y() + rect.height();
+    }
+
+    AhiSize_t bitmapSize = { image.width(), image.height() };
+    AhiBitmap_t bitmap = { bitmapSize, (void*)(image.bits()),
+                           image.bytesPerLine(), pixFmt };
+
+    status = AhiDrawRopSet(d_ptr->context, AHIMAKEROP3(AHIROPSRCCOPY));
+    if (status != AhiStsOk) {
+        qWarning("QAhiScreen::blit(): AhiDrawRopSet failed: %x", status);
+        return;
+    }
+
+    for (int i = 0; i < numRects; ++i) {
+        status = AhiDrawBitmapBlt(d_ptr->context, &dest[i], &src[i],
+                                  &bitmap, 0, 0);
+        if (status != AhiStsOk) {
+            qWarning("QAhiScreen::blit(): AhiDrawBitmapBlt failed: %x",
+                     status);
+            break;
+        }
+    }
+}
+
+void QAhiScreen::solidFill(const QColor &color, const QRegion &reg)
+{
+    AhiSts_t status = AhiStsOk;
+
+    switch (pixelFormat()) {
+    case QImage::Format_ARGB32_Premultiplied:
+    case QImage::Format_ARGB32:
+    case QImage::Format_RGB32:
+        status = AhiDrawBrushFgColorSet(d_ptr->context, color.rgba());
+        break;
+    case QImage::Format_RGB16:
+        status = AhiDrawBrushFgColorSet(d_ptr->context, qt_convRgbTo16(color.rgb()));
+        break;
+    default:
+        qFatal("QAhiScreen::solidFill(): Not implemented for pixel format %d",
+               int(pixelFormat()));
+        break;
+    }
+
+    if (status != AhiStsOk) {
+        qWarning("QAhiScreen::solidFill(): AhiDrawBrushFgColorSet failed: %x",
+                 status);
+        return;
+    }
+
+    status = AhiDrawBrushSet(d_ptr->context, 0, 0, 0, AHIFLAG_BRUSHSOLID);
+    if (status != AhiStsOk) {
+        qWarning("QAhiScreen::solidFill(): AhiDrawBrushSet failed: %x",
+                 status);
+        return;
+    }
+
+    status = AhiDrawRopSet(d_ptr->context, AHIMAKEROP3(AHIROPPATCOPY));
+    if (status != AhiStsOk) {
+        qWarning("QAhiScreen::solidFill(): AhiDrawRopSet failed: %x", status);
+        return;
+    }
+
+    status = AhiDrawSurfDstSet(d_ptr->context, d_ptr->surface, 0);
+    if (status != AhiStsOk) {
+        qWarning("QAhiScreen::solidFill(): AhiDrawSurfDst failed: %x", status);
+        return;
+    }
+
+    const QVector<QRect> rects = (reg & region()).rects();
+    QVarLengthArray<AhiRect_t> ahiRects(rects.size());
+
+    for (int i = 0; i < rects.size(); ++i) {
+        const QRect rect = rects.at(i);
+        ahiRects[i].left = rect.left();
+        ahiRects[i].top = rect.top();
+        ahiRects[i].right = rect.x() + rect.width();
+        ahiRects[i].bottom = rect.y() + rect.height();
+    }
+
+    status = AhiDrawBitBltMulti(d_ptr->context, ahiRects.data(),
+                                0, ahiRects.size());
+    if (status != AhiStsOk)
+        qWarning("QAhiScreen::solidFill(): AhiDrawBitBlt failed: %x", status);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_AHI