summaryrefslogtreecommitdiffstats
path: root/src/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/opengl')
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h1
-rw-r--r--src/opengl/qgl.cpp6
-rw-r--r--src/opengl/qgl.h1
-rw-r--r--src/opengl/qglpixmapfilter.cpp405
-rw-r--r--src/opengl/qpixmapdata_gl.cpp19
-rw-r--r--src/opengl/qpixmapdata_gl_p.h2
6 files changed, 403 insertions, 31 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 209cd36..4cf2a83 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -289,6 +289,7 @@ public:
QScopedPointer<QPixmapFilter> convolutionFilter;
QScopedPointer<QPixmapFilter> colorizeFilter;
QScopedPointer<QPixmapFilter> blurFilter;
+ QScopedPointer<QPixmapFilter> animationBlurFilter;
QScopedPointer<QPixmapFilter> fastBlurFilter;
QScopedPointer<QPixmapFilter> dropShadowFilter;
QScopedPointer<QPixmapFilter> fastDropShadowFilter;
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 621d926..ad177dc 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -1773,10 +1773,12 @@ Q_OPENGL_EXPORT QGLShareRegister* qgl_share_reg()
/*!
\enum QGLContext::BindOption
+ \since 4.6
+
A set of options to decide how to bind a texture using bindTexture().
\value NoBindOption Don't do anything, pass the texture straight
- thru.
+ through.
\value InvertedYBindOption Specifies that the texture should be flipped
over the X axis so that the texture coordinate 0,0 corresponds to
@@ -2158,7 +2160,7 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
#ifndef QT_NO_DEBUG
// Reset the gl error stack...git
- while (glGetError() != GL_NO_ERROR);
+ while (glGetError() != GL_NO_ERROR) ;
#endif
// Scale the pixmap if needed. GL textures needs to have the
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index e14e7fb..079953f 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -399,6 +399,7 @@ private:
friend class QGLTextureGlyphCache;
friend class QGLShareRegister;
friend class QGLSharedResourceGuard;
+ friend class QGLPixmapBlurFilter;
friend QGLFormat::OpenGLVersionFlags QGLFormat::openGLVersionFlags();
#ifdef Q_WS_MAC
public:
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index 2af69e0..ff19e06 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -43,6 +43,8 @@
#include "private/qpixmapdata_gl_p.h"
#include "private/qpaintengineex_opengl2_p.h"
#include "private/qglengineshadermanager_p.h"
+#include "private/qpixmapdata_p.h"
+#include "private/qimagepixmapcleanuphooks_p.h"
#include "qglpixmapfilter_p.h"
#include "qgraphicssystem_gl_p.h"
#include "qpaintengine_opengl_p.h"
@@ -54,7 +56,7 @@
#include "private/qapplication_p.h"
#include "private/qmath_p.h"
-
+#include "qmath.h"
QT_BEGIN_NAMESPACE
@@ -100,7 +102,7 @@ private:
class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter>
{
public:
- QGLPixmapBlurFilter(Qt::RenderHint hint);
+ QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint);
void setUniforms(QGLShaderProgram *program);
@@ -114,16 +116,20 @@ 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 Qt::RenderHint m_hint;
+ mutable QGraphicsBlurEffect::BlurHint m_hint;
};
class QGLPixmapDropShadowFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapDropShadowFilter>
{
public:
- QGLPixmapDropShadowFilter(Qt::RenderHint hint);
+ QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHint hint);
void setUniforms(QGLShaderProgram *program);
@@ -137,7 +143,7 @@ private:
mutable bool m_haveCached;
mutable int m_cachedRadius;
- mutable Qt::RenderHint m_hint;
+ mutable QGraphicsBlurEffect::BlurHint m_hint;
};
extern QGLWidget *qt_gl_share_widget();
@@ -153,13 +159,18 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr
case QPixmapFilter::BlurFilter: {
const QPixmapBlurFilter *proto = static_cast<const QPixmapBlurFilter *>(prototype);
- if (proto->blurHint() == Qt::PerformanceHint || proto->radius() <= 5) {
+ if (proto->blurHint() == QGraphicsBlurEffect::AnimationHint) {
+ if (!d->animationBlurFilter)
+ d->animationBlurFilter.reset(new QGLPixmapBlurFilter(proto->blurHint()));
+ return d->animationBlurFilter.data();
+ }
+ if (proto->blurHint() == QGraphicsBlurEffect::PerformanceHint || proto->radius() <= 5) {
if (!d->fastBlurFilter)
- d->fastBlurFilter.reset(new QGLPixmapBlurFilter(Qt::PerformanceHint));
+ d->fastBlurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::PerformanceHint));
return d->fastBlurFilter.data();
}
if (!d->blurFilter)
- d->blurFilter.reset(new QGLPixmapBlurFilter(Qt::QualityHint));
+ d->blurFilter.reset(new QGLPixmapBlurFilter(QGraphicsBlurEffect::QualityHint));
return d->blurFilter.data();
}
@@ -167,11 +178,11 @@ QPixmapFilter *QGL2PaintEngineEx::pixmapFilter(int type, const QPixmapFilter *pr
const QPixmapDropShadowFilter *proto = static_cast<const QPixmapDropShadowFilter *>(prototype);
if (proto->blurRadius() <= 5) {
if (!d->fastDropShadowFilter)
- d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(Qt::PerformanceHint));
+ d->fastDropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::PerformanceHint));
return d->fastDropShadowFilter.data();
}
if (!d->dropShadowFilter)
- d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(Qt::QualityHint));
+ d->dropShadowFilter.reset(new QGLPixmapDropShadowFilter(QGraphicsBlurEffect::QualityHint));
return d->dropShadowFilter.data();
}
@@ -327,21 +338,344 @@ static QByteArray qt_gl_convertToClamped(const QByteArray &source)
return result;
}
-QGLPixmapBlurFilter::QGLPixmapBlurFilter(Qt::RenderHint hint)
- : m_haveCached(false)
+QGLPixmapBlurFilter::QGLPixmapBlurFilter(QGraphicsBlurEffect::BlurHint hint)
+ : m_animatedBlur(false)
+ , m_haveCached(false)
, m_cachedRadius(0)
, m_hint(hint)
{
}
+// 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)
+{
+ 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)
+ {
+ for (int i = 0; i < qNumCachedBlurTextures; ++i)
+ m_textureIds[i] = textureIds[i];
+ }
+
+ ~QGLBlurTextureInfo()
+ {
+ glDeleteTextures(qNumCachedBlurTextures, m_textureIds);
+ }
+
+ QSize size() const { return m_size; }
+ GLuint textureId(int i) const { return m_textureIds[i]; }
+
+private:
+ GLuint m_textureIds[qNumCachedBlurTextures];
+ QSize m_size;
+};
+
+class QGLBlurTextureCache : public QObject
+{
+public:
+ static QGLBlurTextureCache *cacheForContext(const QGLContext *context);
+
+ QGLBlurTextureCache();
+ ~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);
+
+ void timerEvent(QTimerEvent *event);
+
+private:
+ static void pixmapDestroyed(QPixmap *pixmap);
+
+ QCache<quint64, QGLBlurTextureInfo > cache;
+
+ static QList<QGLBlurTextureCache *> blurTextureCaches;
+
+ int timerId;
+};
+
+QList<QGLBlurTextureCache *> QGLBlurTextureCache::blurTextureCaches;
+
+static void QGLBlurTextureCache_free(void *ptr)
+{
+ delete reinterpret_cast<QGLBlurTextureCache *>(ptr);
+}
+
+Q_GLOBAL_STATIC_WITH_ARGS(QGLContextResource, qt_blur_texture_caches, (QGLBlurTextureCache_free))
+
+QGLBlurTextureCache::QGLBlurTextureCache()
+ : timerId(0)
+{
+ cache.setMaxCost(4 * 1024 * 1024);
+ blurTextureCaches.append(this);
+}
+
+QGLBlurTextureCache::~QGLBlurTextureCache()
+{
+ blurTextureCaches.removeAt(blurTextureCaches.indexOf(this));
+}
+
+void QGLBlurTextureCache::timerEvent(QTimerEvent *event)
+{
+ killTimer(timerId);
+ timerId = 0;
+
+ cache.clear();
+}
+
+QGLBlurTextureCache *QGLBlurTextureCache::cacheForContext(const QGLContext *context)
+{
+ QGLBlurTextureCache *p = reinterpret_cast<QGLBlurTextureCache *>(qt_blur_texture_caches()->value(context));
+ if (!p) {
+ p = new QGLBlurTextureCache;
+ qt_blur_texture_caches()->insert(context, p);
+ }
+ return p;
+}
+
+QGLBlurTextureInfo *QGLBlurTextureCache::takeBlurTextureInfo(const QPixmap &pixmap)
+{
+ return cache.take(pixmap.cacheKey());
+}
+
+void QGLBlurTextureCache::clearBlurTextureInfo(const QPixmap &pixmap)
+{
+ cache.remove(pixmap.cacheKey());
+}
+
+bool QGLBlurTextureCache::hasBlurTextureInfo(const QPixmap &pixmap) const
+{
+ return cache.contains(pixmap.cacheKey());
+}
+
+void QGLBlurTextureCache::insertBlurTextureInfo(const QPixmap &pixmap, QGLBlurTextureInfo *info)
+{
+ static bool hookAdded = false;
+ if (!hookAdded) {
+ QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(pixmapDestroyed);
+ hookAdded = true;
+ }
+
+ QImagePixmapCleanupHooks::enableCleanupHooks(pixmap);
+ cache.insert(pixmap.cacheKey(), info, pixmap.width() * pixmap.height());
+
+ if (timerId)
+ killTimer(timerId);
+
+ timerId = startTimer(1000);
+}
+
+bool QGLBlurTextureCache::fitsInCache(const QPixmap &pixmap) const
+{
+ return pixmap.width() * pixmap.height() <= cache.maxCost();
+}
+
+void QGLBlurTextureCache::pixmapDestroyed(QPixmap *pixmap)
+{
+ foreach (QGLBlurTextureCache *cache, blurTextureCaches) {
+ if (cache->hasBlurTextureInfo(*pixmap))
+ cache->clearBlurTextureInfo(*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 void initializeTexture(GLuint id, int width, int height)
+{
+ 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);
+}
+
bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
{
QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this);
+ QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
+ QGLBlurTextureCache *blurTextureCache = QGLBlurTextureCache::cacheForContext(ctx);
+
+ if (m_hint == 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_hint = QGraphicsBlurEffect::QualityHint;
+ m_singlePass = false;
+
+ QGLFramebufferObjectFormat format;
+ format.setInternalTextureFormat(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);
+
+ // reattach the original FBO texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_2D, fbo->texture(), 0);
+
+ fboPainter.end();
+
+ qgl_fbo_pool()->release(fbo);
+
+ info = new QGLBlurTextureInfo(fboRect.size(), textures);
+ }
+
+ if (!m_haveCached || !m_animatedBlur) {
+ m_haveCached = true;
+ m_animatedBlur = true;
+ m_hint = QGraphicsBlurEffect::AnimationHint;
+ filter->setSource(qt_gl_interpolate_filter);
+ }
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+ filter->setOnPainter(painter);
+
+ qreal logRadius = qLn(radius());
+
+ int t;
+ for (t = -1; t < qNumCachedBlurTextures - 2; ++t) {
+ if (logRadius < qLogBlurLevel(t+1))
+ break;
+ }
+
+ qreal logBase = t >= 0 ? qLogBlurLevel(t) : 0;
+ m_t = qBound(qreal(0), (logRadius - logBase) / (qLogBlurLevel(t+1) - logBase), qreal(1));
+
+ m_textureSize = info->size();
+
+ glActiveTexture(GL_TEXTURE0 + 3);
+ if (t >= 0) {
+ glBindTexture(GL_TEXTURE_2D, info->textureId(t));
+ m_targetSize = info->size();
+ } 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());
+ }
+
+ // 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;
+ }
+
+ 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_hint == Qt::PerformanceHint) {
+ if (m_hint != QGraphicsBlurEffect::QualityHint) {
uint i = 0;
for (; i < (sizeof(fastRadii)/sizeof(*fastRadii))-1; ++i) {
if (fastRadii[i+1] > filterRadius)
@@ -352,9 +686,10 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const
m_singlePass = filterRadius <= 3;
- if (!m_haveCached || filterRadius != m_cachedRadius) {
+ 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);
@@ -389,13 +724,12 @@ bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const
QPainter fboPainter(fbo);
- if (src.hasAlphaChannel()) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
+ 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));
@@ -428,7 +762,29 @@ 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_hint == Qt::QualityHint) {
+ 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;
+ }
+
+ if (m_hint == QGraphicsBlurEffect::QualityHint) {
if (m_singlePass)
program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
else if (m_horizontalBlur)
@@ -578,7 +934,7 @@ QByteArray QGLPixmapBlurFilter::generateGaussianShader(int radius, bool singlePa
return source;
}
-QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(Qt::RenderHint hint)
+QGLPixmapDropShadowFilter::QGLPixmapDropShadowFilter(QGraphicsBlurEffect::BlurHint hint)
: m_haveCached(false)
, m_cachedRadius(0)
, m_hint(hint)
@@ -632,13 +988,12 @@ bool QGLPixmapDropShadowFilter::processGL(QPainter *painter, const QPointF &pos,
QPainter fboPainter(fbo);
- if (src.hasAlphaChannel()) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT);
- }
+ 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));
@@ -685,7 +1040,7 @@ void QGLPixmapDropShadowFilter::setUniforms(QGLShaderProgram *program)
alpha);
}
- if (m_hint == Qt::QualityHint) {
+ if (m_hint == QGraphicsBlurEffect::QualityHint) {
if (m_singlePass)
program->setUniformValue("delta", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
else if (m_horizontalBlur)
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index c965947..5ca37ef 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -89,13 +89,22 @@ static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz)
}
-QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat)
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize)
{
QGLFramebufferObject *chosen = 0;
QGLFramebufferObject *candidate = 0;
for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
QGLFramebufferObject *fbo = m_fbos.at(i);
+ if (strictSize) {
+ if (fbo->size() == requestSize && fbo->format() == requestFormat) {
+ chosen = fbo;
+ break;
+ } else {
+ continue;
+ }
+ }
+
if (fbo->format() == requestFormat) {
// choose the fbo with a matching format and the closest size
if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
@@ -127,7 +136,10 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize
}
if (!chosen) {
- chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
+ if (strictSize)
+ chosen = new QGLFramebufferObject(requestSize, requestFormat);
+ else
+ chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat);
}
if (!chosen->isValid()) {
@@ -140,7 +152,8 @@ QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize
void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
{
- m_fbos << fbo;
+ if (fbo)
+ m_fbos << fbo;
}
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index 6190d38..8a13e03 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -69,7 +69,7 @@ class QGLPixmapData;
class QGLFramebufferObjectPool
{
public:
- QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format);
+ QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format, bool strictSize = false);
void release(QGLFramebufferObject *fbo);
private: