src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/gfxdrivers/powervr/pvreglscreen/pvreglscreen.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** 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 "pvreglscreen.h"
+#include "pvreglwindowsurface.h"
+#include "pvrqwsdrawable_p.h"
+#include <QRegExp>
+#include <qwindowsystem_qws.h>
+#ifndef QT_NO_QWS_TRANSFORMED
+#include <qscreentransformed_qws.h>
+#endif
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/kd.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+//![0]
+PvrEglScreen::PvrEglScreen(int displayId)
+    : QGLScreen(displayId)
+{
+    setOptions(NativeWindows);
+    setSupportsBlitInClients(true);
+    setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId));
+//![0]
+    fd = -1;
+    ttyfd = -1;
+    doGraphicsMode = true;
+    oldKdMode = KD_TEXT;
+    parent = 0;
+
+    // Make sure that the EGL layer is initialized and the drivers loaded.
+    EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
+    if (!eglInitialize(dpy, 0, 0))
+        qWarning("Could not initialize EGL display - are the drivers loaded?");
+
+    // Make sure that screen 0 is initialized.
+    pvrQwsScreenWindow(0);
+}
+
+PvrEglScreen::~PvrEglScreen()
+{
+    if (fd >= 0)
+        ::close(fd);
+}
+
+bool PvrEglScreen::initDevice()
+{
+    openTty();
+    return true;
+}
+
+bool PvrEglScreen::connect(const QString &displaySpec)
+{
+    if (!pvrQwsDisplayOpen())
+        return false;
+
+    // Initialize the QScreen properties.
+    data = (uchar *)(pvrQwsDisplay.screens[0].mapped);
+    w = pvrQwsDisplay.screens[0].screenRect.width;
+    h = pvrQwsDisplay.screens[0].screenRect.height;
+    lstep = pvrQwsDisplay.screens[0].screenStride;
+    dw = w;
+    dh = h;
+    size = h * lstep;
+    mapsize = size;
+    switch (pvrQwsDisplay.screens[0].pixelFormat) {
+	case PVR2D_RGB565:
+            d = 16;
+            setPixelFormat(QImage::Format_RGB16);
+            break;
+	case PVR2D_ARGB4444:
+            d = 16;
+            setPixelFormat(QImage::Format_ARGB4444_Premultiplied);
+            break;
+	case PVR2D_ARGB8888:
+            d = 32;
+            setPixelFormat(QImage::Format_ARGB32_Premultiplied);
+            break;
+        default:
+            pvrQwsDisplayClose();
+            qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat));
+            return false;
+    }
+
+    // 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) {
+        const int dpi = 72;
+        physWidth = qRound(dw * 25.4 / dpi);
+        physHeight = qRound(dh * 25.4 / dpi);
+    }
+
+    // Find the name of the tty device to use.
+    QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
+    if (displayArgs.indexOf(ttyRegExp) != -1)
+        ttyDevice = ttyRegExp.cap(1);
+    if (displayArgs.contains(QLatin1String("nographicsmodeswitch")))
+        doGraphicsMode = false;
+
+    // The screen is ready.
+    return true;
+}
+
+void PvrEglScreen::disconnect()
+{
+    pvrQwsDisplayClose();
+}
+
+void PvrEglScreen::shutdownDevice()
+{
+    closeTty();
+}
+
+void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion &region)
+{
+    QGLScreen::blit(img, topLeft, region);
+    sync();
+}
+
+void PvrEglScreen::solidFill(const QColor &color, const QRegion &region)
+{
+    QGLScreen::solidFill(color, region);
+    sync();
+}
+
+bool PvrEglScreen::chooseContext
+    (QGLContext *context, const QGLContext *shareContext)
+{
+    // We use PvrEglScreenSurfaceFunctions instead.
+    Q_UNUSED(context);
+    Q_UNUSED(shareContext);
+    return false;
+}
+
+bool PvrEglScreen::hasOpenGL()
+{
+    return true;
+}
+
+//![1]
+QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const
+{
+    if (qobject_cast<QGLWidget*>(widget))
+        return new PvrEglWindowSurface(widget, (PvrEglScreen *)this, displayId);
+
+    return QScreen::createSurface(widget);
+}
+
+QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const
+{
+    if (key == QLatin1String("PvrEgl"))
+        return new PvrEglWindowSurface();
+
+    return QScreen::createSurface(key);
+}
+//![1]
+
+#ifndef QT_NO_QWS_TRANSFORMED
+
+static const QScreen *parentScreen
+    (const QScreen *current, const QScreen *lookingFor)
+{
+    if (!current)
+        return 0;
+    switch (current->classId()) {
+    case QScreen::ProxyClass:
+    case QScreen::TransformedClass: {
+        const QScreen *child =
+            static_cast<const QProxyScreen *>(current)->screen();
+        if (child == lookingFor)
+            return current;
+        else
+            return parentScreen(child, lookingFor);
+    }
+    // Not reached.
+
+    case QScreen::MultiClass: {
+        QList<QScreen *> screens = current->subScreens();
+        foreach (QScreen *screen, screens) {
+            if (screen == lookingFor)
+                return current;
+            const QScreen *parent = parentScreen(screen, lookingFor);
+            if (parent)
+                return parent;
+        }
+    }
+    break;
+
+    default: break;
+    }
+    return 0;
+}
+
+int PvrEglScreen::transformation() const
+{
+    // We need to search for our parent screen, which is assumed to be
+    // "Transformed".  If it isn't, then there is no transformation.
+    // There is no direct method to get the parent screen so we need
+    // to search every screen until we find ourselves.
+    if (!parent && qt_screen != this)
+        parent = parentScreen(qt_screen, this);
+    if (!parent)
+        return 0;
+    if (parent->classId() != QScreen::TransformedClass)
+        return 0;
+    return 90 * static_cast<const QTransformedScreen *>(parent)
+                    ->transformation();
+}
+
+#else
+
+int PvrEglScreen::transformation() const
+{
+    return 0;
+}
+
+#endif
+
+void PvrEglScreen::sync()
+{
+    // Put code here to synchronize 2D and 3D operations if necessary.
+}
+
+void PvrEglScreen::openTty()
+{
+    const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
+
+    if (ttyDevice.isEmpty()) {
+        for (const char * const *dev = devs; *dev; ++dev) {
+            ttyfd = ::open(*dev, O_RDWR);
+            if (ttyfd != -1)
+                break;
+        }
+    } else {
+        ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR);
+    }
+
+    if (ttyfd == -1)
+        return;
+
+    ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC);
+
+    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";
+    ::write(ttyfd, termctl, sizeof(termctl));
+}
+
+void PvrEglScreen::closeTty()
+{
+    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";
+    ::write(ttyfd, termctl, sizeof(termctl));
+
+    ::close(ttyfd);
+    ttyfd = -1;
+}
+
+//![2]
+bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native)
+{
+//![2]
+    QWSWindowSurface *surface =
+        static_cast<QWSWindowSurface *>(widget->windowSurface());
+    if (!surface) {
+        // The widget does not have a surface yet, so give it one.
+        surface = new PvrEglWindowSurface(widget, screen, displayId);
+        widget->setWindowSurface(surface);
+    } else if (surface->key() != QLatin1String("PvrEgl")) {
+        // The application has attached a QGLContext to an ordinary QWidget.
+        // Replace the widget's window surface with a new one that can do GL.
+        QRect geometry = widget->frameGeometry();
+        geometry.moveTo(widget->mapToGlobal(QPoint(0, 0)));
+        surface = new PvrEglWindowSurface(widget, screen, displayId);
+        surface->setGeometry(geometry);
+        widget->setWindowSurface(surface);
+        widget->setAttribute(Qt::WA_NoSystemBackground, true);
+    }
+    PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface);
+    *native = (EGLNativeWindowType)(nsurface->nativeDrawable());
+    return true;
+}