summaryrefslogtreecommitdiffstats
path: root/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp')
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp155
1 files changed, 114 insertions, 41 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 2bfbf4a25..a3475c72b 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"
@@ -115,6 +116,7 @@ public Q_SLOTS:
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
@@ -151,10 +153,17 @@ QGLTextureGlyphCache::QGLTextureGlyphCache(QGLContext *context, QFontEngineGlyph
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)
@@ -266,10 +275,6 @@ 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)
@@ -295,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);
@@ -338,9 +344,6 @@ void QGL2PaintEngineExPrivate::useSimpleShader()
}
}
-
-Q_GLOBAL_STATIC(QGL2GradientCache, qt_opengl_gradient_cache)
-
void QGL2PaintEngineExPrivate::updateBrushTexture()
{
// qDebug("QGL2PaintEngineExPrivate::updateBrushTexture()");
@@ -361,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);
@@ -369,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();
@@ -1052,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,
@@ -1071,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);
@@ -1209,11 +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->shaderManager = QGLEngineShaderManager::managerForContext(d->ctx);
+ d->shaderManager->setDirty();
glViewport(0, 0, d->width, d->height);
@@ -1288,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;
@@ -1330,10 +1343,30 @@ void QGL2PaintEngineExPrivate::updateDepthScissorTest()
else
glDisable(GL_DEPTH_TEST);
- if (q->state()->scissorTestEnabled)
+ if (q->state()->scissorTestEnabled) {
+ QRect bounds = q->state()->rectangleClip;
+ if (bounds.isNull() || !q->painter()->hasClipping()) {
+ if (use_system_clip)
+ bounds = systemClip.boundingRect();
+ else
+ bounds = QRect(0, 0, width, height);
+ }
+
glEnable(GL_SCISSOR_TEST);
- else
+ setScissor(bounds);
+ } else {
glDisable(GL_SCISSOR_TEST);
+ }
+}
+
+void QGL2PaintEngineExPrivate::setScissor(const QRect &rect)
+{
+ const int left = rect.left();
+ const int width = rect.width();
+ const int bottom = height - (rect.top() + rect.height());
+ const int height = rect.height();
+
+ glScissor(left, bottom, width, height);
}
void QGL2PaintEngineEx::clipEnabledChanged()
@@ -1349,9 +1382,10 @@ void QGL2PaintEngineEx::clipEnabledChanged()
if (d->use_system_clip) {
state()->currentDepth = -0.5f;
} else {
- glDisable(GL_DEPTH_TEST);
state()->depthTestEnabled = false;
}
+
+ d->updateDepthScissorTest();
}
}
@@ -1423,9 +1457,42 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
if ((d->use_system_clip && rect.contains(d->systemClip.boundingRect()))
|| rect.contains(QRect(0, 0, d->width, d->height)))
return;
+
+ if (state()->rectangleClip.isValid()) {
+ state()->rectangleClip = state()->rectangleClip.intersected(rect.toRect());
+
+ state()->hasRectangleClip = true;
+ state()->scissorTestEnabled = true;
+
+ glEnable(GL_SCISSOR_TEST);
+ d->setScissor(state()->rectangleClip);
+
+ return;
+ }
}
}
+ if (!state()->hasRectangleClip)
+ state()->rectangleClip = QRect();
+
+ if (state()->rectangleClip.isValid() && op != Qt::NoClip && op != Qt::ReplaceClip) {
+ QPainterPath path;
+ path.addRect(state()->rectangleClip);
+
+ state()->rectangleClip = QRect();
+ d->updateDepthScissorTest();
+
+ glDepthFunc(GL_ALWAYS);
+
+ state()->maxDepth = 0.5f;
+ d->writeClip(qtVectorPathForPath(path), state()->maxDepth);
+ state()->currentDepth = 0.25f;
+ state()->depthTestEnabled = true;
+
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+ }
+
switch (op) {
case Qt::NoClip:
if (d->use_system_clip) {
@@ -1446,6 +1513,7 @@ void QGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op)
break;
case Qt::ReplaceClip:
d->systemStateChanged();
+ state()->rectangleClip = QRect();
state()->maxDepth = 0.5f;
glDepthFunc(GL_ALWAYS);
d->writeClip(path, state()->maxDepth);
@@ -1484,27 +1552,30 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
q->state()->depthTestEnabled = false;
q->state()->scissorTestEnabled = false;
q->state()->needsDepthBufferClear = true;
+ q->state()->hasRectangleClip = false;
glDisable(GL_SCISSOR_TEST);
q->state()->currentDepth = -0.5f;
q->state()->maxDepth = 0.5f;
- if (use_system_clip) {
- QRect bounds = systemClip.boundingRect();
- if (systemClip.numRects() == 1
- && bounds == QRect(0, 0, width, height))
- {
- q->state()->needsDepthBufferClear = true;
- } else {
- glEnable(GL_SCISSOR_TEST);
+ q->state()->rectangleClip = QRect(0, 0, width, height);
- const int left = bounds.left();
- const int width = bounds.width();
- const int bottom = height - (bounds.top() + bounds.height());
- const int height = bounds.height();
+ if (use_system_clip) {
+ if (systemClip.numRects() == 1) {
+ QRect bounds = systemClip.boundingRect();
+ if (bounds == QRect(0, 0, width, height)) {
+ use_system_clip = false;
+ return;
+ }
- glScissor(left, bottom, width, height);
+ q->state()->rectangleClip = bounds;
+ q->state()->scissorTestEnabled = true;
+ updateDepthScissorTest();
+ } else {
+ q->state()->rectangleClip = QRect();
+ q->state()->scissorTestEnabled = true;
+ updateDepthScissorTest();
QTransform transform = q->state()->matrix;
q->state()->matrix = QTransform();
@@ -1526,7 +1597,6 @@ void QGL2PaintEngineExPrivate::systemStateChanged()
glEnable(GL_DEPTH_TEST);
q->state()->depthTestEnabled = true;
- q->state()->scissorTestEnabled = true;
q->state()->matrix = transform;
q->transformChanged();
@@ -1601,6 +1671,8 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &oth
currentDepth = other.currentDepth;
maxDepth = other.maxDepth;
canRestoreClip = other.canRestoreClip;
+ rectangleClip = other.rectangleClip;
+ hasRectangleClip = other.hasRectangleClip;
}
QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
@@ -1611,6 +1683,7 @@ QOpenGL2PaintEngineState::QOpenGL2PaintEngineState()
currentDepth = -0.5f;
maxDepth = 0.5f;
canRestoreClip = true;
+ hasRectangleClip = false;
}
QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()