summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/global/qnamespace.qdoc5
-rw-r--r--src/gui/image/qpixmap.cpp2
-rw-r--r--src/gui/image/qpixmap_x11.cpp12
-rw-r--r--src/gui/itemviews/qabstractitemview.cpp8
-rw-r--r--src/gui/itemviews/qitemselectionmodel.h24
-rw-r--r--src/gui/kernel/qapplication.cpp2
-rw-r--r--src/gui/kernel/qapplication_win.cpp25
-rw-r--r--src/gui/kernel/qapplication_x11.cpp3
-rw-r--r--src/gui/kernel/qwidget.cpp4
-rw-r--r--src/gui/kernel/qwidget_win.cpp5
-rw-r--r--src/gui/painting/qpainter.cpp16
-rw-r--r--src/gui/text/qfontengine.cpp12
-rw-r--r--src/gui/text/qfontengine_p.h2
-rw-r--r--src/gui/text/qfontengine_x11.cpp2
-rw-r--r--src/gui/text/qfontengineglyphcache_p.h2
-rw-r--r--src/gui/text/qtextengine_p.h2
-rw-r--r--src/gui/widgets/qspinbox.cpp3
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp64
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h11
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp35
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h9
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp5
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp73
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h96
-rw-r--r--src/opengl/qgl.cpp103
-rw-r--r--src/opengl/qgl.h2
-rw-r--r--src/opengl/qgl_p.h162
-rw-r--r--src/opengl/qgl_win.cpp5
-rw-r--r--src/opengl/qglframebufferobject.cpp8
-rw-r--r--src/opengl/qglpixelbuffer.cpp12
-rw-r--r--src/opengl/qglpixelbuffer_win.cpp8
-rw-r--r--src/opengl/qglpixmapfilter.cpp19
-rw-r--r--src/plugins/gfxdrivers/eglnullws/README48
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullws.pro18
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp181
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h69
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp66
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h47
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp84
-rw-r--r--src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h63
-rw-r--r--src/plugins/gfxdrivers/gfxdrivers.pro1
-rw-r--r--tests/auto/qgl/tst_qgl.cpp28
-rw-r--r--tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp159
44 files changed, 1203 insertions, 303 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index a12e121..9ac6d68 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -530,6 +530,7 @@ public:
AA_DontUseNativeMenuBar = 6,
AA_MacDontSwapCtrlAndMeta = 7,
AA_S60DontConstructApplicationPanes = 8,
+ AA_X11InitThreads = 9,
// Add new attributes before this line
AA_AttributeCount
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index d419759..564164b 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -156,6 +156,11 @@
whole lifetime. This attribute must be set before QApplication is
constructed.
+ \value AA_X11InitThreads Calls XInitThreads() as part of the QApplication
+ construction in order to make Xlib calls thread-safe. This
+ attribute must be set before QApplication is constructed.
+
+
\omitvalue AA_AttributeCount
*/
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index fd2c139..7e41e91 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -99,7 +99,7 @@ static bool qt_pixmap_thread_test()
return false;
}
#ifndef Q_WS_WIN
- if (qApp->thread() != QThread::currentThread()) {
+ if (!QApplication::testAttribute(Qt::AA_X11InitThreads) && qApp->thread() != QThread::currentThread()) {
qWarning("QPixmap: It is not safe to use pixmaps outside the GUI thread");
return false;
}
diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp
index e8dc5ae..afbfa35 100644
--- a/src/gui/image/qpixmap_x11.cpp
+++ b/src/gui/image/qpixmap_x11.cpp
@@ -310,7 +310,7 @@ static int defaultScreen = -1;
QPixmap member functions
*****************************************************************************/
-static int qt_pixmap_serial = 0;
+QBasicAtomicInt qt_pixmap_serial = Q_BASIC_ATOMIC_INITIALIZER(0);
int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0;
QX11PixmapData::QX11PixmapData(PixelType type)
@@ -327,7 +327,7 @@ QPixmapData *QX11PixmapData::createCompatiblePixmapData() const
void QX11PixmapData::resize(int width, int height)
{
- setSerialNumber(++qt_pixmap_serial);
+ setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
w = width;
h = height;
@@ -410,7 +410,7 @@ struct QX11AlphaDetector
void QX11PixmapData::fromImage(const QImage &img,
Qt::ImageConversionFlags flags)
{
- setSerialNumber(++qt_pixmap_serial);
+ setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
w = img.width();
h = img.height();
@@ -1948,7 +1948,7 @@ QPixmap QX11PixmapData::transformed(const QTransform &transform,
x11Data->hd = (Qt::HANDLE)XCreatePixmap(X11->display,
RootWindow(X11->display, xinfo.screen()),
w, h, d);
- x11Data->setSerialNumber(++qt_pixmap_serial);
+ x11Data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
#ifndef QT_NO_XRENDER
if (X11->use_xrender) {
@@ -2199,7 +2199,7 @@ void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect)
const QX11PixmapData *x11Data = static_cast<const QX11PixmapData*>(data);
- setSerialNumber(++qt_pixmap_serial);
+ setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
flags &= ~Uninitialized;
xinfo = x11Data->xinfo;
@@ -2319,7 +2319,7 @@ QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode)
}
QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType);
- data->setSerialNumber(++qt_pixmap_serial);
+ data->setSerialNumber(qt_pixmap_serial.fetchAndAddRelaxed(1));
data->flags = QX11PixmapData::Readonly;
data->share_mode = mode;
data->w = width;
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp
index 15e59ba..ea24328 100644
--- a/src/gui/itemviews/qabstractitemview.cpp
+++ b/src/gui/itemviews/qabstractitemview.cpp
@@ -653,7 +653,7 @@ void QAbstractItemView::setModel(QAbstractItemModel *model)
"QAbstractItemView::setModel",
"A model should return the exact same index "
"(including its internal id/pointer) when asked for it twice in a row.");
- Q_ASSERT_X(d->model->index(0,0).parent() == QModelIndex(),
+ Q_ASSERT_X(!d->model->index(0,0).parent().isValid(),
"QAbstractItemView::setModel",
"The parent of a top level index should be invalid");
@@ -2944,7 +2944,7 @@ int QAbstractItemView::sizeHintForRow(int row) const
{
Q_D(const QAbstractItemView);
- if (row < 0 || row >= d->model->rowCount() || !model())
+ if (row < 0 || row >= d->model->rowCount(d->root))
return -1;
ensurePolished();
@@ -2956,7 +2956,7 @@ int QAbstractItemView::sizeHintForRow(int row) const
for (int c = 0; c < colCount; ++c) {
index = d->model->index(row, c, d->root);
if (QWidget *editor = d->editorForIndex(index).editor)
- height = qMax(height, editor->size().height());
+ height = qMax(height, editor->height());
int hint = d->delegateForIndex(index)->sizeHint(option, index).height();
height = qMax(height, hint);
}
@@ -2975,7 +2975,7 @@ int QAbstractItemView::sizeHintForColumn(int column) const
{
Q_D(const QAbstractItemView);
- if (column < 0 || column >= d->model->columnCount() || !model())
+ if (column < 0 || column >= d->model->columnCount(d->root))
return -1;
ensurePolished();
diff --git a/src/gui/itemviews/qitemselectionmodel.h b/src/gui/itemviews/qitemselectionmodel.h
index 436514f..e2bd06b 100644
--- a/src/gui/itemviews/qitemselectionmodel.h
+++ b/src/gui/itemviews/qitemselectionmodel.h
@@ -101,6 +101,30 @@ public:
{ return (tl == other.tl && br == other.br); }
inline bool operator!=(const QItemSelectionRange &other) const
{ return !operator==(other); }
+ inline bool operator<(const QItemSelectionRange &other) const
+ {
+ // Comparing parents will compare the models, but if two equivalent ranges
+ // in two different models have invalid parents, they would appear the same
+ if (other.tl.model() == tl.model()) {
+ // parent has to be calculated, so we only do so once.
+ const QModelIndex topLeftParent = tl.parent();
+ const QModelIndex otherTopLeftParent = other.tl.parent();
+ if (topLeftParent == otherTopLeftParent) {
+ if (other.tl.row() == tl.row()) {
+ if (other.tl.column() == tl.column()) {
+ if (other.br.row() == br.row()) {
+ return br.column() < other.br.column();
+ }
+ return br.row() < other.br.row();
+ }
+ return tl.column() < other.tl.column();
+ }
+ return tl.row() < other.tl.row();
+ }
+ return topLeftParent < otherTopLeftParent;
+ }
+ return tl.model() < other.tl.model();
+ }
inline bool isValid() const
{
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 4f557d6..6a67369 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -5780,6 +5780,8 @@ Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window,
QGestureManager* QGestureManager::instance()
{
QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ if (!qAppPriv)
+ return 0;
if (!qAppPriv->gestureManager)
qAppPriv->gestureManager = new QGestureManager(qApp);
return qAppPriv->gestureManager;
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index 1af45ba..6f5aa11 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -942,29 +942,36 @@ bool qt_nograb() // application no-grab option
typedef QHash<QString, int> WinClassNameHash;
Q_GLOBAL_STATIC(WinClassNameHash, winclassNames)
+//
+// If 0 is passed as the widget pointer, register a window class
+// for QWidget as default. This is used in QGLTemporaryContext
+// during GL initialization, where we don't want to use temporary
+// QWidgets or QGLWidgets, neither do we want to have separate code
+// to register window classes.
+//
const QString qt_reg_winclass(QWidget *w) // register window class
{
- int flags = w->windowFlags();
+ int flags = w ? w->windowFlags() : 0;
int type = flags & Qt::WindowType_Mask;
uint style;
bool icon;
QString cname;
- if (qt_widget_private(w)->isGLWidget) {
+ if (w && qt_widget_private(w)->isGLWidget) {
cname = QLatin1String("QGLWidget");
style = CS_DBLCLKS;
#ifndef Q_WS_WINCE
style |= CS_OWNDC;
#endif
icon = true;
- } else if (flags & Qt::MSWindowsOwnDC) {
+ } else if (w && (flags & Qt::MSWindowsOwnDC)) {
cname = QLatin1String("QWidgetOwnDC");
style = CS_DBLCLKS;
#ifndef Q_WS_WINCE
style |= CS_OWNDC;
#endif
icon = true;
- } else if (type == Qt::Tool || type == Qt::ToolTip){
+ } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) {
style = CS_DBLCLKS;
if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
@@ -979,7 +986,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class
style |= CS_SAVEBITS;
#endif
icon = false;
- } else if (type == Qt::Popup) {
+ } else if (w && (type == Qt::Popup)) {
cname = QLatin1String("QPopup");
style = CS_DBLCLKS;
#ifndef Q_WS_WINCE
@@ -1050,7 +1057,10 @@ const QString qt_reg_winclass(QWidget *w) // register window class
}
wc.hCursor = 0;
#ifndef Q_WS_WINCE
- wc.hbrBackground = qt_widget_private(w)->isGLWidget ? 0 : (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
+ HBRUSH brush = 0;
+ if (w && !qt_widget_private(w)->isGLWidget)
+ brush = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);
+ wc.hbrBackground = brush;
#else
wc.hbrBackground = 0;
#endif
@@ -1072,8 +1082,7 @@ const QString qt_reg_winclass(QWidget *w) // register window class
Q_GUI_EXPORT const QString qt_getRegisteredWndClass()
{
- QWidget w;
- return qt_reg_winclass(&w);
+ return qt_reg_winclass(0);
}
static void unregWinClasses()
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 9d5a7c0..5e212ca 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -1710,6 +1710,9 @@ void qt_init(QApplicationPrivate *priv, int,
} else {
// Qt controls everything (default)
+ if (QApplication::testAttribute(Qt::AA_X11InitThreads))
+ XInitThreads();
+
// Set application name and class
char *app_class = 0;
if (argv && argv[0]) {
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 2627960..2e980c1 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -12053,8 +12053,8 @@ void QWidget::ungrabGesture(Qt::GestureType gesture)
{
Q_D(QWidget);
if (d->gestureContext.remove(gesture)) {
- QGestureManager *manager = QGestureManager::instance();
- manager->cleanupCachedGestures(this, gesture);
+ if (QGestureManager *manager = QGestureManager::instance())
+ manager->cleanupCachedGestures(this, gesture);
}
}
#endif // QT_NO_GESTURES
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 0f05c6b..a2024e0 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -1634,8 +1634,6 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
}
}
-extern Q_GUI_EXPORT HDC qt_win_display_dc();
-
int QWidget::metric(PaintDeviceMetric m) const
{
Q_D(const QWidget);
@@ -1645,7 +1643,7 @@ int QWidget::metric(PaintDeviceMetric m) const
} else if (m == PdmHeight) {
val = data->crect.height();
} else {
- HDC gdc = qt_win_display_dc();
+ HDC gdc = GetDC(0);
switch (m) {
case PdmDpiX:
case PdmPhysicalDpiX:
@@ -1696,6 +1694,7 @@ int QWidget::metric(PaintDeviceMetric m) const
val = 0;
qWarning("QWidget::metric: Invalid metric command");
}
+ ReleaseDC(0, gdc);
}
return val;
}
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 1bf90e3..a845842 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -155,6 +155,10 @@ static bool qt_painter_thread_test(int devType, const char *what, bool extraCond
#endif
break;
default:
+#ifdef Q_WS_X11
+ if (QApplication::testAttribute(Qt::AA_X11InitThreads))
+ return true;
+#endif
if (!extraCondition && QThread::currentThread() != qApp->thread()) {
qWarning("QPainter: It is not safe to use %s outside the GUI thread", what);
return false;
@@ -5249,7 +5253,7 @@ void QPainter::drawPixmap(const QPointF &p, const QPixmap &pm)
return;
#ifndef QT_NO_DEBUG
- qt_painter_thread_test(d->device->devType(), "drawPixmap()");
+ qt_painter_thread_test(d->device->devType(), "drawPixmap()", true);
#endif
if (d->extended) {
@@ -5319,7 +5323,7 @@ void QPainter::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
if (!d->engine || pm.isNull())
return;
#ifndef QT_NO_DEBUG
- qt_painter_thread_test(d->device->devType(), "drawPixmap()");
+ qt_painter_thread_test(d->device->devType(), "drawPixmap()", true);
#endif
qreal x = r.x();
@@ -5726,7 +5730,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs)
int count = qMin(glyphIndexes.size(), glyphPositions.size());
QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
for (int i=0; i<count; ++i)
- fixedPointPositions[i] = QFixedPoint::fromPointF(position + glyphPositions.at(i));
+ fixedPointPositions[i] = QFixedPoint::fromPointF(position + glyphPositions.at(i));
d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count);
@@ -5735,7 +5739,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs)
void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray,
int glyphCount)
-{
+{
QVarLengthArray<QFixedPoint, 128> positions(glyphCount);
for (int i=0; i<glyphCount; ++i)
positions[i] = QFixedPoint::fromPointF(positionArray[i]);
@@ -5923,7 +5927,7 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText
// Recreate the layout of the static text because the matrix or font has changed
if (staticTextNeedsReinit)
- staticText_d->init();
+ staticText_d->init();
if (transformedPosition != staticText_d->position) { // Translate to actual position
QFixed fx = QFixed::fromReal(transformedPosition.x());
@@ -6663,7 +6667,7 @@ void QPainter::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPo
return;
#ifndef QT_NO_DEBUG
- qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()");
+ qt_painter_thread_test(d->device->devType(), "drawTiledPixmap()", true);
#endif
qreal sw = pixmap.width();
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 2d95bae..3f6b409 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -185,10 +185,6 @@ QFontEngine::QFontEngine()
QFontEngine::~QFontEngine()
{
- for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(),
- end = m_glyphCaches.constEnd(); it != end; ++it) {
- delete it->cache;
- }
m_glyphCaches.clear();
qHBFreeFace(hbFace);
}
@@ -734,14 +730,16 @@ void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data)
{
Q_ASSERT(data);
- GlyphCacheEntry entry = { key, data };
+ GlyphCacheEntry entry;
+ entry.context = key;
+ entry.cache = data;
if (m_glyphCaches.contains(entry))
return;
// Limit the glyph caches to 4. This covers all 90 degree rotations and limits
// memory use when there is continous or random rotation
if (m_glyphCaches.size() == 4)
- delete m_glyphCaches.takeLast().cache;
+ m_glyphCaches.removeLast();
m_glyphCaches.push_front(entry);
@@ -750,7 +748,7 @@ void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data)
QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const
{
for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) {
- QFontEngineGlyphCache *c = it->cache;
+ QFontEngineGlyphCache *c = it->cache.data();
if (key == it->context
&& type == c->cacheType()
&& qtransform_equals_no_translate(c->m_transform, transform)) {
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index d29ef45..4e518d6 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -262,7 +262,7 @@ protected:
private:
struct GlyphCacheEntry {
void *context;
- QFontEngineGlyphCache *cache;
+ QExplicitlySharedDataPointer<QFontEngineGlyphCache> cache;
bool operator==(const GlyphCacheEntry &other) { return context == other.context && cache == other.cache; }
};
diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp
index b7e4be2..aee21f6 100644
--- a/src/gui/text/qfontengine_x11.cpp
+++ b/src/gui/text/qfontengine_x11.cpp
@@ -992,7 +992,7 @@ QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int s
face_id.filename = file_name;
face_id.index = face_index;
- canUploadGlyphsToServer = qApp->thread() == QThread::currentThread();
+ canUploadGlyphsToServer = QApplication::testAttribute(Qt::AA_X11InitThreads) || (qApp->thread() == QThread::currentThread());
subpixelType = Subpixel_None;
if (antialias) {
diff --git a/src/gui/text/qfontengineglyphcache_p.h b/src/gui/text/qfontengineglyphcache_p.h
index 7b82b46..eba16f7 100644
--- a/src/gui/text/qfontengineglyphcache_p.h
+++ b/src/gui/text/qfontengineglyphcache_p.h
@@ -72,7 +72,7 @@
QT_BEGIN_NAMESPACE
-class QFontEngineGlyphCache
+class QFontEngineGlyphCache: public QSharedData
{
public:
enum Type {
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 7270efb..407cf7d 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -128,7 +128,7 @@ struct Q_AUTOTEST_EXPORT QScriptAnalysis
TabOrObject = Tab,
Object = 7
};
- unsigned short script : 8;
+ unsigned short script : 7;
unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61)
unsigned short flags : 3;
inline bool operator == (const QScriptAnalysis &other) const {
diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp
index 2d871d0..10ce144 100644
--- a/src/gui/widgets/qspinbox.cpp
+++ b/src/gui/widgets/qspinbox.cpp
@@ -697,6 +697,9 @@ void QDoubleSpinBox::setSuffix(const QString &suffix)
d->suffix = suffix;
d->updateEdit();
+
+ d->cachedSizeHint = QSize();
+ updateGeometry();
}
/*!
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 40b3641..4b5f53e 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -46,24 +46,29 @@
#include <QMetaEnum>
#endif
+// #define QT_GL_SHARED_SHADER_DEBUG
QT_BEGIN_NAMESPACE
-static void qt_shared_shaders_free(void *data)
+class QGLShaderStorage
{
- delete reinterpret_cast<QGLEngineSharedShaders *>(data);
-}
+public:
+ QGLEngineSharedShaders *shadersForThread(const QGLContext *context) {
+ QGLContextGroupResource<QGLEngineSharedShaders> *&shaders = m_storage.localData();
+ if (!shaders)
+ shaders = new QGLContextGroupResource<QGLEngineSharedShaders>();
+ return shaders->value(context);
+ }
+
+private:
+ QThreadStorage<QGLContextGroupResource<QGLEngineSharedShaders> *> m_storage;
+};
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_shaders, (qt_shared_shaders_free))
+Q_GLOBAL_STATIC(QGLShaderStorage, qt_shader_storage);
QGLEngineSharedShaders *QGLEngineSharedShaders::shadersForContext(const QGLContext *context)
{
- QGLEngineSharedShaders *p = reinterpret_cast<QGLEngineSharedShaders *>(qt_shared_shaders()->value(context));
- if (!p) {
- QGLShareContextScope scope(context);
- qt_shared_shaders()->insert(context, p = new QGLEngineSharedShaders(context));
- }
- return p;
+ return qt_shader_storage()->shadersForThread(context);
}
const char* QGLEngineSharedShaders::qShaderSnippets[] = {
@@ -170,18 +175,20 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
source.clear();
source.append(qShaderSnippets[MainVertexShader]);
source.append(qShaderSnippets[PositionOnlyVertexShader]);
- vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+ vertexShader = new QGLShader(QGLShader::Vertex, context, 0);
+ shaders.append(vertexShader);
if (!vertexShader->compileSourceCode(source))
qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile");
source.clear();
source.append(qShaderSnippets[MainFragmentShader]);
source.append(qShaderSnippets[ShockingPinkSrcFragmentShader]);
- fragShader = new QGLShader(QGLShader::Fragment, context, this);
+ fragShader = new QGLShader(QGLShader::Fragment, context, 0);
+ shaders.append(fragShader);
if (!fragShader->compileSourceCode(source))
qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile");
- simpleShaderProg = new QGLShaderProgram(context, this);
+ simpleShaderProg = new QGLShaderProgram(context, 0);
simpleShaderProg->addShader(vertexShader);
simpleShaderProg->addShader(fragShader);
simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
@@ -198,18 +205,20 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
source.clear();
source.append(qShaderSnippets[MainWithTexCoordsVertexShader]);
source.append(qShaderSnippets[UntransformedPositionVertexShader]);
- vertexShader = new QGLShader(QGLShader::Vertex, context, this);
+ vertexShader = new QGLShader(QGLShader::Vertex, context, 0);
+ shaders.append(vertexShader);
if (!vertexShader->compileSourceCode(source))
qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile");
source.clear();
source.append(qShaderSnippets[MainFragmentShader]);
source.append(qShaderSnippets[ImageSrcFragmentShader]);
- fragShader = new QGLShader(QGLShader::Fragment, context, this);
+ fragShader = new QGLShader(QGLShader::Fragment, context, 0);
+ shaders.append(fragShader);
if (!fragShader->compileSourceCode(source))
qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile");
- blitShaderProg = new QGLShaderProgram(context, this);
+ blitShaderProg = new QGLShaderProgram(context, 0);
blitShaderProg->addShader(vertexShader);
blitShaderProg->addShader(fragShader);
blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
@@ -220,13 +229,21 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
<< simpleShaderProg->log();
}
+#ifdef QT_GL_SHARED_SHADER_DEBUG
+ qDebug(" -> QGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread());
+#endif
}
QGLEngineSharedShaders::~QGLEngineSharedShaders()
{
- QList<QGLEngineShaderProg*>::iterator itr;
- for (itr = cachedPrograms.begin(); itr != cachedPrograms.end(); ++itr)
- delete *itr;
+#ifdef QT_GL_SHARED_SHADER_DEBUG
+ qDebug(" -> ~QGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread());
+#endif
+ qDeleteAll(shaders);
+ shaders.clear();
+
+ qDeleteAll(cachedPrograms);
+ cachedPrograms.clear();
if (blitShaderProg) {
delete blitShaderProg;
@@ -276,7 +293,8 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
source.append(qShaderSnippets[prog.compositionFragShader]);
if (prog.maskFragShader)
source.append(qShaderSnippets[prog.maskFragShader]);
- fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), this);
+ fragShader = new QGLShader(QGLShader::Fragment, ctxGuard.context(), 0);
+ shaders.append(fragShader);
QByteArray description;
#if defined(QT_DEBUG)
// Name the shader for easier debugging
@@ -302,7 +320,8 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
source.clear();
source.append(qShaderSnippets[prog.mainVertexShader]);
source.append(qShaderSnippets[prog.positionVertexShader]);
- vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), this);
+ vertexShader = new QGLShader(QGLShader::Vertex, ctxGuard.context(), 0);
+ shaders.append(vertexShader);
#if defined(QT_DEBUG)
// Name the shader for easier debugging
description.clear();
@@ -320,7 +339,7 @@ QGLEngineShaderProg *QGLEngineSharedShaders::findProgramInCache(const QGLEngineS
newProg = new QGLEngineShaderProg(prog);
// If the shader program's not found in the cache, create it now.
- newProg->program = new QGLShaderProgram(ctxGuard.context(), this);
+ newProg->program = new QGLShaderProgram(ctxGuard.context(), 0);
newProg->program->addShader(vertexShader);
newProg->program->addShader(fragShader);
@@ -413,7 +432,6 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
currentShaderProg(0)
{
sharedShaders = QGLEngineSharedShaders::shadersForContext(context);
- connect(sharedShaders, SIGNAL(shaderProgNeedsChanging()), this, SLOT(shaderProgNeedsChangingSlot()));
}
QGLEngineShaderManager::~QGLEngineShaderManager()
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 06b96ae..e5ababf 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -259,9 +259,9 @@ static const GLuint QT_PMV_MATRIX_3_ATTR = 5;
class QGLEngineShaderProg;
-class QGLEngineSharedShaders : public QObject
+class QGLEngineSharedShaders
{
- Q_OBJECT
+ Q_GADGET
public:
enum SnippetName {
@@ -364,14 +364,12 @@ public:
// full.
void cleanupCustomStage(QGLCustomShaderStage* stage);
-signals:
- void shaderProgNeedsChanging();
-
private:
QGLSharedResourceGuard ctxGuard;
QGLShaderProgram *blitShaderProg;
QGLShaderProgram *simpleShaderProg;
QList<QGLEngineShaderProg*> cachedPrograms;
+ QList<QGLShader *> shaders;
static const char* qShaderSnippets[TotalSnippetCount];
};
@@ -492,9 +490,6 @@ public:
QGLEngineSharedShaders* sharedShaders;
-private slots:
- void shaderProgNeedsChangingSlot() { shaderProgNeedsChanging = true; }
-
private:
QGLContext* ctx;
bool shaderProgNeedsChanging;
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index a1495dd..cbd5eb8 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -42,29 +42,33 @@
#include "qglgradientcache_p.h"
#include <private/qdrawhelper_p.h>
#include <private/qgl_p.h>
-
+#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
-static void QGL2GradientCache_free(void *ptr)
+class QGL2GradientCacheWrapper
{
- delete reinterpret_cast<QGL2GradientCache *>(ptr);
-}
+public:
+ QGL2GradientCache *cacheForContext(const QGLContext *context) {
+ QMutexLocker lock(&m_mutex);
+ return m_resource.value(context);
+ }
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free))
+private:
+ QGLContextGroupResource<QGL2GradientCache> m_resource;
+ QMutex m_mutex;
+};
+
+Q_GLOBAL_STATIC(QGL2GradientCacheWrapper, qt_gradient_caches)
QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
{
- QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context));
- if (!p) {
- QGLShareContextScope scope(context);
- p = new QGL2GradientCache;
- qt_gradient_caches()->insert(context, p);
- }
- return p;
+ return qt_gradient_caches()->cacheForContext(context);
}
-void QGL2GradientCache::cleanCache() {
+void QGL2GradientCache::cleanCache()
+{
+ QMutexLocker lock(&m_mutex);
QGLGradientColorTableHash::const_iterator it = cache.constBegin();
for (; it != cache.constEnd(); ++it) {
const CacheInfo &cache_info = it.value();
@@ -75,6 +79,7 @@ void QGL2GradientCache::cleanCache() {
GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
{
+ QMutexLocker lock(&m_mutex);
quint64 hash_val = 0;
QGradientStops stops = gradient.stops();
@@ -88,7 +93,9 @@ GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
else {
do {
const CacheInfo &cache_info = it.value();
- if (cache_info.stops == stops && cache_info.opacity == opacity && cache_info.interpolationMode == gradient.interpolationMode()) {
+ if (cache_info.stops == stops && cache_info.opacity == opacity
+ && cache_info.interpolationMode == gradient.interpolationMode())
+ {
return cache_info.texId;
}
++it;
diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h
index 0a5f846..7e93d87 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache_p.h
+++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h
@@ -54,6 +54,7 @@
#include <QObject>
#include <QtOpenGL/QtOpenGL>
#include <private/qgl_p.h>
+#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
@@ -75,22 +76,22 @@ class QGL2GradientCache
public:
static QGL2GradientCache *cacheForContext(const QGLContext *context);
- QGL2GradientCache() { }
- ~QGL2GradientCache() {cleanCache();}
+ QGL2GradientCache(const QGLContext *) {}
+ ~QGL2GradientCache() { cleanCache(); }
GLuint getBuffer(const QGradient &gradient, qreal opacity);
inline int paletteSize() const { return 1024; }
-protected:
+private:
inline int maxCacheSize() const { return 60; }
inline void generateGradientColorTable(const QGradient& gradient,
uint *colorTable,
int size, qreal opacity) const;
GLuint addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity);
-
void cleanCache();
QGLGradientColorTableHash cache;
+ QMutex m_mutex;
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 634b315..756180f 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1453,11 +1453,12 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type glyp
QOpenGL2PaintEngineState *s = q->state();
+ void *cacheKey = const_cast<QGLContext *>(QGLContextPrivate::contextGroup(ctx)->context());
QGLTextureGlyphCache *cache =
- (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(ctx, glyphType, QTransform());
+ (QGLTextureGlyphCache *) staticTextItem->fontEngine->glyphCache(cacheKey, glyphType, QTransform());
if (!cache || cache->cacheType() != glyphType) {
cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform());
- staticTextItem->fontEngine->setGlyphCache(ctx, cache);
+ staticTextItem->fontEngine->setGlyphCache(cacheKey, cache);
}
cache->setPaintEnginePrivate(this);
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
index faf4563..9ce5d55 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
@@ -56,53 +56,24 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(const QGLContext *context, QFontEngin
: QImageTextureGlyphCache(type, matrix)
, ctx(0)
, pex(0)
- , m_width(0)
- , m_height(0)
{
- if (context != 0)
- setContext(context);
+#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
+ qDebug(" -> QGLTextureGlyphCache() %p for context %p.", this, ctx);
+#endif
+ setContext(context);
}
QGLTextureGlyphCache::~QGLTextureGlyphCache()
{
- cleanUpContext();
-}
-
-void QGLTextureGlyphCache::cleanUpContext()
-{
- if (ctx) {
- QGLShareContextScope scope(ctx);
-
- if (!ctx->d_ptr->workaround_brokenFBOReadBack && pex != 0)
- glDeleteFramebuffers(1, &m_fbo);
-
- if (m_width || m_height) {
- glDeleteTextures(1, &m_texture);
- m_width = 0;
- m_height = 0;
- m_h = 0;
- }
-
- ctx = 0;
- }
+#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
+ qDebug(" -> ~QGLTextureGlyphCache() %p.", this);
+#endif
}
void QGLTextureGlyphCache::setContext(const QGLContext *context)
{
- cleanUpContext();
-
ctx = context;
-
- // broken FBO readback is a bug in the SGX 1.3 and 1.4 drivers for the N900 where
- // copying between FBO's is broken if the texture is either GL_ALPHA or POT. The
- // workaround is to use a system-memory copy of the glyph cache for this device.
- // Switching to NPOT and GL_RGBA would both cost a lot more graphics memory and
- // be slower, so that is not desireable.
- if (!ctx->d_ptr->workaround_brokenFBOReadBack && pex != 0)
- glGenFramebuffers(1, &m_fbo);
-
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
- SLOT(contextDestroyed(const QGLContext*)));
+ m_h = 0;
}
void QGLTextureGlyphCache::createTextureData(int width, int height)
@@ -124,11 +95,12 @@ void QGLTextureGlyphCache::createTextureData(int width, int height)
if (height < 16)
height = 16;
- glGenTextures(1, &m_texture);
- glBindTexture(GL_TEXTURE_2D, m_texture);
+ QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
+ glGenTextures(1, &glyphTexture->m_texture);
+ glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
- m_width = width;
- m_height = height;
+ glyphTexture->m_width = width;
+ glyphTexture->m_height = height;
QVarLengthArray<uchar> data(width * height);
for (int i = 0; i < data.size(); ++i)
@@ -149,9 +121,10 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
qWarning("QGLTextureGlyphCache::resizeTextureData: Called with no context");
return;
}
+ QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
- int oldWidth = m_width;
- int oldHeight = m_height;
+ int oldWidth = glyphTexture->m_width;
+ int oldHeight = glyphTexture->m_height;
// Make the lower glyph texture size 16 x 16.
if (width < 16)
@@ -159,9 +132,9 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
if (height < 16)
height = 16;
- GLuint oldTexture = m_texture;
+ GLuint oldTexture = glyphTexture->m_texture;
createTextureData(width, height);
-
+
if (pex == 0 || ctx->d_ptr->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::resizeTextureData(width, height);
Q_ASSERT(image().depth() == 8);
@@ -173,7 +146,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
// ### the QTextureGlyphCache API needs to be reworked to allow
// ### resizeTextureData to fail
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, glyphTexture->m_fbo);
GLuint tmp_texture;
glGenTextures(1, &tmp_texture);
@@ -228,7 +201,7 @@ void QGLTextureGlyphCache::resizeTextureData(int width, int height)
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glBindTexture(GL_TEXTURE_2D, m_texture);
+ glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
@@ -250,10 +223,11 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
return;
}
+ QGLGlyphTexture *glyphTexture = m_textureResource.value(ctx);
if (pex == 0 || ctx->d_ptr->workaround_brokenFBOReadBack) {
QImageTextureGlyphCache::fillTexture(c, glyph);
- glBindTexture(GL_TEXTURE_2D, m_texture);
+ glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
const QImage &texture = image();
const uchar *bits = texture.constBits();
bits += c.y * texture.bytesPerLine() + c.x;
@@ -261,7 +235,6 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, c.w, 1, GL_ALPHA, GL_UNSIGNED_BYTE, bits);
bits += texture.bytesPerLine();
}
-
return;
}
@@ -291,7 +264,7 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
}
}
- glBindTexture(GL_TEXTURE_2D, m_texture);
+ glBindTexture(GL_TEXTURE_2D, glyphTexture->m_texture);
if (mask.format() == QImage::Format_RGB32) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
} else {
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
index d291ac3..66aed91 100644
--- a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
@@ -57,14 +57,49 @@
#include <private/qgl_p.h>
#include <qglshaderprogram.h>
+// #define QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
QT_BEGIN_NAMESPACE
class QGL2PaintEngineExPrivate;
-class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QObject, public QImageTextureGlyphCache
+struct QGLGlyphTexture
+{
+ QGLGlyphTexture(const QGLContext *ctx)
+ : m_width(0)
+ , m_height(0)
+ {
+ if (ctx && !ctx->d_ptr->workaround_brokenFBOReadBack)
+ glGenFramebuffers(1, &m_fbo);
+
+#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
+ qDebug(" -> QGLGlyphTexture() %p for context %p.", this, ctx);
+#endif
+ }
+
+ ~QGLGlyphTexture() {
+ const QGLContext *ctx = QGLContext::currentContext();
+#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG
+ qDebug("~QGLGlyphTexture() %p for context %p.", this, ctx);
+#endif
+ // At this point, the context group is made current, so it's safe to
+ // release resources without a makeCurrent() call
+ if (ctx) {
+ if (!ctx->d_ptr->workaround_brokenFBOReadBack)
+ glDeleteFramebuffers(1, &m_fbo);
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+ }
+ }
+
+ GLuint m_texture;
+ GLuint m_fbo;
+ int m_width;
+ int m_height;
+};
+
+class Q_OPENGL_EXPORT QGLTextureGlyphCache : public QImageTextureGlyphCache
{
- Q_OBJECT
public:
QGLTextureGlyphCache(const QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
~QGLTextureGlyphCache();
@@ -75,56 +110,33 @@ public:
virtual int glyphMargin() const;
virtual int glyphPadding() const;
- inline GLuint texture() const { return m_texture; }
+ inline GLuint texture() const {
+ QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
+ QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
+ return glyphTexture ? glyphTexture->m_texture : 0;
+ }
- inline int width() const { return m_width; }
- inline int height() const { return m_height; }
+ inline int width() const {
+ QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
+ QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
+ return glyphTexture ? glyphTexture->m_width : 0;
+ }
+ inline int height() const {
+ QGLTextureGlyphCache *that = const_cast<QGLTextureGlyphCache *>(this);
+ QGLGlyphTexture *glyphTexture = that->m_textureResource.value(ctx);
+ return glyphTexture ? glyphTexture->m_height : 0;
+ }
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
void setContext(const QGLContext *context);
- inline const QGLContext *context() const
- {
- return ctx;
- }
-
-
-
-public Q_SLOTS:
- void contextDestroyed(const QGLContext *context) {
- if (context == ctx) {
- const QGLContext *nextCtx = qt_gl_transfer_context(ctx);
- if (!nextCtx) {
- // the context may not be current, so we cannot directly
- // destroy the fbo and texture here, but since the context
- // is about to be destroyed, the GL server will do the
- // clean up for us anyway
- m_fbo = 0;
- m_texture = 0;
- ctx = 0;
- } else {
- // since the context holding the texture is shared, and
- // about to be destroyed, we have to transfer ownership
- // of the texture to one of the share contexts
- ctx = const_cast<QGLContext *>(nextCtx);
- }
- }
- }
+ inline const QGLContext *context() const { return ctx; }
private:
- void cleanUpContext();
+ QGLContextGroupResource<QGLGlyphTexture> m_textureResource;
const QGLContext *ctx;
-
QGL2PaintEngineExPrivate *pex;
-
- GLuint m_texture;
- GLuint m_fbo;
-
- int m_width;
- int m_height;
-
- QGLShaderProgram *m_program;
};
QT_END_NAMESPACE
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 9effb34..05dae60 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -94,6 +94,8 @@
#include <qmutex.h>
+// #define QT_GL_CONTEXT_RESOURCE_DEBUG
+
QT_BEGIN_NAMESPACE
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
@@ -1653,6 +1655,7 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
#if defined(Q_WS_WIN)
dc = 0;
win = 0;
+ threadId = 0;
pixelFormatId = 0;
cmap = 0;
hbitmap = 0;
@@ -2054,6 +2057,9 @@ QGLContext::~QGLContext()
// remove any textures cached in this context
QGLTextureCache::instance()->removeContextTextures(this);
+ // clean up resources specific to this context
+ d_ptr->cleanup();
+ // clean up resources belonging to this context's group
d_ptr->group->cleanupResources(this);
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
@@ -2062,6 +2068,10 @@ QGLContext::~QGLContext()
void QGLContextPrivate::cleanup()
{
+ QHash<QGLContextResourceBase *, void *>::ConstIterator it;
+ for (it = m_resources.begin(); it != m_resources.end(); ++it)
+ it.key()->freeResource(it.value());
+ m_resources.clear();
}
#define ctx q_ptr
@@ -2114,20 +2124,10 @@ void QGLContextPrivate::syncGlState()
GLuint QGLContext::bindTexture(const QString &fileName)
{
- Q_D(QGLContext);
- QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
- QGLDDSCache::const_iterator it = dds_cache->constFind(fileName);
- if (it != dds_cache->constEnd()) {
- glBindTexture(GL_TEXTURE_2D, it.value());
- return it.value();
- }
-
QGLTexture texture(this);
QSize size = texture.bindCompressedTexture(fileName);
if (!size.isValid())
return 0;
-
- dds_cache->insert(fileName, texture.id);
return texture.id;
}
@@ -2547,7 +2547,8 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
const QX11Info *xinfo = qt_x11Info(paintDevice);
if (pd->classId() == QPixmapData::X11Class && pd->pixelType() == QPixmapData::PixmapType
&& xinfo && xinfo->screen() == pixmap.x11Info().screen()
- && target == GL_TEXTURE_2D)
+ && target == GL_TEXTURE_2D
+ && QApplication::instance()->thread() == QThread::currentThread())
{
texture = bindTextureFromNativePixmap(const_cast<QPixmap*>(&pixmap), key, options);
if (texture) {
@@ -2752,24 +2753,8 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q
*/
void QGLContext::deleteTexture(GLuint id)
{
- Q_D(QGLContext);
-
if (QGLTextureCache::instance()->remove(this, id))
return;
-
- // check the DDS cache if the texture wasn't found in the pixmap/image
- // cache
- QGLDDSCache *dds_cache = &(d->group->m_dds_cache);
- QList<QString> ddsKeys = dds_cache->keys();
- for (int i = 0; i < ddsKeys.size(); ++i) {
- GLuint texture = dds_cache->value(ddsKeys.at(i));
- if (id == texture) {
- dds_cache->remove(ddsKeys.at(i));
- break;
- }
- }
-
- // Finally, actually delete the texture ID
glDeleteTextures(1, &id);
}
@@ -4087,13 +4072,7 @@ bool QGLWidget::event(QEvent *e)
}
#if defined(Q_WS_X11)
- // prevents X errors on some systems, where we get a flush to a
- // hidden widget
- if (e->type() == QEvent::Hide) {
- makeCurrent();
- glFinish();
- doneCurrent();
- } else if (e->type() == QEvent::ParentChange) {
+ if (e->type() == QEvent::ParentChange) {
// if we've reparented a window that has the current context
// bound, we need to rebind that context to the new window id
if (d->glcx == QGLContext::currentContext())
@@ -5060,24 +5039,24 @@ void QGLWidget::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QM
#endif
#ifndef QT_OPENGL_ES_1
-Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_gl_2_engine)
+Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_gl_2_engine)
#endif
#ifndef QT_OPENGL_ES_2
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_gl_engine)
+Q_GLOBAL_STATIC(QGLEngineThreadStorage<QOpenGLPaintEngine>, qt_gl_engine)
#endif
Q_OPENGL_EXPORT QPaintEngine* qt_qgl_paint_engine()
{
#if defined(QT_OPENGL_ES_1)
- return qt_gl_engine();
+ return qt_gl_engine()->engine();
#elif defined(QT_OPENGL_ES_2)
- return qt_gl_2_engine();
+ return qt_gl_2_engine()->engine();
#else
if (qt_gl_preferGL2Engine())
- return qt_gl_2_engine();
+ return qt_gl_2_engine()->engine();
else
- return qt_gl_engine();
+ return qt_gl_engine()->engine();
#endif
}
@@ -5340,13 +5319,23 @@ void QGLContextGroup::removeShare(const QGLContext *context) {
group->m_shares.clear();
}
-QGLContextResource::QGLContextResource(FreeFunc f)
- : free(f), active(0)
+QGLContextGroupResourceBase::QGLContextGroupResourceBase()
+ : active(0)
{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Creating context group resource object %p.", this);
+#endif
}
-QGLContextResource::~QGLContextResource()
+QGLContextGroupResourceBase::~QGLContextGroupResourceBase()
{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Deleting context group resource %p. Group size: %d.", this, m_groups.size());
+#endif
+ for (int i = 0; i < m_groups.size(); ++i) {
+ m_groups.at(i)->m_resources.remove(this);
+ active.deref();
+ }
#ifndef QT_NO_DEBUG
if (active != 0) {
qWarning("QtOpenGL: Resources are still available at program shutdown.\n"
@@ -5356,37 +5345,47 @@ QGLContextResource::~QGLContextResource()
#endif
}
-void QGLContextResource::insert(const QGLContext *key, void *value)
+void QGLContextGroupResourceBase::insert(const QGLContext *context, void *value)
{
- QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Inserting context group resource %p for context %p, managed by %p.", value, context, this);
+#endif
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(context);
Q_ASSERT(!group->m_resources.contains(this));
group->m_resources.insert(this, value);
+ m_groups.append(group);
active.ref();
}
-void *QGLContextResource::value(const QGLContext *key)
+void *QGLContextGroupResourceBase::value(const QGLContext *context)
{
- QGLContextGroup *group = QGLContextPrivate::contextGroup(key);
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(context);
return group->m_resources.value(this, 0);
}
-void QGLContextResource::cleanup(const QGLContext *ctx, void *value)
+void QGLContextGroupResourceBase::cleanup(const QGLContext *ctx, void *value)
{
+#ifdef QT_GL_CONTEXT_RESOURCE_DEBUG
+ qDebug("Cleaning up context group resource %p, for context %p in thread %p.", this, ctx, QThread::currentThread());
+#endif
QGLShareContextScope scope(ctx);
- free(value);
+ freeResource(value);
active.deref();
+
+ QGLContextGroup *group = QGLContextPrivate::contextGroup(ctx);
+ m_groups.removeOne(group);
}
-void QGLContextGroup::cleanupResources(const QGLContext *ctx)
+void QGLContextGroup::cleanupResources(const QGLContext *context)
{
// If there are still shares, then no cleanup to be done yet.
if (m_shares.size() > 1)
return;
// Iterate over all resources and free each in turn.
- QHash<QGLContextResource *, void *>::ConstIterator it;
+ QHash<QGLContextGroupResourceBase *, void *>::ConstIterator it;
for (it = m_resources.begin(); it != m_resources.end(); ++it)
- it.key()->cleanup(ctx, it.value());
+ it.key()->cleanup(context, it.value());
}
QGLSharedResourceGuard::~QGLSharedResourceGuard()
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index f85cad5..9315ac4 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -424,6 +424,7 @@ private:
friend class QGLPixmapData;
friend class QGLPixmapFilterBase;
friend class QGLTextureGlyphCache;
+ friend struct QGLGlyphTexture;
friend class QGLContextGroup;
friend class QGLSharedResourceGuard;
friend class QGLPixmapBlurFilter;
@@ -443,6 +444,7 @@ private:
friend class QGLWidgetGLPaintDevice;
friend class QX11GLPixmapData;
friend class QX11GLSharedContexts;
+ friend class QGLContextResourceBase;
private:
Q_DISABLE_COPY(QGLContext)
};
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index cd5dbbe..dfbc926 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -210,11 +210,9 @@ public:
#endif
};
-class QGLContextResource;
+class QGLContextGroupResourceBase;
class QGLSharedResourceGuard;
-typedef QHash<QString, GLuint> QGLDDSCache;
-
// QGLContextPrivate has the responsibility of creating context groups.
// QGLContextPrivate maintains the reference counter and destroys
// context groups when needed.
@@ -233,22 +231,22 @@ public:
static void addShare(const QGLContext *context, const QGLContext *share);
static void removeShare(const QGLContext *context);
+
private:
QGLContextGroup(const QGLContext *context);
QGLExtensionFuncs m_extensionFuncs;
const QGLContext *m_context; // context group's representative
QList<const QGLContext *> m_shares;
- QHash<QGLContextResource *, void *> m_resources;
+ QHash<QGLContextGroupResourceBase *, void *> m_resources;
QGLSharedResourceGuard *m_guards; // double-linked list of active guards.
QAtomicInt m_refs;
- QGLDDSCache m_dds_cache;
void cleanupResources(const QGLContext *ctx);
friend class QGLContext;
friend class QGLContextPrivate;
- friend class QGLContextResource;
+ friend class QGLContextGroupResourceBase;
};
// Get the context that resources for "ctx" will transfer to once
@@ -313,6 +311,8 @@ class QGLTexture;
// all the GL2 engine uses:
#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
+class QGLContextResourceBase;
+
class QGLContextPrivate
{
Q_DECLARE_PUBLIC(QGLContext)
@@ -347,6 +347,7 @@ public:
QGLCmap* cmap;
HBITMAP hbitmap;
HDC hbitmap_hdc;
+ Qt::HANDLE threadId;
#endif
#ifndef QT_NO_EGL
uint ownsEglContext : 1;
@@ -404,6 +405,7 @@ public:
GLuint current_fbo;
GLuint default_fbo;
QPaintEngine *active_engine;
+ QHash<QGLContextResourceBase *, void *> m_resources;
bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
@@ -612,24 +614,130 @@ inline GLenum qt_gl_preferredTextureTarget()
#endif
}
-// One resource per group of shared contexts.
-class Q_OPENGL_EXPORT QGLContextResource
+/*
+ Base for resources that are shared in a context group.
+*/
+class Q_OPENGL_EXPORT QGLContextGroupResourceBase
{
public:
- typedef void (*FreeFunc)(void *);
- QGLContextResource(FreeFunc f);
- ~QGLContextResource();
- // Set resource 'value' for 'key' and all its shared contexts.
- void insert(const QGLContext *key, void *value);
- // Return resource for 'key' or a shared context.
- void *value(const QGLContext *key);
- // Cleanup 'value' in response to a context group being destroyed.
- void cleanup(const QGLContext *ctx, void *value);
+ QGLContextGroupResourceBase();
+ virtual ~QGLContextGroupResourceBase();
+ void insert(const QGLContext *context, void *value);
+ void *value(const QGLContext *context);
+ void cleanup(const QGLContext *context, void *value);
+ virtual void freeResource(void *value) = 0;
+
+protected:
+ QList<QGLContextGroup *> m_groups;
+
private:
- FreeFunc free;
QAtomicInt active;
};
+/*
+ The QGLContextGroupResource template is used to manage a resource
+ for a group of sharing GL contexts. When the last context in the
+ group is destroyed, or when the QGLContextGroupResource object
+ itself is destroyed (implies potential context switches), the
+ resource will be freed.
+
+ The class used as the template class type needs to have a
+ constructor with the following signature:
+ T(const QGLContext *);
+*/
+template <class T>
+class QGLContextGroupResource : public QGLContextGroupResourceBase
+{
+public:
+ ~QGLContextGroupResource() {
+ for (int i = 0; i < m_groups.size(); ++i) {
+ const QGLContext *context = m_groups.at(i)->context();
+ T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
+ if (resource) {
+ QGLShareContextScope scope(context);
+ delete resource;
+ }
+ }
+ }
+
+ T *value(const QGLContext *context) {
+ T *resource = reinterpret_cast<T *>(QGLContextGroupResourceBase::value(context));
+ if (!resource) {
+ resource = new T(context);
+ insert(context, resource);
+ }
+ return resource;
+ }
+
+protected:
+ void freeResource(void *resource) {
+ delete reinterpret_cast<T *>(resource);
+ }
+};
+
+/*
+ Base for resources that are context specific.
+*/
+class Q_OPENGL_EXPORT QGLContextResourceBase
+{
+public:
+ virtual ~QGLContextResourceBase() {
+ for (int i = 0; i < m_contexts.size(); ++i)
+ m_contexts.at(i)->d_ptr->m_resources.remove(this);
+ }
+
+ void insert(const QGLContext *context, void *value) {
+ context->d_ptr->m_resources.insert(this, value);
+ }
+
+ void *value(const QGLContext *context) {
+ return context->d_ptr->m_resources.value(this, 0);
+ }
+ virtual void freeResource(void *value) = 0;
+
+protected:
+ QList<const QGLContext *> m_contexts;
+};
+
+/*
+ The QGLContextResource template is used to manage a resource for a
+ single GL context. Just before the context is destroyed (while it's
+ still the current context), or when the QGLContextResource object
+ itself is destroyed (implies potential context switches), the
+ resource will be freed. The class used as the template class type
+ needs to have a constructor with the following signature: T(const
+ QGLContext *);
+*/
+template <class T>
+class QGLContextResource : public QGLContextResourceBase
+{
+public:
+ ~QGLContextResource() {
+ for (int i = 0; i < m_contexts.size(); ++i) {
+ const QGLContext *context = m_contexts.at(i);
+ T *resource = reinterpret_cast<T *>(QGLContextResourceBase::value(context));
+ if (resource) {
+ QGLShareContextScope scope(context);
+ delete resource;
+ }
+ }
+ }
+
+ T *value(const QGLContext *context) {
+ T *resource = reinterpret_cast<T *>(QGLContextResourceBase::value(context));
+ if (!resource) {
+ resource = new T(context);
+ insert(context, resource);
+ }
+ return resource;
+ }
+
+protected:
+ void freeResource(void *resource) {
+ delete reinterpret_cast<T *>(resource);
+ }
+};
+
// Put a guard around a GL object identifier and its context.
// When the context goes away, a shared context will be used
// in its place. If there are no more shared contexts, then
@@ -719,6 +827,24 @@ private:
int gl_extensions_length;
};
+
+// this is a class that wraps a QThreadStorage object for storing
+// thread local instances of the GL 1 and GL 2 paint engines
+
+template <class T>
+class QGLEngineThreadStorage
+{
+public:
+ QPaintEngine *engine() {
+ QPaintEngine *&localEngine = storage.localData();
+ if (!localEngine)
+ localEngine = new T;
+ return localEngine;
+ }
+
+private:
+ QThreadStorage<QPaintEngine *> storage;
+};
QT_END_NAMESPACE
#endif // QGL_P_H
diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp
index 5ab944a..3f13ac4 100644
--- a/src/opengl/qgl_win.cpp
+++ b/src/opengl/qgl_win.cpp
@@ -1261,6 +1261,7 @@ void QGLContext::reset()
}
d->dc = 0;
d->win = 0;
+ d->threadId = 0;
d->pixelFormatId = 0;
d->sharing = false;
d->valid = false;
@@ -1283,8 +1284,9 @@ void QGLContext::makeCurrent()
if (d->rc == wglGetCurrentContext() || !d->valid) // already current
return;
- if (d->win) {
+ if (d->win && (!d->dc || d->threadId != QThread::currentThreadId())) {
d->dc = GetDC(d->win);
+ d->threadId = QThread::currentThreadId();
if (!d->dc) {
qwglError("QGLContext::makeCurrent()", "GetDC()");
return;
@@ -1322,6 +1324,7 @@ void QGLContext::doneCurrent()
if (d->win && d->dc) {
ReleaseDC(d->win, d->dc);
d->dc = 0;
+ d->threadId = 0;
}
}
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index deffc20..fe60e83 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -984,11 +984,11 @@ QImage QGLFramebufferObject::toImage() const
}
#if !defined(QT_OPENGL_ES_1)
-Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
+Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
#endif
#ifndef QT_OPENGL_ES_2
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
+Q_GLOBAL_STATIC(QGLEngineThreadStorage<QOpenGLPaintEngine>, qt_buffer_engine)
#endif
/*! \reimp */
@@ -1002,7 +1002,7 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const
#if !defined (QT_OPENGL_ES_2)
if (qt_gl_preferGL2Engine()) {
#endif
- QPaintEngine *engine = qt_buffer_2_engine();
+ QPaintEngine *engine = qt_buffer_2_engine()->engine();
if (engine->isActive() && engine->paintDevice() != this) {
d->engine = new QGL2PaintEngineEx;
return d->engine;
@@ -1014,7 +1014,7 @@ QPaintEngine *QGLFramebufferObject::paintEngine() const
#endif
#if !defined(QT_OPENGL_ES_2)
- QPaintEngine *engine = qt_buffer_engine();
+ QPaintEngine *engine = qt_buffer_engine()->engine();
if (engine->isActive() && engine->paintDevice() != this) {
d->engine = new QOpenGLPaintEngine;
return d->engine;
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 9a8b243..3d9cd21 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -388,25 +388,25 @@ bool QGLPixelBuffer::isValid() const
}
#if !defined(QT_OPENGL_ES_1)
-Q_GLOBAL_STATIC(QGL2PaintEngineEx, qt_buffer_2_engine)
+Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
#endif
#ifndef QT_OPENGL_ES_2
-Q_GLOBAL_STATIC(QOpenGLPaintEngine, qt_buffer_engine)
+Q_GLOBAL_STATIC(QGLEngineThreadStorage<QOpenGLPaintEngine>, qt_buffer_engine)
#endif
/*! \reimp */
QPaintEngine *QGLPixelBuffer::paintEngine() const
{
#if defined(QT_OPENGL_ES_1)
- return qt_buffer_engine();
+ return qt_buffer_engine()->engine();
#elif defined(QT_OPENGL_ES_2)
- return qt_buffer_2_engine();
+ return qt_buffer_2_engine()->engine();
#else
if (qt_gl_preferGL2Engine())
- return qt_buffer_2_engine();
+ return qt_buffer_2_engine()->engine();
else
- return qt_buffer_engine();
+ return qt_buffer_engine()->engine();
#endif
}
diff --git a/src/opengl/qglpixelbuffer_win.cpp b/src/opengl/qglpixelbuffer_win.cpp
index 8d0d105..df83566 100644
--- a/src/opengl/qglpixelbuffer_win.cpp
+++ b/src/opengl/qglpixelbuffer_win.cpp
@@ -239,8 +239,7 @@ static void qt_format_to_attrib_list(bool has_render_texture, const QGLFormat &f
bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidget *shareWidget)
{
- QGLWidget dmy;
- dmy.makeCurrent(); // needed for wglGetProcAddress() to succeed
+ QGLTemporaryContext tempContext;
PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB =
(PFNWGLCREATEPBUFFERARBPROC) wglGetProcAddress("wglCreatePbufferARB");
@@ -254,7 +253,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
if (!wglCreatePbufferARB) // assumes that if one can be resolved, all of them can
return false;
- dc = GetDC(dmy.winId());
+ dc = wglGetCurrentDC();
Q_ASSERT(dc);
PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB =
@@ -284,7 +283,6 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
if (num_formats == 0) {
qWarning("QGLPixelBuffer: Unable to find a pixel format with pbuffer - giving up.");
- ReleaseDC(dmy.winId(), dc);
return false;
}
format = pfiToQGLFormat(dc, pixel_format);
@@ -303,12 +301,10 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge
has_render_texture = false;
if (!pbuf) {
qWarning("QGLPixelBuffer: Unable to create pbuffer [w=%d, h=%d] - giving up.", size.width(), size.height());
- ReleaseDC(dmy.winId(), dc);
return false;
}
}
- ReleaseDC(dmy.winId(), dc);
dc = wglGetPbufferDCARB(pbuf);
ctx = wglCreateContext(dc);
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index bfa5ef1..68586c1 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -315,7 +315,7 @@ class QGLBlurTextureCache : public QObject
public:
static QGLBlurTextureCache *cacheForContext(const QGLContext *context);
- QGLBlurTextureCache();
+ QGLBlurTextureCache(const QGLContext *);
~QGLBlurTextureCache();
QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap);
@@ -336,15 +336,9 @@ private:
};
QList<QGLBlurTextureCache *> QGLBlurTextureCache::blurTextureCaches;
+Q_GLOBAL_STATIC(QGLContextGroupResource<QGLBlurTextureCache>, qt_blur_texture_caches)
-static void QGLBlurTextureCache_free(void *ptr)
-{
- delete reinterpret_cast<QGLBlurTextureCache *>(ptr);
-}
-
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free))
-
-QGLBlurTextureCache::QGLBlurTextureCache()
+QGLBlurTextureCache::QGLBlurTextureCache(const QGLContext *)
: timerId(0)
{
cache.setMaxCost(4 * 1024 * 1024);
@@ -366,12 +360,7 @@ void QGLBlurTextureCache::timerEvent(QTimerEvent *)
QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context)
{
- QGLBlurTextureCache *p = reinterpret_cast<QGLBlurTextureCache *>(qt_blur_texture_caches()->value(context));
- if (!p) {
- p = new QGLBlurTextureCache;
- qt_blur_texture_caches()->insert(context, p);
- }
- return p;
+ return qt_blur_texture_caches()->value(context);
}
QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap)
diff --git a/src/plugins/gfxdrivers/eglnullws/README b/src/plugins/gfxdrivers/eglnullws/README
new file mode 100644
index 0000000..80b88c7
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/README
@@ -0,0 +1,48 @@
+EGL NullWS QScreen Driver
+=========================
+
+If your application draws everything within a single full-screen QGLWidget then
+you may wish to use this QScreen plugin driver. This driver simply returns 0
+(as a EGLNativeWindowType value) when asked by the QtOpenGl module to create a
+native window. Some OpenGL ES implementations (including PowerVR) interpret this
+to mean that a full-screen OpenGL context is desired without any windowing
+support (NullWS).
+
+To tell a Qt/Embedded application to use this driver use the -display command
+line option or the QWS_DISPLAY environment variable. The following driver
+options are supported:
+
+size=WIDTHxHEIGHT Screen size reported by the driver
+format=FORMAT Screen format
+
+Run with '-display eglnullws:help' to get a full list of options (including a
+list of supported format strings).
+
+If you choose a screen format that is not supported by the hardware then the
+QtOpenGl module will write out a list of supported EGL configurations. Use
+one of the supported screen formats from this list.
+
+Using this driver with PowerVR hardware
+---------------------------------------
+
+Using this plugin with PowerVR hardware should give a significant speedup
+compared to running with the Qt powervr driver (with a full-screen QGLWidget).
+This is because sacrificing the window system allows less work to be done in
+order to get graphics on the screen. Using this driver also avoids the memory
+fragmentation issues present in the powervr driver and avoids any direct
+dependencies on the deprecated PVR2D API from Imagination Technologies.
+
+To use this driver ensure you have /etc/powervr.ini with contents similar to
+this:
+
+[default]
+WindowSystem=libpvrPVR2D_FLIPWSEGL.so
+
+This driver will also function with libpvrPVR2D_FRONTWSEGL.so, but that draws
+straight into the framebuffer and will therefore cause flickering (it can be
+useful for performance testing though). The flip plugin uses triple buffering,
+so you will need to set the virtual vertical resolution of your framebuffer to
+be three times the physical vertical resolution of your screen. This can be
+done with 'fbset -vyres'. Failure to do this can cause system crashes. You
+should also ensure that the plugin you choose in powervr.ini is in your library
+path (it may just silently default to the flip plugin if not).
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullws.pro b/src/plugins/gfxdrivers/eglnullws/eglnullws.pro
new file mode 100644
index 0000000..242ab07
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullws.pro
@@ -0,0 +1,18 @@
+TARGET = qeglnullws
+include(../../qpluginbase.pri)
+
+CONFIG += warn_on
+QT += opengl
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers
+
+target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers
+INSTALLS += target
+
+HEADERS = eglnullwsscreen.h \
+ eglnullwsscreenplugin.h \
+ eglnullwswindowsurface.h
+
+SOURCES = eglnullwsscreen.cpp \
+ eglnullwsscreenplugin.cpp \
+ eglnullwswindowsurface.cpp
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp
new file mode 100644
index 0000000..b8ea5d5
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "eglnullwsscreen.h"
+#include "eglnullwswindowsurface.h"
+#include "eglnullwsscreenplugin.h"
+
+#include <QHash>
+#include <QDebug>
+
+namespace
+{
+ class EGLNullWSScreenSurfaceFunctions : public QGLScreenSurfaceFunctions
+ {
+ public:
+ virtual bool createNativeWindow(QWidget *, EGLNativeWindowType *native)
+ { *native = 0; return true; }
+ };
+}
+
+EGLNullWSScreen::EGLNullWSScreen(int displayId) : QGLScreen(displayId) {}
+
+EGLNullWSScreen::~EGLNullWSScreen() {}
+
+bool EGLNullWSScreen::initDevice()
+{
+ setSurfaceFunctions(new EGLNullWSScreenSurfaceFunctions);
+ return true;
+}
+
+static const QHash<QString, QImage::Format> formatDictionary()
+{
+ QHash<QString, QImage::Format> dictionary;
+ dictionary["rgb32"] = QImage::Format_RGB32;
+ dictionary["argb32"] = QImage::Format_ARGB32;
+ dictionary["rgb16"] = QImage::Format_RGB16;
+ dictionary["rgb666"] = QImage::Format_RGB666;
+ dictionary["rgb555"] = QImage::Format_RGB555;
+ dictionary["rgb888"] = QImage::Format_RGB888;
+ dictionary["rgb444"] = QImage::Format_RGB444;
+ return dictionary;
+}
+
+static int depthForFormat(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_RGB32: return 32;
+ case QImage::Format_ARGB32: return 32;
+ case QImage::Format_RGB16: return 16;
+ case QImage::Format_RGB666: return 24;
+ case QImage::Format_RGB555: return 16;
+ case QImage::Format_RGB888: return 24;
+ case QImage::Format_RGB444: return 16;
+ default:
+ Q_ASSERT_X(false, "EGLNullWSScreen", "Unknown format");
+ return -1;
+ }
+}
+
+static void printHelp(const QHash<QString, QImage::Format> &formatDictionary)
+{
+ QByteArray formatsBuf;
+ QTextStream(&formatsBuf) << QStringList(formatDictionary.keys()).join(", ");
+ qWarning(
+ "%s: Valid options are:\n"
+ "size=WIDTHxHEIGHT Screen size reported by this driver\n"
+ "format=FORMAT Screen format, where FORMAT is one of the following:\n"
+ " %s\n",
+ PluginName,
+ formatsBuf.constData());
+}
+
+bool EGLNullWSScreen::connect(const QString &displaySpec)
+{
+ const QStringList args = displaySpec.section(':', 1).split(':', QString::SkipEmptyParts);
+ const QHash<QString, QImage::Format> formatDict = formatDictionary();
+ Q_FOREACH(const QString arg, args) {
+ const QString optionName = arg.section('=', 0, 0);
+ const QString optionArg = arg.section('=', 1);
+ if (optionName == QLatin1String("size")) {
+ w = optionArg.section('x', 0, 0).toInt();
+ h = optionArg.section('x', 1, 1).toInt();
+ } else if (optionName == QLatin1String("format")) {
+ if (formatDict.contains(optionArg))
+ setPixelFormat(formatDict.value(optionArg));
+ else
+ printHelp(formatDict);
+ } else {
+ printHelp(formatDict);
+ }
+ }
+
+ if (w == 0 || h == 0) {
+ w = 640;
+ h = 480;
+ qWarning("%s: Using default screen size %dx%d", PluginName, w, h);
+ }
+ dw = w;
+ dh = h;
+
+ if (pixelFormat() == QImage::Format_Invalid) {
+ qWarning("%s: Using default screen format argb32", PluginName);
+ setPixelFormat(QImage::Format_ARGB32);
+ }
+ d = depthForFormat(pixelFormat());
+
+ static const int Dpi = 120;
+ static const qreal ScalingFactor = static_cast<qreal>(25.4) / Dpi;
+ physWidth = qRound(dw * ScalingFactor);
+ physHeight = qRound(dh * ScalingFactor);
+
+ return true;
+}
+
+void EGLNullWSScreen::disconnect() {}
+
+void EGLNullWSScreen::shutdownDevice() {}
+
+void EGLNullWSScreen::setMode(int /*width*/, int /*height*/, int /*depth*/) {}
+
+void EGLNullWSScreen::blank(bool /*on*/) {}
+
+void EGLNullWSScreen::exposeRegion(QRegion /*r*/, int /*changing*/) {}
+
+QWSWindowSurface* EGLNullWSScreen::createSurface(QWidget *widget) const
+{
+ if (qobject_cast<QGLWidget*>(widget)) {
+ return new EGLNullWSWindowSurface(widget);
+ } else {
+ qWarning("%s: Creating non-GL surface", PluginName);
+ return QScreen::createSurface(widget);
+ }
+}
+
+QWSWindowSurface* EGLNullWSScreen::createSurface(const QString &key) const
+{
+ if (key == QLatin1String("eglnullws")) {
+ return new EGLNullWSWindowSurface;
+ } else {
+ qWarning("%s: Creating non-GL surface", PluginName);
+ return QScreen::createSurface(key);
+ }
+}
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h
new file mode 100644
index 0000000..7f794bc
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreen.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef EGLNULLWSSCREEN
+#define EGLNULLWSSCREEN
+
+#include <QGLScreen>
+
+class EGLNullWSScreen : public QGLScreen
+{
+public:
+ EGLNullWSScreen(int displayId);
+ ~EGLNullWSScreen();
+
+ bool initDevice();
+ bool connect(const QString &displaySpec);
+ void disconnect();
+ void shutdownDevice();
+
+ void setMode(int width, int height, int depth);
+ void blank(bool on);
+
+ void exposeRegion(QRegion r, int changing);
+
+ QWSWindowSurface* createSurface(QWidget *widget) const;
+ QWSWindowSurface* createSurface(const QString &key) const;
+
+ bool hasOpenGL() { return true; }
+};
+
+#endif // EGLNULLWSSCREEN
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp
new file mode 100644
index 0000000..67b3f56
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "eglnullwsscreenplugin.h"
+#include "eglnullwsscreen.h"
+
+#include <QScreenDriverPlugin>
+#include <QStringList>
+
+class EGLNullWSScreenPlugin : public QScreenDriverPlugin
+{
+public:
+ virtual QStringList keys() const;
+ virtual QScreen *create(const QString& driver, int displayId);
+};
+
+QStringList EGLNullWSScreenPlugin::keys() const
+{
+ return QStringList() << QLatin1String(PluginName);
+}
+
+QScreen *EGLNullWSScreenPlugin::create(const QString& driver, int displayId)
+{
+ return (driver.toLower() == QLatin1String(PluginName) ?
+ new EGLNullWSScreen(displayId) : 0);
+}
+
+Q_EXPORT_PLUGIN2(qeglnullws, EGLNullWSScreenPlugin)
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h
new file mode 100644
index 0000000..84f0699
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwsscreenplugin.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef EGLNULLWSSCREENPLUGIN_H
+#define EGLNULLWSSCREENPLUGIN_H
+
+const char *const PluginName = "eglnullws";
+
+#endif // EGLNULLWSSCREENPLUGIN_H
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp
new file mode 100644
index 0000000..da4b728
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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 "eglnullwswindowsurface.h"
+#include "eglnullwsscreenplugin.h"
+
+#include <QGLWidget>
+
+static const QWSWindowSurface::SurfaceFlags Flags
+ = QWSWindowSurface::RegionReserved | QWSWindowSurface::RegionReserved;
+
+EGLNullWSWindowSurface::EGLNullWSWindowSurface(QWidget *w)
+ :
+ QWSGLWindowSurface(w),
+ widget(w)
+{
+ setSurfaceFlags(Flags);
+}
+
+EGLNullWSWindowSurface::EGLNullWSWindowSurface()
+ : widget(0)
+{
+ setSurfaceFlags(Flags);
+}
+
+EGLNullWSWindowSurface::~EGLNullWSWindowSurface() {}
+
+QString EGLNullWSWindowSurface::key() const
+{
+ return QLatin1String(PluginName);
+}
+
+QPaintDevice *EGLNullWSWindowSurface::paintDevice()
+{
+ return widget;
+}
+
+bool EGLNullWSWindowSurface::isValid() const
+{
+ return qobject_cast<QGLWidget *>(window());
+}
+
+QImage EGLNullWSWindowSurface::image() const
+{
+ return QImage();
+}
diff --git a/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h
new file mode 100644
index 0000000..b730415
--- /dev/null
+++ b/src/plugins/gfxdrivers/eglnullws/eglnullwswindowsurface.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 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$
+**
+****************************************************************************/
+
+#ifndef EGLNULLWSWINDOWSURFACE_H
+#define EGLNULLWSWINDOWSURFACE_H
+
+#include <private/qglwindowsurface_qws_p.h>
+
+class EGLNullWSWindowSurface : public QWSGLWindowSurface
+{
+public:
+ EGLNullWSWindowSurface(QWidget *widget);
+ EGLNullWSWindowSurface();
+ virtual ~EGLNullWSWindowSurface();
+
+ virtual QString key() const;
+ virtual QPaintDevice *paintDevice();
+ virtual bool isValid() const;
+ virtual QImage image() const;
+
+private:
+ QWidget *widget;
+};
+
+#endif // EGLNULLWSWINDOWSURFACE_H
diff --git a/src/plugins/gfxdrivers/gfxdrivers.pro b/src/plugins/gfxdrivers/gfxdrivers.pro
index d1ee3f2..1f38942 100644
--- a/src/plugins/gfxdrivers/gfxdrivers.pro
+++ b/src/plugins/gfxdrivers/gfxdrivers.pro
@@ -7,3 +7,4 @@ contains(gfx-plugins, vnc) :SUBDIRS += vnc
contains(gfx-plugins, transformed) :SUBDIRS += transformed
contains(gfx-plugins, svgalib) :SUBDIRS += svgalib
contains(gfx-plugins, powervr) :SUBDIRS += powervr
+contains(gfx-plugins, eglnullws) :SUBDIRS += eglnullws
diff --git a/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp
index 8ee494f..d6a6e9c 100644
--- a/tests/auto/qgl/tst_qgl.cpp
+++ b/tests/auto/qgl/tst_qgl.cpp
@@ -72,7 +72,9 @@ public:
tst_QGL();
virtual ~tst_QGL();
+#ifndef Q_WS_MAC //All tests are disabled on mac as they crash and prevent integration, see QTBUG-12138
private slots:
+#endif
void getSetCheck();
void openGLVersionCheck();
void graphicsViewClipping();
@@ -1871,11 +1873,10 @@ void tst_QGL::destroyFBOAfterContext()
#ifdef QT_BUILD_INTERNAL
-class tst_QGLResource : public QObject
+class tst_QGLResource
{
- Q_OBJECT
public:
- tst_QGLResource(QObject *parent = 0) : QObject(parent) {}
+ tst_QGLResource(const QGLContext * = 0) {}
~tst_QGLResource() { ++deletions; }
static int deletions;
@@ -1883,12 +1884,7 @@ public:
int tst_QGLResource::deletions = 0;
-static void qt_shared_test_free(void *data)
-{
- delete reinterpret_cast<tst_QGLResource *>(data);
-}
-
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shared_test, (qt_shared_test_free))
+Q_GLOBAL_STATIC(QGLContextGroupResource<tst_QGLResource>, qt_shared_test)
#endif
@@ -1908,10 +1904,9 @@ void tst_QGL::shareRegister()
guard.setId(3);
QVERIFY(guard.id() == 3);
- // Add a resource to the first context.
- tst_QGLResource *res1 = new tst_QGLResource();
- QVERIFY(!qt_shared_test()->value(glw1->context()));
- qt_shared_test()->insert(glw1->context(), res1);
+ // Request a tst_QGLResource object for the first context.
+ tst_QGLResource *res1 = qt_shared_test()->value(glw1->context());
+ QVERIFY(res1);
QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
// Create another context that shares with the first.
@@ -1950,10 +1945,9 @@ void tst_QGL::shareRegister()
QGLSharedResourceGuard guard3(glw3->context());
guard3.setId(5);
- // Add a resource to the third context.
- tst_QGLResource *res3 = new tst_QGLResource();
- QVERIFY(!qt_shared_test()->value(glw3->context()));
- qt_shared_test()->insert(glw3->context(), res3);
+ // Request a resource to the third context.
+ tst_QGLResource *res3 = qt_shared_test()->value(glw3->context());
+ QVERIFY(res3);
QVERIFY(qt_shared_test()->value(glw1->context()) == res1);
QVERIFY(qt_shared_test()->value(glw2->context()) == res1);
QVERIFY(qt_shared_test()->value(glw3->context()) == res3);
diff --git a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp
index bfe306d..46bd4a2 100644
--- a/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp
+++ b/tests/auto/qitemselectionmodel/tst_qitemselectionmodel.cpp
@@ -95,6 +95,8 @@ private slots:
void QTBUG5671_layoutChangedWithAllSelected();
void QTBUG2804_layoutChangedTreeSelection();
void deselectRemovedMiddleRange();
+ void rangeOperatorLessThan_data();
+ void rangeOperatorLessThan();
private:
QAbstractItemModel *model;
@@ -2401,6 +2403,163 @@ void tst_QItemSelectionModel::deselectRemovedMiddleRange()
QVERIFY(spy.size() == 1);
}
+static QStandardItemModel* getModel(QObject *parent)
+{
+ QStandardItemModel *model = new QStandardItemModel(parent);
+
+ for (int i = 0; i < 4; ++i) {
+ QStandardItem *parentItem = model->invisibleRootItem();
+ QList<QStandardItem*> list;
+ for (int j = 0; j < 4; ++j) {
+ list.append(new QStandardItem(QString("item %1, %2").arg(i).arg(j)));
+ }
+ parentItem->appendRow(list);
+ parentItem = list.first();
+ for (int j = 0; j < 4; ++j) {
+ QList<QStandardItem*> list;
+ for (int k = 0; k < 4; ++k) {
+ list.append(new QStandardItem(QString("item %1, %2").arg(i).arg(j)));
+ }
+ parentItem->appendRow(list);
+ }
+ }
+ return model;
+}
+
+enum Result {
+ LessThan,
+ NotLessThan,
+ NotEqual
+};
+
+Q_DECLARE_METATYPE(Result);
+
+void tst_QItemSelectionModel::rangeOperatorLessThan_data()
+{
+ QTest::addColumn<int>("parent1");
+ QTest::addColumn<int>("top1");
+ QTest::addColumn<int>("left1");
+ QTest::addColumn<int>("bottom1");
+ QTest::addColumn<int>("right1");
+ QTest::addColumn<int>("parent2");
+ QTest::addColumn<int>("top2");
+ QTest::addColumn<int>("left2");
+ QTest::addColumn<int>("bottom2");
+ QTest::addColumn<int>("right2");
+ QTest::addColumn<Result>("result");
+
+ QTest::newRow("lt01") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 3 << 3 << NotLessThan;
+
+ QTest::newRow("lt02") << -1 << 0 << 0 << 2 << 3
+ << -1 << 0 << 0 << 3 << 3 << LessThan;
+ QTest::newRow("lt03") << -1 << 0 << 0 << 3 << 2
+ << -1 << 0 << 0 << 3 << 3 << LessThan;
+ QTest::newRow("lt04") << -1 << 0 << 0 << 2 << 2
+ << -1 << 0 << 0 << 3 << 3 << LessThan;
+
+ QTest::newRow("lt05") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 2 << 3 << NotLessThan;
+ QTest::newRow("lt06") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 3 << 2 << NotLessThan;
+ QTest::newRow("lt07") << -1 << 0 << 0 << 3 << 3
+ << -1 << 0 << 0 << 2 << 2 << NotLessThan;
+
+ QTest::newRow("lt08") << -1 << 0 << 0 << 3 << 3
+ << 0 << 0 << 0 << 3 << 3 << NotEqual;
+ QTest::newRow("lt09") << 1 << 0 << 0 << 3 << 3
+ << 0 << 0 << 0 << 3 << 3 << NotEqual;
+ QTest::newRow("lt10") << 1 << 0 << 0 << 1 << 1
+ << 0 << 2 << 2 << 3 << 3 << NotEqual;
+ QTest::newRow("lt11") << 1 << 2 << 2 << 3 << 3
+ << 0 << 0 << 0 << 1 << 1 << NotEqual;
+
+ QTest::newRow("lt12") << -1 << 0 << 0 << 1 << 1
+ << -1 << 2 << 2 << 3 << 3 << LessThan;
+ QTest::newRow("lt13") << -1 << 2 << 2 << 3 << 3
+ << -1 << 0 << 0 << 1 << 1 << NotLessThan;
+ QTest::newRow("lt14") << 1 << 0 << 0 << 1 << 1
+ << 1 << 2 << 2 << 3 << 3 << LessThan;
+ QTest::newRow("lt15") << 1 << 2 << 2 << 3 << 3
+ << 1 << 0 << 0 << 1 << 1 << NotLessThan;
+
+ QTest::newRow("lt16") << -1 << 0 << 0 << 2 << 2
+ << -1 << 1 << 1 << 3 << 3 << LessThan;
+ QTest::newRow("lt17") << -1 << 1 << 1 << 3 << 3
+ << -1 << 0 << 0 << 2 << 2 << NotLessThan;
+ QTest::newRow("lt18") << 1 << 0 << 0 << 2 << 2
+ << 1 << 1 << 1 << 3 << 3 << LessThan;
+ QTest::newRow("lt19") << 1 << 1 << 1 << 3 << 3
+ << 1 << 0 << 0 << 2 << 2 << NotLessThan;
+}
+
+void tst_QItemSelectionModel::rangeOperatorLessThan()
+{
+ QStandardItemModel *model1 = getModel(this);
+ QStandardItemModel *model2 = getModel(this);
+
+ QFETCH(int, parent1);
+ QFETCH(int, top1);
+ QFETCH(int, left1);
+ QFETCH(int, bottom1);
+ QFETCH(int, right1);
+ QFETCH(int, parent2);
+ QFETCH(int, top2);
+ QFETCH(int, left2);
+ QFETCH(int, bottom2);
+ QFETCH(int, right2);
+ QFETCH(Result, result);
+
+ QModelIndex p1 = model1->index(parent1, 0);
+
+ QModelIndex tl1 = model1->index(top1, left1, p1);
+ QModelIndex br1 = model1->index(bottom1, right1, p1);
+
+ QItemSelectionRange r1(tl1, br1);
+
+ QModelIndex p2 = model1->index(parent2, 0);
+
+ QModelIndex tl2 = model1->index(top2, left2, p2);
+ QModelIndex br2 = model1->index(bottom2, right2, p2);
+
+ QItemSelectionRange r2(tl2, br2);
+
+ if (result == LessThan)
+ QVERIFY(r1 < r2);
+ else if (result == NotLessThan)
+ QVERIFY(!(r1 < r2));
+ else if (result == NotEqual)
+ if (!(r1 < r2))
+ QVERIFY(r2 < r1);
+
+ // Ranges in different models are always non-equal
+
+ QModelIndex p3 = model2->index(parent1, 0);
+
+ QModelIndex tl3 = model2->index(top1, left1, p3);
+ QModelIndex br3 = model2->index(bottom1, right1, p3);
+
+ QItemSelectionRange r3(tl3, br3);
+
+ if (!(r1 < r3))
+ QVERIFY(r3 < r1);
+
+ if (!(r2 < r3))
+ QVERIFY(r3 < r2);
+
+ QModelIndex p4 = model2->index(parent2, 0);
+
+ QModelIndex tl4 = model2->index(top2, left2, p4);
+ QModelIndex br4 = model2->index(bottom2, right2, p4);
+
+ QItemSelectionRange r4(tl4, br4);
+
+ if (!(r1 < r4))
+ QVERIFY(r4 < r1);
+
+ if (!(r2 < r4))
+ QVERIFY(r4 < r2);
+}
QTEST_MAIN(tst_QItemSelectionModel)
#include "tst_qitemselectionmodel.moc"