summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
authorJason Barron <jbarron@trolltech.com>2009-07-24 09:45:33 (GMT)
committerJason Barron <jbarron@trolltech.com>2009-07-27 13:04:30 (GMT)
commit3643028959f0b38350e57e60ba4000435b75e592 (patch)
treec129e4dee11487abd437ab8ebd993ba261e06fa6 /src/opengl
parentcf66c667a97c0079141eb3f2d9e997b7378ae792 (diff)
parentc36139c665e61866aff4bf8572890a735167a7d0 (diff)
downloadQt-3643028959f0b38350e57e60ba4000435b75e592.zip
Qt-3643028959f0b38350e57e60ba4000435b75e592.tar.gz
Qt-3643028959f0b38350e57e60ba4000435b75e592.tar.bz2
Merge commit 'qt/master-stable'
Conflicts: configure.exe qmake/Makefile.unix qmake/generators/makefile.cpp src/corelib/global/qglobal.h src/corelib/kernel/kernel.pri src/corelib/kernel/qcoreevent.cpp src/corelib/kernel/qsharedmemory_unix.cpp src/gui/graphicsview/qgraphicsscene.cpp src/gui/kernel/qaction.cpp src/gui/kernel/qaction.h src/gui/kernel/qaction_p.h src/gui/kernel/qapplication.cpp src/gui/kernel/qapplication.h src/gui/kernel/qwidget.cpp src/gui/kernel/qwidget.h src/gui/kernel/qwidget_mac.mm src/gui/painting/qgraphicssystemfactory.cpp src/gui/styles/qwindowsstyle.cpp src/gui/text/qfontengine_qpf.cpp src/gui/widgets/qabstractscrollarea_p.h src/network/access/qnetworkaccessdebugpipebackend.cpp src/network/socket/qlocalsocket_unix.cpp src/network/socket/qnativesocketengine_p.h src/network/socket/qnativesocketengine_unix.cpp src/openvg/qpaintengine_vg.cpp tests/auto/q3sqlcursor/tst_q3sqlcursor.cpp tests/auto/qcssparser/qcssparser.pro tests/auto/qdir/tst_qdir.cpp tests/auto/qfile/tst_qfile.cpp tests/auto/qobject/tst_qobject.cpp tests/auto/qpathclipper/qpathclipper.pro tests/auto/qprocess/tst_qprocess.cpp tests/auto/qsettings/tst_qsettings.cpp tests/auto/qsharedpointer/qsharedpointer.pro tests/auto/qsqlquerymodel/qsqlquerymodel.pro tests/auto/qsqlrelationaltablemodel/qsqlrelationaltablemodel.pro tests/auto/qsqltablemodel/qsqltablemodel.pro tests/auto/qsqlthread/qsqlthread.pro tests/auto/qwidget/tst_qwidget.cpp
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp62
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h29
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache.cpp29
-rw-r--r--src/opengl/gl2paintengineex/qglgradientcache_p.h27
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp163
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h25
-rw-r--r--src/opengl/qgl.cpp479
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qgl_p.h169
-rw-r--r--src/opengl/qgl_win.cpp16
-rw-r--r--src/opengl/qgl_x11.cpp140
-rw-r--r--src/opengl/qgl_x11egl.cpp11
-rw-r--r--src/opengl/qglextensions_p.h2
-rw-r--r--src/opengl/qglframebufferobject.cpp27
-rw-r--r--src/opengl/qglpixelbuffer.cpp2
-rw-r--r--src/opengl/qglpixmapfilter.cpp2
-rw-r--r--src/opengl/qpaintengine_opengl.cpp2
-rw-r--r--src/opengl/qpixmapdata_gl.cpp49
-rw-r--r--src/opengl/qpixmapdata_gl_p.h6
-rw-r--r--src/opengl/qwindowsurface_gl.cpp2
20 files changed, 846 insertions, 397 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 4b73ca9..d7c91b8 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -49,6 +49,28 @@
QT_BEGIN_NAMESPACE
+static void QGLEngineShaderManager_free(void *ptr)
+{
+ delete reinterpret_cast<QGLEngineShaderManager *>(ptr);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_shader_managers, (QGLEngineShaderManager_free))
+
+QGLEngineShaderManager *QGLEngineShaderManager::managerForContext(const QGLContext *context)
+{
+ QGLEngineShaderManager *p = reinterpret_cast<QGLEngineShaderManager *>(qt_shader_managers()->value(context));
+ if (!p) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != context)
+ const_cast<QGLContext *>(context)->makeCurrent();
+ p = new QGLEngineShaderManager(const_cast<QGLContext *>(context));
+ qt_shader_managers()->insert(context, p);
+ if (oldContext && oldContext != context)
+ oldContext->makeCurrent();
+ }
+ return p;
+}
+
const char* QGLEngineShaderManager::qglEngineShaderSourceCode[] = {
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
@@ -190,27 +212,33 @@ QGLEngineShaderManager::~QGLEngineShaderManager()
//###
}
-
-uint QGLEngineShaderManager::getUniformIdentifier(const char *uniformName)
-{
- uniformIdentifiers << uniformName;
- return uniformIdentifiers.size() - 1;
-}
-
-uint QGLEngineShaderManager::getUniformLocation(uint id)
+uint QGLEngineShaderManager::getUniformLocation(Uniform id)
{
QVector<uint> &uniformLocations = currentShaderProg->uniformLocations;
- uint oldSize = uniformLocations.size();
- if (oldSize <= id) {
- uint newSize = id + 1;
- uniformLocations.resize(newSize);
-
- for (uint i = oldSize; i < newSize; ++i)
- uniformLocations[i] = GLuint(-1);
- }
+ if (uniformLocations.isEmpty())
+ uniformLocations.fill(GLuint(-1), NumUniforms);
+
+ static const char *uniformNames[] = {
+ "imageTexture",
+ "patternColor",
+ "globalOpacity",
+ "depth",
+ "pmvMatrix",
+ "maskTexture",
+ "fragmentColor",
+ "linearData",
+ "angle",
+ "halfViewportSize",
+ "fmp",
+ "fmp2_m_radius2",
+ "inverse_2_fmp2_m_radius2",
+ "invertedTextureSize",
+ "brushTransform",
+ "brushTexture"
+ };
if (uniformLocations.at(id) == GLuint(-1))
- uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformIdentifiers.at(id));
+ uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]);
return uniformLocations.at(id);
}
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 34f0768..99711bd40 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -220,6 +220,7 @@
#include <QGLShader>
#include <QGLShaderProgram>
#include <QPainter>
+#include <private/qgl_p.h>
QT_BEGIN_HEADER
@@ -274,6 +275,26 @@ public:
TextureSrcWithPattern = Qt::TexturePattern+4
};
+ enum Uniform {
+ ImageTexture,
+ PatternColor,
+ GlobalOpacity,
+ Depth,
+ PmvMatrix,
+ MaskTexture,
+ FragmentColor,
+ LinearData,
+ Angle,
+ HalfViewportSize,
+ Fmp,
+ Fmp2MRadius2,
+ Inverse2Fmp2MRadius2,
+ InvertedTextureSize,
+ BrushTransform,
+ BrushTexture,
+ NumUniforms
+ };
+
// There are optimisations we can do, depending on the brush transform:
// 1) May not have to apply perspective-correction
// 2) Can use lower precision for matrix
@@ -285,8 +306,7 @@ public:
void setMaskType(MaskType);
void setCompositionMode(QPainter::CompositionMode);
- uint getUniformIdentifier(const char *uniformName);
- uint getUniformLocation(uint id);
+ uint getUniformLocation(Uniform id);
void setDirty(); // someone has manually changed the current shader program
bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
@@ -295,6 +315,8 @@ public:
QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
+ static QGLEngineShaderManager *managerForContext(const QGLContext *context);
+
enum ShaderName {
MainVertexShader,
MainWithTexCoordsVertexShader,
@@ -352,6 +374,7 @@ public:
TotalShaderCount, InvalidShaderName
};
+
/*
// These allow the ShaderName enum to be used as a cache key
const int mainVertexOffset = 0;
@@ -391,8 +414,6 @@ private:
void compileNamedShader(QGLEngineShaderManager::ShaderName name, QGLShader::ShaderType type);
static const char* qglEngineShaderSourceCode[TotalShaderCount];
-
- QVector<const char *> uniformIdentifiers;
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qglgradientcache.cpp b/src/opengl/gl2paintengineex/qglgradientcache.cpp
index 8c6b4f0..7c54bb9 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache.cpp
+++ b/src/opengl/gl2paintengineex/qglgradientcache.cpp
@@ -46,6 +46,28 @@
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))
+
+QGL2GradientCache *QGL2GradientCache::cacheForContext(const QGLContext *context)
+{
+ QGL2GradientCache *p = reinterpret_cast<QGL2GradientCache *>(qt_gradient_caches()->value(context));
+ if (!p) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != context)
+ const_cast<QGLContext *>(context)->makeCurrent();
+ p = new QGL2GradientCache;
+ qt_gradient_caches()->insert(context, p);
+ if (oldContext && oldContext != context)
+ oldContext->makeCurrent();
+ }
+ return p;
+}
+
void QGL2GradientCache::cleanCache() {
QGLGradientColorTableHash::const_iterator it = cache.constBegin();
for (; it != cache.constEnd(); ++it) {
@@ -55,13 +77,8 @@ void QGL2GradientCache::cleanCache() {
cache.clear();
}
-GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx)
+GLuint QGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity)
{
- if (buffer_ctx && !qgl_share_reg()->checkSharing(buffer_ctx, ctx))
- cleanCache();
-
- buffer_ctx = ctx;
-
quint64 hash_val = 0;
QGradientStops stops = gradient.stops();
diff --git a/src/opengl/gl2paintengineex/qglgradientcache_p.h b/src/opengl/gl2paintengineex/qglgradientcache_p.h
index 55c7b65..ba698bc 100644
--- a/src/opengl/gl2paintengineex/qglgradientcache_p.h
+++ b/src/opengl/gl2paintengineex/qglgradientcache_p.h
@@ -53,12 +53,12 @@
#include <QMultiHash>
#include <QObject>
#include <QtOpenGL/QtOpenGL>
+#include <private/qgl_p.h>
QT_BEGIN_NAMESPACE
-class QGL2GradientCache : public QObject
+class QGL2GradientCache
{
- Q_OBJECT
struct CacheInfo
{
inline CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode) :
@@ -73,16 +73,12 @@ class QGL2GradientCache : public QObject
typedef QMultiHash<quint64, CacheInfo> QGLGradientColorTableHash;
public:
- QGL2GradientCache() : QObject(), buffer_ctx(0)
- {
-/*
- connect(QGLSignalProxy::instance(),
- SIGNAL(aboutToDestroyContext(const QGLContext *)),
- SLOT(cleanupGLContextRefs(const QGLContext *)));
-*/
- }
+ static QGL2GradientCache *cacheForContext(const QGLContext *context);
+
+ QGL2GradientCache() { }
+ ~QGL2GradientCache() {cleanCache();}
- GLuint getBuffer(const QGradient &gradient, qreal opacity, const QGLContext *ctx);
+ GLuint getBuffer(const QGradient &gradient, qreal opacity);
inline int paletteSize() const { return 1024; }
protected:
@@ -95,15 +91,6 @@ protected:
void cleanCache();
QGLGradientColorTableHash cache;
- const QGLContext *buffer_ctx;
-
-public slots:
- void cleanupGLContextRefs(const QGLContext *context) {
- if (context == buffer_ctx) {
- cleanCache();
- buffer_ctx = 0;
- }
- }
};
QT_END_NAMESPACE
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index c4f5891..5c85b40 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -74,6 +74,7 @@
#include <private/qpainter_p.h>
#include <private/qfontengine_p.h>
#include <private/qtextureglyphcache_p.h>
+#include <private/qpixmapdata_gl_p.h>
#include "qglgradientcache_p.h"
#include "qglengineshadermanager_p.h"
@@ -88,8 +89,9 @@ static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush
static const GLuint QT_MASK_TEXTURE_UNIT = 1;
static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2;
-class QGLTextureGlyphCache : public QTextureGlyphCache
+class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
{
+ Q_OBJECT
public:
QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
~QGLTextureGlyphCache();
@@ -105,6 +107,25 @@ public:
inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
+
+public Q_SLOTS:
+ void contextDestroyed(const QGLContext *context) {
+ if (context == ctx) {
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(ctx);
+ if (shares.isEmpty()) {
+ glDeleteFramebuffers(1, &m_fbo);
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+ 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 *>(shares.at(0));
+ }
+ }
+ }
+
private:
QGLContext *ctx;
@@ -126,14 +147,23 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyph
, m_height(0)
{
glGenFramebuffers(1, &m_fbo);
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)),
+ SLOT(contextDestroyed(const QGLContext *)));
}
QGLTextureGlyphCache::~QGLTextureGlyphCache()
{
- glDeleteFramebuffers(1, &m_fbo);
-
- if (m_width || m_height)
- glDeleteTextures(1, &m_texture);
+ if (ctx) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != ctx)
+ ctx->makeCurrent();
+ glDeleteFramebuffers(1, &m_fbo);
+
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+ if (oldContext && oldContext != ctx)
+ oldContext->makeCurrent();
+ }
}
void QGLTextureGlyphCache::createTextureData(int width, int height)
@@ -231,8 +261,11 @@ void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
if (mask.format() == QImage::Format_RGB32) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, m_height - c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
} else {
- mask = mask.convertToFormat(QImage::Format_Indexed8);
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
+ // If the width of the uploaded data is not a multiple of four bytes, we get some garbage
+ // in the glyph cache, probably because of a driver bug.
+ // Convert to ARGB32 to get a multiple of 4 bytes per line.
+ mask = mask.convertToFormat(QImage::Format_ARGB32);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_BGRA, GL_UNSIGNED_BYTE, mask.bits());
}
}
@@ -242,16 +275,12 @@ extern QImage qt_imageForBrush(int brushStyle, bool invert);
QGL2PaintEngineExPrivate::~QGL2PaintEngineExPrivate()
{
- if (shaderManager) {
- delete shaderManager;
- shaderManager = 0;
- }
}
void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMode, bool smoothPixmapTransform, GLuint id)
{
// glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT); //### Is it always this texture unit?
- if (id != -1 && id == lastTexture)
+ if (id != GLuint(-1) && id == lastTexture)
return;
lastTexture = id;
@@ -271,6 +300,7 @@ void QGL2PaintEngineExPrivate::updateTextureFilter(GLenum target, GLenum wrapMod
QColor QGL2PaintEngineExPrivate::premultiplyColor(QColor c, GLfloat opacity)
{
qreal alpha = c.alphaF() * opacity;
+ c.setAlphaF(alpha);
c.setRedF(c.redF() * alpha);
c.setGreenF(c.greenF() * alpha);
c.setBlueF(c.blueF() * alpha);
@@ -314,9 +344,6 @@ void QGL2PaintEngineExPrivate::useSimpleShader()
}
}
-
-Q_GLOBAL_STATIC(QGL2GradientCache, qt_opengl_gradient_cache)
-
void QGL2PaintEngineExPrivate::updateBrushTexture()
{
// qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
@@ -337,7 +364,10 @@ void QGL2PaintEngineExPrivate::updateBrushTexture()
// We apply global opacity in the fragment shaders, so we always pass 1.0
// for opacity to the cache.
- GLuint texId = qt_opengl_gradient_cache()->getBuffer(*g, 1.0, ctx);
+ GLuint texId = QGL2GradientCache::cacheForContext(ctx)->getBuffer(*g, 1.0);
+
+ glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, texId);
if (g->spread() == QGradient::RepeatSpread || g->type() == QGradient::ConicalGradient)
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, true);
@@ -345,9 +375,6 @@ void QGL2PaintEngineExPrivate::updateBrushTexture()
updateTextureFilter(GL_TEXTURE_2D, GL_MIRRORED_REPEAT_IBM, true);
else
updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, true);
-
- glActiveTexture(GL_TEXTURE0 + QT_BRUSH_TEXTURE_UNIT);
- glBindTexture(GL_TEXTURE_2D, texId);
}
else if (style == Qt::TexturePattern) {
const QPixmap& texPixmap = currentBrush->texture();
@@ -372,7 +399,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
if (style == Qt::SolidPattern) {
QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
- shaderManager->currentProgram()->setUniformValue(location(FragmentColor), col);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::FragmentColor), col);
}
else {
// All other brushes have a transform and thus need the translation point:
@@ -383,10 +410,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
- shaderManager->currentProgram()->setUniformValue(location(PatternColor), col);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
QVector2D halfViewportSize(width*0.5, height*0.5);
- shaderManager->currentProgram()->setUniformValue(location(HalfViewportSize), halfViewportSize);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::LinearGradientPattern) {
const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush->gradient());
@@ -403,10 +430,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
1.0f / (l.x() * l.x() + l.y() * l.y())
);
- shaderManager->currentProgram()->setUniformValue(location(LinearData), linearData);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::LinearData), linearData);
QVector2D halfViewportSize(width*0.5, height*0.5);
- shaderManager->currentProgram()->setUniformValue(location(HalfViewportSize), halfViewportSize);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::ConicalGradientPattern) {
const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush->gradient());
@@ -414,10 +441,10 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
GLfloat angle = -(g->angle() * 2 * Q_PI) / 360.0;
- shaderManager->currentProgram()->setUniformValue(location(Angle), angle);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Angle), angle);
QVector2D halfViewportSize(width*0.5, height*0.5);
- shaderManager->currentProgram()->setUniformValue(location(HalfViewportSize), halfViewportSize);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::RadialGradientPattern) {
const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush->gradient());
@@ -427,15 +454,15 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
translationPoint = realFocal;
QPointF fmp = realCenter - realFocal;
- shaderManager->currentProgram()->setUniformValue(location(Fmp), fmp);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp), fmp);
GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius;
- shaderManager->currentProgram()->setUniformValue(location(Fmp2MRadius2), fmp2_m_radius2);
- shaderManager->currentProgram()->setUniformValue(location(Inverse2Fmp2MRadius2),
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2),
GLfloat(1.0 / (2.0*fmp2_m_radius2)));
QVector2D halfViewportSize(width*0.5, height*0.5);
- shaderManager->currentProgram()->setUniformValue(location(HalfViewportSize), halfViewportSize);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else if (style == Qt::TexturePattern) {
translationPoint = q->state()->brushOrigin;
@@ -444,14 +471,14 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
if (qHasPixmapTexture(*currentBrush) && currentBrush->texture().isQBitmap()) {
QColor col = premultiplyColor(currentBrush->color(), (GLfloat)q->state()->opacity);
- shaderManager->currentProgram()->setUniformValue(location(PatternColor), col);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
}
QSizeF invertedTextureSize( 1.0 / texPixmap.width(), 1.0 / texPixmap.height() );
- shaderManager->currentProgram()->setUniformValue(location(InvertedTextureSize), invertedTextureSize);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::InvertedTextureSize), invertedTextureSize);
QVector2D halfViewportSize(width*0.5, height*0.5);
- shaderManager->currentProgram()->setUniformValue(location(HalfViewportSize), halfViewportSize);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
}
else
qWarning("QGL2PaintEngineEx: Unimplemented fill style");
@@ -460,8 +487,8 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
QTransform gl_to_qt(1, 0, 0, -1, 0, height);
QTransform inv_matrix = gl_to_qt * (brushQTransform * q->state()->matrix).inverted() * translate;
- shaderManager->currentProgram()->setUniformValue(location(BrushTransform), inv_matrix);
- shaderManager->currentProgram()->setUniformValue(location(BrushTexture), QT_BRUSH_TEXTURE_UNIT);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTransform), inv_matrix);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT);
}
brushUniformsDirty = false;
}
@@ -599,11 +626,11 @@ void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& s
shaderManager->setSrcPixelType(pattern ? QGLEngineShaderManager::PatternSrc : QGLEngineShaderManager::ImageSrc);
shaderManager->setTextureCoordsEnabled(true);
if (prepareForDraw(opaque))
- shaderManager->currentProgram()->setUniformValue(location(ImageTexture), QT_IMAGE_TEXTURE_UNIT);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
if (pattern) {
QColor col = premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity);
- shaderManager->currentProgram()->setUniformValue(location(PatternColor), col);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PatternColor), col);
}
GLfloat dx = 1.0 / textureSize.width();
@@ -655,6 +682,11 @@ void QGL2PaintEngineEx::sync()
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
+ glDisable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+ glDepthMask(true);
+ glClearDepth(1);
+
d->needsSync = true;
}
@@ -847,17 +879,17 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
updateBrushUniforms();
if (shaderMatrixUniformDirty) {
- shaderManager->currentProgram()->setUniformValue(location(PmvMatrix), pmvMatrix);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PmvMatrix), pmvMatrix);
shaderMatrixUniformDirty = false;
}
if (depthUniformDirty) {
- shaderManager->currentProgram()->setUniformValue(location(Depth), (GLfloat)q->state()->currentDepth);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Depth), (GLfloat)q->state()->currentDepth);
depthUniformDirty = false;
}
if (useGlobalOpacityUniform && opacityUniformDirty) {
- shaderManager->currentProgram()->setUniformValue(location(GlobalOpacity), (GLfloat)q->state()->opacity);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity);
opacityUniformDirty = false;
}
@@ -1023,14 +1055,18 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c
QGLContext *ctx = d->ctx;
glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- GLuint id = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true);
+ QGLTexture *texture = ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, true, true);
+
+ GLfloat top = texture->yInverted ? (pixmap.height() - src.top()) : src.top();
+ GLfloat bottom = texture->yInverted ? (pixmap.height() - src.bottom()) : src.bottom();
+ QGLRect srcRect(src.left(), top, src.right(), bottom);
bool isBitmap = pixmap.isQBitmap();
bool isOpaque = !isBitmap && !pixmap.hasAlphaChannel();
d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT,
- state()->renderHints & QPainter::SmoothPixmapTransform, id);
- d->drawTexture(dest, src, pixmap.size(), isOpaque, isBitmap);
+ state()->renderHints & QPainter::SmoothPixmapTransform, texture->id);
+ d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap);
}
void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src,
@@ -1042,7 +1078,8 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
QGLContext *ctx = d->ctx;
glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- GLuint id = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
+ GLuint id = texture->id;
d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT,
state()->renderHints & QPainter::SmoothPixmapTransform, id);
@@ -1140,7 +1177,7 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
prepareForDraw(false); // Text always causes src pixels to be transparent
- shaderManager->currentProgram()->setUniformValue(location(MaskTexture), QT_MASK_TEXTURE_UNIT);
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
if (vertexCoordinateArray.data() != oldVertexCoordinateDataPtr)
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
@@ -1180,28 +1217,8 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
qt_resolve_version_2_0_functions(d->ctx);
#endif
- if (d->shaderManager) {
- d->shaderManager->setDirty();
- } else {
- d->shaderManager = new QGLEngineShaderManager(d->ctx);
-
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::ImageTexture] = d->shaderManager->getUniformIdentifier("imageTexture");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::PatternColor] = d->shaderManager->getUniformIdentifier("patternColor");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::GlobalOpacity] = d->shaderManager->getUniformIdentifier("globalOpacity");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::Depth] = d->shaderManager->getUniformIdentifier("depth");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::PmvMatrix] = d->shaderManager->getUniformIdentifier("pmvMatrix");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::MaskTexture] = d->shaderManager->getUniformIdentifier("maskTexture");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::FragmentColor] = d->shaderManager->getUniformIdentifier("fragmentColor");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::LinearData] = d->shaderManager->getUniformIdentifier("linearData");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::Angle] = d->shaderManager->getUniformIdentifier("angle");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::HalfViewportSize] = d->shaderManager->getUniformIdentifier("halfViewportSize");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::Fmp] = d->shaderManager->getUniformIdentifier("fmp");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::Fmp2MRadius2] = d->shaderManager->getUniformIdentifier("fmp2_m_radius2");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::Inverse2Fmp2MRadius2] = d->shaderManager->getUniformIdentifier("inverse_2_fmp2_m_radius2");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::InvertedTextureSize] = d->shaderManager->getUniformIdentifier("invertedTextureSize");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::BrushTransform] = d->shaderManager->getUniformIdentifier("brushTransform");
- d->uniformIdentifiers[QGL2PaintEngineExPrivate::BrushTexture] = d->shaderManager->getUniformIdentifier("brushTexture");
- }
+ d->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx);
+ d->shaderManager->setDirty();
glViewport(0, 0, d->width, d->height);
@@ -1276,6 +1293,14 @@ bool QGL2PaintEngineEx::end()
glUseProgram(0);
d->transferMode(BrushDrawingMode);
d->drawable.swapBuffers();
+#if defined(Q_WS_X11)
+ // On some (probably all) drivers, deleting an X pixmap which has been bound to a texture
+ // before calling glFinish/swapBuffers renders garbage. Presumably this is because X deletes
+ // the pixmap behind the driver's back before it's had a chance to use it. To fix this, we
+ // reference all QPixmaps which have been bound to stop them being deleted and only deref
+ // them here, after swapBuffers, where they can be safely deleted.
+ ctx->d_func()->boundPixmaps.clear();
+#endif
d->drawable.doneCurrent();
d->ctx->d_ptr->active_engine = 0;
@@ -1408,7 +1433,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
if (state()->matrix.type() <= QTransform::TxScale) {
rect = state()->matrix.mapRect(rect);
- if (d->use_system_clip && rect.contains(d->systemClip.boundingRect())
+ if ((d->use_system_clip && rect.contains(d->systemClip.boundingRect()))
|| rect.contains(QRect(0, 0, d->width, d->height)))
return;
}
@@ -1606,3 +1631,5 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
}
QT_END_NAMESPACE
+
+#include "qpaintengineex_opengl2.moc"
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 0d28a49..ec447a3 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -221,32 +221,11 @@ public:
void systemStateChanged();
uint use_system_clip : 1;
- enum Uniform {
- ImageTexture,
- PatternColor,
- GlobalOpacity,
- Depth,
- PmvMatrix,
- MaskTexture,
- FragmentColor,
- LinearData,
- Angle,
- HalfViewportSize,
- Fmp,
- Fmp2MRadius2,
- Inverse2Fmp2MRadius2,
- InvertedTextureSize,
- BrushTransform,
- BrushTexture,
- NumUniforms
- };
-
- uint location(Uniform uniform)
+ uint location(QGLEngineShaderManager::Uniform uniform)
{
- return shaderManager->getUniformLocation(uniformIdentifiers[uniform]);
+ return shaderManager->getUniformLocation(uniform);
}
- uint uniformIdentifiers[NumUniforms];
GLuint lastTexture;
bool needsSync;
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 2e99fc7..7211309 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -87,7 +87,6 @@
#include <private/qglpixelbuffer_p.h>
#include <private/qwindowsurface_gl_p.h>
#include "qcolormap.h"
-#include "qcache.h"
#include "qfile.h"
#include "qlibrary.h"
@@ -142,6 +141,7 @@ QGLSignalProxy *QGLSignalProxy::instance()
/*!
\namespace QGL
+ \inmodule QtOpenGL
\brief The QGL namespace specifies miscellaneous identifiers used
in the Qt OpenGL module.
@@ -1394,39 +1394,99 @@ int qt_next_power_of_two(int v)
return v;
}
-class QGLTexture {
-public:
- QGLTexture(const QGLContext *ctx, GLuint tx_id, GLenum tx_target, bool _clean = false)
- : context(ctx), id(tx_id), target(tx_target), clean(_clean) {}
- ~QGLTexture() {
- if (clean) {
- QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
- QGLContext *ctx = const_cast<QGLContext *>(context);
- bool switch_context = current && current != ctx && !qgl_share_reg()->checkSharing(current, ctx);
- if (switch_context)
- ctx->makeCurrent();
- glDeleteTextures(1, &id);
- if (switch_context)
- current->makeCurrent();
- }
- }
-
- const QGLContext *context;
- GLuint id;
- GLenum target;
- bool clean;
-};
-
-typedef QCache<qint64, QGLTexture> QGLTextureCache;
-static int qt_tex_cache_limit = 64*1024; // cache ~64 MB worth of textures - this is not accurate though
-static QGLTextureCache *qt_tex_cache = 0;
-
typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
typedef void (*_qt_image_cleanup_hook_64)(qint64);
extern Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64;
extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;
+static QGLTextureCache *qt_gl_texture_cache = 0;
+
+QGLTextureCache::QGLTextureCache()
+ : m_cache(64*1024) // cache ~64 MB worth of textures - this is not accurate though
+{
+ Q_ASSERT(qt_gl_texture_cache == 0);
+ qt_gl_texture_cache = this;
+ qt_pixmap_cleanup_hook_64 = cleanupHook;
+ qt_image_cleanup_hook_64 = cleanupHook;
+}
+
+QGLTextureCache::~QGLTextureCache()
+{
+ qt_gl_texture_cache = 0;
+ qt_pixmap_cleanup_hook_64 = 0;
+ qt_image_cleanup_hook_64 = 0;
+}
+
+void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
+{
+ if (m_cache.totalCost() + cost > m_cache.maxCost()) {
+ // the cache is full - make an attempt to remove something
+ const QList<qint64> keys = m_cache.keys();
+ int i = 0;
+ while (i < m_cache.count()
+ && (m_cache.totalCost() + cost > m_cache.maxCost())) {
+ QGLTexture *tex = m_cache.object(keys.at(i));
+ if (tex->context == ctx)
+ m_cache.remove(keys.at(i));
+ ++i;
+ }
+ }
+ m_cache.insert(key, texture, cost);
+}
+
+bool QGLTextureCache::remove(QGLContext* ctx, GLuint textureId)
+{
+ QList<qint64> keys = m_cache.keys();
+ for (int i = 0; i < keys.size(); ++i) {
+ QGLTexture *tex = m_cache.object(keys.at(i));
+ if (tex->id == textureId && tex->context == ctx) {
+ tex->clean = true; // forces a glDeleteTextures() call
+ m_cache.remove(keys.at(i));
+ return true;
+ }
+ }
+ return false;
+}
+
+void QGLTextureCache::removeContextTextures(QGLContext* ctx)
+{
+ QList<qint64> keys = m_cache.keys();
+ for (int i = 0; i < keys.size(); ++i) {
+ const qint64 &key = keys.at(i);
+ if (m_cache.object(key)->context == ctx)
+ m_cache.remove(key);
+ }
+}
+
+QGLTextureCache* QGLTextureCache::instance()
+{
+ if (!qt_gl_texture_cache)
+ qt_gl_texture_cache = new QGLTextureCache;
+
+ return qt_gl_texture_cache;
+}
+
+/*
+ a hook that removes textures from the cache when a pixmap/image
+ is deref'ed
+*/
+void QGLTextureCache::cleanupHook(qint64 cacheKey)
+{
+ // ### remove when the GL texture cache becomes thread-safe
+ if (qApp->thread() != QThread::currentThread())
+ return;
+ QGLTexture *texture = instance()->getTexture(cacheKey);
+ if (texture && texture->clean)
+ instance()->remove(cacheKey);
+}
+
+void QGLTextureCache::deleteIfEmpty()
+{
+ if (instance()->size() == 0)
+ delete instance();
+}
+
// DDS format structure
struct DDSFormat {
quint32 dwSize;
@@ -1555,21 +1615,8 @@ QGLContext::~QGLContext()
{
Q_D(QGLContext);
// remove any textures cached in this context
- if (qt_tex_cache) {
- QList<qint64> keys = qt_tex_cache->keys();
- for (int i = 0; i < keys.size(); ++i) {
- const qint64 &key = keys.at(i);
- if (qt_tex_cache->object(key)->context == this)
- qt_tex_cache->remove(key);
- }
- // ### thread safety
- if (qt_tex_cache->size() == 0) {
- qt_pixmap_cleanup_hook_64 = 0;
- qt_image_cleanup_hook_64 = 0;
- delete qt_tex_cache;
- qt_tex_cache = 0;
- }
- }
+ QGLTextureCache::instance()->removeContextTextures(this);
+ QGLTextureCache::deleteIfEmpty(); // ### thread safety
QGLSignalProxy::instance()->emitAboutToDestroyContext(this);
reset();
@@ -1699,21 +1746,6 @@ GLuint QGLContext::bindTexture(const QString &fileName)
return tx_id;
}
-/*
- a hook that removes textures from the cache when a pixmap/image
- is deref'ed
-*/
-static void qt_gl_clean_cache(qint64 cacheKey)
-{
- // ### remove when the GL texture cache becomes thread-safe
- if (qApp->thread() != QThread::currentThread())
- return;
- if (qt_tex_cache) {
- QGLTexture *texture = qt_tex_cache->object(cacheKey);
- if (texture && texture->clean)
- qt_tex_cache->remove(cacheKey);
- }
-}
static void convertToGLFormatHelper(QImage &dst, const QImage &img, GLenum texture_format)
{
@@ -1833,7 +1865,28 @@ QImage QGLContextPrivate::convertToGLFormat(const QImage &image, bool force_prem
return result;
}
-GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
+/*! \internal */
+QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean)
+{
+ const qint64 key = image.cacheKey();
+ QGLTexture *texture = textureCacheLookup(key, target);
+ if (texture) {
+ glBindTexture(target, texture->id);
+ return texture;
+ }
+
+ if (!texture)
+ texture = bindTexture(image, target, format, key, clean);
+ // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
+ Q_ASSERT(texture);
+
+ if (texture->id > 0)
+ const_cast<QImage &>(image).data_ptr()->is_cached = true;
+
+ return texture;
+}
+
+QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format,
const qint64 key, bool clean)
{
Q_Q(QGLContext);
@@ -1851,11 +1904,6 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint
// the GL_BGRA format is only present in GL version >= 1.2
GLenum texture_format = (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
? GL_BGRA : GL_RGBA;
- if (!qt_tex_cache) {
- qt_tex_cache = new QGLTextureCache(qt_tex_cache_limit);
- qt_pixmap_cleanup_hook_64 = qt_gl_clean_cache;
- qt_image_cleanup_hook_64 = qt_gl_clean_cache;
- }
// Scale the pixmap if needed. GL textures needs to have the
// dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
@@ -1928,53 +1976,26 @@ GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint
// this assumes the size of a texture is always smaller than the max cache size
int cost = img.width()*img.height()*4/1024;
- if (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost()) {
- // the cache is full - make an attempt to remove something
- const QList<qint64> keys = qt_tex_cache->keys();
- int i = 0;
- while (i < qt_tex_cache->count()
- && (qt_tex_cache->totalCost() + cost > qt_tex_cache->maxCost())) {
- QGLTexture *tex = qt_tex_cache->object(keys.at(i));
- if (tex->context == q)
- qt_tex_cache->remove(keys.at(i));
- ++i;
- }
- }
- qt_tex_cache->insert(key, new QGLTexture(q, tx_id, target, clean), cost);
- return tx_id;
+ QGLTexture *texture = new QGLTexture(q, tx_id, target, clean, false);
+ QGLTextureCache::instance()->insert(q, key, texture, cost);
+ return texture;
}
-bool QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target, GLuint *id)
+QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum target)
{
Q_Q(QGLContext);
- if (qt_tex_cache) {
- QGLTexture *texture = qt_tex_cache->object(key);
- if (texture && texture->target == target
- && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context)))
- {
- *id = texture->id;
- return true;
- }
+ QGLTexture *texture = QGLTextureCache::instance()->getTexture(key);
+ if (texture && texture->target == target
+ && (texture->context == q || qgl_share_reg()->checkSharing(q, texture->context)))
+ {
+ return texture;
}
- return false;
+ return 0;
}
-/*! \internal */
-GLuint QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint format, bool clean)
-{
- const qint64 key = image.cacheKey();
- GLuint id;
- if (textureCacheLookup(key, target, &id)) {
- glBindTexture(target, id);
- return id;
- }
- GLuint cached = bindTexture(image, target, format, key, clean);
- const_cast<QImage &>(image).data_ptr()->is_cached = (cached > 0);
- return cached;
-}
/*! \internal */
-GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean)
+QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert)
{
Q_Q(QGLContext);
QPixmapData *pd = pixmap.pixmapData();
@@ -1982,20 +2003,41 @@ GLuint QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLin
if (target == GL_TEXTURE_2D && pd->classId() == QPixmapData::OpenGLClass) {
const QGLPixmapData *data = static_cast<const QGLPixmapData *>(pd);
- if (data->isValidContext(q))
- return data->bind();
+ if (data->isValidContext(q)) {
+ data->bind();
+ return data->texture();
+ }
}
#endif
const qint64 key = pixmap.cacheKey();
- GLuint id;
- if (textureCacheLookup(key, target, &id)) {
- glBindTexture(target, id);
- return id;
+ QGLTexture *texture = textureCacheLookup(key, target);
+ if (texture) {
+ glBindTexture(target, texture->id);
+ return texture;
}
- GLuint cached = bindTexture(pixmap.toImage(), target, format, key, clean);
- const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = (cached > 0);
- return cached;
+
+#if defined(Q_WS_X11)
+ // Try to use texture_from_pixmap
+ if (pd->classId() == QPixmapData::X11Class) {
+ QPixmap *thatPixmap = const_cast<QPixmap*>(&pixmap);
+ texture = bindTextureFromNativePixmap(thatPixmap, key, canInvert);
+ if (texture) {
+ texture->clean = clean;
+ boundPixmaps.insert(thatPixmap->data_ptr(), QPixmap(pixmap));
+ }
+ }
+#endif
+
+ if (!texture)
+ texture = bindTexture(pixmap.toImage(), target, format, key, clean);
+ // NOTE: bindTexture(const QImage&, GLenum, GLint, const qint64, bool) should never return null
+ Q_ASSERT(texture);
+
+ if (texture->id > 0)
+ const_cast<QPixmap &>(pixmap).data_ptr()->is_cached = true;
+
+ return texture;
}
/*! \internal */
@@ -2061,7 +2103,8 @@ int QGLContextPrivate::maxTextureSize()
GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
{
Q_D(QGLContext);
- return d->bindTexture(image, target, format, false);
+ QGLTexture *texture = d->bindTexture(image, target, format, false);
+ return texture->id;
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -2069,7 +2112,8 @@ GLuint QGLContext::bindTexture(const QImage &image, GLenum target, GLint format)
GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMacCompatGLint format)
{
Q_D(QGLContext);
- return d->bindTexture(image, GLenum(target), GLint(format), false);
+ QGLTexture *texture = d->bindTexture(image, GLenum(target), GLint(format), false);
+ return texture->id;
}
#endif
@@ -2080,7 +2124,8 @@ GLuint QGLContext::bindTexture(const QImage &image, QMacCompatGLenum target, QMa
GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
Q_D(QGLContext);
- return d->bindTexture(pixmap, target, format, false);
+ QGLTexture *texture = d->bindTexture(pixmap, target, format, false, false);
+ return texture->id;
}
#ifdef Q_MAC_COMPAT_GL_FUNCTIONS
@@ -2088,7 +2133,8 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, GLenum target, GLint forma
GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, QMacCompatGLint format)
{
Q_D(QGLContext);
- return d->bindTexture(pixmap, GLenum(target), GLint(format), false);
+ QGLTexture *texture = d->bindTexture(pixmap, GLenum(target), GLint(format), false, false);
+ return texture->id;
}
#endif
@@ -2101,17 +2147,8 @@ GLuint QGLContext::bindTexture(const QPixmap &pixmap, QMacCompatGLenum target, Q
*/
void QGLContext::deleteTexture(GLuint id)
{
- if (qt_tex_cache) {
- QList<qint64> keys = qt_tex_cache->keys();
- for (int i = 0; i < keys.size(); ++i) {
- QGLTexture *tex = qt_tex_cache->object(keys.at(i));
- if (tex->id == id && tex->context == this) {
- tex->clean = true; // forces a glDeleteTextures() call
- qt_tex_cache->remove(keys.at(i));
- return;
- }
- }
- }
+ if (QGLTextureCache::instance()->remove(this, id))
+ return;
// check the DDS cache if the texture wasn't found in the pixmap/image
// cache
@@ -2305,9 +2342,7 @@ void QGLContext::drawTexture(const QPointF &point, QMacCompatGLuint textureId, Q
*/
void QGLContext::setTextureCacheLimit(int size)
{
- qt_tex_cache_limit = size;
- if (qt_tex_cache)
- qt_tex_cache->setMaxCost(qt_tex_cache_limit);
+ QGLTextureCache::instance()->setMaxCost(size);
}
/*!
@@ -2317,7 +2352,7 @@ void QGLContext::setTextureCacheLimit(int size)
*/
int QGLContext::textureCacheLimit()
{
- return qt_tex_cache_limit;
+ return QGLTextureCache::instance()->maxCost();
}
@@ -3361,8 +3396,13 @@ bool QGLWidget::event(QEvent *e)
#elif defined(Q_WS_WIN)
if (e->type() == QEvent::ParentChange) {
QGLContext *newContext = new QGLContext(d->glcx->requestedFormat(), this);
- qgl_share_reg()->replaceShare(d->glcx, newContext);
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(d->glcx);
setContext(newContext);
+ for (int i = 0; i < shares.size(); ++i) {
+ if (newContext != shares.at(i))
+ qgl_share_reg()->addShare(newContext, shares.at(i));
+ }
+
// the overlay needs to be recreated as well
delete d->olcx;
if (isValid() && context()->format().hasOverlay()) {
@@ -4332,6 +4372,9 @@ void QGLExtensions::init_extensions()
if (extensions.contains(QLatin1String("EXT_framebuffer_blit")))
glExtensions |= FramebufferBlit;
+ if (extensions.contains(QLatin1String("GL_ARB_texture_non_power_of_two")))
+ glExtensions |= NPOTTextures;
+
QGLContext cx(QGLFormat::defaultFormat());
if (glExtensions & TextureCompression) {
qt_glCompressedTexImage2DARB = (pfn_glCompressedTexImage2DARB) cx.getProcAddress(QLatin1String("glCompressedTexImage2DARB"));
@@ -4539,32 +4582,34 @@ QGLFormat QGLDrawable::format() const
GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format)
{
+ QGLTexture *texture;
if (widget)
- return widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
+ texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
else if (buffer)
- return buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true);
+ texture = buffer->d_func()->qctx->d_func()->bindTexture(image, target, format, true);
else if (fbo && QGLContext::currentContext())
- return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true);
+ texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(image, target, format, true);
#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
else if (wsurf)
- return wsurf->context()->d_func()->bindTexture(image, target, format, true);
+ texture = wsurf->context()->d_func()->bindTexture(image, target, format, true);
#endif
- return 0;
+ return texture->id;
}
GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
+ QGLTexture *texture;
if (widget)
- return widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true);
+ texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true, true);
else if (buffer)
- return buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true);
+ texture = buffer->d_func()->qctx->d_func()->bindTexture(pixmap, target, format, true, true);
else if (fbo && QGLContext::currentContext())
- return const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true);
+ texture = const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(pixmap, target, format, true, true);
#if defined(Q_WS_QWS) || (!defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL))
else if (wsurf)
- return wsurf->context()->d_func()->bindTexture(pixmap, target, format, true);
+ texture = wsurf->context()->d_func()->bindTexture(pixmap, target, format, true, true);
#endif
- return 0;
+ return texture->id;
}
QColor QGLDrawable::backgroundColor() const
@@ -4610,4 +4655,156 @@ bool QGLDrawable::autoFillBackground() const
return false;
}
+
+bool QGLShareRegister::checkSharing(const QGLContext *context1, const QGLContext *context2) {
+ bool sharing = (context1 && context2 && context1->d_ptr->groupResources == context2->d_ptr->groupResources);
+ return sharing;
+}
+
+void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
+ Q_ASSERT(context && share);
+ if (context->d_ptr->groupResources == share->d_ptr->groupResources)
+ return;
+
+ // Make sure 'context' is not already shared with another group of contexts.
+ Q_ASSERT(reg.find(context->d_ptr->groupResources) == reg.end());
+ Q_ASSERT(context->d_ptr->groupResources->refs == 1);
+
+ // Free 'context' group resources and make it use the same resources as 'share'.
+ delete context->d_ptr->groupResources;
+ context->d_ptr->groupResources = share->d_ptr->groupResources;
+ context->d_ptr->groupResources->refs.ref();
+
+ // Maintain a list of all the contexts in each group of sharing contexts.
+ SharingHash::iterator it = reg.find(share->d_ptr->groupResources);
+ if (it == reg.end())
+ it = reg.insert(share->d_ptr->groupResources, ContextList() << share);
+ it.value() << context;
+}
+
+QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
+ SharingHash::const_iterator it = reg.find(context->d_ptr->groupResources);
+ if (it == reg.end())
+ return ContextList();
+ return it.value();
+}
+
+void QGLShareRegister::removeShare(const QGLContext *context) {
+ SharingHash::iterator it = reg.find(context->d_ptr->groupResources);
+ if (it == reg.end())
+ return;
+
+ int count = it.value().removeAll(context);
+ Q_ASSERT(count == 1);
+
+ Q_ASSERT(it.value().size() != 0);
+ if (it.value().size() == 1)
+ reg.erase(it);
+}
+
+QGLContextResource::QGLContextResource(FreeFunc f, QObject *parent)
+ : QObject(parent), free(f)
+{
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext *)), this, SLOT(aboutToDestroyContext(const QGLContext *)));
+}
+
+QGLContextResource::~QGLContextResource()
+{
+ while (!m_resources.empty())
+ remove(m_resources.begin().key());
+}
+
+void QGLContextResource::insert(const QGLContext *key, void *value)
+{
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ if (shares.size() == 0)
+ shares.append(key);
+ void *oldValue = 0;
+ for (int i = 0; i < shares.size(); ++i) {
+ ResourceHash::iterator it = m_resources.find(shares.at(i));
+ if (it != m_resources.end()) {
+ Q_ASSERT(oldValue == 0 || oldValue == it.value());
+ oldValue = it.value();
+ it.value() = value;
+ } else {
+ m_resources.insert(shares.at(i), value);
+ }
+ }
+ if (oldValue != 0 && oldValue != value) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != key)
+ const_cast<QGLContext *>(key)->makeCurrent();
+ free(oldValue);
+ if (oldContext && oldContext != key)
+ oldContext->makeCurrent();
+ }
+}
+
+void *QGLContextResource::value(const QGLContext *key)
+{
+ ResourceHash::const_iterator it = m_resources.find(key);
+ // Check if there is a value associated with 'key'.
+ if (it != m_resources.end())
+ return it.value();
+ // Check if there is a value associated with sharing contexts.
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ for (int i = 0; i < shares.size() && it == m_resources.end(); ++i)
+ it = m_resources.find(shares.at(i));
+ if (it == m_resources.end())
+ return 0; // Didn't find anything.
+
+ // Found something! Share this info with all the buddies.
+ for (int i = 0; i < shares.size(); ++i)
+ m_resources.insert(shares.at(i), it.value());
+ return it.value();
+}
+
+void QGLContextResource::remove(const QGLContext *key)
+{
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ if (shares.size() == 0)
+ shares.append(key);
+ void *oldValue = 0;
+ for (int i = 0; i < shares.size(); ++i) {
+ ResourceHash::iterator it = m_resources.find(shares.at(i));
+ if (it != m_resources.end()) {
+ Q_ASSERT(oldValue == 0 || oldValue == it.value());
+ oldValue = it.value();
+ m_resources.erase(it);
+ }
+ }
+ if (oldValue != 0) {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != key)
+ const_cast<QGLContext *>(key)->makeCurrent();
+ free(oldValue);
+ if (oldContext && oldContext != key)
+ oldContext->makeCurrent();
+ }
+}
+
+void QGLContextResource::aboutToDestroyContext(const QGLContext *key)
+{
+ ResourceHash::iterator it = m_resources.find(key);
+ if (it == m_resources.end())
+ return;
+
+ QList<const QGLContext *> shares = qgl_share_reg()->shares(key);
+ if (shares.size() > 1) {
+ Q_ASSERT(key->isSharing());
+ // At least one of the shared contexts must stay in the cache.
+ // Otherwise, the value pointer is lost.
+ for (int i = 0; i < 2/*shares.size()*/; ++i)
+ m_resources.insert(shares.at(i), it.value());
+ } else {
+ QGLContext *oldContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ if (oldContext != key)
+ const_cast<QGLContext *>(key)->makeCurrent();
+ free(it.value());
+ if (oldContext && oldContext != key)
+ oldContext->makeCurrent();
+ }
+ m_resources.erase(it);
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index 24a4bbb..9ee200b 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -365,6 +365,7 @@ private:
friend class QGLPixmapData;
friend class QGLPixmapFilterBase;
friend class QGLTextureGlyphCache;
+ friend class QGLShareRegister;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
#ifdef Q_WS_MAC
public:
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 85e9bd7..85dae0d 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -60,10 +60,7 @@
#include "QtCore/qthreadstorage.h"
#include "QtCore/qhash.h"
#include "private/qwidget_p.h"
-
-#if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL)
-#include "private/qpixmapdata_gl_p.h"
-#endif
+#include "qcache.h"
#ifndef QT_OPENGL_ES_1_CL
#define q_vertexType float
@@ -196,17 +193,26 @@ public:
#endif
};
+struct QGLContextGroupResources
+{
+ QGLContextGroupResources() : refs(1) { }
+ QGLExtensionFuncs extensionFuncs;
+ QAtomicInt refs;
+};
+
+class QGLTexture;
+
class QGLContextPrivate
{
Q_DECLARE_PUBLIC(QGLContext)
public:
- explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {}
- ~QGLContextPrivate() {}
- GLuint bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
+ explicit QGLContextPrivate(QGLContext *context) : internal_context(false), q_ptr(context) {groupResources = new QGLContextGroupResources;}
+ ~QGLContextPrivate() {if (!groupResources->refs.deref()) delete groupResources;}
+ QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, bool clean);
+ QGLTexture *bindTexture(const QImage &image, GLenum target, GLint format, const qint64 key,
bool clean = false);
- GLuint bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean);
- GLuint bindTexture(const QImage &image, GLenum target, GLint format, bool clean);
- bool textureCacheLookup(const qint64 key, GLenum target, GLuint *id);
+ QGLTexture *bindTexture(const QPixmap &pixmap, GLenum target, GLint format, bool clean, bool canInvert = false);
+ QGLTexture *textureCacheLookup(const qint64 key, GLenum target);
void init(QPaintDevice *dev, const QGLFormat &format);
QImage convertToGLFormat(const QImage &image, bool force_premul, GLenum texture_format);
int maxTextureSize();
@@ -234,6 +240,8 @@ public:
void* pbuf;
quint32 gpm;
int screen;
+ QHash<QPixmapData*, QPixmap> boundPixmaps;
+ QGLTexture *bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool internal);
#endif
#if defined(Q_WS_MAC)
bool update;
@@ -257,14 +265,14 @@ public:
QGLContext *q_ptr;
QGLFormat::OpenGLVersionFlags version_flags;
- QGLExtensionFuncs extensionFuncs;
+ QGLContextGroupResources *groupResources;
GLint max_texture_size;
GLuint current_fbo;
QPaintEngine *active_engine;
#ifdef Q_WS_WIN
- static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->extensionFuncs; }
+ static inline QGLExtensionFuncs& qt_get_extension_funcs(const QGLContext *ctx) { return ctx->d_ptr->groupResources->extensionFuncs; }
#endif
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
@@ -293,6 +301,7 @@ class QGLPixelBuffer;
class QGLFramebufferObject;
class QWSGLWindowSurface;
class QGLWindowSurface;
+class QGLPixmapData;
class QGLDrawable {
public:
QGLDrawable() : widget(0), buffer(0), fbo(0)
@@ -353,7 +362,8 @@ public:
PackedDepthStencil = 0x00000200,
NVFloatBuffer = 0x00000400,
PixelBufferObject = 0x00000800,
- FramebufferBlit = 0x00001000
+ FramebufferBlit = 0x00001000,
+ NPOTTextures = 0x00002000
};
Q_DECLARE_FLAGS(Extensions, Extension)
@@ -371,61 +381,89 @@ struct QGLThreadContext {
};
extern QThreadStorage<QGLThreadContext *> qgl_context_storage;
-typedef QMultiHash<const QGLContext *, const QGLContext *> QGLSharingHash;
class QGLShareRegister
{
public:
QGLShareRegister() {}
~QGLShareRegister() { reg.clear(); }
- bool checkSharing(const QGLContext *context1, const QGLContext *context2, const QGLContext * skip=0) {
- if (context1 == context2)
- return true;
- QList<const QGLContext *> shares = reg.values(context1);
- for (int k=0; k<shares.size(); ++k) {
- const QGLContext *ctx = shares.at(k);
- if (ctx == skip) // avoid an indirect circular loop (infinite recursion)
- continue;
- if (ctx == context2)
- return true;
- if (checkSharing(ctx, context2, context1))
- return true;
- }
- return false;
- }
+ bool checkSharing(const QGLContext *context1, const QGLContext *context2);
+ void addShare(const QGLContext *context, const QGLContext *share);
+ QList<const QGLContext *> shares(const QGLContext *context);
+ void removeShare(const QGLContext *context);
+private:
+ // Use a context's 'groupResources' pointer to uniquely identify a group.
+ typedef QList<const QGLContext *> ContextList;
+ typedef QHash<const QGLContextGroupResources *, ContextList> SharingHash;
+ SharingHash reg;
+};
- void addShare(const QGLContext *context, const QGLContext *share) {
- reg.insert(context, share); // context sharing works both ways
- reg.insert(share, context);
- }
+extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
- void removeShare(const QGLContext *context) {
- QGLSharingHash::iterator it = reg.begin();
- while (it != reg.end()) {
- if (it.key() == context || it.value() == context)
- it = reg.erase(it);
- else
- ++it;
+class QGLTexture {
+public:
+ QGLTexture(QGLContext *ctx = 0, GLuint tx_id = 0, GLenum tx_target = GL_TEXTURE_2D,
+ bool _clean = false, bool _yInverted = false)
+ : context(ctx), id(tx_id), target(tx_target), clean(_clean), yInverted(_yInverted)
+#if defined(Q_WS_X11)
+ , boundPixmap(0)
+#endif
+ {}
+
+ ~QGLTexture() {
+ if (clean) {
+ QGLContext *current = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLContext *ctx = const_cast<QGLContext *>(context);
+ Q_ASSERT(ctx);
+ bool switch_context = current != ctx && !qgl_share_reg()->checkSharing(current, ctx);
+ if (switch_context)
+ ctx->makeCurrent();
+#if defined(Q_WS_X11)
+ // Although glXReleaseTexImage is a glX call, it must be called while there
+ // is a current context - the context the pixmap was bound to a texture in.
+ // Otherwise the release doesn't do anything and you get BadDrawable errors
+ // when you come to delete the context.
+ deleteBoundPixmap();
+#endif
+ glDeleteTextures(1, &id);
+ if (switch_context && current)
+ current->makeCurrent();
}
- }
+ }
- void replaceShare(const QGLContext *oldContext, const QGLContext *newContext) {
- QGLSharingHash::iterator it = reg.begin();
- while (it != reg.end()) {
- if (it.key() == oldContext)
- reg.insert(newContext, it.value());
- else if (it.value() == oldContext)
- reg.insert(it.key(), newContext);
- ++it;
- }
- removeShare(oldContext);
- }
+ QGLContext *context;
+ GLuint id;
+ GLenum target;
+ bool clean;
+ bool yInverted; // NOTE: Y-Inverted textures are for internal use only!
+#if defined(Q_WS_X11)
+ Qt::HANDLE boundPixmap;
+ void deleteBoundPixmap(); // in qgl_x11.cpp/qgl_x11egl.cpp
+#endif
+};
+
+class QGLTextureCache {
+public:
+ QGLTextureCache();
+ ~QGLTextureCache();
+
+ void insert(QGLContext *ctx, qint64 key, QGLTexture *texture, int cost);
+ void remove(quint64 key) { m_cache.remove(key); }
+ bool remove(QGLContext *ctx, GLuint textureId);
+ void removeContextTextures(QGLContext *ctx);
+ int size() { return m_cache.size(); }
+ void setMaxCost(int newMax) { m_cache.setMaxCost(newMax); }
+ int maxCost() {return m_cache.maxCost(); }
+ QGLTexture* getTexture(quint64 key) { return m_cache.object(key); }
+
+ static QGLTextureCache *instance();
+ static void deleteIfEmpty();
+ static void cleanupHook(qint64 cacheKey);
private:
- QGLSharingHash reg;
+ QCache<qint64, QGLTexture> m_cache;
};
-extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
#ifdef Q_WS_QWS
extern QPaintEngine* qt_qgl_paint_engine();
@@ -460,6 +498,29 @@ inline GLenum qt_gl_preferredTextureTarget()
#endif
}
+// One resource per group of shared contexts.
+class QGLContextResource : public QObject
+{
+ Q_OBJECT
+public:
+ typedef void (*FreeFunc)(void *);
+ QGLContextResource(FreeFunc f, QObject *parent = 0);
+ ~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);
+ // Free resource for 'key' and all its shared contexts.
+ void remove(const QGLContext *key);
+private slots:
+ // Remove entry 'key' from cache and delete resource if there are no shared contexts.
+ void aboutToDestroyContext(const QGLContext *key);
+private:
+ typedef QHash<const QGLContext *, void *> ResourceHash;
+ ResourceHash m_resources;
+ FreeFunc free;
+};
+
QT_END_NAMESPACE
#endif // QGL_P_H
diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp
index 40b0ce7..232d47b 100644
--- a/src/opengl/qgl_win.cpp
+++ b/src/opengl/qgl_win.cpp
@@ -51,7 +51,7 @@
#include <qdebug.h>
#include <qcolor.h>
-#include <windows.h>
+#include <qt_windows.h>
typedef bool (APIENTRY *PFNWGLGETPIXELFORMATATTRIBIVARB)(HDC hdc,
int iPixelFormat,
@@ -642,14 +642,10 @@ public:
QString windowClassName = qt_getRegisteredWndClass();
if (parent && !parent->internalWinId())
parent = parent->nativeParentWidget();
- QT_WA({
- const TCHAR *cname = (TCHAR*)windowClassName.utf16();
- dmy_id = CreateWindow(cname, 0, 0, 0, 0, 1, 1,
- parent ? parent->winId() : 0, 0, qWinAppInst(), 0);
- } , {
- dmy_id = CreateWindowA(windowClassName.toLatin1(), 0, 0, 0, 0, 1, 1,
- parent ? parent->winId() : 0, 0, qWinAppInst(), 0);
- });
+
+ dmy_id = CreateWindow((const wchar_t *)windowClassName.utf16(),
+ 0, 0, 0, 0, 1, 1,
+ parent ? parent->winId() : 0, 0, qWinAppInst(), 0);
dmy_pdc = GetDC(dmy_id);
PIXELFORMATDESCRIPTOR dmy_pfd;
@@ -1417,7 +1413,7 @@ void QGLWidget::setContext(QGLContext *context,
}
if (!d->glcx->isValid()) {
- bool wasSharing = shareContext || oldcx && oldcx->isSharing();
+ bool wasSharing = shareContext || (oldcx && oldcx->isSharing());
d->glcx->create(shareContext ? shareContext : oldcx);
// the above is a trick to keep disp lists etc when a
// QGLWidget has been reparented, so remove the sharing
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index 631625b..43bdec7 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -52,6 +52,7 @@
#include "qdebug.h"
#include <private/qfontengine_ft_p.h>
#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
#ifdef Q_OS_HPUX
// for GLXPBuffer
#include <private/qglpixelbuffer_p.h>
@@ -81,6 +82,25 @@ extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
#define GLX_SAMPLES_ARB 100001
#endif
+#ifndef GLX_EXT_texture_from_pixmap
+#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
+#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
+#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
+#define GLX_BIND_TO_TEXTURE_RGBA_EXT 0x20D1
+#define GLX_BIND_TO_MIPMAP_TEXTURE_EXT 0x20D2
+#define GLX_BIND_TO_TEXTURE_TARGETS_EXT 0x20D3
+#define GLX_Y_INVERTED_EXT 0x20D4
+#define GLX_TEXTURE_FORMAT_EXT 0x20D5
+#define GLX_TEXTURE_TARGET_EXT 0x20D6
+#define GLX_MIPMAP_TEXTURE_EXT 0x20D7
+#define GLX_TEXTURE_FORMAT_NONE_EXT 0x20D8
+#define GLX_TEXTURE_FORMAT_RGB_EXT 0x20D9
+#define GLX_TEXTURE_FORMAT_RGBA_EXT 0x20DA
+#define GLX_TEXTURE_2D_EXT 0x20DC
+#define GLX_TEXTURE_RECTANGLE_EXT 0x20DD
+#define GLX_FRONT_LEFT_EXT 0x20DE
+#endif
+
/*
The qt_gl_choose_cmap function is internal and used by QGLWidget::setContext()
and GLX (not Windows). If the application can't find any sharable
@@ -1516,4 +1536,124 @@ void QGLExtensions::init()
}
}
+
+typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*);
+typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
+static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
+static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
+static bool qt_resolved_texture_from_pixmap = false;
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert)
+{
+ Q_Q(QGLContext);
+
+ if (pm->data_ptr()->classId() != QPixmapData::X11Class)
+ return 0;
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pm->data_ptr());
+ const QX11Info *x11Info = qt_x11Info(pm);
+
+
+ // Check to see if we have NPOT texture support
+ // TODO: Use GLX_TEXTURE_RECTANGLE_EXT texture target on systems without npot textures
+ if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) &&
+ !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
+ return 0;
+
+ if (!qt_resolved_texture_from_pixmap) {
+ qt_resolved_texture_from_pixmap = true;
+
+ QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
+ if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) {
+#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4)
+ void *handle = dlopen(NULL, RTLD_LAZY);
+ if (handle) {
+ glXBindTexImageEXT = (qt_glXBindTexImageEXT) dlsym(handle, "glXBindTexImageEXT");
+ glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) dlsym(handle, "glXReleaseTexImageEXT");
+ dlclose(handle);
+ }
+ if (!glXBindTexImageEXT)
+#endif
+ {
+ extern const QString qt_gl_library_name();
+ QLibrary lib(qt_gl_library_name());
+ glXBindTexImageEXT = (qt_glXBindTexImageEXT) lib.resolve("glXBindTexImageEXT");
+ glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) lib.resolve("glXReleaseTexImageEXT");
+ }
+ }
+ }
+
+ if (!glXBindTexImageEXT)
+ return 0;
+
+#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
+ return 0;
+#else
+ GLXFBConfig *configList = 0;
+ GLXFBConfig glxPixmapConfig;
+ int configCount = 0;
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ int configAttribs[] = {
+ hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
+ GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False,
+ XNone
+// GLX_BIND_TO_MIPMAP_TEXTURE_EXT, False,
+// GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_1D_BIT_EXT or GLX_TEXTURE_2D_BIT_EXT or GLX_TEXTURE_RECTANGLE_BIT_EXT
+ };
+ configList = glXChooseFBConfig(x11Info->display(), x11Info->screen(), configAttribs, &configCount);
+ if (!configList)
+ return 0;
+ glxPixmapConfig = configList[0];
+ XFree(configList);
+
+ GLXPixmap glxPixmap;
+ int pixmapAttribs[] = {
+ GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, False,
+ XNone
+// GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT or GLX_TEXTURE_FORMAT_RGB_EXT or GLX_TEXTURE_FORMAT_NONE_EXT,
+// GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT or GLX_TEXTURE_RECTANGLE_EXT,
+// GLX_MIPMAP_TEXTURE_EXT, True or False,
+ };
+
+ // Wrap the X Pixmap into a GLXPixmap:
+ glxPixmap = glXCreatePixmap(x11Info->display(), glxPixmapConfig, pixmapData->handle(), pixmapAttribs);
+
+ if (!glxPixmap)
+ return 0;
+
+ int yInverted;
+ glXGetFBConfigAttrib(x11Info->display(), glxPixmapConfig, GLX_Y_INVERTED_EXT, &yInverted);
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ glXBindTexImageEXT(x11Info->display(), glxPixmap, GLX_FRONT_LEFT_EXT, 0);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, yInverted);
+ texture->boundPixmap = glxPixmap;
+
+ // We assume the cost of bound pixmaps is zero
+ QGLTextureCache::instance()->insert(q, key, texture, 0);
+
+ return texture;
+#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
+}
+
+void QGLTexture::deleteBoundPixmap()
+{
+ if (boundPixmap) {
+ glXReleaseTexImageEXT(QX11Info::display(), boundPixmap, GLX_FRONT_LEFT_EXT);
+ glXDestroyPixmap(QX11Info::display(), boundPixmap);
+ boundPixmap = 0;
+ }
+}
+
+
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 9db3a30..99b026d 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -469,4 +469,15 @@ void QGLWidgetPrivate::recreateEglSurface(bool force)
}
}
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert)
+{
+ // TODO
+ return 0;
+}
+
+void QGLTexture::deleteBoundPixmap()
+{
+ //TODO
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qglextensions_p.h b/src/opengl/qglextensions_p.h
index 3bb42c8..4f15197 100644
--- a/src/opengl/qglextensions_p.h
+++ b/src/opengl/qglextensions_p.h
@@ -535,7 +535,7 @@ struct QGLExtensionFuncs
#endif
#ifndef GL_MAX_SAMPLES_EXT
-#define GL_MAX_SAMPLES_EXT 0x8D5
+#define GL_MAX_SAMPLES_EXT 0x8D57
#endif
#ifndef GL_DRAW_FRAMEBUFFER_EXT
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp
index e033076..f8607cc 100644
--- a/src/opengl/qglframebufferobject.cpp
+++ b/src/opengl/qglframebufferobject.cpp
@@ -109,8 +109,6 @@ public:
*/
/*!
- \since 4.6
-
Creates a QGLFramebufferObjectFormat object with properties specifying
the format of an OpenGL framebuffer object.
@@ -146,8 +144,6 @@ QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(int samples,
}
/*!
- \since 4.6
-
Constructs a copy of \a other.
*/
@@ -158,8 +154,6 @@ QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjec
}
/*!
- \since 4.6
-
Assigns \a other to this object.
*/
@@ -170,8 +164,6 @@ QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFrame
}
/*!
- \since 4.6
-
Destroys the QGLFramebufferObjectFormat.
*/
QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
@@ -180,8 +172,6 @@ QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
}
/*!
- \since 4.6
-
Sets the number of samples per pixel for a multisample framebuffer object
to \a samples.
A sample count of 0 represents a regular non-multisample framebuffer object.
@@ -194,8 +184,6 @@ void QGLFramebufferObjectFormat::setSamples(int samples)
}
/*!
- \since 4.6
-
Returns the number of samples per pixel if a framebuffer object
is a multisample framebuffer object. Otherwise, returns 0.
@@ -207,8 +195,6 @@ int QGLFramebufferObjectFormat::samples() const
}
/*!
- \since 4.6
-
Sets the attachments a framebuffer object should have to \a attachment.
\sa attachment()
@@ -219,8 +205,6 @@ void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment
}
/*!
- \since 4.6
-
Returns the status of the depth and stencil buffers attached to
a framebuffer object.
@@ -232,8 +216,6 @@ QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
}
/*!
- \since 4.6
-
Sets the texture target of the texture attached to a framebuffer object to
\a target. Ignored for multisample framebuffer objects.
@@ -245,8 +227,6 @@ void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
}
/*!
- \since 4.6
-
Returns the texture target of the texture attached to a framebuffer object.
Ignored for multisample framebuffer objects.
@@ -258,8 +238,6 @@ GLenum QGLFramebufferObjectFormat::textureTarget() const
}
/*!
- \since 4.6
-
Sets the internal format of a framebuffer object's texture or multisample
framebuffer object's color buffer to \a internalFormat.
@@ -271,8 +249,6 @@ void QGLFramebufferObjectFormat::setInternalFormat(GLenum internalFormat)
}
/*!
- \since 4.6
-
Returns the internal format of a framebuffer object's texture or
multisample framebuffer object's color buffer.
@@ -1055,8 +1031,7 @@ GLuint QGLFramebufferObject::handle() const
}
/*! \fn int QGLFramebufferObject::devType() const
-
- \reimp
+ \internal
*/
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 2669cb3..e40a037 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -590,7 +590,7 @@ QGLFormat QGLPixelBuffer::format() const
}
/*! \fn int QGLPixelBuffer::devType() const
- \reimp
+ \internal
*/
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index 7514743..5a06763 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const
{
- const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true);
+ const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true, false);
}
void QGLPixmapFilterBase::drawImpl(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF& source) const
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index cd04379..63ce73a 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -3963,7 +3963,7 @@ void QOpenGLPaintEnginePrivate::strokePath(const QPainterPath &path, bool use_ca
QPen pen = cpen;
if (txscale != 1)
- pen.setWidthF(pen.width() * txscale);
+ pen.setWidthF(pen.widthF() * txscale);
if (use_cache)
fillPath(qt_opengl_stroke_cache()->getStrokedPath(temp.map(path), pen));
else
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index f0c7e20..e3ee2b2 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -97,7 +97,6 @@ static int qt_gl_pixmap_serial = 0;
QGLPixmapData::QGLPixmapData(PixelType type)
: QPixmapData(type, OpenGLClass)
, m_renderFbo(0)
- , m_textureId(0)
, m_engine(0)
, m_ctx(0)
, m_dirty(false)
@@ -113,9 +112,9 @@ QGLPixmapData::~QGLPixmapData()
if (!shareWidget)
return;
- if (m_textureId) {
+ if (m_texture.id) {
QGLShareContextScope ctx(shareWidget->context());
- glDeleteTextures(1, &m_textureId);
+ glDeleteTextures(1, &m_texture.id);
}
}
@@ -148,10 +147,10 @@ void QGLPixmapData::resize(int width, int height)
is_null = (w <= 0 || h <= 0);
d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
- if (m_textureId) {
+ if (m_texture.id) {
QGLShareContextScope ctx(qt_gl_share_widget()->context());
- glDeleteTextures(1, &m_textureId);
- m_textureId = 0;
+ glDeleteTextures(1, &m_texture.id);
+ m_texture.id = 0;
}
m_source = QImage();
@@ -172,9 +171,9 @@ void QGLPixmapData::ensureCreated() const
const GLenum format = qt_gl_preferredTextureFormat();
const GLenum target = GL_TEXTURE_2D;
- if (!m_textureId) {
- glGenTextures(1, &m_textureId);
- glBindTexture(target, m_textureId);
+ if (!m_texture.id) {
+ glGenTextures(1, &m_texture.id);
+ glBindTexture(target, m_texture.id);
GLenum format = m_hasAlpha ? GL_RGBA : GL_RGB;
glTexImage2D(target, 0, format, w, h, 0,
GL_RGBA, GL_UNSIGNED_BYTE, 0);
@@ -185,13 +184,15 @@ void QGLPixmapData::ensureCreated() const
if (!m_source.isNull()) {
const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, format);
- glBindTexture(target, m_textureId);
+ glBindTexture(target, m_texture.id);
glTexSubImage2D(target, 0, 0, 0, w, h, format,
GL_UNSIGNED_BYTE, tx.bits());
if (useFramebufferObjects())
m_source = QImage();
}
+
+ m_texture.clean = false;
}
QGLFramebufferObject *QGLPixmapData::fbo() const
@@ -223,10 +224,10 @@ void QGLPixmapData::fromImage(const QImage &image,
is_null = (w <= 0 || h <= 0);
d = pixelType() == QPixmapData::PixmapType ? 32 : 1;
- if (m_textureId) {
+ if (m_texture.id) {
QGLShareContextScope ctx(qt_gl_share_widget()->context());
- glDeleteTextures(1, &m_textureId);
- m_textureId = 0;
+ glDeleteTextures(1, &m_texture.id);
+ m_texture.id = 0;
}
}
@@ -256,9 +257,9 @@ void QGLPixmapData::fill(const QColor &color)
bool hasAlpha = color.alpha() != 255;
if (hasAlpha && !m_hasAlpha) {
- if (m_textureId) {
- glDeleteTextures(1, &m_textureId);
- m_textureId = 0;
+ if (m_texture.id) {
+ glDeleteTextures(1, &m_texture.id);
+ m_texture.id = 0;
m_dirty = true;
}
m_hasAlpha = color.alpha() != 255;
@@ -303,6 +304,8 @@ QImage QGLPixmapData::fillImage(const QColor &color) const
return img;
}
+extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
+
QImage QGLPixmapData::toImage() const
{
if (!isValid())
@@ -319,8 +322,7 @@ QImage QGLPixmapData::toImage() const
}
QGLShareContextScope ctx(qt_gl_share_widget()->context());
- extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
- glBindTexture(GL_TEXTURE_2D, m_textureId);
+ glBindTexture(GL_TEXTURE_2D, m_texture.id);
return qt_gl_read_texture(QSize(w, h), true, true);
}
@@ -350,7 +352,7 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_2D, m_textureId, 0);
+ GL_TEXTURE_2D, m_texture.id, 0);
const int x0 = 0;
const int x1 = w;
@@ -488,7 +490,7 @@ GLuint QGLPixmapData::bind(bool copyBack) const
ensureCreated();
}
- GLuint id = m_textureId;
+ GLuint id = m_texture.id;
glBindTexture(GL_TEXTURE_2D, id);
return id;
}
@@ -496,7 +498,12 @@ GLuint QGLPixmapData::bind(bool copyBack) const
GLuint QGLPixmapData::textureId() const
{
ensureCreated();
- return m_textureId;
+ return m_texture.id;
+}
+
+QGLTexture* QGLPixmapData::texture() const
+{
+ return &m_texture;
}
extern int qt_defaultDpiX();
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index a6aa22d..671f9a7 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -53,6 +53,7 @@
// We mean it.
//
+#include "qgl_p.h"
#include "qgl.h"
#include "private/qpixmapdata_p.h"
@@ -80,10 +81,11 @@ public:
void fill(const QColor &color);
bool hasAlphaChannel() const;
QImage toImage() const;
- QPaintEngine* paintEngine() const;
+ QPaintEngine *paintEngine() const;
GLuint bind(bool copyBack = true) const;
GLuint textureId() const;
+ QGLTexture *texture() const;
bool isValidContext(const QGLContext *ctx) const;
@@ -116,10 +118,10 @@ private:
QImage fillImage(const QColor &color) const;
mutable QGLFramebufferObject *m_renderFbo;
- mutable GLuint m_textureId;
mutable QPaintEngine *m_engine;
mutable QGLContext *m_ctx;
mutable QImage m_source;
+ mutable QGLTexture m_texture;
// the texture is not in sync with the source image
mutable bool m_dirty;
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index 3a7a07e..eec725e 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -171,7 +171,7 @@ QGLGraphicsSystem::QGLGraphicsSystem()
}
}
#elif defined(Q_WS_WIN)
- QGLWindowSurface::surfaceFormat.setDoubleBuffer(false);
+ QGLWindowSurface::surfaceFormat.setDoubleBuffer(true);
qt_win_owndc_required = true;
#endif