summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorRitt Konstantin <qnx@ics.com>2011-06-21 11:51:14 (GMT)
committerHarald Fernengel <harald.fernengel@nokia.com>2011-06-21 12:05:47 (GMT)
commitf9fbd3bec50252168054f90f4143d79d0a08db00 (patch)
treee6bcf1876b057974b01d11011490a51b81a75c07 /src/gui
parent72e78283d69dc4570b51c02afab8a34d1e7385c2 (diff)
downloadQt-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.pri2
-rw-r--r--src/gui/embedded/qscreen_qws.h3
-rw-r--r--src/gui/embedded/qscreenqnx_qws.cpp409
-rw-r--r--src/gui/embedded/qscreenqnx_qws.h1
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);