Track API change in QPlatformNativeInterface
[profile/ivi/qtbase.git] / src / plugins / gfxdrivers / powervr / pvreglscreen / pvreglscreen.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "pvreglscreen.h"
43 #include "pvreglwindowsurface.h"
44 #include "pvrqwsdrawable_p.h"
45 #include <QRegExp>
46 #include <qwindowsystem_qws.h>
47 #ifndef QT_NO_QWS_TRANSFORMED
48 #include <qscreentransformed_qws.h>
49 #endif
50 #include <sys/stat.h>
51 #include <sys/ioctl.h>
52 #include <sys/kd.h>
53 #include <fcntl.h>
54 #include <unistd.h>
55
56 //![0]
57 PvrEglScreen::PvrEglScreen(int displayId)
58     : QGLScreen(displayId)
59 {
60     setOptions(NativeWindows);
61     setSupportsBlitInClients(true);
62     setSurfaceFunctions(new PvrEglScreenSurfaceFunctions(this, displayId));
63 //![0]
64     fd = -1;
65     ttyfd = -1;
66     doGraphicsMode = true;
67     oldKdMode = KD_TEXT;
68     parent = 0;
69
70     // Make sure that the EGL layer is initialized and the drivers loaded.
71     EGLDisplay dpy = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
72     if (!eglInitialize(dpy, 0, 0))
73         qWarning("Could not initialize EGL display - are the drivers loaded?");
74
75     // Make sure that screen 0 is initialized.
76     pvrQwsScreenWindow(0);
77 }
78
79 PvrEglScreen::~PvrEglScreen()
80 {
81     if (fd >= 0)
82         ::close(fd);
83 }
84
85 bool PvrEglScreen::initDevice()
86 {
87     openTty();
88     return true;
89 }
90
91 bool PvrEglScreen::connect(const QString &displaySpec)
92 {
93     if (!pvrQwsDisplayOpen())
94         return false;
95
96     // Initialize the QScreen properties.
97     data = (uchar *)(pvrQwsDisplay.screens[0].mapped);
98     w = pvrQwsDisplay.screens[0].screenRect.width;
99     h = pvrQwsDisplay.screens[0].screenRect.height;
100     lstep = pvrQwsDisplay.screens[0].screenStride;
101     dw = w;
102     dh = h;
103     size = h * lstep;
104     mapsize = size;
105     switch (pvrQwsDisplay.screens[0].pixelFormat) {
106         case PVR2D_RGB565:
107             d = 16;
108             setPixelFormat(QImage::Format_RGB16);
109             break;
110         case PVR2D_ARGB4444:
111             d = 16;
112             setPixelFormat(QImage::Format_ARGB4444_Premultiplied);
113             break;
114         case PVR2D_ARGB8888:
115             d = 32;
116             setPixelFormat(QImage::Format_ARGB32_Premultiplied);
117             break;
118         default:
119             pvrQwsDisplayClose();
120             qWarning("PvrEglScreen::connect: unsupported pixel format %d", (int)(pvrQwsDisplay.screens[0].pixelFormat));
121             return false;
122     }
123
124     // Handle display physical size spec.
125     QStringList displayArgs = displaySpec.split(QLatin1Char(':'));
126     QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)"));
127     int dimIdxW = displayArgs.indexOf(mmWidthRx);
128     QRegExp mmHeightRx(QLatin1String("mmHeight=?(\\d+)"));
129     int dimIdxH = displayArgs.indexOf(mmHeightRx);
130     if (dimIdxW >= 0) {
131         mmWidthRx.exactMatch(displayArgs.at(dimIdxW));
132         physWidth = mmWidthRx.cap(1).toInt();
133         if (dimIdxH < 0)
134             physHeight = dh*physWidth/dw;
135     }
136     if (dimIdxH >= 0) {
137         mmHeightRx.exactMatch(displayArgs.at(dimIdxH));
138         physHeight = mmHeightRx.cap(1).toInt();
139         if (dimIdxW < 0)
140             physWidth = dw*physHeight/dh;
141     }
142     if (dimIdxW < 0 && dimIdxH < 0) {
143         const int dpi = 72;
144         physWidth = qRound(dw * 25.4 / dpi);
145         physHeight = qRound(dh * 25.4 / dpi);
146     }
147
148     // Find the name of the tty device to use.
149     QRegExp ttyRegExp(QLatin1String("tty=(.*)"));
150     if (displayArgs.indexOf(ttyRegExp) != -1)
151         ttyDevice = ttyRegExp.cap(1);
152     if (displayArgs.contains(QLatin1String("nographicsmodeswitch")))
153         doGraphicsMode = false;
154
155     // The screen is ready.
156     return true;
157 }
158
159 void PvrEglScreen::disconnect()
160 {
161     pvrQwsDisplayClose();
162 }
163
164 void PvrEglScreen::shutdownDevice()
165 {
166     closeTty();
167 }
168
169 void PvrEglScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion &region)
170 {
171     QGLScreen::blit(img, topLeft, region);
172     sync();
173 }
174
175 void PvrEglScreen::solidFill(const QColor &color, const QRegion &region)
176 {
177     QGLScreen::solidFill(color, region);
178     sync();
179 }
180
181 bool PvrEglScreen::chooseContext
182     (QGLContext *context, const QGLContext *shareContext)
183 {
184     // We use PvrEglScreenSurfaceFunctions instead.
185     Q_UNUSED(context);
186     Q_UNUSED(shareContext);
187     return false;
188 }
189
190 bool PvrEglScreen::hasOpenGL()
191 {
192     return true;
193 }
194
195 //![1]
196 QWSWindowSurface* PvrEglScreen::createSurface(QWidget *widget) const
197 {
198     if (qobject_cast<QGLWidget*>(widget))
199         return new PvrEglWindowSurface(widget, (PvrEglScreen *)this, displayId);
200
201     return QScreen::createSurface(widget);
202 }
203
204 QWSWindowSurface* PvrEglScreen::createSurface(const QString &key) const
205 {
206     if (key == QLatin1String("PvrEgl"))
207         return new PvrEglWindowSurface();
208
209     return QScreen::createSurface(key);
210 }
211 //![1]
212
213 #ifndef QT_NO_QWS_TRANSFORMED
214
215 static const QScreen *parentScreen
216     (const QScreen *current, const QScreen *lookingFor)
217 {
218     if (!current)
219         return 0;
220     switch (current->classId()) {
221     case QScreen::ProxyClass:
222     case QScreen::TransformedClass: {
223         const QScreen *child =
224             static_cast<const QProxyScreen *>(current)->screen();
225         if (child == lookingFor)
226             return current;
227         else
228             return parentScreen(child, lookingFor);
229     }
230     // Not reached.
231
232     case QScreen::MultiClass: {
233         QList<QScreen *> screens = current->subScreens();
234         foreach (QScreen *screen, screens) {
235             if (screen == lookingFor)
236                 return current;
237             const QScreen *parent = parentScreen(screen, lookingFor);
238             if (parent)
239                 return parent;
240         }
241     }
242     break;
243
244     default: break;
245     }
246     return 0;
247 }
248
249 int PvrEglScreen::transformation() const
250 {
251     // We need to search for our parent screen, which is assumed to be
252     // "Transformed".  If it isn't, then there is no transformation.
253     // There is no direct method to get the parent screen so we need
254     // to search every screen until we find ourselves.
255     if (!parent && qt_screen != this)
256         parent = parentScreen(qt_screen, this);
257     if (!parent)
258         return 0;
259     if (parent->classId() != QScreen::TransformedClass)
260         return 0;
261     return 90 * static_cast<const QTransformedScreen *>(parent)
262                     ->transformOrientation();
263 }
264
265 #else
266
267 int PvrEglScreen::transformation() const
268 {
269     return 0;
270 }
271
272 #endif
273
274 void PvrEglScreen::sync()
275 {
276     // Put code here to synchronize 2D and 3D operations if necessary.
277 }
278
279 void PvrEglScreen::openTty()
280 {
281     const char *const devs[] = {"/dev/tty0", "/dev/tty", "/dev/console", 0};
282
283     if (ttyDevice.isEmpty()) {
284         for (const char * const *dev = devs; *dev; ++dev) {
285             ttyfd = ::open(*dev, O_RDWR);
286             if (ttyfd != -1)
287                 break;
288         }
289     } else {
290         ttyfd = ::open(ttyDevice.toAscii().constData(), O_RDWR);
291     }
292
293     if (ttyfd == -1)
294         return;
295
296     ::fcntl(ttyfd, F_SETFD, FD_CLOEXEC);
297
298     if (doGraphicsMode) {
299         ioctl(ttyfd, KDGETMODE, &oldKdMode);
300         if (oldKdMode != KD_GRAPHICS) {
301             int ret = ioctl(ttyfd, KDSETMODE, KD_GRAPHICS);
302             if (ret == -1)
303                 doGraphicsMode = false;
304         }
305     }
306
307     // No blankin' screen, no blinkin' cursor!, no cursor!
308     const char termctl[] = "\033[9;0]\033[?33l\033[?25l\033[?1c";
309     ::write(ttyfd, termctl, sizeof(termctl));
310 }
311
312 void PvrEglScreen::closeTty()
313 {
314     if (ttyfd == -1)
315         return;
316
317     if (doGraphicsMode)
318         ioctl(ttyfd, KDSETMODE, oldKdMode);
319
320     // Blankin' screen, blinkin' cursor!
321     const char termctl[] = "\033[9;15]\033[?33h\033[?25h\033[?0c";
322     ::write(ttyfd, termctl, sizeof(termctl));
323
324     ::close(ttyfd);
325     ttyfd = -1;
326 }
327
328 //![2]
329 bool PvrEglScreenSurfaceFunctions::createNativeWindow(QWidget *widget, EGLNativeWindowType *native)
330 {
331 //![2]
332     QWSWindowSurface *surface =
333         static_cast<QWSWindowSurface *>(widget->windowSurface());
334     if (!surface) {
335         // The widget does not have a surface yet, so give it one.
336         surface = new PvrEglWindowSurface(widget, screen, displayId);
337         widget->setWindowSurface(surface);
338     } else if (surface->key() != QLatin1String("PvrEgl")) {
339         // The application has attached a QGLContext to an ordinary QWidget.
340         // Replace the widget's window surface with a new one that can do GL.
341         QRect geometry = widget->frameGeometry();
342         geometry.moveTo(widget->mapToGlobal(QPoint(0, 0)));
343         surface = new PvrEglWindowSurface(widget, screen, displayId);
344         surface->setGeometry(geometry);
345         widget->setWindowSurface(surface);
346         widget->setAttribute(Qt::WA_NoSystemBackground, true);
347     }
348     PvrEglWindowSurface *nsurface = static_cast<PvrEglWindowSurface*>(surface);
349     *native = (EGLNativeWindowType)(nsurface->nativeDrawable());
350     return true;
351 }