summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2010-01-08 10:53:28 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2010-01-08 10:53:28 (GMT)
commit2e62227f950aac8205f2b67e4d7d046836b2c799 (patch)
tree87e91115d86896949f69e8c8d993ba795422ef3b /src/opengl
parent9b0502aa6abf6bb9c07f205bccdf2d9c65027bde (diff)
parent118e7a807d0764dee97612589fe5d7072d271e1e (diff)
downloadQt-2e62227f950aac8205f2b67e4d7d046836b2c799.zip
Qt-2e62227f950aac8205f2b67e4d7d046836b2c799.tar.gz
Qt-2e62227f950aac8205f2b67e4d7d046836b2c799.tar.bz2
Merge branch '4.6'
Conflicts: src/corelib/io/qfsfileengine.cpp src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp src/opengl/opengl.pro
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp46
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h4
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp423
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h17
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp216
-rw-r--r--src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h123
-rw-r--r--src/opengl/opengl.pro6
-rw-r--r--src/opengl/qgl.cpp86
-rw-r--r--src/opengl/qgl.h3
-rw-r--r--src/opengl/qgl_egl.cpp2
-rw-r--r--src/opengl/qgl_mac.mm2
-rw-r--r--src/opengl/qgl_p.h34
-rw-r--r--src/opengl/qgl_win.cpp2
-rw-r--r--src/opengl/qgl_x11.cpp71
-rw-r--r--src/opengl/qgl_x11egl.cpp118
-rw-r--r--src/opengl/qglpixelbuffer.cpp2
-rw-r--r--src/opengl/qglshaderprogram.cpp67
-rw-r--r--src/opengl/qglshaderprogram.h4
18 files changed, 719 insertions, 507 deletions
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index d28d5f3..326ea1f 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -218,6 +218,23 @@ QGLEngineSharedShaders::QGLEngineSharedShaders(const QGLContext* context)
}
+QGLEngineSharedShaders::~QGLEngineSharedShaders()
+{
+ QList<QGLEngineShaderProg*>::iterator itr;
+ for (itr = cachedPrograms.begin(); itr != cachedPrograms.end(); ++itr)
+ delete *itr;
+
+ if (blitShaderProg) {
+ delete blitShaderProg;
+ blitShaderProg = 0;
+ }
+
+ if (simpleShaderProg) {
+ delete simpleShaderProg;
+ simpleShaderProg = 0;
+ }
+}
+
#if defined (QT_DEBUG)
QByteArray QGLEngineSharedShaders::snippetNameStr(SnippetName name)
{
@@ -505,7 +522,27 @@ QGLShaderProgram* QGLEngineShaderManager::currentProgram()
if (currentShaderProg)
return currentShaderProg->program;
else
- return simpleProgram();
+ return sharedShaders->simpleProgram();
+}
+
+void QGLEngineShaderManager::useSimpleProgram()
+{
+ sharedShaders->simpleProgram()->bind();
+ QGLContextPrivate* ctx_d = ctx->d_func();
+ ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
+ ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false);
+ ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
+ shaderProgNeedsChanging = true;
+}
+
+void QGLEngineShaderManager::useBlitProgram()
+{
+ sharedShaders->blitProgram()->bind();
+ QGLContextPrivate* ctx_d = ctx->d_func();
+ ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
+ ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true);
+ ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false);
+ shaderProgNeedsChanging = true;
}
QGLShaderProgram* QGLEngineShaderManager::simpleProgram()
@@ -716,6 +753,13 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
customSrcStage->setUniforms(currentShaderProg->program);
}
+ // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it
+ // doesn't use are disabled)
+ QGLContextPrivate* ctx_d = ctx->d_func();
+ ctx_d->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true);
+ ctx_d->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg->useTextureCoords);
+ ctx_d->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg->useOpacityAttribute);
+
shaderProgNeedsChanging = false;
return true;
}
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 1ec4cdc..a3464d4 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -344,6 +344,7 @@ public:
*/
QGLEngineSharedShaders(const QGLContext *context);
+ ~QGLEngineSharedShaders();
QGLShaderProgram *simpleProgram() { return simpleShaderProg; }
QGLShaderProgram *blitProgram() { return blitShaderProg; }
@@ -468,6 +469,9 @@ public:
void setDirty(); // someone has manually changed the current shader program
bool useCorrectShaderProg(); // returns true if the shader program needed to be changed
+ void useSimpleProgram();
+ void useBlitProgram();
+
QGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen
QGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers
QGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 98be0cb..c411ba2 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -75,7 +75,6 @@
#include <QPaintEngine>
#include <private/qpainter_p.h>
#include <private/qfontengine_p.h>
-#include <private/qtextureglyphcache_p.h>
#include <private/qpixmapdata_gl_p.h>
#include <private/qdatabuffer_p.h>
#include <private/qtriangulator_p.h>
@@ -83,8 +82,8 @@
#include "qglgradientcache_p.h"
#include "qglengineshadermanager_p.h"
#include "qgl2pexvertexarray_p.h"
-
#include "qtriangulatingstroker_p.h"
+#include "qtextureglyphcache_gl_p.h"
#include <QDebug>
@@ -92,254 +91,6 @@ QT_BEGIN_NAMESPACE
//#define QT_GL_NO_SCISSOR_TEST
-static const GLuint GL_STENCIL_HIGH_BIT = 0x80;
-static const GLuint QT_BRUSH_TEXTURE_UNIT = 0;
-static const GLuint QT_IMAGE_TEXTURE_UNIT = 0; //Can be the same as brush texture unit
-static const GLuint QT_MASK_TEXTURE_UNIT = 1;
-static const GLuint QT_BACKGROUND_TEXTURE_UNIT = 2;
-
-#ifdef Q_WS_WIN
-extern Q_GUI_EXPORT bool qt_cleartype_enabled;
-#endif
-
-class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
-{
- Q_OBJECT
-public:
- QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
- ~QGLTextureGlyphCache();
-
- virtual void createTextureData(int width, int height);
- virtual void resizeTextureData(int width, int height);
- virtual void fillTexture(const Coord &c, glyph_t glyph);
- virtual int glyphMargin() const;
-
- inline GLuint texture() const { return m_texture; }
-
- inline int width() const { return m_width; }
- inline int height() const { return m_height; }
-
- 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 *>((ctx == shares.at(0)) ? shares.at(1) : shares.at(0));
- }
- }
- }
-
-private:
- QGLContext *ctx;
-
- QGL2PaintEngineExPrivate *pex;
-
- GLuint m_texture;
- GLuint m_fbo;
-
- int m_width;
- int m_height;
-
- QGLShaderProgram *m_program;
-};
-
-QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
- : QTextureGlyphCache(type, matrix)
- , ctx(context)
- , m_width(0)
- , m_height(0)
-{
- glGenFramebuffers(1, &m_fbo);
- connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
- SLOT(contextDestroyed(const QGLContext*)));
-}
-
-QGLTextureGlyphCache::~QGLTextureGlyphCache()
-{
- if (ctx) {
- QGLShareContextScope scope(ctx);
- glDeleteFramebuffers(1, &m_fbo);
-
- if (m_width || m_height)
- glDeleteTextures(1, &m_texture);
- }
-}
-
-void QGLTextureGlyphCache::createTextureData(int width, int height)
-{
- glGenTextures(1, &m_texture);
- glBindTexture(GL_TEXTURE_2D, m_texture);
-
- m_width = width;
- m_height = height;
-
- QVarLengthArray<uchar> data(width * height);
- for (int i = 0; i < data.size(); ++i)
- data[i] = 0;
-
- if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
- else
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
-
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-}
-
-void QGLTextureGlyphCache::resizeTextureData(int width, int height)
-{
- // ### the QTextureGlyphCache API needs to be reworked to allow
- // ### resizeTextureData to fail
-
- int oldWidth = m_width;
- int oldHeight = m_height;
-
- GLuint oldTexture = m_texture;
- createTextureData(width, height);
-
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
-
- GLuint tmp_texture;
- glGenTextures(1, &tmp_texture);
- glBindTexture(GL_TEXTURE_2D, tmp_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glBindTexture(GL_TEXTURE_2D, 0);
- glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_2D, tmp_texture, 0);
-
- glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
- glBindTexture(GL_TEXTURE_2D, oldTexture);
-
- pex->transferMode(BrushDrawingMode);
-
-#ifndef QT_OPENGL_ES_2
- if (pex->inRenderText)
- glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT | GL_SCISSOR_BIT);
-#endif
-
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_BLEND);
-
- glViewport(0, 0, oldWidth, oldHeight);
-
- float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 };
- float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
-
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
-
- glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
- glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
-
- pex->shaderManager->blitProgram()->bind();
- pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
- pex->shaderManager->setDirty();
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
-
- glBindTexture(GL_TEXTURE_2D, m_texture);
-
-#ifdef QT_OPENGL_ES_2
- QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
- buffer.resize(4*oldWidth*oldHeight);
- glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
-
- // do an in-place conversion from GL_RGBA to GL_ALPHA
- for (int i=0; i<oldWidth*oldHeight; ++i)
- buffer.data()[i] = buffer.at(4*i + 3);
-
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight,
- GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data());
-#else
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
-#endif
-
- glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_RENDERBUFFER_EXT, 0);
- glDeleteTextures(1, &tmp_texture);
- glDeleteTextures(1, &oldTexture);
-
- glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
-
- glViewport(0, 0, pex->width, pex->height);
- pex->updateClipScissorTest();
-
-#ifndef QT_OPENGL_ES_2
- if (pex->inRenderText)
- glPopAttrib();
-#endif
-}
-
-void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
-{
- QImage mask = textureMapForGlyph(glyph);
- const int maskWidth = mask.width();
- const int maskHeight = mask.height();
-
- if (mask.format() == QImage::Format_Mono) {
- mask = mask.convertToFormat(QImage::Format_Indexed8);
- for (int y = 0; y < maskHeight; ++y) {
- uchar *src = (uchar *) mask.scanLine(y);
- for (int x = 0; x < maskWidth; ++x)
- src[x] = -src[x]; // convert 0 and 1 into 0 and 255
- }
- }
-
-
- glBindTexture(GL_TEXTURE_2D, 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 {
-#ifdef QT_OPENGL_ES2
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
-#else
- // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
- // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
- // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
- // multiple of four bytes per line, and most of the glyph shows up correctly in the
- // texture, which makes me think that this is a driver bug.
- // One workaround is to make sure the mask width is a multiple of four bytes, for instance
- // by converting it to a format with four bytes per pixel. Another is to copy one line at a
- // time.
-
- for (int i = 0; i < maskHeight; ++i)
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
-#endif
- }
-}
-
-int QGLTextureGlyphCache::glyphMargin() const
-{
-#if defined(Q_WS_MAC)
- return 2;
-#elif defined (Q_WS_X11)
- return 0;
-#else
- return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
-#endif
-}
-
extern QImage qt_imageForBrush(int brushStyle, bool invert);
////////////////////////////////// Private Methods //////////////////////////////////////////
@@ -414,14 +165,14 @@ void QGL2PaintEngineExPrivate::setBrush(const QBrush& brush)
void QGL2PaintEngineExPrivate::useSimpleShader()
{
- shaderManager->simpleProgram()->bind();
- shaderManager->setDirty();
+ shaderManager->useSimpleProgram();
if (matrixDirty)
updateMatrix();
if (simpleShaderMatrixUniformDirty) {
- shaderManager->simpleProgram()->setUniformValue("pmvMatrix", pmvMatrix);
+ const GLuint location = shaderManager->simpleProgram()->uniformLocation("pmvMatrix");
+ glUniformMatrix3fv(location, 1, GL_FALSE, (GLfloat*)pmvMatrix);
simpleShaderMatrixUniformDirty = false;
}
}
@@ -608,19 +359,28 @@ void QGL2PaintEngineExPrivate::updateMatrix()
const GLfloat wfactor = 2.0f / width;
const GLfloat hfactor = -2.0f / height;
+ GLfloat dx = transform.dx();
+ GLfloat dy = transform.dy();
+
+ // Non-integer translates can have strange effects for some rendering operations such as
+ // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid.
+ if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) {
+ // 0.50 needs to rounded down to 0.0 for consistency with raster engine:
+ dx = ceilf(dx - 0.5f);
+ dy = ceilf(dy - 0.5f);
+ }
if (addOffset) {
- pmvMatrix[2][0] = (wfactor * (transform.dx() + 0.49f)) - transform.m33();
- pmvMatrix[2][1] = (hfactor * (transform.dy() + 0.49f)) + transform.m33();
- } else {
- pmvMatrix[2][0] = (wfactor * transform.dx()) - transform.m33();
- pmvMatrix[2][1] = (hfactor * transform.dy()) + transform.m33();
+ dx += 0.49f;
+ dy += 0.49f;
}
pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13();
pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23();
+ pmvMatrix[2][0] = (wfactor * dx) - transform.m33();
pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13();
pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23();
+ pmvMatrix[2][1] = (hfactor * dy) + transform.m33();
pmvMatrix[0][2] = transform.m13();
pmvMatrix[1][2] = transform.m23();
pmvMatrix[2][2] = transform.m33();
@@ -718,6 +478,11 @@ void QGL2PaintEngineExPrivate::drawTexture(const QGLRect& dest, const QGLRect& s
matrixDirty = true;
}
+ if (snapToPixelGrid) {
+ snapToPixelGrid = false;
+ matrixDirty = true;
+ }
+
if (prepareForDraw(opaque))
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
@@ -746,6 +511,10 @@ void QGL2PaintEngineEx::beginNativePainting()
QGLContext *ctx = d->ctx;
glUseProgram(0);
+ // Disable all the vertex attribute arrays:
+ for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
+ glDisableVertexAttribArray(i);
+
#ifndef QT_OPENGL_ES_2
// be nice to people who mix OpenGL 1.x code with QPainter commands
// by setting modelview and projection matrices to mirror the GL 1
@@ -791,6 +560,9 @@ void QGL2PaintEngineExPrivate::resetGLState()
glDepthMask(true);
glDepthFunc(GL_LESS);
glClearDepth(1);
+ glStencilMask(0xff);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc(GL_ALWAYS, 0, 0xff);
}
void QGL2PaintEngineEx::endNativePainting()
@@ -805,34 +577,20 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
return;
if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
- glDisableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glDisableVertexAttribArray(QT_OPACITY_ATTR);
-
lastTextureUsed = GLuint(-1);
}
if (newMode == TextDrawingMode) {
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
-
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
}
if (newMode == ImageDrawingMode) {
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
-
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticVertexCoordinateArray);
glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, staticTextureCoordinateArray);
}
if (newMode == ImageArrayDrawingMode) {
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
- glEnableVertexAttribArray(QT_TEXTURE_COORDS_ATTR);
- glEnableVertexAttribArray(QT_OPACITY_ATTR);
-
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray.data());
glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray.data());
glVertexAttribPointer(QT_OPACITY_ATTR, 1, GL_FLOAT, GL_FALSE, 0, opacityArray.data());
@@ -891,6 +649,11 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
matrixDirty = true;
}
+ if (snapToPixelGrid) {
+ snapToPixelGrid = false;
+ matrixDirty = true;
+ }
+
// Might need to call updateMatrix to re-calculate inverseScale
if (matrixDirty)
updateMatrix();
@@ -959,7 +722,6 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
}
prepareForDraw(currentBrush.isOpaque());
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
#ifdef QT_OPENGL_CACHE_AS_VBOS
glBindBuffer(GL_ARRAY_BUFFER, cache->vbo);
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, 0);
@@ -1085,20 +847,11 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path)
// Pass when high bit is set, replace stencil value with 0
glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT);
}
-
prepareForDraw(currentBrush.isOpaque());
- if (inRenderText)
- prepareDepthRangeForRenderText();
-
// Stencil the brush onto the dest buffer
composite(vertexCoordinateArray.boundingRect());
-
- if (inRenderText)
- restoreDepthRangeForRenderText();
-
glStencilMask(0);
-
updateClipScissorTest();
}
}
@@ -1138,13 +891,6 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
useSimpleShader();
glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d
-#ifndef QT_OPENGL_ES_2
- if (inRenderText) {
- glPushAttrib(GL_ENABLE_BIT);
- glDisable(GL_DEPTH_TEST);
- }
-#endif
-
if (mode == WindingFillMode) {
Q_ASSERT(stops && !count);
if (q->state()->clipTestEnabled) {
@@ -1185,10 +931,8 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
glStencilMask(GL_STENCIL_HIGH_BIT);
#if 0
glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
#else
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
@@ -1198,21 +942,13 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data,
} else {
glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff);
}
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
#endif
}
// Enable color writes & disable stencil writes
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-
-#ifndef QT_OPENGL_ES_2
- if (inRenderText)
- glPopAttrib();
-#endif
-
}
/*
@@ -1306,7 +1042,7 @@ bool QGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
updateBrushUniforms();
if (shaderMatrixUniformDirty) {
- shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::PmvMatrix), pmvMatrix);
+ glUniformMatrix3fv(location(QGLEngineShaderManager::PmvMatrix), 1, GL_FALSE, (GLfloat*)pmvMatrix);
shaderMatrixUniformDirty = false;
}
@@ -1328,12 +1064,8 @@ void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect)
boundingRect.right, boundingRect.top
};
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, rectVerts);
-
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
}
// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans.
@@ -1341,7 +1073,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, i
GLenum primitive)
{
// Now setup the pointer to the vertex array:
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data);
int previousStop = 0;
@@ -1355,31 +1086,6 @@ void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, i
glDrawArrays(primitive, previousStop, stop - previousStop);
previousStop = stop;
}
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
-}
-
-void QGL2PaintEngineExPrivate::prepareDepthRangeForRenderText()
-{
-#ifndef QT_OPENGL_ES_2
- // Get the z translation value from the model view matrix and
- // transform it using the ortogonal projection with z-near = 0,
- // and z-far = 1, which is used in QGLWidget::renderText()
- GLdouble model[4][4];
- glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
- float deviceZ = -2 * model[3][2] - 1;
-
- glGetFloatv(GL_DEPTH_RANGE, depthRange);
- float windowZ = depthRange[0] + (deviceZ + 1) * 0.5 * (depthRange[1] - depthRange[0]);
-
- glDepthRange(windowZ, windowZ);
-#endif
-}
-
-void QGL2PaintEngineExPrivate::restoreDepthRangeForRenderText()
-{
-#ifndef QT_OPENGL_ES_2
- glDepthRange(depthRange[0], depthRange[1]);
-#endif
}
/////////////////////////////////// Public Methods //////////////////////////////////////////
@@ -1399,10 +1105,7 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
if (qbrush_style(brush) == Qt::NoBrush)
return;
-
- if (!d->inRenderText)
- ensureActive();
-
+ ensureActive();
d->setBrush(brush);
d->fill(path);
}
@@ -1439,6 +1142,11 @@ void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen)
matrixDirty = true;
}
+ if (snapToPixelGrid) {
+ snapToPixelGrid = false;
+ matrixDirty = true;
+ }
+
const Qt::PenStyle penStyle = qpen_style(pen);
const QBrush &penBrush = qpen_brush(pen);
const bool opaque = penBrush.isOpaque() && s->opacity > 0.99;
@@ -1464,7 +1172,6 @@ void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen)
if (opaque) {
prepareForDraw(opaque);
- glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, stroker.vertices());
glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2);
@@ -1473,8 +1180,6 @@ void QGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen)
// d->prepareForDraw(true);
// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2);
- glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR);
-
} else {
qreal width = qpen_widthf(pen) / 2;
if (width == 0)
@@ -1620,8 +1325,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
{
Q_D(QGL2PaintEngineEx);
- if (!d->inRenderText)
- ensureActive();
+ ensureActive();
QOpenGL2PaintEngineState *s = state();
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
@@ -1640,7 +1344,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem
? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat)
: d->glyphCacheType;
- if (d->inRenderText || txtype > QTransform::TxTranslate)
+ if (txtype > QTransform::TxTranslate)
glyphType = QFontEngineGlyphCache::Raster_A8;
if (glyphType == QFontEngineGlyphCache::Raster_RGBMask
@@ -1682,8 +1386,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
if (cache->width() == 0 || cache->height() == 0)
return;
- if (inRenderText)
- transferMode(BrushDrawingMode);
transferMode(TextDrawingMode);
int margin = cache->glyphMargin();
@@ -1715,13 +1417,14 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
addOffset = false;
matrixDirty = true;
}
+ if (!snapToPixelGrid) {
+ snapToPixelGrid = true;
+ matrixDirty = true;
+ }
QBrush pensBrush = q->state()->pen.brush();
setBrush(pensBrush);
- if (inRenderText)
- prepareDepthRangeForRenderText();
-
if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
// Subpixel antialiasing without gamma correction
@@ -1806,9 +1509,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::MaskTexture), QT_MASK_TEXTURE_UNIT);
glDrawArrays(GL_TRIANGLES, 0, 6 * glyphs.size());
-
- if (inRenderText)
- restoreDepthRangeForRenderText();
}
void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int dataCount, const QPixmap &pixmap, QDrawPixmaps::DrawingHints hints)
@@ -1839,6 +1539,11 @@ void QGL2PaintEngineExPrivate::drawPixmaps(const QDrawPixmaps::Data *drawingData
matrixDirty = true;
}
+ if (snapToPixelGrid) {
+ snapToPixelGrid = false;
+ matrixDirty = true;
+ }
+
bool allOpaque = true;
for (int i = 0; i < dataCount; ++i) {
@@ -1956,11 +1661,9 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
d->shaderManager = new QGLEngineShaderManager(d->ctx);
- if (!d->inRenderText) {
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- }
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
#if !defined(QT_OPENGL_ES_2)
glDisable(GL_MULTISAMPLE);
@@ -1970,6 +1673,7 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev)
#if !defined(QT_OPENGL_ES_2)
#if defined(Q_WS_WIN)
+ extern Q_GUI_EXPORT bool qt_cleartype_enabled;
if (qt_cleartype_enabled)
#endif
d->glyphCacheType = QFontEngineGlyphCache::Raster_RGBMask;
@@ -2041,6 +1745,7 @@ void QGL2PaintEngineEx::ensureActive()
glViewport(0, 0, d->width, d->height);
d->needsSync = false;
d->shaderManager->setDirty();
+ d->ctx->d_func()->syncGlState();
setState(state());
}
}
@@ -2125,6 +1830,10 @@ void QGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value)
addOffset = false;
matrixDirty = true;
}
+ if (snapToPixelGrid) {
+ snapToPixelGrid = false;
+ matrixDirty = true;
+ }
if (matrixDirty)
updateMatrix();
@@ -2404,12 +2113,6 @@ QPainterState *QGL2PaintEngineEx::createState(QPainterState *orig) const
return s;
}
-void QGL2PaintEngineEx::setRenderTextActive(bool active)
-{
- Q_D(QGL2PaintEngineEx);
- d->inRenderText = active;
-}
-
QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other)
: QPainterState(other)
{
@@ -2434,5 +2137,3 @@ 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 0746221..f3cba17 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -73,6 +73,12 @@ enum EngineMode {
QT_BEGIN_NAMESPACE
+#define GL_STENCIL_HIGH_BIT GLuint(0x80)
+#define QT_BRUSH_TEXTURE_UNIT GLuint(0)
+#define QT_IMAGE_TEXTURE_UNIT GLuint(0) //Can be the same as brush texture unit
+#define QT_MASK_TEXTURE_UNIT GLuint(1)
+#define QT_BACKGROUND_TEXTURE_UNIT GLuint(2)
+
class QGL2PaintEngineExPrivate;
@@ -167,9 +173,9 @@ public:
width(0), height(0),
ctx(0),
useSystemClip(true),
+ snapToPixelGrid(false),
addOffset(false),
- inverseScale(1),
- inRenderText(false)
+ inverseScale(1)
{ }
~QGL2PaintEngineExPrivate();
@@ -215,10 +221,6 @@ public:
return shaderManager->getUniformLocation(uniform);
}
-
- void prepareDepthRangeForRenderText();
- void restoreDepthRangeForRenderText();
-
void clearClip(uint value);
void writeClip(const QVectorPath &path, uint value);
void resetClipIfNeeded();
@@ -228,7 +230,6 @@ public:
void regenerateClip();
void systemStateChanged();
-
static QGLEngineShaderManager* shaderManagerForEngine(QGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; }
static QGL2PaintEngineExPrivate *getData(QGL2PaintEngineEx *engine) { return engine->d_func(); }
static void cleanupVectorPath(QPaintEngineEx *engine, void *data);
@@ -266,6 +267,7 @@ public:
GLfloat staticVertexCoordinateArray[8];
GLfloat staticTextureCoordinateArray[8];
+ bool snapToPixelGrid;
bool addOffset; // When enabled, adds a 0.49,0.49 offset to matrix in updateMatrix
GLfloat pmvMatrix[3][3];
GLfloat inverseScale;
@@ -273,7 +275,6 @@ public:
GLuint lastTextureUsed;
bool needsSync;
- bool inRenderText;
bool multisamplingAlwaysEnabled;
GLfloat depthRange[2];
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
new file mode 100644
index 0000000..047876f
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtextureglyphcache_gl_p.h"
+#include "qpaintengineex_opengl2_p.h"
+
+#ifdef Q_WS_WIN
+extern Q_GUI_EXPORT bool qt_cleartype_enabled;
+#endif
+
+QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix)
+ : QTextureGlyphCache(type, matrix)
+ , ctx(context)
+ , m_width(0)
+ , m_height(0)
+{
+ glGenFramebuffers(1, &m_fbo);
+ connect(QGLSignalProxy::instance(), SIGNAL(aboutToDestroyContext(const QGLContext*)),
+ SLOT(contextDestroyed(const QGLContext*)));
+}
+
+QGLTextureGlyphCache::~QGLTextureGlyphCache()
+{
+ if (ctx) {
+ QGLShareContextScope scope(ctx);
+ glDeleteFramebuffers(1, &m_fbo);
+
+ if (m_width || m_height)
+ glDeleteTextures(1, &m_texture);
+ }
+}
+
+void QGLTextureGlyphCache::createTextureData(int width, int height)
+{
+ glGenTextures(1, &m_texture);
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+ m_width = width;
+ m_height = height;
+
+ QVarLengthArray<uchar> data(width * height);
+ for (int i = 0; i < data.size(); ++i)
+ data[i] = 0;
+
+ if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+ else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+}
+
+void QGLTextureGlyphCache::resizeTextureData(int width, int height)
+{
+ // ### the QTextureGlyphCache API needs to be reworked to allow
+ // ### resizeTextureData to fail
+
+ int oldWidth = m_width;
+ int oldHeight = m_height;
+
+ GLuint oldTexture = m_texture;
+ createTextureData(width, height);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_fbo);
+
+ GLuint tmp_texture;
+ glGenTextures(1, &tmp_texture);
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, tmp_texture, 0);
+
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ pex->transferMode(BrushDrawingMode);
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ float vertexCoordinateArray[] = { -1, -1, 1, -1, 1, 1, -1, 1 };
+ float textureCoordinateArray[] = { 0, 0, 1, 0, 1, 1, 0, 1 };
+
+ glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
+ glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
+
+ pex->shaderManager->useBlitProgram();
+ pex->shaderManager->blitProgram()->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+#ifdef QT_OPENGL_ES_2
+ QDataBuffer<uchar> buffer(4*oldWidth*oldHeight);
+ buffer.resize(4*oldWidth*oldHeight);
+ glReadPixels(0, 0, oldWidth, oldHeight, GL_RGBA, GL_UNSIGNED_BYTE, buffer.data());
+
+ // do an in-place conversion from GL_RGBA to GL_ALPHA
+ for (int i=0; i<oldWidth*oldHeight; ++i)
+ buffer.data()[i] = buffer.at(4*i + 3);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight,
+ GL_ALPHA, GL_UNSIGNED_BYTE, buffer.data());
+#else
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+#endif
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_RENDERBUFFER_EXT, 0);
+ glDeleteTextures(1, &tmp_texture);
+ glDeleteTextures(1, &oldTexture);
+
+ glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
+
+ glViewport(0, 0, pex->width, pex->height);
+ pex->updateClipScissorTest();
+}
+
+void QGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph)
+{
+ QImage mask = textureMapForGlyph(glyph);
+ const int maskWidth = mask.width();
+ const int maskHeight = mask.height();
+
+ if (mask.format() == QImage::Format_Mono) {
+ mask = mask.convertToFormat(QImage::Format_Indexed8);
+ for (int y = 0; y < maskHeight; ++y) {
+ uchar *src = (uchar *) mask.scanLine(y);
+ for (int x = 0; x < maskWidth; ++x)
+ src[x] = -src[x]; // convert 0 and 1 into 0 and 255
+ }
+ }
+
+
+ glBindTexture(GL_TEXTURE_2D, 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 {
+#ifdef QT_OPENGL_ES2
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, GL_ALPHA, GL_UNSIGNED_BYTE, mask.bits());
+#else
+ // glTexSubImage2D() might cause some garbage to appear in the texture if the mask width is
+ // not a multiple of four bytes. The bug appeared on a computer with 32-bit Windows Vista
+ // and nVidia GeForce 8500GT. GL_UNPACK_ALIGNMENT is set to four bytes, 'mask' has a
+ // multiple of four bytes per line, and most of the glyph shows up correctly in the
+ // texture, which makes me think that this is a driver bug.
+ // One workaround is to make sure the mask width is a multiple of four bytes, for instance
+ // by converting it to a format with four bytes per pixel. Another is to copy one line at a
+ // time.
+
+ for (int i = 0; i < maskHeight; ++i)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y + i, maskWidth, 1, GL_ALPHA, GL_UNSIGNED_BYTE, mask.scanLine(i));
+#endif
+ }
+}
+
+int QGLTextureGlyphCache::glyphMargin() const
+{
+#if defined(Q_WS_MAC)
+ return 2;
+#elif defined (Q_WS_X11)
+ return 0;
+#else
+ return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
+#endif
+}
diff --git a/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
new file mode 100644
index 0000000..393893c
--- /dev/null
+++ b/src/opengl/gl2paintengineex/qtextureglyphcache_gl_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtOpenGL module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEXTUREGLYPHCACHE_GL_P_H
+#define QTEXTUREGLYPHCACHE_GL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtextureglyphcache_p.h>
+#include <private/qgl_p.h>
+#include <qglshaderprogram.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class QGL2PaintEngineExPrivate;
+
+class QGLTextureGlyphCache : public QObject, public QTextureGlyphCache
+{
+ Q_OBJECT
+public:
+ QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyphCache::Type type, const QTransform &matrix);
+ ~QGLTextureGlyphCache();
+
+ virtual void createTextureData(int width, int height);
+ virtual void resizeTextureData(int width, int height);
+ virtual void fillTexture(const Coord &c, glyph_t glyph);
+ virtual int glyphMargin() const;
+
+ inline GLuint texture() const { return m_texture; }
+
+ inline int width() const { return m_width; }
+ inline int height() const { return m_height; }
+
+ inline void setPaintEnginePrivate(QGL2PaintEngineExPrivate *p) { pex = p; }
+
+
+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);
+ }
+ }
+ }
+
+private:
+ QGLContext *ctx;
+
+ QGL2PaintEngineExPrivate *pex;
+
+ GLuint m_texture;
+ GLuint m_fbo;
+
+ int m_width;
+ int m_height;
+
+ QGLShaderProgram *m_program;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index ec01db0..69cfd30 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -55,7 +55,8 @@ SOURCES += qgl.cpp \
gl2paintengineex/qglengineshadersource_p.h \
gl2paintengineex/qglcustomshaderstage_p.h \
gl2paintengineex/qtriangulatingstroker_p.h \
- gl2paintengineex/qtriangulator_p.h
+ gl2paintengineex/qtriangulator_p.h \
+ gl2paintengineex/qtextureglyphcache_gl_p.h
SOURCES += qglshaderprogram.cpp \
qglpixmapfilter.cpp \
@@ -69,7 +70,8 @@ SOURCES += qgl.cpp \
gl2paintengineex/qpaintengineex_opengl2.cpp \
gl2paintengineex/qglcustomshaderstage.cpp \
gl2paintengineex/qtriangulatingstroker.cpp \
- gl2paintengineex/qtriangulator.cpp
+ gl2paintengineex/qtriangulator.cpp \
+ gl2paintengineex/qtextureglyphcache_gl.cpp
}
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 9d4b488..7e922ac 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -1537,6 +1537,18 @@ void QGLContextGroup::removeGuard(QGLSharedResourceGuard *guard)
m_guards = guard->m_next;
}
+const QGLContext *qt_gl_transfer_context(const QGLContext *ctx)
+{
+ if (!ctx)
+ return 0;
+ QList<const QGLContext *> shares
+ (QGLContextPrivate::contextGroup(ctx)->shares());
+ if (shares.size() >= 2)
+ return (ctx == shares.at(0)) ? shares.at(1) : shares.at(0);
+ else
+ return 0;
+}
+
QGLContextPrivate::~QGLContextPrivate()
{
if (!group->m_refs.deref()) {
@@ -1585,6 +1597,8 @@ void QGLContextPrivate::init(QPaintDevice *dev, const QGLFormat &format)
current_fbo = 0;
default_fbo = 0;
active_engine = 0;
+ for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i)
+ vertexAttributeArraysEnabledState[i] = false;
}
QGLContext* QGLContext::currentCtx = 0;
@@ -1830,12 +1844,6 @@ struct DDSFormat {
#define GL_GENERATE_MIPMAP_HINT_SGIS 0x8192
#endif
-Q_GLOBAL_STATIC(QGLShareRegister, _qgl_share_reg)
-Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
-{
- return _qgl_share_reg();
-}
-
/*!
\class QGLContext
\brief The QGLContext class encapsulates an OpenGL rendering context.
@@ -1975,6 +1983,35 @@ void QGLContextPrivate::cleanup()
{
}
+#define ctx q_ptr
+void QGLContextPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled)
+{
+ Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT);
+ Q_ASSERT(glEnableVertexAttribArray);
+
+ if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled)
+ glDisableVertexAttribArray(arrayIndex);
+
+ if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled)
+ glEnableVertexAttribArray(arrayIndex);
+
+ vertexAttributeArraysEnabledState[arrayIndex] = enabled;
+}
+
+void QGLContextPrivate::syncGlState()
+{
+ Q_ASSERT(glEnableVertexAttribArray);
+ for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) {
+ if (vertexAttributeArraysEnabledState[i])
+ glEnableVertexAttribArray(i);
+ else
+ glDisableVertexAttribArray(i);
+ }
+
+}
+#undef ctx
+
+
/*!
\overload
@@ -3055,7 +3092,7 @@ bool QGLContext::create(const QGLContext* shareContext)
wd->usesDoubleBufferedGLContext = d->glFormat.doubleBuffer();
}
if (d->sharing) // ok, we managed to share
- qgl_share_reg()->addShare(this, shareContext);
+ QGLContextGroup::addShare(this, shareContext);
return d->valid;
}
@@ -4479,9 +4516,9 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
int height = d->glcx->device()->height();
bool auto_swap = autoBufferSwap();
+ QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
+ qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
QPaintEngine *engine = paintEngine();
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
if (engine->isActive()) {
@@ -4501,11 +4538,6 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
d->disable_clear_on_painter_begin = true;
- if (engine->type() == QPaintEngine::OpenGL2) {
- qt_save_gl_state();
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
p = new QPainter(this);
}
@@ -4529,11 +4561,8 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font,
delete p;
setAutoBufferSwap(auto_swap);
d->disable_clear_on_painter_begin = false;
- if (engine->type() == QPaintEngine::OpenGL2)
- qt_restore_gl_state();
}
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+ qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
#else // QT_OPENGL_ES
Q_UNUSED(x);
Q_UNUSED(y);
@@ -4581,9 +4610,9 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
&win_x, &win_y, &win_z);
win_y = height - win_y; // y is inverted
+ QPaintEngine::Type oldEngineType = qgl_engine_selector()->preferredPaintEngine();
+ qgl_engine_selector()->setPreferredPaintEngine(QPaintEngine::OpenGL);
QPaintEngine *engine = paintEngine();
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(true);
QPainter *p;
bool reuse_painter = false;
bool use_depth_testing = glIsEnabled(GL_DEPTH_TEST);
@@ -4597,8 +4626,6 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
setAutoBufferSwap(false);
// disable glClear() as a result of QPainter::begin()
d->disable_clear_on_painter_begin = true;
- if (engine->type() == QPaintEngine::OpenGL2)
- qt_save_gl_state();
p = new QPainter(this);
}
@@ -4627,13 +4654,10 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con
} else {
p->end();
delete p;
- if (engine->type() == QPaintEngine::OpenGL2)
- qt_restore_gl_state();
setAutoBufferSwap(auto_swap);
d->disable_clear_on_painter_begin = false;
}
- if (engine->type() == QPaintEngine::OpenGL2)
- static_cast<QGL2PaintEngineEx *>(engine)->setRenderTextActive(false);
+ qgl_engine_selector()->setPreferredPaintEngine(oldEngineType);
#else // QT_OPENGL_ES
Q_UNUSED(x);
Q_UNUSED(y);
@@ -5029,8 +5053,6 @@ void QGLWidgetPrivate::initContext(QGLContext *context, const QGLWidget* shareWi
if (!glcx)
glcx = new QGLContext(QGLFormat::defaultFormat(), q);
-
- q->setAttribute(Qt::WA_NoSystemBackground);
}
#if defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
@@ -5054,7 +5076,7 @@ Q_OPENGL_EXPORT const QString qt_gl_library_name()
}
#endif
-void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *share) {
+void QGLContextGroup::addShare(const QGLContext *context, const QGLContext *share) {
Q_ASSERT(context && share);
if (context->d_ptr->group == share->d_ptr->group)
return;
@@ -5075,11 +5097,7 @@ void QGLShareRegister::addShare(const QGLContext *context, const QGLContext *sha
group->m_shares.append(context);
}
-QList<const QGLContext *> QGLShareRegister::shares(const QGLContext *context) {
- return context->d_ptr->group->m_shares;
-}
-
-void QGLShareRegister::removeShare(const QGLContext *context) {
+void QGLContextGroup::removeShare(const QGLContext *context) {
// Remove the context from the group.
QGLContextGroup *group = context->d_ptr->group;
if (group->m_shares.isEmpty())
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index d2fe5fb..c5ad945 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -410,11 +410,12 @@ private:
friend class QOpenGLPaintEnginePrivate;
friend class QGL2PaintEngineEx;
friend class QGL2PaintEngineExPrivate;
+ friend class QGLEngineShaderManager;
friend class QGLWindowSurface;
friend class QGLPixmapData;
friend class QGLPixmapFilterBase;
friend class QGLTextureGlyphCache;
- friend class QGLShareRegister;
+ friend class QGLContextGroup;
friend class QGLSharedResourceGuard;
friend class QGLPixmapBlurFilter;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp
index 839e8eb..084db32 100644
--- a/src/opengl/qgl_egl.cpp
+++ b/src/opengl/qgl_egl.cpp
@@ -152,7 +152,7 @@ void QGLContext::reset()
d->valid = false;
d->transpColor = QColor();
d->initDone = false;
- qgl_share_reg()->removeShare(this);
+ QGLContextGroup::removeShare(this);
}
void QGLContext::makeCurrent()
diff --git a/src/opengl/qgl_mac.mm b/src/opengl/qgl_mac.mm
index 4dd822d..8ecc48b 100644
--- a/src/opengl/qgl_mac.mm
+++ b/src/opengl/qgl_mac.mm
@@ -476,7 +476,7 @@ void QGLContext::reset()
d->valid = false;
d->transpColor = QColor();
d->initDone = false;
- qgl_share_reg()->removeShare(this);
+ QGLContextGroup::removeShare(this);
}
void QGLContext::makeCurrent()
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index a075a31..37781d5 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -232,9 +232,8 @@ class QGLSharedResourceGuard;
typedef QHash<QString, GLuint> QGLDDSCache;
// QGLContextPrivate has the responsibility of creating context groups.
-// QGLContextPrivate and QGLShareRegister will both maintain the reference counter and destroy
+// QGLContextPrivate maintains the reference counter and destroys
// context groups when needed.
-// QGLShareRegister has the responsibility of keeping the context pointer up to date.
class QGLContextGroup
{
public:
@@ -243,9 +242,13 @@ public:
QGLExtensionFuncs &extensionFuncs() {return m_extensionFuncs;}
const QGLContext *context() const {return m_context;}
bool isSharing() const { return m_shares.size() >= 2; }
+ QList<const QGLContext *> shares() const { return m_shares; }
void addGuard(QGLSharedResourceGuard *guard);
void removeGuard(QGLSharedResourceGuard *guard);
+
+ static void addShare(const QGLContext *context, const QGLContext *share);
+ static void removeShare(const QGLContext *context);
private:
QGLContextGroup(const QGLContext *context) : m_context(context), m_guards(0), m_refs(1) { }
@@ -259,14 +262,21 @@ private:
void cleanupResources(const QGLContext *ctx);
- friend class QGLShareRegister;
friend class QGLContext;
friend class QGLContextPrivate;
friend class QGLContextResource;
};
+// Get the context that resources for "ctx" will transfer to once
+// "ctx" is destroyed. Returns null if nothing is sharing with ctx.
+Q_OPENGL_EXPORT const QGLContext *qt_gl_transfer_context(const QGLContext *);
+
class QGLTexture;
+// This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's
+// all the GL2 engine uses:
+#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3
+
class QGLContextPrivate
{
Q_DECLARE_PUBLIC(QGLContext)
@@ -286,6 +296,9 @@ public:
void cleanup();
+ void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true);
+ void syncGlState(); // Makes sure the GL context's state is what we think it is
+
#if defined(Q_WS_WIN)
void updateFormatVersion();
#endif
@@ -346,6 +359,8 @@ public:
GLuint default_fbo;
QPaintEngine *active_engine;
+ bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT];
+
static inline QGLContextGroup *contextGroup(const QGLContext *ctx) { return ctx->d_ptr->group; }
#ifdef Q_WS_WIN
@@ -409,19 +424,6 @@ public:
Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions)
-class Q_OPENGL_EXPORT QGLShareRegister
-{
-public:
- QGLShareRegister() {}
- ~QGLShareRegister() {}
-
- void addShare(const QGLContext *context, const QGLContext *share);
- QList<const QGLContext *> shares(const QGLContext *context);
- void removeShare(const QGLContext *context);
-};
-
-extern Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg();
-
// Temporarily make a context current if not already current or
// shared with the current contex. The previous context is made
// current when the object goes out of scope.
diff --git a/src/opengl/qgl_win.cpp b/src/opengl/qgl_win.cpp
index c2170e0..357f726 100644
--- a/src/opengl/qgl_win.cpp
+++ b/src/opengl/qgl_win.cpp
@@ -1267,7 +1267,7 @@ void QGLContext::reset()
delete d->cmap;
d->cmap = 0;
d->initDone = false;
- qgl_share_reg()->removeShare(this);
+ QGLContextGroup::removeShare(this);
}
//
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index 9c3fc79..9fca28c 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -825,7 +825,7 @@ void QGLContext::reset()
d->valid = false;
d->transpColor = QColor();
d->initDone = false;
- qgl_share_reg()->removeShare(this);
+ QGLContextGroup::removeShare(this);
}
@@ -1132,6 +1132,72 @@ void *QGLContext::getProcAddress(const QString &proc) const
return glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(proc.toLatin1().data()));
}
+//
+// This class is used to create a temporary, minimal GL context, which is used
+// to retrive GL version and extension info. It's significantly faster to
+// construct than a QGLWidget, and it doesn't have the recursive creation
+// problem that QGLWidget would have. E.g. creating a temporary QGLWidget to
+// retrieve GL info as part of the QGLWidget initialization.
+//
+class QGLTempContext
+{
+public:
+ QGLTempContext(int screen = 0) :
+ initialized(false),
+ old_drawable(0),
+ old_context(0)
+ {
+ int attribs[] = {GLX_RGBA, XNone};
+ XVisualInfo *vi = glXChooseVisual(X11->display, screen, attribs);
+ if (!vi) {
+ qWarning("QGLTempContext: No GL capable X visuals available.");
+ return;
+ }
+
+ int useGL;
+ glXGetConfig(X11->display, vi, GLX_USE_GL, &useGL);
+ if (!useGL) {
+ XFree(vi);
+ return;
+ }
+
+ old_drawable = glXGetCurrentDrawable();
+ old_context = glXGetCurrentContext();
+
+ XSetWindowAttributes a;
+ a.colormap = qt_gl_choose_cmap(X11->display, vi);
+ drawable = XCreateWindow(X11->display, RootWindow(X11->display, screen),
+ 0, 0, 1, 1, 0,
+ vi->depth, InputOutput, vi->visual,
+ CWColormap, &a);
+ context = glXCreateContext(X11->display, vi, 0, True);
+ if (context && glXMakeCurrent(X11->display, drawable, context)) {
+ initialized = true;
+ } else {
+ qWarning("QGLTempContext: Unable to create GL context.");
+ XDestroyWindow(X11->display, drawable);
+ }
+ XFree(vi);
+ }
+
+ ~QGLTempContext() {
+ if (initialized) {
+ glXMakeCurrent(X11->display, 0, 0);
+ glXDestroyContext(X11->display, context);
+ XDestroyWindow(X11->display, drawable);
+ }
+ if (old_drawable && old_context)
+ glXMakeCurrent(X11->display, old_drawable, old_context);
+ }
+
+private:
+ bool initialized;
+ Window drawable;
+ GLXContext context;
+ GLXDrawable old_drawable;
+ GLXContext old_context;
+};
+
/*****************************************************************************
QGLOverlayWidget (Internal overlay class for X11)
*****************************************************************************/
@@ -1574,8 +1640,7 @@ void QGLExtensions::init()
return;
init_done = true;
- QGLWidget dmy;
- dmy.makeCurrent();
+ QGLTempContext context;
init_extensions();
// nvidia 9x.xx unix drivers contain a bug which requires us to call glFinish before releasing an fbo
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index 19026b3..d6281f7 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -52,6 +52,116 @@
QT_BEGIN_NAMESPACE
+
+bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config,
+ const QX11Info &x11Info, bool useArgbVisual);
+//
+// QGLTempContext is a class for creating a temporary GL context
+// (which is needed during QGLWidget initialization to retrieve GL
+// extension info). Faster to construct than a full QGLWidget.
+//
+class QGLTempContext
+{
+public:
+ QGLTempContext(int screen = 0) :
+ initialized(false),
+ window(0),
+ context(0),
+ surface(0)
+ {
+ display = eglGetDisplay(EGLNativeDisplayType(X11->display));
+
+ if (!eglInitialize(display, NULL, NULL)) {
+ qWarning("QGLTempContext: Unable to initialize EGL display.");
+ return;
+ }
+
+ EGLConfig config;
+ int numConfigs = 0;
+ EGLint attribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+#ifdef QT_OPENGL_ES_2
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+#endif
+ EGL_NONE
+ };
+
+ eglChooseConfig(display, attribs, &config, 1, &numConfigs);
+ if (!numConfigs) {
+ qWarning("QGLTempContext: No EGL configurations available.");
+ return;
+ }
+
+ XVisualInfo visualInfo;
+ XVisualInfo *vi;
+ int numVisuals;
+ EGLint id = 0;
+
+ eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &id);
+ if (id == 0) {
+ // EGL_NATIVE_VISUAL_ID is optional and might not be supported
+ // on some implementations - we'll have to do it the hard way
+ QX11Info xinfo;
+ qt_egl_setup_x11_visual(visualInfo, display, config, xinfo, false);
+ } else {
+ visualInfo.visualid = id;
+ }
+ vi = XGetVisualInfo(X11->display, VisualIDMask, &visualInfo, &numVisuals);
+ if (!vi || numVisuals < 1) {
+ qWarning("QGLTempContext: Unable to get X11 visual info id.");
+ return;
+ }
+
+ window = XCreateWindow(X11->display, RootWindow(X11->display, screen),
+ 0, 0, 1, 1, 0,
+ vi->depth, InputOutput, vi->visual,
+ 0, 0);
+
+ surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType) window, NULL);
+
+ if (surface == EGL_NO_SURFACE) {
+ qWarning("QGLTempContext: Error creating EGL surface.");
+ XFree(vi);
+ XDestroyWindow(X11->display, window);
+ return;
+ }
+
+ EGLint contextAttribs[] = {
+#ifdef QT_OPENGL_ES_2
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+#endif
+ EGL_NONE
+ };
+ context = eglCreateContext(display, config, 0, contextAttribs);
+ if (context != EGL_NO_CONTEXT
+ && eglMakeCurrent(display, surface, surface, context))
+ {
+ initialized = true;
+ } else {
+ qWarning("QGLTempContext: Error creating EGL context.");
+ eglDestroySurface(display, surface);
+ XDestroyWindow(X11->display, window);
+ }
+ XFree(vi);
+ }
+
+ ~QGLTempContext() {
+ if (initialized) {
+ eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglDestroyContext(display, context);
+ eglDestroySurface(display, surface);
+ XDestroyWindow(X11->display, window);
+ }
+ }
+
+private:
+ bool initialized;
+ Window window;
+ EGLContext context;
+ EGLSurface surface;
+ EGLDisplay display;
+};
+
bool QGLFormat::hasOpenGLOverlays()
{
return false;
@@ -239,7 +349,7 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf
// If EGL does not know the visual ID, so try to select an appropriate one ourselves, first
// using XRender if we're supposed to have an alpha, then falling back to XGetVisualInfo
-
+
#if !defined(QT_NO_XRENDER)
if (vi.visualid == 0 && useArgbVisual) {
// Try to use XRender to find an ARGB visual we can use
@@ -446,12 +556,8 @@ void QGLExtensions::init()
init_done = true;
// We need a context current to initialize the extensions.
- QGLWidget tmpWidget;
- tmpWidget.makeCurrent();
-
+ QGLTempContext context;
init_extensions();
-
- tmpWidget.doneCurrent();
}
// Re-creates the EGL surface if the window ID has changed or if force is true
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index 7c97ebb..fab6efc 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -127,7 +127,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form
qctx = new QGLContext(format);
qctx->d_func()->sharing = (shareWidget != 0);
if (shareWidget != 0 && shareWidget->d_func()->glcx) {
- qgl_share_reg()->addShare(qctx, shareWidget->d_func()->glcx);
+ QGLContextGroup::addShare(qctx, shareWidget->d_func()->glcx);
shareWidget->d_func()->glcx->d_func()->sharing = true;
}
diff --git a/src/opengl/qglshaderprogram.cpp b/src/opengl/qglshaderprogram.cpp
index f9737a56..b4191dc 100644
--- a/src/opengl/qglshaderprogram.cpp
+++ b/src/opengl/qglshaderprogram.cpp
@@ -2275,42 +2275,6 @@ void QGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value
\overload
Sets the uniform variable at \a location in the current context
- to a 2x2 matrix \a value. The matrix elements must be specified
- in column-major order.
-
- \sa setAttributeValue()
- \since 4.6.2
-*/
-void QGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2])
-{
- Q_D(QGLShaderProgram);
- Q_UNUSED(d);
- if (location != -1)
- glUniformMatrix2fv(location, 1, GL_FALSE, value[0]);
-}
-
-/*!
- \overload
-
- Sets the uniform variable at \a location in the current context
- to a 3x3 matrix \a value. The matrix elements must be specified
- in column-major order.
-
- \sa setAttributeValue()
- \since 4.6.2
-*/
-void QGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3])
-{
- Q_D(QGLShaderProgram);
- Q_UNUSED(d);
- if (location != -1)
- glUniformMatrix3fv(location, 1, GL_FALSE, value[0]);
-}
-
-/*!
- \overload
-
- Sets the uniform variable at \a location in the current context
to a 4x4 matrix \a value. The matrix elements must be specified
in column-major order.
@@ -2324,37 +2288,6 @@ void QGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4])
glUniformMatrix4fv(location, 1, GL_FALSE, value[0]);
}
-
-/*!
- \overload
-
- Sets the uniform variable called \a name in the current context
- to a 2x2 matrix \a value. The matrix elements must be specified
- in column-major order.
-
- \sa setAttributeValue()
- \since 4.6.2
-*/
-void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2])
-{
- setUniformValue(uniformLocation(name), value);
-}
-
-/*!
- \overload
-
- Sets the uniform variable called \a name in the current context
- to a 3x3 matrix \a value. The matrix elements must be specified
- in column-major order.
-
- \sa setAttributeValue()
- \since 4.6.2
-*/
-void QGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3])
-{
- setUniformValue(uniformLocation(name), value);
-}
-
/*!
\overload
diff --git a/src/opengl/qglshaderprogram.h b/src/opengl/qglshaderprogram.h
index 4eb80dd..deeaee2 100644
--- a/src/opengl/qglshaderprogram.h
+++ b/src/opengl/qglshaderprogram.h
@@ -216,8 +216,6 @@ public:
void setUniformValue(int location, const QMatrix4x2& value);
void setUniformValue(int location, const QMatrix4x3& value);
void setUniformValue(int location, const QMatrix4x4& value);
- void setUniformValue(int location, const GLfloat value[2][2]);
- void setUniformValue(int location, const GLfloat value[3][3]);
void setUniformValue(int location, const GLfloat value[4][4]);
void setUniformValue(int location, const QTransform& value);
@@ -244,8 +242,6 @@ public:
void setUniformValue(const char *name, const QMatrix4x2& value);
void setUniformValue(const char *name, const QMatrix4x3& value);
void setUniformValue(const char *name, const QMatrix4x4& value);
- void setUniformValue(const char *name, const GLfloat value[2][2]);
- void setUniformValue(const char *name, const GLfloat value[3][3]);
void setUniformValue(const char *name, const GLfloat value[4][4]);
void setUniformValue(const char *name, const QTransform& value);