diff options
author | Ritt Konstantin <qnx@ics.com> | 2011-06-21 11:51:14 (GMT) |
---|---|---|
committer | Harald Fernengel <harald.fernengel@nokia.com> | 2011-06-21 12:05:47 (GMT) |
commit | f9fbd3bec50252168054f90f4143d79d0a08db00 (patch) | |
tree | e6bcf1876b057974b01d11011490a51b81a75c07 /src/gui | |
parent | 72e78283d69dc4570b51c02afab8a34d1e7385c2 (diff) | |
download | Qt-f9fbd3bec50252168054f90f4143d79d0a08db00.zip Qt-f9fbd3bec50252168054f90f4143d79d0a08db00.tar.gz Qt-f9fbd3bec50252168054f90f4143d79d0a08db00.tar.bz2 |
massive improvements for the QNX screen driver
* implement the QWS client-server mode support;
* implement argb8888 (32bpp), rgb888 (24bpp) and rgb565 (16bpp) formats support
(both big- and little-endian);
* make the driver to use the system-configured/supported WxHxD dimensions
rather than a hard-coded WxHx'argb8888' one;
* implement screen blanking (dpms) support;
* proper resources clean-up on errors;
* code cleanups and various minor improvements
Merge-request: 1259
Reviewed-by: Harald Fernengel <harald.fernengel@nokia.com>
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/embedded/embedded.pri | 2 | ||||
-rw-r--r-- | src/gui/embedded/qscreen_qws.h | 3 | ||||
-rw-r--r-- | src/gui/embedded/qscreenqnx_qws.cpp | 409 | ||||
-rw-r--r-- | src/gui/embedded/qscreenqnx_qws.h | 1 |
4 files changed, 254 insertions, 161 deletions
diff --git a/src/gui/embedded/embedded.pri b/src/gui/embedded/embedded.pri index 31f0bc6..836c116 100644 --- a/src/gui/embedded/embedded.pri +++ b/src/gui/embedded/embedded.pri @@ -117,7 +117,7 @@ embedded { contains( gfx-drivers, qnx ) { HEADERS += embedded/qscreenqnx_qws.h SOURCES += embedded/qscreenqnx_qws.cpp - LIBS += -lgf + LIBS_PRIVATE += -lgf } contains( gfx-drivers, integrityfb ) { diff --git a/src/gui/embedded/qscreen_qws.h b/src/gui/embedded/qscreen_qws.h index 2ecc6e7..5ff90f9 100644 --- a/src/gui/embedded/qscreen_qws.h +++ b/src/gui/embedded/qscreen_qws.h @@ -44,7 +44,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qpoint.h> -#include <QtCore/qlist.h> +#include <QtCore/qstringlist.h> #include <QtGui/qrgb.h> #include <QtCore/qrect.h> #include <QtGui/qimage.h> @@ -357,6 +357,7 @@ private: friend class QVNCScreen; friend class QLinuxFbScreen; friend class QVFbScreen; + friend class QQnxScreen; friend class QProxyScreen; friend class QIntfbScreen; #endif diff --git a/src/gui/embedded/qscreenqnx_qws.cpp b/src/gui/embedded/qscreenqnx_qws.cpp index 4afe087..d34e732 100644 --- a/src/gui/embedded/qscreenqnx_qws.cpp +++ b/src/gui/embedded/qscreenqnx_qws.cpp @@ -40,7 +40,9 @@ ****************************************************************************/ #include "qscreenqnx_qws.h" -#include "qdebug.h" + +#include <qapplication.h> +#include <qregexp.h> #include <gf/gf.h> @@ -52,6 +54,10 @@ struct QQnxScreenContext inline QQnxScreenContext() : device(0), display(0), layer(0), hwSurface(0), memSurface(0), context(0) {} + inline ~QQnxScreenContext() + { cleanup(); } + + void cleanup(); gf_dev_t device; gf_dev_info_t deviceInfo; @@ -64,6 +70,35 @@ struct QQnxScreenContext gf_context_t context; }; +void QQnxScreenContext::cleanup() +{ + if (context) { + gf_context_free(context); + context = 0; + } + if (memSurface) { + gf_surface_free(memSurface); + memSurface = 0; + } + if (hwSurface) { + gf_surface_free(hwSurface); + hwSurface = 0; + } + if (layer) { + gf_layer_detach(layer); + layer = 0; + } + if (display) { + gf_display_detach(display); + display = 0; + } + if (device) { + gf_dev_detach(device); + device = 0; + } +} + + /*! \class QQnxScreen \preliminary @@ -117,19 +152,23 @@ QQnxScreen::~QQnxScreen() delete d; } -/*! \reimp +/*! + \reimp */ bool QQnxScreen::initDevice() { - // implement this if you have multiple processes that want to access the display - // (not required if QT_NO_QWS_MULTIPROCESS is set) +#ifndef QT_NO_QWS_CURSOR + QScreenCursor::initSoftwareCursor(); +#endif + return true; } -/*! \internal - Attaches to the named device \a name. +/*! + \internal + Attaches to the named device \a name. */ -static bool attachDevice(QQnxScreenContext * const d, const char *name) +static inline bool attachDevice(QQnxScreenContext * const d, const char *name) { int ret = gf_dev_attach(&d->device, name, &d->deviceInfo); if (ret != GF_ERR_OK) { @@ -139,193 +178,231 @@ static bool attachDevice(QQnxScreenContext * const d, const char *name) return true; } -/*! \internal - Attaches to the display at index \a displayIndex. - */ -static bool attachDisplay(QQnxScreenContext * const d, int displayIndex) +/*! + \internal + Attaches to the display at index \a displayIndex. +*/ +static inline bool attachDisplay(QQnxScreenContext * const d, int displayIndex) { int ret = gf_display_attach(&d->display, d->device, displayIndex, &d->displayInfo); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_display_attach(%d) failed with error code %d", - displayIndex, ret); + qWarning("QQnxScreen: gf_display_attach(%d) failed with error code %d", displayIndex, ret); return false; } return true; } -/*! \internal - Attaches to the layer \a layerIndex. - */ -static bool attachLayer(QQnxScreenContext * const d, int layerIndex) +/*! + \internal + Attaches to the layer \a layerIndex. +*/ +static inline bool attachLayer(QQnxScreenContext * const d, int layerIndex) { - int ret = gf_layer_attach(&d->layer, d->display, layerIndex, 0); + unsigned flags = QApplication::type() != QApplication::GuiServer ? GF_LAYER_ATTACH_PASSIVE : 0; + int ret = gf_layer_attach(&d->layer, d->display, layerIndex, flags); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_layer_attach(%d) failed with error code %d", layerIndex, - ret); + qWarning("QQnxScreen: gf_layer_attach(%d) failed with error code %d", layerIndex, ret); return false; } - gf_layer_enable(d->layer); return true; } -/*! \internal - Creates a new hardware surface (usually on the Gfx card memory) with the dimensions \a w * \a h. - */ -static bool createHwSurface(QQnxScreenContext * const d, int w, int h) +/*! + \internal + Creates a new hardware surface (usually on the Gfx card memory) with the dimensions \a w * \a h. +*/ +static inline bool createHwSurface(QQnxScreenContext * const d, int w, int h) { int ret = gf_surface_create_layer(&d->hwSurface, &d->layer, 1, 0, - w, h, GF_FORMAT_ARGB8888, 0, 0); + w, h, d->displayInfo.format, 0, 0); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_surface_create_layer(%dx%d) failed with error code %d", - w, h, ret); + qWarning("QQnxScreen: gf_surface_create_layer(%dx%d) failed with error code %d", w, h, ret); return false; } gf_layer_set_surfaces(d->layer, &d->hwSurface, 1); + gf_layer_enable(d->layer); + ret = gf_layer_update(d->layer, 0); if (ret != GF_ERR_OK) { qWarning("QQnxScreen: gf_layer_update() failed with error code %d\n", ret); return false; } - return true; -} - -/*! \internal - Creates an in-memory, linear accessible surface of dimensions \a w * \a h. - This is the main surface that QWS blits to. - */ -static bool createMemSurface(QQnxScreenContext * const d, int w, int h) -{ - // Note: gf_surface_attach() could also be used, so we'll create the buffer - // and let the surface point to it. Here, we use surface_create instead. - - int ret = gf_surface_create(&d->memSurface, d->device, w, h, - GF_FORMAT_ARGB8888, 0, - GF_SURFACE_CREATE_CPU_FAST_ACCESS | GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE - | GF_SURFACE_PHYS_CONTIG | GF_SURFACE_CREATE_SHAREABLE); + ret = gf_context_create(&d->context); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_surface_create(%dx%d) failed with error code %d", - w, h, ret); + qWarning("QQnxScreen: gf_context_create() failed with error code %d", ret); return false; } - gf_surface_get_info(d->memSurface, &d->memSurfaceInfo); - - if (d->memSurfaceInfo.sid == unsigned(GF_SID_INVALID)) { - qWarning("QQnxScreen: gf_surface_get_info() failed."); + ret = gf_context_set_surface(d->context, d->hwSurface); + if (ret != GF_ERR_OK) { + qWarning("QQnxScreen: gf_context_set_surface() failed with error code %d", ret); return false; } return true; } -/* \internal - Creates a QNX gf context and sets our memory surface on it. - */ -static bool createContext(QQnxScreenContext * const d) +/*! + \internal + Creates an in-memory, linear accessible surface of dimensions \a w * \a h. + This is the main surface that QWS blits to. +*/ +static inline bool createMemSurface(QQnxScreenContext * const d, int w, int h) { - int ret = gf_context_create(&d->context); +#ifndef QT_NO_QWS_MULTIPROCESS + if (QApplication::type() != QApplication::GuiServer) { + unsigned sidlist[64]; + int n = gf_surface_sidlist(d->device, sidlist); // undocumented API + for (int i = 0; i < n; ++i) { + int ret = gf_surface_attach_by_sid(&d->memSurface, d->device, sidlist[i]); + if (ret == GF_ERR_OK) { + gf_surface_get_info(d->memSurface, &d->memSurfaceInfo); + if (d->memSurfaceInfo.sid != unsigned(GF_SID_INVALID)) { + // can we use the surface's vaddr? + unsigned flags = GF_SURFACE_CPU_LINEAR_READABLE | GF_SURFACE_CPU_LINEAR_WRITEABLE; + if ((d->memSurfaceInfo.flags & flags) == flags) + return true; + } + + gf_surface_free(d->memSurface); + d->memSurface = 0; + } + } + qWarning("QQnxScreen: cannot attach to an usable surface; create a new one."); + } +#endif + int ret = gf_surface_create(&d->memSurface, d->device, w, h, d->displayInfo.format, 0, + GF_SURFACE_CREATE_CPU_FAST_ACCESS | GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE + | GF_SURFACE_CREATE_PHYS_CONTIG | GF_SURFACE_CREATE_SHAREABLE); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_context_create() failed with error code %d", ret); + qWarning("QQnxScreen: gf_surface_create(%dx%d) failed with error code %d", + w, h, ret); return false; } - ret = gf_context_set_surface(d->context, d->memSurface); - if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_context_set_surface() failed with error code %d", ret); + gf_surface_get_info(d->memSurface, &d->memSurfaceInfo); + + if (d->memSurfaceInfo.sid == unsigned(GF_SID_INVALID)) { + qWarning("QQnxScreen: gf_surface_get_info() failed."); return false; } return true; } -/*! \reimp - Connects to QNX's io-display based device based on the \a displaySpec parameters - from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation - for possible parameters. +/*! + \reimp + Connects to QNX's io-display based device based on the \a displaySpec parameters + from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation + for possible parameters. - \sa QQnxScreen - */ + \sa QQnxScreen +*/ bool QQnxScreen::connect(const QString &displaySpec) { const QStringList params = displaySpec.split(QLatin1Char(':'), QString::SkipEmptyParts); - bool isOk = false; - QRegExp deviceRegExp(QLatin1String("^device=(.+)$")); - if (params.indexOf(deviceRegExp) != -1) { - isOk = attachDevice(d, deviceRegExp.cap(1).toLocal8Bit().constData()); - } else { - // no device specified - attach to device 0 (the default) - isOk = attachDevice(d, GF_DEVICE_INDEX(0)); + // default to device 0 + int deviceIndex = 0; + if (!params.isEmpty()) { + QRegExp deviceRegExp(QLatin1String("^device=(.+)$")); + if (params.indexOf(deviceRegExp) != -1) + deviceIndex = deviceRegExp.cap(1).toInt(); } - if (!isOk) + if (!attachDevice(d, GF_DEVICE_INDEX(deviceIndex))) return false; qDebug("QQnxScreen: Attached to Device, number of displays: %d", d->deviceInfo.ndisplays); - // default to display 0 - int displayIndex = 0; - QRegExp displayRegexp(QLatin1String("^display=(\\d+)$")); - if (params.indexOf(displayRegexp) != -1) { - displayIndex = displayRegexp.cap(1).toInt(); + // default to display id passed to constructor + int displayIndex = displayId; + if (!params.isEmpty()) { + QRegExp displayRegexp(QLatin1String("^display=(\\d+)$")); + if (params.indexOf(displayRegexp) != -1) + displayIndex = displayRegexp.cap(1).toInt(); } if (!attachDisplay(d, displayIndex)) return false; qDebug("QQnxScreen: Attached to Display %d, resolution %dx%d, refresh %d Hz", - displayIndex, d->displayInfo.xres, d->displayInfo.yres, - d->displayInfo.refresh); - + displayIndex, d->displayInfo.xres, d->displayInfo.yres, d->displayInfo.refresh); // default to main_layer_index from the displayInfo struct - int layerIndex = 0; - QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$")); - if (params.indexOf(layerRegexp) != -1) { - layerIndex = layerRegexp.cap(1).toInt(); - } else { - layerIndex = d->displayInfo.main_layer_index; + int layerIndex = d->displayInfo.main_layer_index; + if (!params.isEmpty()) { + QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$")); + if (params.indexOf(layerRegexp) != -1) + layerIndex = layerRegexp.cap(1).toInt(); } if (!attachLayer(d, layerIndex)) return false; + // determine the pixel format and the pixel type + switch (d->displayInfo.format) { +#if defined(QT_QWS_DEPTH_32) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_ARGB8888: + pixeltype = QScreen::BGRPixel; + // fall through + case GF_FORMAT_BGRA8888: + setPixelFormat(QImage::Format_ARGB32); + break; +#endif +#if defined(QT_QWS_DEPTH_24) + case GF_FORMAT_BGR888: + pixeltype = QScreen::BGRPixel; + setPixelFormat(QImage::Format_RGB888); + break; +#endif +#if defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_PACK_RGB565: + case GF_FORMAT_PKLE_RGB565: + case GF_FORMAT_PKBE_RGB565: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + setFrameBufferLittleEndian((d->displayInfo.format & GF_FORMAT_PKLE) == GF_FORMAT_PKLE); +#endif + setPixelFormat(QImage::Format_RGB16); + break; +#endif + default: + return false; + } + // tell QWSDisplay the width and height of the display w = dw = d->displayInfo.xres; h = dh = d->displayInfo.yres; - - // we only support 32 bit displays for now. - QScreen::d = 32; + QScreen::d = (d->displayInfo.format & GF_FORMAT_BPP); // colour depth // assume 72 dpi as default, to calculate the physical dimensions if not specified const int defaultDpi = 72; - - // Handle display physical size spec. - QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$")); - if (params.indexOf(mmWidthRegexp) == -1) { - physWidth = qRound(dw * 25.4 / defaultDpi); - } else { - physWidth = mmWidthRegexp.cap(1).toInt(); + // Handle display physical size + physWidth = qRound(dw * 25.4 / defaultDpi); + physHeight = qRound(dh * 25.4 / defaultDpi); + if (!params.isEmpty()) { + QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$")); + if (params.indexOf(mmWidthRegexp) != -1) + physWidth = mmWidthRegexp.cap(1).toInt(); + + QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$")); + if (params.indexOf(mmHeightRegexp) != -1) + physHeight = mmHeightRegexp.cap(1).toInt(); } - QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$")); - if (params.indexOf(mmHeightRegexp) == -1) { - physHeight = qRound(dh * 25.4 / defaultDpi); - } else { - physHeight = mmHeightRegexp.cap(1).toInt(); + if (QApplication::type() == QApplication::GuiServer) { + // create a hardware surface with our dimensions. In the old days, it was possible + // to get a pointer directly to the hw surface, so we could blit directly. Now, we + // have to use one indirection more, because it's not guaranteed that the hw surface + // is mappable into our process. + if (!createHwSurface(d, w, h)) + return false; } - // create a hardware surface with our dimensions. In the old days, it was possible - // to get a pointer directly to the hw surface, so we could blit directly. Now, we - // have to use one indirection more, because it's not guaranteed that the hw surface - // is mappable into our process. - if (!createHwSurface(d, w, h)) - return false; - // create an in-memory linear surface that is used by QWS. QWS will blit directly in here. if (!createMemSurface(d, w, h)) return false; @@ -338,72 +415,84 @@ bool QQnxScreen::connect(const QString &displaySpec) // the overall size of the in-memory buffer is linestep * height size = mapsize = lstep * h; - // create a QNX drawing context - if (!createContext(d)) - return false; - - // we're always using a software cursor for now. Initialize it here. - QScreenCursor::initSoftwareCursor(); - // done, the driver should be connected to the display now. return true; } -/*! \reimp - */ +/*! + \reimp +*/ void QQnxScreen::disconnect() { - if (d->context) - gf_context_free(d->context); - - if (d->memSurface) - gf_surface_free(d->memSurface); - - if (d->hwSurface) - gf_surface_free(d->hwSurface); - - if (d->layer) - gf_layer_detach(d->layer); - - if (d->display) - gf_display_detach(d->display); - - if (d->device) - gf_dev_detach(d->device); - - d->memSurface = 0; - d->hwSurface = 0; - d->context = 0; - d->layer = 0; - d->display = 0; - d->device = 0; + d->cleanup(); } -/*! \reimp - */ +/*! + \reimp +*/ void QQnxScreen::shutdownDevice() { } - -/*! \reimp - QQnxScreen doesn't support setting the mode, use io-display instead. - */ +/*! + \reimp + QQnxScreen doesn't support setting the mode, use io-display instead. +*/ void QQnxScreen::setMode(int,int,int) { qWarning("QQnxScreen: Unable to change mode, use io-display instead."); } -/*! \reimp - */ +/*! + \reimp +*/ bool QQnxScreen::supportsDepth(int depth) const { - // only 32-bit for the moment - return depth == 32; + gf_modeinfo_t displayMode; + for (int i = 0; gf_display_query_mode(d->display, i, &displayMode) == GF_ERR_OK; ++i) { + switch (displayMode.primary_format) { +#if defined(QT_QWS_DEPTH_32) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_ARGB8888: + case GF_FORMAT_BGRA8888: + if (depth == 32) + return true; + break; +#endif +#if defined(QT_QWS_DEPTH_24) + case GF_FORMAT_BGR888: + if (depth == 24) + return true; + break; +#endif +#if defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_PACK_RGB565: + case GF_FORMAT_PKLE_RGB565: + case GF_FORMAT_PKBE_RGB565: + if (depth == 16) + return true; + break; +#endif + default: + break; + } + } + + return false; } -/*! \reimp - */ +/*! + \reimp +*/ +void QQnxScreen::blank(bool on) +{ + int ret = gf_display_set_dpms(d->display, on ? GF_DPMS_OFF : GF_DPMS_ON); + if (ret != GF_ERR_OK) + qWarning("QQnxScreen: gf_display_set_dpms() failed with error code %d", ret); +} + +/*! + \reimp +*/ void QQnxScreen::exposeRegion(QRegion r, int changing) { // here is where the actual magic happens. QWS will call exposeRegion whenever @@ -414,6 +503,10 @@ void QQnxScreen::exposeRegion(QRegion r, int changing) QScreen::exposeRegion(r, changing); // now our in-memory surface should be up to date with the latest changes. + + if (!d->hwSurface) + return; + // the code below copies the region from the in-memory surface to the hardware. // just get the bounding rectangle of the region. Most screen updates are rectangular @@ -432,16 +525,14 @@ void QQnxScreen::exposeRegion(QRegion r, int changing) // blit the changed region from the memory surface to the hardware surface ret = gf_draw_blit2(d->context, d->memSurface, d->hwSurface, - br.x(), br.y(), br.right(), br.bottom(), br.x(), br.y()); - if (ret != GF_ERR_OK) { + br.x(), br.y(), br.right(), br.bottom(), br.x(), br.y()); + if (ret != GF_ERR_OK) qWarning("QQnxScreen: gf_draw_blit2() failed with error code %d", ret); - } // flush all drawing commands (in our case, a single blit) ret = gf_draw_flush(d->context); - if (ret != GF_ERR_OK) { + if (ret != GF_ERR_OK) qWarning("QQnxScreen: gf_draw_flush() failed with error code %d", ret); - } // tell QNX that we're done drawing. gf_draw_end(d->context); diff --git a/src/gui/embedded/qscreenqnx_qws.h b/src/gui/embedded/qscreenqnx_qws.h index 38c0ac9..6f6d18a 100644 --- a/src/gui/embedded/qscreenqnx_qws.h +++ b/src/gui/embedded/qscreenqnx_qws.h @@ -66,6 +66,7 @@ public: void shutdownDevice(); void setMode(int,int,int); bool supportsDepth(int) const; + void blank(bool on); void exposeRegion(QRegion r, int changing); |