diff options
author | Martin Smith <msmith@trolltech.com> | 2009-12-18 09:07:46 (GMT) |
---|---|---|
committer | Martin Smith <msmith@trolltech.com> | 2009-12-18 09:07:46 (GMT) |
commit | 0d212670c06ed54ac785e0bb945c792947d388f5 (patch) | |
tree | c4f6c6762ad42df463f30e05e090fa2cfa9de77a /src/opengl | |
parent | 371420d5f31a04b91c01807139d49e97db040bee (diff) | |
parent | 7c1283fca1ef2e742b5794600e00edf0c3e3020f (diff) | |
download | Qt-0d212670c06ed54ac785e0bb945c792947d388f5.zip Qt-0d212670c06ed54ac785e0bb945c792947d388f5.tar.gz Qt-0d212670c06ed54ac785e0bb945c792947d388f5.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/oslo-staging-1 into 4.6
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/gl2paintengineex/qglcustomshaderstage_p.h | 2 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 96 | ||||
-rw-r--r-- | src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h | 3 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 115 | ||||
-rw-r--r-- | src/opengl/qgl.h | 1 | ||||
-rw-r--r-- | src/opengl/qgl_egl.cpp | 34 | ||||
-rw-r--r-- | src/opengl/qgl_p.h | 49 | ||||
-rw-r--r-- | src/opengl/qgl_x11.cpp | 24 | ||||
-rw-r--r-- | src/opengl/qgl_x11egl.cpp | 48 | ||||
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 6 | ||||
-rw-r--r-- | src/opengl/qglpixmapfilter.cpp | 754 | ||||
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 2 |
12 files changed, 396 insertions, 738 deletions
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h index e319389..e0033be 100644 --- a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h +++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h @@ -68,7 +68,7 @@ class Q_OPENGL_EXPORT QGLCustomShaderStage public: QGLCustomShaderStage(); virtual ~QGLCustomShaderStage(); - virtual void setUniforms(QGLShaderProgram*) = 0; + virtual void setUniforms(QGLShaderProgram*) {} void setUniformsDirty(); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 3fce384..fb9bcb4 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -589,53 +589,31 @@ void QGL2PaintEngineExPrivate::updateMatrix() // matrix multiplication as most of the components are trivial. const QTransform& transform = q->state()->matrix; - if (mode == TextDrawingMode) { - // Text drawing mode is only used for non-scaling transforms - pmvMatrix[0][0] = 2.0 / width; - pmvMatrix[0][1] = 0.0; - pmvMatrix[0][2] = 0.0; - pmvMatrix[0][3] = 0.0; - pmvMatrix[1][0] = 0.0; - pmvMatrix[1][1] = -2.0 / height; - pmvMatrix[1][2] = 0.0; - pmvMatrix[1][3] = 0.0; - pmvMatrix[2][0] = 0.0; - pmvMatrix[2][1] = 0.0; - pmvMatrix[2][2] = -1.0; - pmvMatrix[2][3] = 0.0; - pmvMatrix[3][0] = pmvMatrix[0][0] * qRound(transform.dx()) - 1.0; - pmvMatrix[3][1] = pmvMatrix[1][1] * qRound(transform.dy()) + 1.0; - pmvMatrix[3][2] = 0.0; - pmvMatrix[3][3] = 1.0; - - inverseScale = 1; - } else { - qreal wfactor = 2.0 / width; - qreal hfactor = -2.0 / height; - - pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13(); - pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13(); - pmvMatrix[0][2] = 0.0; - pmvMatrix[0][3] = transform.m13(); - pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23(); - pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23(); - pmvMatrix[1][2] = 0.0; - pmvMatrix[1][3] = transform.m23(); - pmvMatrix[2][0] = 0.0; - pmvMatrix[2][1] = 0.0; - pmvMatrix[2][2] = -1.0; - pmvMatrix[2][3] = 0.0; - pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33(); - pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33(); - pmvMatrix[3][2] = 0.0; - pmvMatrix[3][3] = transform.m33(); - - // 1/10000 == 0.0001, so we have good enough res to cover curves - // that span the entire widget... - inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), - qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), - qreal(0.0001)); - } + qreal wfactor = 2.0 / width; + qreal hfactor = -2.0 / height; + + pmvMatrix[0][0] = wfactor * transform.m11() - transform.m13(); + pmvMatrix[0][1] = hfactor * transform.m12() + transform.m13(); + pmvMatrix[0][2] = 0.0; + pmvMatrix[0][3] = transform.m13(); + pmvMatrix[1][0] = wfactor * transform.m21() - transform.m23(); + pmvMatrix[1][1] = hfactor * transform.m22() + transform.m23(); + pmvMatrix[1][2] = 0.0; + pmvMatrix[1][3] = transform.m23(); + pmvMatrix[2][0] = 0.0; + pmvMatrix[2][1] = 0.0; + pmvMatrix[2][2] = -1.0; + pmvMatrix[2][3] = 0.0; + pmvMatrix[3][0] = wfactor * transform.dx() - transform.m33(); + pmvMatrix[3][1] = hfactor * transform.dy() + transform.m33(); + pmvMatrix[3][2] = 0.0; + pmvMatrix[3][3] = transform.m33(); + + // 1/10000 == 0.0001, so we have good enough res to cover curves + // that span the entire widget... + inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), + qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), + qreal(0.0001)); matrixDirty = false; @@ -817,17 +795,12 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) lastTexture = GLuint(-1); } - if (mode == TextDrawingMode) - matrixDirty = true; - 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()); - - matrixDirty = true; } if (newMode == ImageDrawingMode) { @@ -930,7 +903,7 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) int floatSizeInBytes = vertexCount * 2 * sizeof(float); cache->vertexCount = vertexCount; cache->primitiveType = GL_TRIANGLE_FAN; - cache->iscale = inverseScale; + cache->iscale = inverseScale; #ifdef QT_OPENGL_CACHE_AS_VBOS glGenBuffers(1, &cache->vbo); glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); @@ -1545,21 +1518,21 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); - bool drawCached = true; + QTransform::TransformationType txtype = s->matrix.type(); - if (s->matrix.type() > QTransform::TxTranslate) - drawCached = false; + float det = s->matrix.determinant(); + bool drawCached = txtype < QTransform::TxProject; - // don't try to cache huge fonts + // don't try to cache huge fonts or vastly transformed fonts const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64) + if (pixelSize * pixelSize * qAbs(det) >= 64 * 64 || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(ti.fontEngine->glyphFormat) : d->glyphCacheType; - if (d->inRenderText) + if (d->inRenderText || txtype > QTransform::TxTranslate) glyphType = QFontEngineGlyphCache::Raster_A8; if (glyphType == QFontEngineGlyphCache::Raster_RGBMask @@ -1581,7 +1554,6 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly const QTextItemInt &ti) { Q_Q(QGL2PaintEngineEx); - QOpenGL2PaintEngineState *s = q->state(); QVarLengthArray<QFixedPoint> positions; QVarLengthArray<glyph_t> glyphs; @@ -1589,10 +1561,10 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, QFontEngineGly ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); QGLTextureGlyphCache *cache = - (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, s->matrix); + (QGLTextureGlyphCache *) ti.fontEngine->glyphCache(ctx, glyphType, QTransform()); if (!cache || cache->cacheType() != glyphType) { - cache = new QGLTextureGlyphCache(ctx, glyphType, s->matrix); + cache = new QGLTextureGlyphCache(ctx, glyphType, QTransform()); ti.fontEngine->setGlyphCache(ctx, cache); } diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 0084476..77ca3a8 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -291,10 +291,7 @@ public: QScopedPointer<QPixmapFilter> convolutionFilter; QScopedPointer<QPixmapFilter> colorizeFilter; QScopedPointer<QPixmapFilter> blurFilter; - QScopedPointer<QPixmapFilter> animationBlurFilter; - QScopedPointer<QPixmapFilter> fastBlurFilter; QScopedPointer<QPixmapFilter> dropShadowFilter; - QScopedPointer<QPixmapFilter> fastDropShadowFilter; QSet<QVectorPath::CacheEntry *> pathCaches; QVector<GLuint> unusedVBOSToClean; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 1bd1b91..466e851 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -397,8 +397,7 @@ static inline GLint qgluProject(GLdouble objx, GLdouble objy, GLdouble objz, \i \link setDirectRendering() Direct rendering:\endlink Enabled. \i \link setOverlay() Overlay:\endlink Disabled. \i \link setPlane() Plane:\endlink 0 (i.e., normal plane). - \i \link setSampleBuffers() Multisample buffers:\endlink Enabled on - OpenGL/ES 2.0, disabled on other platforms. + \i \link setSampleBuffers() Multisample buffers:\endlink Disabled. \endlist */ @@ -2064,6 +2063,29 @@ QGLTexture *QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G // #define QGL_BIND_TEXTURE_DEBUG +// map from Qt's ARGB endianness-dependent format to GL's big-endian RGBA layout +static inline void qgl_byteSwapImage(QImage &img, GLenum pixel_type) +{ + const int width = img.width(); + const int height = img.height(); + + if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV + || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) + { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); + } + } else { + for (int i = 0; i < height; ++i) { + uint *p = (uint *) img.scanLine(i); + for (int x = 0; x < width; ++x) + p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); + } + } +} + QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, GLint internalFormat, const qint64 key, QGLContext::BindOptions options) { @@ -2216,23 +2238,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G // 32 in the switch above is for the RGB16 case, where we set // the format to GL_RGB Q_ASSERT(img.depth() == 32); - const int width = img.width(); - const int height = img.height(); - - if (pixel_type == GL_UNSIGNED_INT_8_8_8_8_REV - || (pixel_type == GL_UNSIGNED_BYTE && QSysInfo::ByteOrder == QSysInfo::LittleEndian)) { - for (int i=0; i < height; ++i) { - uint *p = (uint *) img.scanLine(i); - for (int x=0; x<width; ++x) - p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00); - } - } else { - for (int i=0; i < height; ++i) { - uint *p = (uint *) img.scanLine(i); - for (int x=0; x<width; ++x) - p[x] = (p[x] << 8) | ((p[x] >> 24) & 0xff); - } - } + qgl_byteSwapImage(img, pixel_type); } #ifdef QT_OPENGL_ES // OpenGL/ES requires that the internal and external formats be identical. @@ -3804,6 +3810,11 @@ bool QGLWidget::event(QEvent *e) } #if defined(QT_OPENGL_ES) + // A re-parent is likely to destroy the X11 window and re-create it. It is important + // that we free the EGL surface _before_ the winID changes - otherwise we can leak. + if (e->type() == QEvent::ParentAboutToChange) + d->glcx->d_func()->destroyEglSurfaceForDevice(); + if ((e->type() == QEvent::ParentChange) || (e->type() == QEvent::WindowStateChange)) { // The window may have been re-created during re-parent or state change - if so, the EGL // surface will need to be re-created. @@ -4291,6 +4302,7 @@ static void qt_save_gl_state() glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } @@ -4344,6 +4356,10 @@ static void qt_gl_draw_text(QPainter *p, int x, int y, const QString &str, \note This function clears the stencil buffer. \note This function is not supported on OpenGL/ES systems. + + \note This function temporarily disables depth-testing when the + text is drawn. + \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. */ @@ -4434,6 +4450,13 @@ void QGLWidget::renderText(int x, int y, const QString &str, const QFont &font, have the labels move with the model as it is rotated etc. \note This function is not supported on OpenGL/ES systems. + + \note If depth testing is enabled before this function is called, + then the drawn text will be depth-tested against the models that + have already been drawn in the scene. Use \c{glDisable(GL_DEPTH_TEST)} + before calling this function to annotate the models without + depth-testing the text. + \l{Overpainting Example}{Overpaint} with QPainter::drawText() instead. */ void QGLWidget::renderText(double x, double y, double z, const QString &str, const QFont &font, int) @@ -4823,38 +4846,39 @@ QGLWidget::QGLWidget(QGLContext *context, QWidget *parent, void QGLExtensions::init_extensions() { - QList<QByteArray> extensions = QByteArray(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))).split(' '); - if (extensions.contains("GL_ARB_texture_rectangle")) + QGLExtensionMatcher extensions(reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS))); + + if (extensions.match("GL_ARB_texture_rectangle")) glExtensions |= TextureRectangle; - if (extensions.contains("GL_ARB_multisample")) + if (extensions.match("GL_ARB_multisample")) glExtensions |= SampleBuffers; - if (extensions.contains("GL_SGIS_generate_mipmap")) + if (extensions.match("GL_SGIS_generate_mipmap")) glExtensions |= GenerateMipmap; - if (extensions.contains("GL_ARB_texture_compression")) + if (extensions.match("GL_ARB_texture_compression")) glExtensions |= TextureCompression; - if (extensions.contains("GL_EXT_texture_compression_s3tc")) + if (extensions.match("GL_EXT_texture_compression_s3tc")) glExtensions |= DDSTextureCompression; - if (extensions.contains("GL_OES_compressed_ETC1_RGB8_texture")) + if (extensions.match("GL_OES_compressed_ETC1_RGB8_texture")) glExtensions |= ETC1TextureCompression; - if (extensions.contains("GL_IMG_texture_compression_pvrtc")) + if (extensions.match("GL_IMG_texture_compression_pvrtc")) glExtensions |= PVRTCTextureCompression; - if (extensions.contains("GL_ARB_fragment_program")) + if (extensions.match("GL_ARB_fragment_program")) glExtensions |= FragmentProgram; - if (extensions.contains("GL_ARB_fragment_shader")) + if (extensions.match("GL_ARB_fragment_shader")) glExtensions |= FragmentShader; - if (extensions.contains("GL_ARB_texture_mirrored_repeat")) + if (extensions.match("GL_ARB_texture_mirrored_repeat")) glExtensions |= MirroredRepeat; - if (extensions.contains("GL_EXT_framebuffer_object")) + if (extensions.match("GL_EXT_framebuffer_object")) glExtensions |= FramebufferObject; - if (extensions.contains("GL_EXT_stencil_two_side")) + if (extensions.match("GL_EXT_stencil_two_side")) glExtensions |= StencilTwoSide; - if (extensions.contains("GL_EXT_stencil_wrap")) + if (extensions.match("GL_EXT_stencil_wrap")) glExtensions |= StencilWrap; - if (extensions.contains("GL_EXT_packed_depth_stencil")) + if (extensions.match("GL_EXT_packed_depth_stencil")) glExtensions |= PackedDepthStencil; - if (extensions.contains("GL_NV_float_buffer")) + if (extensions.match("GL_NV_float_buffer")) glExtensions |= NVFloatBuffer; - if (extensions.contains("GL_ARB_pixel_buffer_object")) + if (extensions.match("GL_ARB_pixel_buffer_object")) glExtensions |= PixelBufferObject; #if defined(QT_OPENGL_ES_2) glExtensions |= FramebufferObject; @@ -4862,26 +4886,26 @@ void QGLExtensions::init_extensions() glExtensions |= FragmentShader; #endif #if defined(QT_OPENGL_ES_1) || defined(QT_OPENGL_ES_1_CL) - if (extensions.contains("GL_OES_framebuffer_object")) + if (extensions.match("GL_OES_framebuffer_object")) glExtensions |= FramebufferObject; #endif #if defined(QT_OPENGL_ES) - if (extensions.contains("GL_OES_packed_depth_stencil")) + if (extensions.match("GL_OES_packed_depth_stencil")) glExtensions |= PackedDepthStencil; #endif - if (extensions.contains("GL_ARB_framebuffer_object")) { + if (extensions.match("GL_ARB_framebuffer_object")) { // ARB_framebuffer_object also includes EXT_framebuffer_blit. glExtensions |= FramebufferObject; glExtensions |= FramebufferBlit; } - if (extensions.contains("GL_EXT_framebuffer_blit")) + if (extensions.match("GL_EXT_framebuffer_blit")) glExtensions |= FramebufferBlit; - if (extensions.contains("GL_ARB_texture_non_power_of_two")) + if (extensions.match("GL_ARB_texture_non_power_of_two")) glExtensions |= NPOTTextures; - if (extensions.contains("GL_EXT_bgra")) + if (extensions.match("GL_EXT_bgra")) glExtensions |= BGRATextureFormat; } @@ -5363,11 +5387,12 @@ QSize QGLTexture::bindCompressedTexturePVR(const char *buf, int len) // Restore the default pixel alignment for later texture uploads. glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - // Set the invert flag for the texture. + // Set the invert flag for the texture. The "vertical flip" + // flag in PVR is the opposite sense to our sense of inversion. if ((pvrHeader->flags & PVR_VERTICAL_FLIP) != 0) - options |= QGLContext::InvertedYBindOption; - else options &= ~QGLContext::InvertedYBindOption; + else + options |= QGLContext::InvertedYBindOption; return QSize(pvrHeader->width, pvrHeader->height); } diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 079953f..2076c46 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -546,6 +546,7 @@ private: friend class QGLPixelBuffer; friend class QGLPixelBufferPrivate; friend class QGLContext; + friend class QGLContextPrivate; friend class QGLOverlayWidget; friend class QOpenGLPaintEngine; friend class QGLPaintDevice; diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index fbf0349..839e8eb 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -142,19 +142,7 @@ void QGLContext::reset() d->cleanup(); doneCurrent(); if (d->eglContext) { - if (d->eglSurface != EGL_NO_SURFACE) { -#ifdef Q_WS_X11 - // Make sure we don't call eglDestroySurface on a surface which - // was created for a different winId: - if (d->paintDevice->devType() == QInternal::Widget) { - QGLWidget* w = static_cast<QGLWidget*>(d->paintDevice); - - if (w->d_func()->eglSurfaceWindowId == w->winId()) - eglDestroySurface(d->eglContext->display(), d->eglSurface); - } else -#endif - eglDestroySurface(d->eglContext->display(), d->eglSurface); - } + d->destroyEglSurfaceForDevice(); delete d->eglContext; } d->eglContext = 0; @@ -198,6 +186,26 @@ void QGLContext::swapBuffers() const d->eglContext->swapBuffers(d->eglSurface); } +void QGLContextPrivate::destroyEglSurfaceForDevice() +{ + if (eglSurface != EGL_NO_SURFACE) { +#ifdef Q_WS_X11 + // Make sure we don't call eglDestroySurface on a surface which + // was created for a different winId: + if (paintDevice->devType() == QInternal::Widget) { + QGLWidget* w = static_cast<QGLWidget*>(paintDevice); + + if (w->d_func()->eglSurfaceWindowId == w->winId()) + eglDestroySurface(eglContext->display(), eglSurface); + else + qWarning("WARNING: Potential EGL surface leak!"); + } else +#endif + eglDestroySurface(eglContext->display(), eglSurface); + eglSurface = EGL_NO_SURFACE; + } +} + void QGLWidget::setMouseTracking(bool enable) { QWidget::setMouseTracking(enable); diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 179d69a..99c0f33 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -133,9 +133,6 @@ public: : ref(1) { opts = QGL::DoubleBuffer | QGL::DepthBuffer | QGL::Rgba | QGL::DirectRendering | QGL::StencilBuffer; -#if defined(QT_OPENGL_ES_2) - opts |= QGL::SampleBuffers; -#endif pln = 0; depthSize = accumSize = stencilSize = redSize = greenSize = blueSize = alphaSize = -1; numSamples = -1; @@ -291,6 +288,7 @@ public: #if defined(QT_OPENGL_ES) QEglContext *eglContext; EGLSurface eglSurface; + void destroyEglSurfaceForDevice(); #elif defined(Q_WS_X11) || defined(Q_WS_MAC) void* cx; #endif @@ -397,7 +395,7 @@ public: Q_DECLARE_OPERATORS_FOR_FLAGS(QGLExtensions::Extensions) -class Q_AUTOTEST_EXPORT QGLShareRegister +class Q_OPENGL_EXPORT QGLShareRegister { public: QGLShareRegister() {} @@ -613,6 +611,49 @@ private: friend class QGLContextGroup; }; + +// This class can be used to match GL extensions with doing any mallocs. The +// class assumes that the GL extension string ends with a space character, +// which it should do on all conformant platforms. Create the object and pass +// in a pointer to the extension string, then call match() on each extension +// that should be matched. The match() function takes the extension name +// *without* the terminating space character as input. + +class QGLExtensionMatcher +{ +public: + QGLExtensionMatcher(const char *str) + : gl_extensions(str), gl_extensions_length(qstrlen(str)) + {} + + bool match(const char *str) { + int str_length = qstrlen(str); + const char *extensions = gl_extensions; + int extensions_length = gl_extensions_length; + + while (1) { + // the total length that needs to be matched is the str_length + + // the space character that terminates the extension name + if (extensions_length < str_length + 1) + return false; + if (qstrncmp(extensions, str, str_length) == 0 && extensions[str_length] == ' ') + return true; + + int split_pos = 0; + while (split_pos < extensions_length && extensions[split_pos] != ' ') + ++split_pos; + ++split_pos; // added for the terminating space character + extensions += split_pos; + extensions_length -= split_pos; + } + return false; + } + +private: + const char *gl_extensions; + int gl_extensions_length; +}; + QT_END_NAMESPACE #endif // QGL_P_H diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index a037282..9c3fc79 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -343,8 +343,8 @@ void* qglx_getProcAddress(const char* procName) static bool triedResolvingGlxGetProcAddress = false; if (!triedResolvingGlxGetProcAddress) { triedResolvingGlxGetProcAddress = true; - QList<QByteArray> glxExt = QByteArray(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)).split(' '); - if (glxExt.contains("GLX_ARB_get_proc_address")) { + QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); + if (extensions.match("GLX_ARB_get_proc_address")) { #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { @@ -523,8 +523,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) if (!d->gpm) return false; } - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' '); - if (glxExt.contains("GLX_SGI_video_sync")) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + if (extensions.match("GLX_SGI_video_sync")) { if (d->glFormat.swapInterval() == -1) d->glFormat.setSwapInterval(0); } else { @@ -630,8 +630,8 @@ void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) static bool useTranspExt = false; static bool useTranspExtChecked = false; if (f.plane() && !useTranspExtChecked && d->paintDevice) { - QByteArray estr(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); - useTranspExt = estr.contains("GLX_EXT_visual_info"); + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + useTranspExt = extensions.match("GLX_EXT_visual_info"); //# (A bit simplistic; that could theoretically be a substring) if (useTranspExt) { QByteArray cstr(glXGetClientString(xinfo->display(), GLX_VENDOR)); @@ -875,8 +875,8 @@ void QGLContext::swapBuffers() const static bool resolved = false; if (!resolved) { const QX11Info *xinfo = qt_x11Info(d->paintDevice); - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' '); - if (glxExt.contains("GLX_SGI_video_sync")) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + if (extensions.match("GLX_SGI_video_sync")) { glXGetVideoSyncSGI = (qt_glXGetVideoSyncSGI)qglx_getProcAddress("glXGetVideoSyncSGI"); glXWaitVideoSyncSGI = (qt_glXWaitVideoSyncSGI)qglx_getProcAddress("glXWaitVideoSyncSGI"); } @@ -1107,8 +1107,8 @@ void *QGLContext::getProcAddress(const QString &proc) const if (resolved && !glXGetProcAddressARB) return 0; if (!glXGetProcAddressARB) { - QList<QByteArray> glxExt = QByteArray(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)).split(' '); - if (glxExt.contains("GLX_ARB_get_proc_address")) { + QGLExtensionMatcher extensions(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS)); + if (extensions.match("GLX_ARB_get_proc_address")) { #if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { @@ -1609,8 +1609,8 @@ static bool qt_resolveTextureFromPixmap(QPaintDevice *paintDevice) return false; // Can't use TFP without NPOT } const QX11Info *xinfo = qt_x11Info(paintDevice); - QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(xinfo->display(), xinfo->screen())).split(' '); - if (glxExt.contains("GLX_EXT_texture_from_pixmap")) { + QGLExtensionMatcher extensions(glXQueryExtensionsString(xinfo->display(), xinfo->screen())); + if (extensions.match("GLX_EXT_texture_from_pixmap")) { glXBindTexImageEXT = (qt_glXBindTexImageEXT) qglx_getProcAddress("glXBindTexImageEXT"); glXReleaseTexImageEXT = (qt_glXReleaseTexImageEXT) qglx_getProcAddress("glXReleaseTexImageEXT"); } diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index a868e83..19026b3 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -173,10 +173,16 @@ void QGLWidget::updateOverlayGL() //handle overlay } +//#define QT_DEBUG_X11_VISUAL_SELECTION 1 + bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig config, const QX11Info &x11Info, bool useArgbVisual) { bool foundVisualIsArgb = useArgbVisual; +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("qt_egl_setup_x11_visual() - useArgbVisual=%d", useArgbVisual); +#endif + memset(&vi, 0, sizeof(XVisualInfo)); EGLint eglConfigColorSize; @@ -199,7 +205,9 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf XRenderPictFormat *format; format = XRenderFindVisualFormat(x11Info.display(), chosenVisualInfo->visual); if (format->type == PictTypeDirect && format->direct.alphaMask) { -// qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using ARGB X Visual ID (%d) provided by EGL", (int)vi.visualid); +#endif foundVisualIsArgb = true; vi = *chosenVisualInfo; } @@ -212,7 +220,9 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf #endif { if (eglConfigColorSize == chosenVisualInfo->depth) { -// qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid); +#endif vi = *chosenVisualInfo; } else qWarning("Warning: EGL suggested using X visual ID %d (%d bpp) for config %d (%d bpp), but the depths do not match!", @@ -248,7 +258,9 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf if (format->type == PictTypeDirect && format->direct.alphaMask) { vi = matchingVisuals[i]; foundVisualIsArgb = true; -// qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Using X Visual ID (%d) for ARGB visual as provided by XRender", (int)vi.visualid); +#endif break; } } @@ -272,24 +284,28 @@ bool qt_egl_setup_x11_visual(XVisualInfo &vi, EGLDisplay display, EGLConfig conf } else qWarning(" - Falling back to X11 suggested depth (%d)", depth); } -// else -// qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + else + qDebug("Using X Visual ID (%d) for EGL provided depth (%d)", (int)vi.visualid, depth); +#endif // Don't try to use ARGB now unless the visual is 32-bit - even then it might stil fail :-( if (useArgbVisual) foundVisualIsArgb = vi.depth == 32; //### We might at some point (soon) get ARGB4444 } -// qDebug("Visual Info:"); -// qDebug(" bits_per_rgb=%d", vi.bits_per_rgb); -// qDebug(" red_mask=0x%x", vi.red_mask); -// qDebug(" green_mask=0x%x", vi.green_mask); -// qDebug(" blue_mask=0x%x", vi.blue_mask); -// qDebug(" colormap_size=%d", vi.colormap_size); -// qDebug(" c_class=%d", vi.c_class); -// qDebug(" depth=%d", vi.depth); -// qDebug(" screen=%d", vi.screen); -// qDebug(" visualid=%d", vi.visualid); +#ifdef QT_DEBUG_X11_VISUAL_SELECTION + qDebug("Visual Info:"); + qDebug(" bits_per_rgb=%d", vi.bits_per_rgb); + qDebug(" red_mask=0x%x", vi.red_mask); + qDebug(" green_mask=0x%x", vi.green_mask); + qDebug(" blue_mask=0x%x", vi.blue_mask); + qDebug(" colormap_size=%d", vi.colormap_size); + qDebug(" c_class=%d", vi.c_class); + qDebug(" depth=%d", vi.depth); + qDebug(" screen=%d", vi.screen); + qDebug(" visualid=%d", vi.visualid); +#endif return foundVisualIsArgb; } @@ -320,7 +336,7 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext, // If the application has set WA_TranslucentBackground and not explicitly set // the alpha buffer size to zero, modify the format so it have an alpha channel QGLFormat& fmt = d->glcx->d_func()->glFormat; - const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground); + const bool tryArgbVisual = testAttribute(Qt::WA_TranslucentBackground) || fmt.alpha(); if (tryArgbVisual && fmt.alphaBufferSize() == -1) fmt.setAlphaBufferSize(1); diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index d0297c9..4b5c30a 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -597,6 +597,12 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, the constructors that take a QGLFramebufferObject parameter, and set the QGLFramebufferObject::samples() property to a non-zero value. + When painting to a QGLFramebufferObject using QPainter, the state of + the current GL context will be altered by the paint engine to reflect + its needs. Applications should not rely upon the GL state being reset + to its original conditions, particularly the current shader program, + GL viewport, texture units, and drawing modes. + For multisample framebuffer objects a color render buffer is created, otherwise a texture with the specified texture target is created. The color render buffer or texture will have the specified internal diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index c478630..d4bcbe9 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -55,11 +55,17 @@ #include "qgl_p.h" #include "private/qapplication_p.h" +#include "private/qdrawhelper_p.h" +#include "private/qmemrotate_p.h" #include "private/qmath_p.h" #include "qmath.h" QT_BEGIN_NAMESPACE +// qpixmapfilter.cpp +void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); +QImage qt_halfScaled(const QImage &source); + void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const { const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, QGLContext::BindOptions(QGLContext::DefaultBindOption | QGLContext::MemoryManagedBindOption)); @@ -102,48 +108,21 @@ private: class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter> { public: - QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints); - - void setUniforms(QGLShaderProgram *program); - - static QByteArray generateGaussianShader(int radius, bool singlePass = false, bool dropShadow = false); + QGLPixmapBlurFilter(); protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; - -private: - - mutable QSize m_textureSize; - mutable bool m_horizontalBlur; - mutable bool m_singlePass; - mutable bool m_animatedBlur; - - mutable qreal m_t; - mutable QSize m_targetSize; - - mutable bool m_haveCached; - mutable int m_cachedRadius; - mutable QGraphicsBlurEffect::BlurHints m_hints; }; class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter> { public: - QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints); + QGLPixmapDropShadowFilter(); void setUniforms(QGLShaderProgram *program); protected: bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const; - -private: - mutable QSize m_textureSize; - mutable bool m_horizontalBlur; - mutable bool m_singlePass; - - mutable bool m_haveCached; - mutable int m_cachedRadius; - mutable QGraphicsBlurEffect::BlurHints m_hints; }; extern QGLWidget *qt_gl_share_widget(); @@ -158,31 +137,14 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr return d->colorizeFilter.data(); case QPixmapFilter::BlurFilter: { - const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype); - if (proto->blurHints() & QGraphicsBlurEffect::AnimationHint) { - if (!d->animationBlurFilter) - d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHints())); - return d->animationBlurFilter.data(); - } - if ((proto->blurHints() & QGraphicsBlurEffect::QualityHint) && proto->radius() > 5) { - if (!d->blurFilter) - d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint)); - return d->blurFilter.data(); - } - if (!d->fastBlurFilter) - d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint)); - return d->fastBlurFilter.data(); + if (!d->blurFilter) + d->blurFilter.reset(new QGLPixmapBlurFilter()); + return d->blurFilter.data(); } case QPixmapFilter::DropShadowFilter: { - const QPixmapDropShadowFilter *proto = static_cast<const QPixmapDropShadowFilter *>(prototype); - if (proto->blurRadius() <= 5) { - if (!d->fastDropShadowFilter) - d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint)); - return d->fastDropShadowFilter.data(); - } if (!d->dropShadowFilter) - d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint)); + d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter()); return d->dropShadowFilter.data(); } @@ -311,59 +273,43 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *painter, const QPointF &pos return true; } -static const char *qt_gl_texture_sampling_helper = - "lowp float texture2DAlpha(lowp sampler2D src, highp vec2 srcCoords) {\n" - " return texture2D(src, srcCoords).a;\n" - "}\n"; - -QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHints hints) - : m_animatedBlur(false) - , m_haveCached(false) - , m_cachedRadius(0) - , m_hints(hints) -{ -} - -// should be even numbers as they will be divided by two -static const int qCachedBlurLevels[] = { 6, 14, 30 }; -static const int qNumCachedBlurTextures = sizeof(qCachedBlurLevels) / sizeof(*qCachedBlurLevels); -static const int qMaxCachedBlurLevel = qCachedBlurLevels[qNumCachedBlurTextures - 1]; - -static qreal qLogBlurLevel(int level) +QGLPixmapBlurFilter::QGLPixmapBlurFilter() { - static bool initialized = false; - static qreal logBlurLevelCache[qNumCachedBlurTextures]; - if (!initialized) { - for (int i = 0; i < qNumCachedBlurTextures; ++i) - logBlurLevelCache[i] = qLn(qCachedBlurLevels[i]); - initialized = true; - } - return logBlurLevelCache[level]; } class QGLBlurTextureInfo { public: - QGLBlurTextureInfo(QSize size, GLuint textureIds[]) - : m_size(size) + QGLBlurTextureInfo(const QImage &image, GLuint tex, qreal r) + : m_texture(tex) + , m_radius(r) { - for (int i = 0; i < qNumCachedBlurTextures; ++i) - m_textureIds[i] = textureIds[i]; + m_paddedImage << image; } ~QGLBlurTextureInfo() { - glDeleteTextures(qNumCachedBlurTextures, m_textureIds); + glDeleteTextures(1, &m_texture); } - QSize size() const { return m_size; } - GLuint textureId(int i) const { return m_textureIds[i]; } + QImage paddedImage(int scaleLevel = 0) const; + GLuint texture() const { return m_texture; } + qreal radius() const { return m_radius; } private: - GLuint m_textureIds[qNumCachedBlurTextures]; - QSize m_size; + mutable QList<QImage> m_paddedImage; + GLuint m_texture; + qreal m_radius; }; +QImage QGLBlurTextureInfo::paddedImage(int scaleLevel) const +{ + for (int i = m_paddedImage.size() - 1; i <= scaleLevel; ++i) + m_paddedImage << qt_halfScaled(m_paddedImage.at(i)); + + return m_paddedImage.at(scaleLevel); +} + class QGLBlurTextureCache : public QObject { public: @@ -373,7 +319,6 @@ public: ~QGLBlurTextureCache(); QGLBlurTextureInfo *takeBlurTextureInfo(const QPixmap &pixmap); - bool fitsInCache(const QPixmap &pixmap) const; bool hasBlurTextureInfo(const QPixmap &pixmap) const; void insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info); void clearBlurTextureInfo(const QPixmap &pixmap); @@ -458,12 +403,7 @@ void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTe if (timerId) killTimer(timerId); - timerId = startTimer(1000); -} - -bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const -{ - return pixmap.width() * pixmap.height() <= cache.maxCost(); + timerId = startTimer(8000); } void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) @@ -474,567 +414,217 @@ void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap) } } -static const char *qt_gl_interpolate_filter = - "uniform lowp float interpolationValue;" - "uniform lowp sampler2D interpolateTarget;" - "uniform highp vec4 interpolateMapping;" - "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" - "{" - " return mix(texture2D(interpolateTarget, interpolateMapping.xy + interpolateMapping.zw * srcCoords)," - " texture2D(src, srcCoords), interpolationValue);" - "}"; +static const int qAnimatedBlurLevelIncrement = 16; +static const int qMaxBlurHalfScaleLevel = 1; -static void initializeTexture(GLuint id, int width, int height) +static GLuint generateBlurTexture(const QSize &size, GLenum format = GL_RGBA) { - glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - 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); + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0, format, + GL_UNSIGNED_BYTE, 0); + return texture; } -bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const +static inline uint nextMultiple(uint x, uint multiplier) { - QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this); - - QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); - - if ((m_hints & QGraphicsBlurEffect::AnimationHint) && blurTextureCache->fitsInCache(src)) { - QRect targetRect = src.rect().adjusted(-qMaxCachedBlurLevel, -qMaxCachedBlurLevel, qMaxCachedBlurLevel, qMaxCachedBlurLevel); - // ensure even dimensions (going to divide by two) - targetRect.setWidth((targetRect.width() + 1) & ~1); - targetRect.setHeight((targetRect.height() + 1) & ~1); - - QGLBlurTextureInfo *info = 0; - if (blurTextureCache->hasBlurTextureInfo(src)) { - info = blurTextureCache->takeBlurTextureInfo(src); - } else { - m_animatedBlur = false; - m_hints = QGraphicsBlurEffect::QualityHint; - m_singlePass = false; - - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(GL_RGBA)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size() / 2, format, true); - - if (!fbo) - return false; - - QPainter fboPainter(fbo); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(fboPainter.paintEngine()); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - // ensure GL_LINEAR filtering is used for scaling down to half the size - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - fboPainter.drawPixmap(qMaxCachedBlurLevel / 2, qMaxCachedBlurLevel / 2, - targetRect.width() / 2 - qMaxCachedBlurLevel, targetRect.height() / 2 - qMaxCachedBlurLevel, src); - - GLuint textures[qNumCachedBlurTextures]; // blur textures - glGenTextures(qNumCachedBlurTextures, textures); - GLuint temp; // temp texture - glGenTextures(1, &temp); - - initializeTexture(temp, fbo->width(), fbo->height()); - m_textureSize = fbo->size(); - - int currentBlur = 0; - - QRect fboRect(0, 0, fbo->width(), fbo->height()); - GLuint sourceTexture = fbo->texture(); - for (int i = 0; i < qNumCachedBlurTextures; ++i) { - int targetBlur = qCachedBlurLevels[i] / 2; - - int blurDelta = qRound(qSqrt(targetBlur * targetBlur - currentBlur * currentBlur)); - QByteArray source = generateGaussianShader(blurDelta); - filter->setSource(source); - - currentBlur = targetBlur; - - // now we're going to be nasty and keep using the same FBO with different textures - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, temp, 0); - - m_horizontalBlur = true; - filter->setOnPainter(&fboPainter); - engine->drawTexture(fboRect, sourceTexture, fbo->size(), fboRect); - filter->removeFromPainter(&fboPainter); - - sourceTexture = textures[i]; - initializeTexture(sourceTexture, fbo->width(), fbo->height()); - - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, textures[i], 0); - - m_horizontalBlur = false; - filter->setOnPainter(&fboPainter); - engine->drawTexture(fboRect, temp, fbo->size(), fboRect); - filter->removeFromPainter(&fboPainter); - } - - glDeleteTextures(1, &temp); + uint mod = x % multiplier; + if (mod == 0) + return x; + return x + multiplier - mod; +} - // reattach the original FBO texture - glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_2D, fbo->texture(), 0); +void qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, + quint32 *dest, int dstStride); - fboPainter.end(); +bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const +{ + if (radius() < 1) { + painter->drawPixmap(pos, src); + return true; + } - qgl_fbo_pool()->release(fbo); + qreal actualRadius = radius(); - info = new QGLBlurTextureInfo(fboRect.size(), textures); - } + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - if (!m_haveCached || !m_animatedBlur) { - m_haveCached = true; - m_animatedBlur = true; - m_hints = QGraphicsBlurEffect::AnimationHint; - filter->setSource(qt_gl_interpolate_filter); - } + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); + QGLBlurTextureInfo *info = 0; + int padding = nextMultiple(qCeil(actualRadius), qAnimatedBlurLevelIncrement); + QRect targetRect = src.rect().adjusted(-padding, -padding, padding, padding); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); + // pad so that we'll be able to half-scale qMaxBlurHalfScaleLevel times + targetRect.setWidth((targetRect.width() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1)); + targetRect.setHeight((targetRect.height() + (qMaxBlurHalfScaleLevel-1)) & ~(qMaxBlurHalfScaleLevel-1)); - qreal logRadius = qLn(radius()); + QSize textureSize; - int t; - for (t = -1; t < qNumCachedBlurTextures - 2; ++t) { - if (logRadius < qLogBlurLevel(t+1)) - break; - } + info = blurTextureCache->takeBlurTextureInfo(src); + if (!info || info->radius() < actualRadius) { + QSize paddedSize = targetRect.size() / 2; - qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0; - m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1)); + QImage padded(paddedSize.height(), paddedSize.width(), QImage::Format_ARGB32_Premultiplied); + padded.fill(0); - m_textureSize = info->size(); + if (info) { + int oldPadding = qRound(info->radius()); - glActiveTexture(GL_TEXTURE0 + 3); - if (t >= 0) { - glBindTexture(GL_TEXTURE_2D, info->textureId(t)); - m_targetSize = info->size(); + QPainter p(&padded); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.drawImage((padding - oldPadding) / 2, (padding - oldPadding) / 2, info->paddedImage()); + p.end(); } else { - QGLTexture *texture = - ctx->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, - QGLContext::InternalBindOption - | QGLContext::CanFlipNativePixmapBindOption); - m_targetSize = src.size(); - if (!(texture->options & QGLContext::InvertedYBindOption)) - m_targetSize.setHeight(-m_targetSize.height()); + // TODO: combine byteswapping and memrotating into one by declaring + // custom GL_RGBA pixel type and qt_colorConvert template for it + QImage prepadded = qt_halfScaled(src.toImage()).convertToFormat(QImage::Format_ARGB32_Premultiplied); + + // byte-swap and memrotates in one go + qt_memrotate90_gl(reinterpret_cast<const quint32*>(prepadded.bits()), + prepadded.width(), prepadded.height(), prepadded.bytesPerLine(), + reinterpret_cast<quint32*>(padded.scanLine(padding / 2)) + padding / 2, + padded.bytesPerLine()); } - // restrict the target rect to the max of the radii we are interpolating between - int radiusDelta = qMaxCachedBlurLevel - qCachedBlurLevels[t+1]; - targetRect = targetRect.translated(pos.toPoint()).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); - - radiusDelta /= 2; - QRect sourceRect = QRect(QPoint(), m_textureSize).adjusted(radiusDelta, radiusDelta, -radiusDelta, -radiusDelta); - - engine->drawTexture(targetRect, info->textureId(t+1), m_textureSize, sourceRect); - - glActiveTexture(GL_TEXTURE0 + 3); - glBindTexture(GL_TEXTURE_2D, 0); - - filter->removeFromPainter(painter); - blurTextureCache->insertBlurTextureInfo(src, info); - - return true; - } + delete info; + info = new QGLBlurTextureInfo(padded, generateBlurTexture(paddedSize), padding); - if (blurTextureCache->hasBlurTextureInfo(src)) - blurTextureCache->clearBlurTextureInfo(src); - - int actualRadius = qRound(radius()); - int filterRadius = actualRadius; - int fastRadii[] = { 1, 2, 3, 5, 8, 15, 25 }; - if (!(m_hints & QGraphicsBlurEffect::QualityHint)) { - uint i = 0; - for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) { - if (fastRadii[i+1] > filterRadius) - break; - } - filterRadius = fastRadii[i]; + textureSize = paddedSize; + } else { + textureSize = QSize(info->paddedImage().height(), info->paddedImage().width()); } - m_singlePass = filterRadius <= 3; - - if (!m_haveCached || m_animatedBlur || filterRadius != m_cachedRadius) { - // Only regenerate the shader from source if parameters have changed. - m_haveCached = true; - m_animatedBlur = false; - m_cachedRadius = filterRadius; - QByteArray source = generateGaussianShader(filterRadius, m_singlePass); - filter->setSource(source); + actualRadius *= qreal(0.5); + int level = 1; + for (; level < qMaxBlurHalfScaleLevel; ++level) { + if (actualRadius <= 16) + break; + actualRadius *= qreal(0.5); } - QRect targetRect = QRectF(src.rect()).translated(pos).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect(); + const int s = (1 << level); - if (m_singlePass) { - // prepare for updateUniforms - m_textureSize = src.size(); + int prepadding = qRound(info->radius()); + padding = qMin(prepadding, qCeil(actualRadius) << level); + targetRect = src.rect().adjusted(-padding, -padding, padding, padding); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(pos.x(), pos.y())); - painter->fillRect(targetRect, pixmapBrush); - filter->removeFromPainter(painter); - } else { - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format); + targetRect.setWidth(targetRect.width() & ~(s-1)); + targetRect.setHeight(targetRect.height() & ~(s-1)); - if (!fbo) - return false; + int paddingDelta = (prepadding - padding) >> level; - // prepare for updateUniforms - m_textureSize = src.size(); + QRect subRect(paddingDelta, paddingDelta, targetRect.width() >> level, targetRect.height() >> level); + QImage sourceImage = info->paddedImage(level-1); - // horizontal pass, to pixmap - m_horizontalBlur = true; + QImage subImage(subRect.height(), subRect.width(), QImage::Format_ARGB32_Premultiplied); + qt_rectcopy((QRgb *)subImage.bits(), ((QRgb *)sourceImage.scanLine(paddingDelta)) + paddingDelta, + 0, 0, subRect.height(), subRect.width(), subImage.bytesPerLine(), sourceImage.bytesPerLine()); - QPainter fboPainter(fbo); + GLuint texture = info->texture(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); + qt_blurImage(subImage, actualRadius, blurHints() & QGraphicsBlurEffect::QualityHint, 1); - // ensure GL_LINEAR filtering is used - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - filter->setOnPainter(&fboPainter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); - fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush); - filter->removeFromPainter(&fboPainter); - fboPainter.end(); + // subtract one pixel off the end to prevent the bilinear sampling from sampling uninitialized data + QRect textureSubRect = subImage.rect().adjusted(0, 0, -1, -1); + QRectF targetRectF = QRectF(targetRect).adjusted(0, 0, -targetRect.width() / qreal(textureSize.width()), -targetRect.height() / qreal(textureSize.height())); - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + glBindTexture(GL_TEXTURE_2D, texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subImage.width(), subImage.height(), GL_RGBA, + GL_UNSIGNED_BYTE, const_cast<const QImage &>(subImage).bits()); - // vertical pass, to painter - m_horizontalBlur = false; - m_textureSize = fbo->size(); + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRect(QPoint(), targetRect.size()).translated(0, fbo->height() - targetRect.height())); - filter->removeFromPainter(painter); - painter->restore(); + // texture is flipped on the y-axis + targetRectF = QRectF(targetRectF.x(), targetRectF.bottom(), targetRectF.width(), -targetRectF.height()); + engine->drawTexture(targetRectF.translated(pos), texture, textureSize, textureSubRect); - qgl_fbo_pool()->release(fbo); - } + blurTextureCache->insertBlurTextureInfo(src, info); return true; } -void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program) -{ - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (m_animatedBlur) { - program->setUniformValue("interpolateTarget", 3); - program->setUniformValue("interpolationValue", GLfloat(m_t)); - - if (m_textureSize == m_targetSize) { - program->setUniformValue("interpolateMapping", 0.0f, 0.0f, 1.0f, 1.0f); - } else { - float offsetX = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.width()); - float offsetY = (-qMaxCachedBlurLevel - 0.5) / qreal(m_targetSize.height()); - - if (m_targetSize.height() < 0) - offsetY = 1 + offsetY; - - float scaleX = 2.0f * qreal(m_textureSize.width()) / qreal(m_targetSize.width()); - float scaleY = 2.0f * qreal(m_textureSize.height()) / qreal(m_targetSize.height()); - - program->setUniformValue("interpolateMapping", offsetX, offsetY, scaleX, scaleY); - } - - return; - } +static const char *qt_gl_drop_shadow_filter = + "uniform lowp vec4 shadowColor;" + "lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords)" + "{" + " return shadowColor * texture2D(src, srcCoords.yx).a;" + "}"; - if (m_hints & QGraphicsBlurEffect::QualityHint) { - if (m_singlePass) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height()); - } else { - qreal blur = radius() / qreal(m_cachedRadius); - - if (m_singlePass) - program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", blur / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, blur / m_textureSize.height()); - } -} -static inline qreal gaussian(qreal dx, qreal sigma) +QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter() { - return exp(-dx * dx / (2 * sigma * sigma)) / (Q_2PI * sigma * sigma); + setSource(qt_gl_drop_shadow_filter); } -QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePass, bool dropShadow) +bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const { - Q_ASSERT(radius >= 1); - - radius = qMin(127, radius); - - static QCache<uint, QByteArray> shaderSourceCache; - uint key = radius | (int(singlePass) << 7) | (int(dropShadow) << 8); - QByteArray *cached = shaderSourceCache.object(key); - if (cached) - return *cached; - - QByteArray source; - source.reserve(1000); - source.append(qt_gl_texture_sampling_helper); - - source.append("uniform highp vec2 delta;\n"); - if (dropShadow) - source.append("uniform mediump vec4 shadowColor;\n"); - source.append("lowp vec4 customShader(lowp sampler2D src, highp vec2 srcCoords) {\n"); - - QVector<qreal> sampleOffsets; - QVector<qreal> weights; - - QVector<qreal> gaussianComponents; - - qreal sigma = radius / 1.65; - - qreal sum = 0; - for (int i = -radius; i < radius; ++i) { - float value = gaussian(i, sigma); - gaussianComponents << value; - sum += value; - } - - // normalize - for (int i = 0; i < gaussianComponents.size(); ++i) - gaussianComponents[i] /= sum; - - for (int i = 0; i < gaussianComponents.size() - 1; i += 2) { - qreal weight = gaussianComponents.at(i) + gaussianComponents.at(i + 1); - qreal offset = i - radius + gaussianComponents.at(i + 1) / weight; - - sampleOffsets << offset; - weights << weight; - } - - int limit = sampleOffsets.size(); - if (singlePass) - limit *= limit; - - QByteArray baseCoordinate = "srcCoords"; - - for (int i = 0; i < limit; ++i) { - QByteArray coordinate = baseCoordinate; - - qreal weight; - if (singlePass) { - const int xIndex = i % sampleOffsets.size(); - const int yIndex = i / sampleOffsets.size(); - - const qreal deltaX = sampleOffsets.at(xIndex); - const qreal deltaY = sampleOffsets.at(yIndex); - weight = weights.at(xIndex) * weights.at(yIndex); - - if (!qFuzzyCompare(deltaX, deltaY)) { - coordinate.append(" + vec2(delta.x * float("); - coordinate.append(QByteArray::number(deltaX)); - coordinate.append("), delta.y * float("); - coordinate.append(QByteArray::number(deltaY)); - coordinate.append("))"); - } else if (!qFuzzyIsNull(deltaX)) { - coordinate.append(" + delta * float("); - coordinate.append(QByteArray::number(deltaX)); - coordinate.append(")"); - } - } else { - const qreal delta = sampleOffsets.at(i); - weight = weights.at(i); - if (!qFuzzyIsNull(delta)) { - coordinate.append(" + delta * float("); - coordinate.append(QByteArray::number(delta)); - coordinate.append(")"); - } - } - - if (i == 0) { - if (dropShadow) - source.append(" mediump float sample = "); - else - source.append(" mediump vec4 sample = "); - } else { - if (dropShadow) - source.append(" sample += "); - else - source.append(" sample += "); - } + QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this); - source.append("texture2D(src, "); - source.append(coordinate); - source.append(")"); + qreal r = blurRadius(); + QRectF targetRectUnaligned = QRectF(src.rect()).translated(pos + offset()).adjusted(-r, -r, r, r); + QRect targetRect = targetRectUnaligned.toAlignedRect(); - if (dropShadow) - source.append(".a"); + // ensure even dimensions (going to divide by two) + targetRect.setWidth((targetRect.width() + 1) & ~1); + targetRect.setHeight((targetRect.height() + 1) & ~1); - if (!qFuzzyCompare(weight, qreal(1))) { - source.append(" * float("); - source.append(QByteArray::number(weight)); - source.append(");\n"); - } else { - source.append(";\n"); - } - } + QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); + QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx); - source.append(" return "); - if (dropShadow) - source.append("shadowColor * "); - source.append("sample;\n"); - source.append("}\n"); + QGLBlurTextureInfo *info = blurTextureCache->takeBlurTextureInfo(src); + if (!info || info->radius() != r) { + QImage half = qt_halfScaled(src.toImage().alphaChannel()); - cached = new QByteArray(source); - shaderSourceCache.insert(key, cached); + qreal rx = r + targetRect.left() - targetRectUnaligned.left(); + qreal ry = r + targetRect.top() - targetRectUnaligned.top(); - return source; -} + QImage image = QImage(targetRect.size() / 2, QImage::Format_Indexed8); + image.setColorTable(half.colorTable()); + image.fill(0); + int dx = qRound(rx * qreal(0.5)); + int dy = qRound(ry * qreal(0.5)); + qt_rectcopy(image.bits(), half.bits(), dx, dy, + half.width(), half.height(), + image.bytesPerLine(), half.bytesPerLine()); -QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHints hints) - : m_haveCached(false) - , m_cachedRadius(0) - , m_hints(hints) -{ -} + qt_blurImage(image, r * qreal(0.5), false, 1); -bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const -{ - QGLPixmapDropShadowFilter *filter = const_cast<QGLPixmapDropShadowFilter *>(this); + GLuint texture = generateBlurTexture(image.size(), GL_ALPHA); - int actualRadius = qRound(blurRadius()); - int filterRadius = actualRadius; - m_singlePass = filterRadius <= 3; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image.width(), image.height(), GL_ALPHA, + GL_UNSIGNED_BYTE, image.bits()); - if (!m_haveCached || filterRadius != m_cachedRadius) { - // Only regenerate the shader from source if parameters have changed. - m_haveCached = true; - m_cachedRadius = filterRadius; - QByteArray source = QGLPixmapBlurFilter::generateGaussianShader(filterRadius, m_singlePass, true); - filter->setSource(source); + info = new QGLBlurTextureInfo(image, texture, r); } - QRect targetRect = QRectF(src.rect()).translated(pos + offset()).adjusted(-actualRadius, -actualRadius, actualRadius, actualRadius).toAlignedRect(); - - if (m_singlePass) { - // prepare for updateUniforms - m_textureSize = src.size(); - - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(pos.x() + offset().x(), pos.y() + offset().y())); - painter->fillRect(targetRect, pixmapBrush); - filter->removeFromPainter(painter); - painter->restore(); - } else { - QGLFramebufferObjectFormat format; - format.setInternalTextureFormat(GLenum(src.hasAlphaChannel() ? GL_RGBA : GL_RGB)); - QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(targetRect.size(), format); - - if (!fbo) - return false; - - // prepare for updateUniforms - m_textureSize = src.size(); - - // horizontal pass, to pixmap - m_horizontalBlur = true; - - QPainter fboPainter(fbo); + GLuint texture = info->texture(); - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - // ensure GL_LINEAR filtering is used - fboPainter.setRenderHint(QPainter::SmoothPixmapTransform); - fboPainter.setCompositionMode(QPainter::CompositionMode_Source); - filter->setOnPainter(&fboPainter); - QBrush pixmapBrush = src; - pixmapBrush.setTransform(QTransform::fromTranslate(actualRadius, actualRadius)); - fboPainter.fillRect(QRect(0, 0, targetRect.width(), targetRect.height()), pixmapBrush); - filter->removeFromPainter(&fboPainter); - fboPainter.end(); - - QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + filter->setOnPainter(painter); - // vertical pass, to painter - m_horizontalBlur = false; - m_textureSize = fbo->size(); + QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine()); + painter->setRenderHint(QPainter::SmoothPixmapTransform); - painter->save(); - // ensure GL_LINEAR filtering is used - painter->setRenderHint(QPainter::SmoothPixmapTransform); - filter->setOnPainter(painter); - engine->drawTexture(targetRect, fbo->texture(), fbo->size(), QRectF(0, fbo->height() - targetRect.height(), targetRect.width(), targetRect.height())); - filter->removeFromPainter(painter); - painter->restore(); + engine->drawTexture(targetRect, texture, info->paddedImage().size(), info->paddedImage().rect()); - qgl_fbo_pool()->release(fbo); - } + filter->removeFromPainter(painter); // Now draw the actual pixmap over the top. painter->drawPixmap(pos, src, srcRect); + blurTextureCache->insertBlurTextureInfo(src, info); + return true; } void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - QColor col = color(); - if (m_horizontalBlur && !m_singlePass) { - program->setUniformValue("shadowColor", 1.0f, 1.0f, 1.0f, 1.0f); - } else { - qreal alpha = col.alphaF(); - program->setUniformValue("shadowColor", col.redF() * alpha, - col.greenF() * alpha, - col.blueF() * alpha, - alpha); - } - - if (m_hints & QGraphicsBlurEffect::QualityHint) { - if (m_singlePass) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", 1.0 / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, 1.0 / m_textureSize.height()); - } else { - qreal blur = blurRadius() / qreal(m_cachedRadius); - - if (m_singlePass) - program->setUniformValue("delta", blur / m_textureSize.width(), blur / m_textureSize.height()); - else if (m_horizontalBlur) - program->setUniformValue("delta", blur / m_textureSize.width(), 0.0); - else - program->setUniformValue("delta", 0.0, blur / m_textureSize.height()); - } + qreal alpha = col.alphaF(); + program->setUniformValue("shadowColor", col.redF() * alpha, + col.greenF() * alpha, + col.blueF() * alpha, + alpha); } QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 0299cea..4e1d50d 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -424,6 +424,7 @@ bool QGLPixmapData::fromFile(const QString &filename, const char *format, resize(0, 0); data = file.readAll(); file.close(); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); QSize size = m_texture.bindCompressedTexture (data.constData(), data.size(), format); if (!size.isEmpty()) { @@ -449,6 +450,7 @@ bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, const char *buf = reinterpret_cast<const char *>(buffer); if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) { resize(0, 0); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); QSize size = m_texture.bindCompressedTexture(buf, int(len), format); if (!size.isEmpty()) { w = size.width(); |