summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2010-07-06 12:35:02 +0200
committerQt Continuous Integration System <qt-info@nokia.com>2010-07-06 12:35:02 +0200
commitebb539d3852658a104e6d59804ea9ad813f9e82d (patch)
tree463880587981051da456cc7cf8ca3e1bcbc0634c
parent32d6c5adb9d75ad7e3b2cef818f6b17d77d0f929 (diff)
parent40c8aba524831dd0d2f8dfcdf07797f5c2c47f5b (diff)
Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2: (24 commits) QGLPixelBuffer should not rely on temporary QGLWidgets. Initialize pex. Remove warning. Fix the tests for the internal GL resource system. Rework how QGLTextureGlyphCache makes use of the resource system. The group pointer should no longer be a part of the 64 bit int. Enable glyph uploads from a thread in the X11 font engine. Make qt_pixmap_serial thread-safe. Clean up debug output. Clarification regarding the WA_X11InitThreads flag. Rework the internal GL resource system yet again. Check Qt::AA_X11InitThreads to determine pixmap usage in threads. Add an application attribute to control XInitThreads(). Unnecessary alloc + remove unused headers. QGLPixelBuffer should manage its own paint engines. Remove the DDS texture cache. Make the GL texture cache share textures between shared contexts. Redesigned how GL resource management works. Don't use the QGLSignalProxy to clean up the thread-local shaders. Simplify how the QGLEngineSharedShaders object is cleaned up. ...
-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/kernel/qapplication_win.cpp25
-rw-r--r--src/gui/kernel/qapplication_x11.cpp3
-rw-r--r--src/gui/kernel/qwidget_win.cpp5
-rw-r--r--src/gui/painting/qpainter.cpp16
-rw-r--r--src/gui/text/qfontengine_x11.cpp2
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp64
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h11
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp15
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h4
-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.cpp102
-rw-r--r--src/opengl/qgl.h2
-rw-r--r--src/opengl/qgl_p.h161
-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--tests/auto/qgl/tst_qgl.cpp26
24 files changed, 394 insertions, 283 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index a12e12119c..9ac6d687da 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 d41975996f..564164b88e 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 fd2c139c93..7e41e917a2 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 e8dc5aeae0..afbfa35238 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/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index 1af45ba0b6..6f5aa1120d 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 9d5a7c06b1..5e212ca42b 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_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 0f05c6b694..a2024e007c 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 1bf90e365d..a845842857 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_x11.cpp b/src/gui/text/qfontengine_x11.cpp
index b7e4be2c9a..aee21f6e46 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/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 40b3641708..4b5f53e0e8 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 06b96ae60c..e5ababff32 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 a1495dd8a9..f1b095ddce 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -46,22 +46,11 @@
QT_BEGIN_NAMESPACE
-static void QGL2GradientCache_free(void *ptr)
-{
- delete reinterpret_cast<QGL2GradientCache *>(ptr);
-}
-
-Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_gradient_caches, (QGL2GradientCache_free))
+Q_GLOBAL_STATIC(QGLContextGroupResource<QGL2GradientCache>, 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()->value(context);
}
void QGL2GradientCache::cleanCache() {
diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h
index 0a5f846af8..8ecb34ea2e 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache_p.h
+++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h
@@ -75,8 +75,8 @@ 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; }
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 634b315bad..756180f045 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 faf4563f80..9ce5d551bc 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 d291ac3c45..66aed914ed 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 9effb347af..3f2af9d7d0 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)
@@ -2054,6 +2056,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 +2067,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 +2123,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 +2546,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 +2752,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 +4071,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 +5038,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 +5318,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 +5344,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 f85cad56cc..9315ac48de 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 cd5dbbe9f9..eca4a29abe 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)
@@ -404,6 +404,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 +613,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 +826,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/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index deffc2075b..fe60e8366b 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 9a8b243659..3d9cd2151a 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 8d0d105d38..df83566d19 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 bfa5ef180b..68586c141c 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/tests/auto/qgl/tst_qgl.cpp b/tests/auto/qgl/tst_qgl.cpp
index 8ee494f08e..c05f730135 100644
--- a/tests/auto/qgl/tst_qgl.cpp
+++ b/tests/auto/qgl/tst_qgl.cpp
@@ -1871,11 +1871,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 +1882,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 +1902,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 +1943,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);