source: trunk/src/gui/embedded/qscreenqnx_qws.cpp@ 855

Last change on this file since 855 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 13.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscreenqnx_qws.h"
43#include "qdebug.h"
44
45#include <gf/gf.h>
46
47QT_BEGIN_NAMESPACE
48
49// This struct holds all the pointers to QNX's internals
50struct QQnxScreenContext
51{
52 inline QQnxScreenContext()
53 : device(0), display(0), layer(0), hwSurface(0), memSurface(0), context(0)
54 {}
55
56 gf_dev_t device;
57 gf_dev_info_t deviceInfo;
58 gf_display_t display;
59 gf_display_info_t displayInfo;
60 gf_layer_t layer;
61 gf_surface_t hwSurface;
62 gf_surface_t memSurface;
63 gf_surface_info_t memSurfaceInfo;
64 gf_context_t context;
65};
66
67/*!
68 \class QQnxScreen
69 \preliminary
70 \ingroup qws
71 \since 4.6
72 \internal
73
74 \brief The QQnxScreen class implements a screen driver
75 for QNX io-display based devices.
76
77 Note - you never have to instanciate this class, the QScreenDriverFactory
78 does that for us based on the \c{QWS_DISPLAY} environment variable.
79
80 To activate this driver, set \c{QWS_DISPLAY} to \c{qnx}.
81
82 Example:
83 \c{QWS_DISPLAY=qnx; export QWS_DISPLAY}
84
85 By default, the main layer of the first display of the first device is used.
86 If you have multiple graphic cards, multiple displays or multiple layers and
87 don't want to connect to the default, you can override that with setting
88 the corresponding options \c{device}, \c{display} or \c{layer} in the \c{QWS_DISPLAY} variable:
89
90 \c{QWS_DISPLAY=qnx:device=3:display=4:layer=5}
91
92 In addition, it is suggested to set the physical width and height of the display.
93 QQnxScreen will use that information to compute the dots per inch (DPI) in order to render
94 fonts correctly. If this informaiton is omitted, QQnxScreen defaults to 72 dpi.
95
96 \c{QWS_DISPLAY=qnx:mmWidth=120:mmHeight=80}
97
98 \c{mmWidth} and \c{mmHeight} are the physical width/height of the screen in millimeters.
99
100 \sa QScreen, QScreenDriverPlugin, {Running Qt for Embedded Linux Applications}{Running Applications}
101*/
102
103/*!
104 Constructs a QQnxScreen object. The \a display_id argument
105 identifies the Qt for Embedded Linux server to connect to.
106*/
107QQnxScreen::QQnxScreen(int display_id)
108 : QScreen(display_id), d(new QQnxScreenContext)
109{
110}
111
112/*!
113 Destroys this QQnxScreen object.
114*/
115QQnxScreen::~QQnxScreen()
116{
117 delete d;
118}
119
120/*! \reimp
121*/
122bool QQnxScreen::initDevice()
123{
124 // implement this if you have multiple processes that want to access the display
125 // (not required if QT_NO_QWS_MULTIPROCESS is set)
126 return true;
127}
128
129/*! \internal
130 Attaches to the named device \a name.
131*/
132static bool attachDevice(QQnxScreenContext * const d, const char *name)
133{
134 int ret = gf_dev_attach(&d->device, name, &d->deviceInfo);
135 if (ret != GF_ERR_OK) {
136 qWarning("QQnxScreen: gf_dev_attach(%s) failed with error code %d", name, ret);
137 return false;
138 }
139 return true;
140}
141
142/*! \internal
143 Attaches to the display at index \a displayIndex.
144 */
145static bool attachDisplay(QQnxScreenContext * const d, int displayIndex)
146{
147 int ret = gf_display_attach(&d->display, d->device, displayIndex, &d->displayInfo);
148 if (ret != GF_ERR_OK) {
149 qWarning("QQnxScreen: gf_display_attach(%d) failed with error code %d",
150 displayIndex, ret);
151 return false;
152 }
153 return true;
154}
155
156/*! \internal
157 Attaches to the layer \a layerIndex.
158 */
159static bool attachLayer(QQnxScreenContext * const d, int layerIndex)
160{
161 int ret = gf_layer_attach(&d->layer, d->display, layerIndex, 0);
162 if (ret != GF_ERR_OK) {
163 qWarning("QQnxScreen: gf_layer_attach(%d) failed with error code %d", layerIndex,
164 ret);
165 return false;
166 }
167 gf_layer_enable(d->layer);
168
169 return true;
170}
171
172/*! \internal
173 Creates a new hardware surface (usually on the Gfx card memory) with the dimensions \a w * \a h.
174 */
175static bool createHwSurface(QQnxScreenContext * const d, int w, int h)
176{
177 int ret = gf_surface_create_layer(&d->hwSurface, &d->layer, 1, 0,
178 w, h, GF_FORMAT_ARGB8888, 0, 0);
179 if (ret != GF_ERR_OK) {
180 qWarning("QQnxScreen: gf_surface_create_layer(%dx%d) failed with error code %d",
181 w, h, ret);
182 return false;
183 }
184
185 gf_layer_set_surfaces(d->layer, &d->hwSurface, 1);
186
187 ret = gf_layer_update(d->layer, 0);
188 if (ret != GF_ERR_OK) {
189 qWarning("QQnxScreen: gf_layer_update() failed with error code %d\n", ret);
190 return false;
191 }
192
193 return true;
194}
195
196/*! \internal
197 Creates an in-memory, linear accessible surface of dimensions \a w * \a h.
198 This is the main surface that QWS blits to.
199 */
200static bool createMemSurface(QQnxScreenContext * const d, int w, int h)
201{
202 // Note: gf_surface_attach() could also be used, so we'll create the buffer
203 // and let the surface point to it. Here, we use surface_create instead.
204
205 int ret = gf_surface_create(&d->memSurface, d->device, w, h,
206 GF_FORMAT_ARGB8888, 0,
207 GF_SURFACE_CREATE_CPU_FAST_ACCESS | GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE
208 | GF_SURFACE_PHYS_CONTIG | GF_SURFACE_CREATE_SHAREABLE);
209 if (ret != GF_ERR_OK) {
210 qWarning("QQnxScreen: gf_surface_create(%dx%d) failed with error code %d",
211 w, h, ret);
212 return false;
213 }
214
215 gf_surface_get_info(d->memSurface, &d->memSurfaceInfo);
216
217 if (d->memSurfaceInfo.sid == unsigned(GF_SID_INVALID)) {
218 qWarning("QQnxScreen: gf_surface_get_info() failed.");
219 return false;
220 }
221
222 return true;
223}
224
225/* \internal
226 Creates a QNX gf context and sets our memory surface on it.
227 */
228static bool createContext(QQnxScreenContext * const d)
229{
230 int ret = gf_context_create(&d->context);
231 if (ret != GF_ERR_OK) {
232 qWarning("QQnxScreen: gf_context_create() failed with error code %d", ret);
233 return false;
234 }
235
236 ret = gf_context_set_surface(d->context, d->memSurface);
237 if (ret != GF_ERR_OK) {
238 qWarning("QQnxScreen: gf_context_set_surface() failed with error code %d", ret);
239 return false;
240 }
241
242 return true;
243}
244
245/*! \reimp
246 Connects to QNX's io-display based device based on the \a displaySpec parameters
247 from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation
248 for possible parameters.
249
250 \sa QQnxScreen
251 */
252bool QQnxScreen::connect(const QString &displaySpec)
253{
254 const QStringList params = displaySpec.split(QLatin1Char(':'), QString::SkipEmptyParts);
255
256 bool isOk = false;
257 QRegExp deviceRegExp(QLatin1String("^device=(.+)$"));
258 if (params.indexOf(deviceRegExp) != -1) {
259 isOk = attachDevice(d, deviceRegExp.cap(1).toLocal8Bit().constData());
260 } else {
261 // no device specified - attach to device 0 (the default)
262 isOk = attachDevice(d, GF_DEVICE_INDEX(0));
263 }
264
265 if (!isOk)
266 return false;
267
268 qDebug("QQnxScreen: Attached to Device, number of displays: %d", d->deviceInfo.ndisplays);
269
270 // default to display 0
271 int displayIndex = 0;
272 QRegExp displayRegexp(QLatin1String("^display=(\\d+)$"));
273 if (params.indexOf(displayRegexp) != -1) {
274 displayIndex = displayRegexp.cap(1).toInt();
275 }
276
277 if (!attachDisplay(d, displayIndex))
278 return false;
279
280 qDebug("QQnxScreen: Attached to Display %d, resolution %dx%d, refresh %d Hz",
281 displayIndex, d->displayInfo.xres, d->displayInfo.yres,
282 d->displayInfo.refresh);
283
284
285 // default to main_layer_index from the displayInfo struct
286 int layerIndex = 0;
287 QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$"));
288 if (params.indexOf(layerRegexp) != -1) {
289 layerIndex = layerRegexp.cap(1).toInt();
290 } else {
291 layerIndex = d->displayInfo.main_layer_index;
292 }
293
294 if (!attachLayer(d, layerIndex))
295 return false;
296
297 // tell QWSDisplay the width and height of the display
298 w = dw = d->displayInfo.xres;
299 h = dh = d->displayInfo.yres;
300
301 // we only support 32 bit displays for now.
302 QScreen::d = 32;
303
304 // assume 72 dpi as default, to calculate the physical dimensions if not specified
305 const int defaultDpi = 72;
306
307 // Handle display physical size spec.
308 QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$"));
309 if (params.indexOf(mmWidthRegexp) == -1) {
310 physWidth = qRound(dw * 25.4 / defaultDpi);
311 } else {
312 physWidth = mmWidthRegexp.cap(1).toInt();
313 }
314
315 QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$"));
316 if (params.indexOf(mmHeightRegexp) == -1) {
317 physHeight = qRound(dh * 25.4 / defaultDpi);
318 } else {
319 physHeight = mmHeightRegexp.cap(1).toInt();
320 }
321
322 // create a hardware surface with our dimensions. In the old days, it was possible
323 // to get a pointer directly to the hw surface, so we could blit directly. Now, we
324 // have to use one indirection more, because it's not guaranteed that the hw surface
325 // is mappable into our process.
326 if (!createHwSurface(d, w, h))
327 return false;
328
329 // create an in-memory linear surface that is used by QWS. QWS will blit directly in here.
330 if (!createMemSurface(d, w, h))
331 return false;
332
333 // set the address of the in-memory buffer that QWS is blitting to
334 data = d->memSurfaceInfo.vaddr;
335 // set the line stepping
336 lstep = d->memSurfaceInfo.stride;
337
338 // the overall size of the in-memory buffer is linestep * height
339 size = mapsize = lstep * h;
340
341 // create a QNX drawing context
342 if (!createContext(d))
343 return false;
344
345 // we're always using a software cursor for now. Initialize it here.
346 QScreenCursor::initSoftwareCursor();
347
348 // done, the driver should be connected to the display now.
349 return true;
350}
351
352/*! \reimp
353 */
354void QQnxScreen::disconnect()
355{
356 if (d->context)
357 gf_context_free(d->context);
358
359 if (d->memSurface)
360 gf_surface_free(d->memSurface);
361
362 if (d->hwSurface)
363 gf_surface_free(d->hwSurface);
364
365 if (d->layer)
366 gf_layer_detach(d->layer);
367
368 if (d->display)
369 gf_display_detach(d->display);
370
371 if (d->device)
372 gf_dev_detach(d->device);
373
374 d->memSurface = 0;
375 d->hwSurface = 0;
376 d->context = 0;
377 d->layer = 0;
378 d->display = 0;
379 d->device = 0;
380}
381
382/*! \reimp
383 */
384void QQnxScreen::shutdownDevice()
385{
386}
387
388
389/*! \reimp
390 QQnxScreen doesn't support setting the mode, use io-display instead.
391 */
392void QQnxScreen::setMode(int,int,int)
393{
394 qWarning("QQnxScreen: Unable to change mode, use io-display instead.");
395}
396
397/*! \reimp
398 */
399bool QQnxScreen::supportsDepth(int depth) const
400{
401 // only 32-bit for the moment
402 return depth == 32;
403}
404
405/*! \reimp
406 */
407void QQnxScreen::exposeRegion(QRegion r, int changing)
408{
409 // here is where the actual magic happens. QWS will call exposeRegion whenever
410 // a region on the screen is dirty and needs to be updated on the actual screen.
411
412 // first, call the parent implementation. The parent implementation will update
413 // the region on our in-memory surface
414 QScreen::exposeRegion(r, changing);
415
416 // now our in-memory surface should be up to date with the latest changes.
417 // the code below copies the region from the in-memory surface to the hardware.
418
419 // just get the bounding rectangle of the region. Most screen updates are rectangular
420 // anyways. Code could be optimized to blit each and every member of the region
421 // individually, but in real life, the speed-up is neglectable
422 const QRect br = r.boundingRect();
423 if (br.isEmpty())
424 return; // ignore empty regions because gf_draw_blit2 doesn't like 0x0 dimensions
425
426 // start drawing.
427 int ret = gf_draw_begin(d->context);
428 if (ret != GF_ERR_OK) {
429 qWarning("QQnxScreen: gf_draw_begin() failed with error code %d", ret);
430 return;
431 }
432
433 // blit the changed region from the memory surface to the hardware surface
434 ret = gf_draw_blit2(d->context, d->memSurface, d->hwSurface,
435 br.x(), br.y(), br.right(), br.bottom(), br.x(), br.y());
436 if (ret != GF_ERR_OK) {
437 qWarning("QQnxScreen: gf_draw_blit2() failed with error code %d", ret);
438 }
439
440 // flush all drawing commands (in our case, a single blit)
441 ret = gf_draw_flush(d->context);
442 if (ret != GF_ERR_OK) {
443 qWarning("QQnxScreen: gf_draw_flush() failed with error code %d", ret);
444 }
445
446 // tell QNX that we're done drawing.
447 gf_draw_end(d->context);
448}
449
450QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.