summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSamuel Rødal <sroedal@trolltech.com>2009-07-28 10:25:55 (GMT)
committerSamuel Rødal <sroedal@trolltech.com>2009-07-28 12:19:18 (GMT)
commitdbdc54791e585f3c6bf62c1a091ef844a66483ba (patch)
tree75b5f14c4b1a8176b53b23d93f0b6f7dcc688365 /src
parent610aa1737a206fe97628a3375a543400ea0761fa (diff)
parent0431548ddffc56f74cc60e7d341ade3920adefb1 (diff)
downloadQt-dbdc54791e585f3c6bf62c1a091ef844a66483ba.zip
Qt-dbdc54791e585f3c6bf62c1a091ef844a66483ba.tar.gz
Qt-dbdc54791e585f3c6bf62c1a091ef844a66483ba.tar.bz2
Merge commit 'qt-graphics-team/pixmapfilters-redux' into kinetic-graphicseffect
Conflicts: src/opengl/gl2paintengineex/qglengineshadermanager.cpp src/opengl/gl2paintengineex/qglengineshadermanager_p.h src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h Merge custom shader / GL blur pixmap filter implementation from graphics team repo with implementation from kinetic graphics-team repo.
Diffstat (limited to 'src')
-rw-r--r--src/gui/graphicsview/qgraphicseffect.cpp4
-rw-r--r--src/gui/image/qpixmapfilter.cpp450
-rw-r--r--src/gui/image/qpixmapfilter_p.h51
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage.cpp4
-rw-r--r--src/opengl/gl2paintengineex/qglcustomshaderstage_p.h3
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp37
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h22
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadersource_p.h8
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp23
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h9
-rw-r--r--src/opengl/qglpixmapfilter.cpp277
-rw-r--r--src/opengl/qpixmapdata_gl.cpp134
-rw-r--r--src/opengl/qpixmapdata_gl_p.h13
13 files changed, 698 insertions, 337 deletions
diff --git a/src/gui/graphicsview/qgraphicseffect.cpp b/src/gui/graphicsview/qgraphicseffect.cpp
index 8d2c416..31a437a 100644
--- a/src/gui/graphicsview/qgraphicseffect.cpp
+++ b/src/gui/graphicsview/qgraphicseffect.cpp
@@ -373,13 +373,13 @@ static QImage blurred(const QImage& image, const QRect& rect, int radius)
int QGraphicsBlurEffect::blurRadius() const
{
Q_D(const QGraphicsBlurEffect);
- return int(d->filter->blurRadius());
+ return int(d->filter->radius());
}
void QGraphicsBlurEffect::setBlurRadius(int radius)
{
Q_D(QGraphicsBlurEffect);
- d->filter->setBlurRadius(radius);
+ d->filter->setRadius(radius);
}
QRectF QGraphicsBlurEffect::boundingRect() const
diff --git a/src/gui/image/qpixmapfilter.cpp b/src/gui/image/qpixmapfilter.cpp
index 2b275a3..b7b3733 100644
--- a/src/gui/image/qpixmapfilter.cpp
+++ b/src/gui/image/qpixmapfilter.cpp
@@ -478,6 +478,225 @@ void QPixmapConvolutionFilter::draw(QPainter *painter, const QPointF &p, const Q
}
}
+/*!
+ \class QPixmapBlurFilter
+ \since 4.6
+ \ingroup multimedia
+
+ \brief The QPixmapBlurFilter class provides blur filtering
+ for pixmaps.
+
+ QPixmapBlurFilter implements a blur pixmap filter,
+ which is applied when \l{QPixmapFilter::}{draw()} is called.
+
+ The filter lets you specialize the radius of the blur as well
+ as the quality.
+
+ By default, the blur effect is produced by applying an exponential
+ filter generated from the specified blurRadius(). Paint engines
+ may override this with a custom blur that is faster on the
+ underlying hardware.
+
+ \sa {Pixmap Filters Example}, QPixmapConvolutionFilter, QPixmapDropShadowFilter
+
+ \internal
+*/
+
+class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate
+{
+public:
+ QPixmapBlurFilterPrivate() : radius(5), quality(Qt::FastTransformation) {}
+
+ int radius;
+ Qt::TransformationMode quality;
+};
+
+
+/*!
+ Constructs a pixmap blur filter.
+
+ \internal
+*/
+QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent)
+ : QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent)
+{
+}
+
+/*!
+ Destructor of pixmap blur filter.
+
+ \internal
+*/
+QPixmapBlurFilter::~QPixmapBlurFilter()
+{
+}
+
+/*!
+ Sets the radius of the blur filter. Higher radius produces increased blurriness.
+
+ \internal
+*/
+void QPixmapBlurFilter::setRadius(int radius)
+{
+ Q_D(QPixmapBlurFilter);
+ d->radius = radius;
+}
+
+/*!
+ Gets the radius of the blur filter.
+
+ \internal
+*/
+int QPixmapBlurFilter::radius() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->radius;
+}
+
+/*!
+ Setting the quality to FastTransformation causes the implementation
+ to trade off visual quality to blur the image faster. Setting the
+ quality to SmoothTransformation causes the implementation to improve
+ visual quality at the expense of speed. The implementation is free
+ to ignore this value if it only has a single blur algorithm.
+
+ \internal
+*/
+void QPixmapBlurFilter::setQuality(Qt::TransformationMode quality)
+{
+ Q_D(QPixmapBlurFilter);
+ d->quality = quality;
+}
+
+/*!
+ Gets the quality of the blur filter.
+
+ \internal
+*/
+Qt::TransformationMode QPixmapBlurFilter::quality() const
+{
+ Q_D(const QPixmapBlurFilter);
+ return d->quality;
+}
+
+/*!
+ \reimp
+
+ \internal
+*/
+QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
+{
+ return rect;
+}
+
+// Blur the image according to the blur radius
+// Based on exponential blur algorithm by Jani Huhtanen
+// (maximum radius is set to 16)
+static QImage blurred(const QImage& image, const QRect& rect, int radius)
+{
+ int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
+ int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
+
+ QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ int r1 = rect.top();
+ int r2 = rect.bottom();
+ int c1 = rect.left();
+ int c2 = rect.right();
+
+ int bpl = result.bytesPerLine();
+ int rgba[4];
+ unsigned char* p;
+
+ for (int col = c1; col <= c2; col++) {
+ p = result.scanLine(r1) + col * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p += bpl;
+ for (int j = r1; j < r2; j++, p += bpl)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int row = r1; row <= r2; row++) {
+ p = result.scanLine(row) + c1 * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p += 4;
+ for (int j = c1; j < c2; j++, p += 4)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int col = c1; col <= c2; col++) {
+ p = result.scanLine(r2) + col * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p -= bpl;
+ for (int j = r1; j < r2; j++, p -= bpl)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ for (int row = r1; row <= r2; row++) {
+ p = result.scanLine(row) + c2 * 4;
+ for (int i = 0; i < 4; i++)
+ rgba[i] = p[i] << 4;
+
+ p -= 4;
+ for (int j = c1; j < c2; j++, p -= 4)
+ for (int i = 0; i < 4; i++)
+ p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
+ }
+
+ return result;
+}
+
+/*!
+ \reimp
+
+ \internal
+*/
+void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &p, const QPixmap &src, const QRectF &srcRect) const
+{
+ Q_D(const QPixmapBlurFilter);
+ if (!painter->isActive())
+ return;
+
+ if (d->radius == 0) {
+ painter->drawPixmap(srcRect.translated(p), src, srcRect);
+ return;
+ }
+
+ QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
+ static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0;
+ QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
+ if (blurFilter) {
+ blurFilter->setRadius(d->radius);
+ blurFilter->setQuality(d->quality);
+ blurFilter->draw(painter, p, src, srcRect);
+ delete blurFilter;
+ return;
+ }
+
+ QImage srcImage;
+ QImage destImage;
+
+ if (srcRect.isNull()) {
+ srcImage = src.toImage();
+ destImage = blurred(srcImage, srcImage.rect(), d->radius);
+ } else {
+ QRect rect = srcRect.toAlignedRect().intersected(src.rect());
+
+ srcImage = src.copy(rect).toImage();
+ destImage = blurred(srcImage, srcImage.rect(), d->radius);
+ }
+
+ painter->drawImage(p, destImage);
+}
+
// grayscales the image to dest (could be same). If rect isn't defined
// destination image size is used to determine the dimension of grayscaling
// process.
@@ -841,235 +1060,4 @@ void QPixmapDropShadowFilter::draw(QPainter *p,
p->drawPixmap(pos, px, src);
}
-/*!
- \class QPixmapBlurFilter
- \since 4.6
- \ingroup multimedia
-
- \brief The QPixmapBlurFilter class is a convenience class
- for drawing pixmaps with blur effects.
-
- By default, the blur effect is produced by applying an exponential
- filter generated from the specified blurRadius(). Paint engines
- may override this with a custom blur that is faster on the
- underlying hardware.
-
- \sa QPixmapConvolutionFilter
-
- \internal
- */
-
-class QPixmapBlurFilterPrivate : public QPixmapFilterPrivate
-{
-public:
- QPixmapBlurFilterPrivate()
- : quality(QPixmapBlurFilter::High), radius(1) {}
-
- QPixmapBlurFilter::BlurQuality quality;
- qreal radius;
-};
-
-/*!
- Constructs blur filter and attaches it to \a parent.
-
- \internal
-*/
-QPixmapBlurFilter::QPixmapBlurFilter(QObject *parent)
- : QPixmapFilter(*new QPixmapBlurFilterPrivate, BlurFilter, parent)
-{
- Q_D(QPixmapBlurFilter);
- setBlurRadius(4);
-}
-
-/*!
- Destroys blur filter.
-
- \internal
-*/
-QPixmapBlurFilter::~QPixmapBlurFilter()
-{
-}
-
-/*!
- \enum QPixmapFilter::BlurQuality
- \since 4.6
- \ingroup multimedia
- This enum describes the quality of blur to apply to pixmaps.
-
- \value Fast Blur faster, potentially losing some quality.
- \value High Produce the best high-quality blur possible, even if slower.
-
- \internal
-*/
-
-/*!
- Returns the quality of the blur. The default value is High.
-
- \sa blurRadius()
- \internal
-*/
-QPixmapBlurFilter::BlurQuality QPixmapBlurFilter::blurQuality() const
-{
- Q_D(const QPixmapBlurFilter);
- return d->quality;
-}
-
-/*!
- Sets the quality of the blur to the \a blurQuality specified.
-
- Setting the quality to Faster causes the implementation to trade
- off visual quality to blur the image faster. Setting the quality
- to High causes the implementation to improve visual quality
- at the expense of speed. The implementation is free to ignore
- this value if it only has a single blur algorithm.
-
- \sa setBlurRadius()
- \internal
-*/
-void QPixmapBlurFilter::setBlurQuality(BlurQuality blurQuality)
-{
- Q_D(QPixmapBlurFilter);
- d->quality = blurQuality;
-}
-
-/*!
- Returns the radius in pixels of the blur. The default value is 4.
-
- A smaller radius results in a sharper image.
-
- \sa blurQuality()
- \internal
-*/
-qreal QPixmapBlurFilter::blurRadius() const
-{
- Q_D(const QPixmapBlurFilter);
- return d->radius;
-}
-
-/*!
- Sets the radius in pixels of the blur to the \a radius specified.
-
- Using a smaller radius results in a sharper image.
-
- \sa setBlurQuality()
- \internal
-*/
-void QPixmapBlurFilter::setBlurRadius(qreal blurRadius)
-{
- Q_D(QPixmapBlurFilter);
- d->radius = blurRadius;
-}
-
-/*!
- \internal
- */
-QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
-{
- Q_D(const QPixmapBlurFilter);
- qreal delta = d->radius * 3;
- QRectF blurRect(rect);
- blurRect.adjust(-delta, -delta, delta, delta);
- return blurRect;
-}
-
-// Blur the image according to the blur radius
-// Based on exponential blur algorithm by Jani Huhtanen
-// (maximum radius is set to 16)
-static QImage blurred(const QImage& image, const QRect& rect, int radius)
-{
- int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
- int alpha = (radius < 1) ? 16 : (radius > 17) ? 1 : tab[radius-1];
-
- QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- int r1 = rect.top();
- int r2 = rect.bottom();
- int c1 = rect.left();
- int c2 = rect.right();
-
- int bpl = result.bytesPerLine();
- int rgba[4];
- unsigned char* p;
-
- for (int col = c1; col <= c2; col++) {
- p = result.scanLine(r1) + col * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p += bpl;
- for (int j = r1; j < r2; j++, p += bpl)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- for (int row = r1; row <= r2; row++) {
- p = result.scanLine(row) + c1 * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p += 4;
- for (int j = c1; j < c2; j++, p += 4)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- for (int col = c1; col <= c2; col++) {
- p = result.scanLine(r2) + col * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p -= bpl;
- for (int j = r1; j < r2; j++, p -= bpl)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- for (int row = r1; row <= r2; row++) {
- p = result.scanLine(row) + c2 * 4;
- for (int i = 0; i < 4; i++)
- rgba[i] = p[i] << 4;
-
- p -= 4;
- for (int j = c1; j < c2; j++, p -= 4)
- for (int i = 0; i < 4; i++)
- p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
- }
-
- return result;
-}
-
-/*!
- \internal
- */
-void QPixmapBlurFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const
-{
- Q_D(const QPixmapBlurFilter);
-
- QPixmapFilter *filter = painter->paintEngine() && painter->paintEngine()->isExtended() ?
- static_cast<QPaintEngineEx *>(painter->paintEngine())->createPixmapFilter(type()) : 0;
- QPixmapBlurFilter *blurFilter = static_cast<QPixmapBlurFilter*>(filter);
- if (blurFilter) {
- blurFilter->setBlurQuality(d->quality);
- blurFilter->setBlurRadius(d->radius);
- blurFilter->draw(painter, dest, src, srcRect);
- delete blurFilter;
- return;
- }
-
- QImage srcImage;
- QImage destImage;
-
- if (srcRect.isNull()) {
- srcImage = src.toImage();
- destImage = blurred(srcImage, srcImage.rect(), int(d->radius + 0.5));
- } else {
- QRect rect = srcRect.toAlignedRect().intersected(src.rect());
-
- srcImage = src.copy(rect).toImage();
- destImage = blurred(srcImage, srcImage.rect(), int(d->radius + 0.5));
- }
-
- qreal delta = d->radius * 3;
- painter->drawImage(dest - QPointF(delta, delta), destImage);
-}
-
QT_END_NAMESPACE
diff --git a/src/gui/image/qpixmapfilter_p.h b/src/gui/image/qpixmapfilter_p.h
index ca27cbf..ac393a1 100644
--- a/src/gui/image/qpixmapfilter_p.h
+++ b/src/gui/image/qpixmapfilter_p.h
@@ -118,6 +118,30 @@ private:
int columns() const;
};
+class QPixmapBlurFilterPrivate;
+
+class Q_GUI_EXPORT QPixmapBlurFilter : public QPixmapFilter
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPixmapBlurFilter)
+
+public:
+ QPixmapBlurFilter(QObject *parent = 0);
+ ~QPixmapBlurFilter();
+
+ void setRadius(int radius);
+ void setQuality(Qt::TransformationMode mode);
+
+ int radius() const;
+ Qt::TransformationMode quality() const;
+
+ QRectF boundingRectFor(const QRectF &rect) const;
+ void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const;
+
+private:
+ friend class QGLPixmapBlurFilter;
+};
+
class QPixmapColorizeFilterPrivate;
class Q_GUI_EXPORT QPixmapColorizeFilter : public QPixmapFilter
@@ -159,33 +183,6 @@ public:
inline void setOffset(qreal dx, qreal dy) { setOffset(QPointF(dx, dy)); }
};
-class QPixmapBlurFilterPrivate;
-
-class Q_GUI_EXPORT QPixmapBlurFilter : public QPixmapFilter
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QPixmapBlurFilter)
-
-public:
- QPixmapBlurFilter(QObject *parent = 0);
- ~QPixmapBlurFilter();
-
- enum BlurQuality
- {
- Fast,
- High
- };
-
- BlurQuality blurQuality() const;
- void setBlurQuality(BlurQuality blurQuality);
-
- qreal blurRadius() const;
- void setBlurRadius(qreal blurRadius);
-
- QRectF boundingRectFor(const QRectF &rect) const;
- void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect = QRectF()) const;
-};
-
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
index bcd9f27..a82caa0 100644
--- a/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage.cpp
@@ -110,9 +110,9 @@ void QGLCustomShaderStage::removeFromPainter(QPainter* p)
d->m_manager->setCustomStage(0);
}
-const char* QGLCustomShaderStage::source()
+const char* QGLCustomShaderStage::source() const
{
- Q_D(QGLCustomShaderStage);
+ Q_D(const QGLCustomShaderStage);
return d->m_source.constData();
}
diff --git a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
index 659f7ba..70e9ff0 100644
--- a/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
+++ b/src/opengl/gl2paintengineex/qglcustomshaderstage_p.h
@@ -71,9 +71,10 @@ public:
virtual void setUniforms(QGLShaderProgram*) = 0;
void setUniformsDirty();
+
bool setOnPainter(QPainter*);
void removeFromPainter(QPainter*);
- const char* source();
+ const char* source() const;
protected:
void setSource(const QByteArray&);
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 848a7f1..dab1257 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -87,7 +87,6 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
useTextureCoords(false),
compositionMode(QPainter::CompositionMode_SourceOver),
customSrcStage(0),
- customSrcStagePrev(0),
blitShaderProg(0),
simpleShaderProg(0),
currentShaderProg(0)
@@ -162,7 +161,7 @@ QGLEngineShaderManager::QGLEngineShaderManager(QGLContext* context)
#if defined(QT_DEBUG)
// Check that all the elements have been filled:
for (int i = 0; i < TotalShaderCount; ++i) {
- if (qglEngineShaderSourceCode[i] == 0) {
+ if (i != CustomImageSrcFragmentShader && qglEngineShaderSourceCode[i] == 0) {
int enumIndex = staticMetaObject.indexOfEnumerator("ShaderName");
QMetaEnum m = staticMetaObject.enumerator(enumIndex);
@@ -314,10 +313,9 @@ void QGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode)
void QGLEngineShaderManager::setCustomStage(QGLCustomShaderStage* stage)
{
// If the custom shader has changed, then destroy the previous compilation.
- if (customSrcStagePrev && stage && customSrcStagePrev != stage)
- removeCustomStage(customSrcStagePrev);
+ if (customSrcStage && stage && customSrcStage != stage)
+ removeCustomStage(customSrcStage);
- customSrcStagePrev = customSrcStage;
customSrcStage = stage;
shaderProgNeedsChanging = true;
}
@@ -326,7 +324,7 @@ void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage)
{
Q_UNUSED(stage); // Currently we only support one at a time...
- QGLShader* compiledShader = compiledShaders[CustomImageSrcFragmentShader];
+ QGLShader *compiledShader = compiledShaders[CustomImageSrcFragmentShader];
if (!compiledShader)
return;
@@ -341,10 +339,8 @@ void QGLEngineShaderManager::removeCustomStage(QGLCustomShaderStage* stage)
}
}
- delete compiledShader;
compiledShaders[CustomImageSrcFragmentShader] = 0;
customSrcStage = 0;
- customSrcStagePrev = 0;
shaderProgNeedsChanging = true;
}
@@ -456,7 +452,6 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
requiredProgram.positionVertexShader = compiledShaders[positionVertexShaderName];
requiredProgram.srcPixelFragShader = compiledShaders[srcPixelFragShaderName];
-
const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus;
const bool hasMask = maskType != QGLEngineShaderManager::NoMask;
@@ -545,7 +540,6 @@ bool QGLEngineShaderManager::useCorrectShaderProg()
else
requiredProgram.compositionFragShader = 0;
-
// At this point, requiredProgram is fully populated so try to find the program in the cache
bool foundProgramInCache = false;
for (int i = 0; i < cachedPrograms.size(); ++i) {
@@ -612,15 +606,24 @@ void QGLEngineShaderManager::compileNamedShader(QGLEngineShaderManager::ShaderNa
if (compiledShaders[name])
return;
- QGLShader *newShader = new QGLShader(type, ctx, this);
+ QGLShader *newShader;
- const char* sourceCode;
- if (name == CustomImageSrcFragmentShader)
- sourceCode = customSrcStage->source();
- else
- sourceCode = qglEngineShaderSourceCode[name];
+ QByteArray source;
+ if (name == CustomImageSrcFragmentShader) {
+ source = customSrcStage->source();
+ source += qglslCustomSrcFragmentShader;
- newShader->compile(sourceCode);
+ newShader = customShaderCache.object(source);
+ if (!newShader) {
+ newShader = new QGLShader(type, ctx, this);
+ newShader->compile(source);
+ customShaderCache.insert(source, newShader);
+ }
+ } else {
+ source = qglEngineShaderSourceCode[name];
+ newShader = new QGLShader(type, ctx, this);
+ newShader->compile(source);
+ }
#if defined(QT_DEBUG)
// Name the shader for easier debugging
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 9d881cc..69574ba 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -199,23 +199,23 @@
O = Global Opacity
- CUSTOM SHADER CODE (idea, depricated)
+ CUSTOM SHADER CODE
==================
The use of custom shader code is supported by the engine for drawImage and
drawPixmap calls. This is implemented via hooks in the fragment pipeline.
+
The custom shader is passed to the engine as a partial fragment shader
(QGLCustomShaderStage). The shader will implement a pre-defined method name
which Qt's fragment pipeline will call:
- lowp vec4 customShader()
-
- Depending on the custom type, the custom shader has a small API it can use
- to read pixels. The basic custom type is for image/pixmap drawing and thus
- can use the following to sample the src texture (non-premultiplied)
+ lowp vec4 customShader(sampler2d src, vec2 srcCoords)
- lowp vec4 QSampleSrcPixel(mediump vec2 coords)
+ The provided src and srcCoords parameters can be used to sample from the
+ source image.
+ Transformations, clipping, opacity, and composition modes set using QPainter
+ will be respected when using the custom shader hook.
*/
#ifndef QGLENGINE_SHADER_MANAGER_H
@@ -233,7 +233,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(OpenGL)
-
struct QGLEngineShaderProg
{
QGLShader* mainVertexShader;
@@ -276,7 +275,7 @@ struct QGLEngineCachedShaderProg
static const GLuint QT_VERTEX_COORDS_ATTR = 0;
static const GLuint QT_TEXTURE_COORDS_ATTR = 1;
-class QGLEngineShaderManager : public QObject
+class Q_OPENGL_EXPORT QGLEngineShaderManager : public QObject
{
Q_OBJECT
public:
@@ -362,6 +361,7 @@ public:
MainFragmentShader,
ImageSrcFragmentShader,
+ CustomSrcFragmentShader,
ImageSrcWithPatternFragmentShader,
NonPremultipliedImageSrcFragmentShader,
CustomImageSrcFragmentShader,
@@ -408,7 +408,6 @@ public:
Q_ENUMS(ShaderName)
#endif
-
private:
QGLContext* ctx;
bool shaderProgNeedsChanging;
@@ -421,12 +420,13 @@ private:
bool useTextureCoords;
QPainter::CompositionMode compositionMode;
QGLCustomShaderStage* customSrcStage;
- QGLCustomShaderStage* customSrcStagePrev;
QGLShaderProgram* blitShaderProg;
QGLShaderProgram* simpleShaderProg;
QGLEngineShaderProg* currentShaderProg;
+ QCache<QByteArray, QGLShader> customShaderCache;
+
// TODO: Possibly convert to a LUT
QList<QGLEngineShaderProg> cachedPrograms;
diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
index 4e32f91..e379aa3 100644
--- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
@@ -290,6 +290,14 @@ static const char* const qglslImageSrcFragmentShader = "\
return texture2D(imageTexture, textureCoords); \
}";
+static const char* const qglslCustomSrcFragmentShader = "\
+ varying highp vec2 textureCoords; \
+ uniform sampler2D imageTexture; \
+ lowp vec4 customShader(sampler2D texture, vec2 coords); \
+ lowp vec4 srcPixel() { \
+ return customShader(imageTexture, textureCoords); \
+ }";
+
static const char* const qglslImageSrcWithPatternFragmentShader = "\
varying highp vec2 textureCoords; \
uniform lowp vec4 patternColor; \
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index b04c7e6..db306a5 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1092,6 +1092,21 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel());
}
+void QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
+{
+ Q_D(QGL2PaintEngineEx);
+ ensureActive();
+ d->transferMode(ImageDrawingMode);
+
+ QGLContext *ctx = d->ctx;
+ glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT,
+ state()->renderHints & QPainter::SmoothPixmapTransform, textureId);
+ d->drawTexture(dest, src, size, false);
+}
+
void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
Q_D(QGL2PaintEngineEx);
@@ -1636,6 +1651,14 @@ QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState()
{
}
+QPixmapFilter *QGL2PaintEngineEx::createPixmapFilter(int type) const
+{
+ const QGLContext *ctx = QGLContext::currentContext();
+ if (ctx)
+ return ctx->d_func()->createPixmapFilter(type);
+ return 0;
+}
+
QT_END_NAMESPACE
#include "qpaintengineex_opengl2.moc"
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 21c296d..3ff2dca 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -88,8 +88,7 @@ public:
bool canRestoreClip;
};
-
-class QGL2PaintEngineEx : public QPaintEngineEx
+class Q_OPENGL_EXPORT QGL2PaintEngineEx : public QPaintEngineEx
{
Q_DECLARE_PRIVATE(QGL2PaintEngineEx)
public:
@@ -116,9 +115,10 @@ public:
virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
-
virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
Qt::ImageConversionFlags flags = Qt::AutoColor);
+ virtual void drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr);
+
virtual void drawTextItem(const QPointF &p, const QTextItem &textItem);
Type type() const { return OpenGL2; }
@@ -134,6 +134,9 @@ public:
virtual void sync();
const QGLContext* context();
+
+ QPixmapFilter *createPixmapFilter(int type) const;
+
private:
Q_DISABLE_COPY(QGL2PaintEngineEx)
};
diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp
index 5a06763..1e72fd8 100644
--- a/src/opengl/qglpixmapfilter.cpp
+++ b/src/opengl/qglpixmapfilter.cpp
@@ -40,20 +40,24 @@
****************************************************************************/
#include "private/qpixmapfilter_p.h"
+#include "private/qpixmapdata_gl_p.h"
+#include "private/qpaintengineex_opengl2_p.h"
+#include "private/qglengineshadermanager_p.h"
#include "qglpixmapfilter_p.h"
#include "qgraphicssystem_gl_p.h"
#include "qpaintengine_opengl_p.h"
+#include "qcache.h"
-#include "qglpixelbuffer.h"
+#include "qglframebufferobject.h"
#include "qglshaderprogram.h"
#include "qgl_p.h"
#include "private/qapplication_p.h"
+#include "private/qmath_p.h"
QT_BEGIN_NAMESPACE
-
void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const
{
const_cast<QGLContext *>(QGLContext::currentContext())->d_func()->bindTexture(src, GL_TEXTURE_2D, GL_RGBA, true, false);
@@ -97,6 +101,27 @@ private:
mutable int m_kernelHeight;
};
+class QGLPixmapBlurFilter : public QGLCustomShaderStage, public QGLPixmapFilter<QPixmapBlurFilter>
+{
+public:
+ QGLPixmapBlurFilter();
+ ~QGLPixmapBlurFilter();
+
+ void setUniforms(QGLShaderProgram *program);
+
+protected:
+ bool processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &srcRect) const;
+
+private:
+ static QByteArray generateBlurShader(int radius, bool gaussianBlur);
+
+ mutable QGLShader *m_shader;
+
+ mutable QSize m_textureSize;
+
+ QGLShaderProgram *m_program;
+};
+
extern QGLWidget *qt_gl_share_widget();
QPixmapFilter *QGLContextPrivate::createPixmapFilter(int type) const
@@ -105,6 +130,8 @@ QPixmapFilter *QGLContextPrivate::createPixmapFilter(int type) const
case QPixmapFilter::ColorizeFilter:
return new QGLPixmapColorizeFilter;
+ case QPixmapFilter::BlurFilter:
+ return new QGLPixmapBlurFilter;
case QPixmapFilter::ConvolutionFilter:
return new QGLPixmapConvolutionFilter;
@@ -281,4 +308,250 @@ bool QGLPixmapConvolutionFilter::processGL(QPainter *, const QPointF &pos, const
return true;
}
+QGLPixmapBlurFilter::QGLPixmapBlurFilter()
+{
+}
+
+QGLPixmapBlurFilter::~QGLPixmapBlurFilter()
+{
+}
+
+bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const
+{
+ QGLPixmapBlurFilter *filter = const_cast<QGLPixmapBlurFilter *>(this);
+ filter->setSource(generateBlurShader(radius(), quality() == Qt::SmoothTransformation));
+
+ QGLFramebufferObjectFormat format;
+ format.setInternalFormat(src.hasAlphaChannel() ? GL_RGBA : GL_RGB);
+ QGLFramebufferObject *fbo = qgl_fbo_pool()->acquire(src.size(), format);
+
+ if (!fbo)
+ return false;
+
+ glBindTexture(GL_TEXTURE_2D, fbo->texture());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(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);
+
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(painter->paintEngine());
+
+ engine->syncState();
+ painter->save();
+
+ // ensure GL_LINEAR filtering is used
+ painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
+ // prepare for updateUniforms
+ m_textureSize = src.size();
+
+ // first pass, to fbo
+ fbo->bind();
+ if (src.hasAlphaChannel()) {
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ filter->setOnPainter(painter);
+
+ QTransform transform = engine->state()->matrix;
+ if (!transform.isIdentity()) {
+ engine->state()->matrix = QTransform();
+ engine->transformChanged();
+ }
+
+ engine->drawPixmap(src.rect().translated(0, painter->device()->height() - fbo->height()),
+ src, src.rect());
+
+ if (!transform.isIdentity()) {
+ engine->state()->matrix = transform;
+ engine->transformChanged();
+ }
+
+ fbo->release();
+
+ // second pass, to widget
+ m_program->setUniformValue("delta", 0.0, 1.0);
+ engine->drawTexture(src.rect().translated(pos.x(), pos.y()), fbo->texture(), fbo->size(), src.rect().translated(0, fbo->height() - src.height()));
+ filter->removeFromPainter(painter);
+
+ painter->restore();
+
+ qgl_fbo_pool()->release(fbo);
+
+ return true;
+}
+
+void QGLPixmapBlurFilter::setUniforms(QGLShaderProgram *program)
+{
+ program->setUniformValue("invTextureSize", 1.0 / m_textureSize.width(), 1.0 / m_textureSize.height());
+ program->setUniformValue("delta", 1.0, 0.0);
+
+ m_program = program;
+}
+
+static inline qreal gaussian(qreal dx, qreal sigma)
+{
+ return exp(-dx * dx / (2 * sigma * sigma)) / (Q_2PI * sigma * sigma);
+}
+
+QByteArray QGLPixmapBlurFilter::generateBlurShader(int radius, bool gaussianBlur)
+{
+ Q_ASSERT(radius >= 1);
+
+ QByteArray source;
+ source.reserve(1000);
+
+ source.append("uniform highp vec2 invTextureSize;\n");
+
+ bool separateXY = true;
+ bool clip = false;
+
+ if (separateXY) {
+ source.append("uniform highp vec2 delta;\n");
+
+ if (clip)
+ source.append("uniform highp vec2 clip;\n");
+ } else if (clip) {
+ source.append("uniform highp vec4 clip;\n");
+ }
+
+ source.append("mediump vec4 customShader(sampler2D src, vec2 srcCoords) {\n");
+
+ QVector<qreal> sampleOffsets;
+ QVector<qreal> weights;
+
+ if (gaussianBlur) {
+ 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;
+ }
+
+ // odd size ?
+ if (gaussianComponents.size() & 1) {
+ sampleOffsets << radius;
+ weights << gaussianComponents.last();
+ }
+ } else {
+ for (int i = 0; i < radius; ++i) {
+ sampleOffsets << 2 * i - radius + 0.5;
+ weights << qreal(1);
+ }
+ sampleOffsets << radius;
+ weights << qreal(0.5);
+ }
+
+ int currentVariable = 1;
+ source.append(" mediump vec4 sample = vec4(0.0);\n");
+ source.append(" mediump vec2 coord;\n");
+
+ qreal weightSum = 0;
+ if (separateXY) {
+ source.append(" mediump float c;\n");
+ for (int i = 0; i < sampleOffsets.size(); ++i) {
+ qreal delta = sampleOffsets.at(i);
+
+ ++currentVariable;
+
+ QByteArray coordinate = "srcCoords";
+ if (delta != qreal(0)) {
+ coordinate.append(" + invTextureSize * delta * float(");
+ coordinate.append(QByteArray::number(delta));
+ coordinate.append(")");
+ }
+
+ source.append(" coord = ");
+ source.append(coordinate);
+ source.append(";\n");
+
+ if (clip) {
+ source.append(" c = dot(coord, delta);\n");
+ source.append(" if (c > clip.x && c < clip.y)\n ");
+ }
+
+ source.append(" sample += texture2D(src, coord)");
+
+ weightSum += weights.at(i);
+ if (weights.at(i) != qreal(1)) {
+ source.append(" * float(");
+ source.append(QByteArray::number(weights.at(i)));
+ source.append(");\n");
+ } else {
+ source.append(";\n");
+ }
+ }
+ } else {
+ for (int y = 0; y < sampleOffsets.size(); ++y) {
+ for (int x = 0; x < sampleOffsets.size(); ++x) {
+ QByteArray coordinate = "srcCoords";
+
+ qreal dx = sampleOffsets.at(x);
+ qreal dy = sampleOffsets.at(y);
+
+ if (dx != qreal(0) || dy != qreal(0)) {
+ coordinate.append(" + invTextureSize * vec2(float(");
+ coordinate.append(QByteArray::number(dx));
+ coordinate.append("), float(");
+ coordinate.append(QByteArray::number(dy));
+ coordinate.append("))");
+ }
+
+ source.append(" coord = ");
+ source.append(coordinate);
+ source.append(";\n");
+
+ if (clip)
+ source.append(" if (coord.x > clip.x && coord.x < clip.y && coord.y > clip.z && coord.y < clip.w)\n ");
+
+ source.append(" sample += texture2D(src, coord)");
+
+ ++currentVariable;
+
+ weightSum += weights.at(x) * weights.at(y);
+ if ((weights.at(x) != qreal(1) || weights.at(y) != qreal(1))) {
+ source.append(" * float(");
+ source.append(QByteArray::number(weights.at(x) * weights.at(y)));
+ source.append(");\n");
+ } else {
+ source.append(";\n");
+ }
+ }
+ }
+ }
+
+ source.append(" return ");
+ if (!gaussianBlur) {
+ source.append("float(");
+ if (separateXY)
+ source.append(QByteArray::number(1 / weightSum));
+ else
+ source.append(QByteArray::number(1 / weightSum));
+ source.append(") * ");
+ }
+ source.append("sample;\n");
+ source.append("}\n");
+
+ return source;
+}
+
QT_END_NAMESPACE
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index e3ee2b2..c0eed4d 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -55,6 +55,85 @@ QT_BEGIN_NAMESPACE
extern QGLWidget* qt_gl_share_widget();
+/*!
+ \class QGLFramebufferObjectPool
+ \since 4.6
+
+ \brief The QGLFramebufferObject class provides a pool of framebuffer
+ objects for offscreen rendering purposes.
+
+ When requesting an FBO of a given size and format, an FBO of the same
+ format and a size at least as big as the requested size will be returned.
+
+ \internal
+*/
+
+static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo)
+{
+ return qAbs(size.width() * size.height() - fbo->width() * fbo->height());
+}
+
+QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat)
+{
+ QGLFramebufferObject *chosen = 0;
+ QGLFramebufferObject *candidate = 0;
+ for (int i = 0; !chosen && i < m_fbos.size(); ++i) {
+ QGLFramebufferObject *fbo = m_fbos.at(i);
+
+ QGLFramebufferObjectFormat format = fbo->format();
+ if (format.samples() == requestFormat.samples()
+ && format.attachment() == requestFormat.attachment()
+ && format.textureTarget() == requestFormat.textureTarget()
+ && format.internalFormat() == requestFormat.internalFormat())
+ {
+ // choose the fbo with a matching format and the closest size
+ if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo))
+ candidate = fbo;
+ }
+
+ if (candidate) {
+ m_fbos.removeOne(candidate);
+
+ const QSize fboSize = candidate->size();
+ QSize sz = fboSize;
+
+ if (sz.width() < requestSize.width())
+ sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5)));
+ if (sz.height() < requestSize.height())
+ sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5)));
+
+ // wasting too much space?
+ if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 2.5)
+ sz = requestSize;
+
+ if (sz != fboSize) {
+ delete candidate;
+ qDebug() << "Resizing fbo in pool:" << sz;
+ candidate = new QGLFramebufferObject(sz, requestFormat);
+ }
+
+ chosen = candidate;
+ }
+ }
+
+ if (!chosen) {
+ qDebug() << "Creating new fbo in pool:" << requestSize;
+ chosen = new QGLFramebufferObject(requestSize, requestFormat);
+ }
+
+ if (!chosen->isValid()) {
+ delete chosen;
+ chosen = 0;
+ }
+
+ return chosen;
+}
+
+void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo)
+{
+ m_fbos << fbo;
+}
+
class QGLShareContextScope
{
public:
@@ -332,8 +411,11 @@ struct TextureBuffer
QGL2PaintEngineEx *engine;
};
-static QVector<TextureBuffer> textureBufferStack;
-static int currentTextureBuffer = 0;
+Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool)
+QGLFramebufferObjectPool* qgl_fbo_pool()
+{
+ return _qgl_fbo_pool();
+}
void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
{
@@ -380,7 +462,8 @@ void QGLPixmapData::swapBuffers()
copyBackFromRenderFbo(false);
m_renderFbo->release();
- --currentTextureBuffer;
+ qgl_fbo_pool()->release(m_renderFbo);
+ delete m_engine;
m_renderFbo = 0;
m_engine = 0;
@@ -398,19 +481,6 @@ void QGLPixmapData::doneCurrent()
m_renderFbo->release();
}
-static TextureBuffer createTextureBuffer(const QSize &size, QGL2PaintEngineEx *engine = 0)
-{
- TextureBuffer buffer;
- QGLFramebufferObjectFormat fmt;
- fmt.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
- fmt.setSamples(4);
-
- buffer.fbo = new QGLFramebufferObject(size, fmt);
- buffer.engine = engine ? engine : new QGL2PaintEngineEx;
-
- return buffer;
-}
-
bool QGLPixmapData::useFramebufferObjects()
{
return QGLFramebufferObject::hasOpenGLFramebufferObjects()
@@ -433,33 +503,15 @@ QPaintEngine* QGLPixmapData::paintEngine() const
qt_gl_share_widget()->makeCurrent();
QGLShareContextScope ctx(qt_gl_share_widget()->context());
- if (textureBufferStack.size() <= currentTextureBuffer) {
- textureBufferStack << createTextureBuffer(size());
- } else {
- QSize sz = textureBufferStack.at(currentTextureBuffer).fbo->size();
- if (sz.width() < w || sz.height() < h) {
- if (sz.width() < w)
- sz.setWidth(qMax(w, qRound(sz.width() * 1.5)));
- if (sz.height() < h)
- sz.setHeight(qMax(h, qRound(sz.height() * 1.5)));
-
- // wasting too much space?
- if (sz.width() * sz.height() > w * h * 2.5)
- sz = QSize(w, h);
-
- delete textureBufferStack.at(currentTextureBuffer).fbo;
- textureBufferStack[currentTextureBuffer] =
- createTextureBuffer(sz, textureBufferStack.at(currentTextureBuffer).engine);
- qDebug() << "Creating new pixmap texture buffer:" << sz;
- }
- }
-
- if (textureBufferStack.at(currentTextureBuffer).fbo->isValid()) {
- m_renderFbo = textureBufferStack.at(currentTextureBuffer).fbo;
- m_engine = textureBufferStack.at(currentTextureBuffer).engine;
+ QGLFramebufferObjectFormat format;
+ format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format.setSamples(4);
+ format.setInternalFormat(m_hasAlpha ? GL_RGBA : GL_RGB);
- ++currentTextureBuffer;
+ m_renderFbo = qgl_fbo_pool()->acquire(size(), format);
+ if (m_renderFbo) {
+ m_engine = new QGL2PaintEngineEx;
return m_engine;
}
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index 671f9a7..14fb072 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -62,6 +62,19 @@ QT_BEGIN_NAMESPACE
class QPaintEngine;
class QGLFramebufferObject;
+class QGLFramebufferObjectFormat;
+
+class QGLFramebufferObjectPool
+{
+public:
+ QGLFramebufferObject *acquire(const QSize &size, const QGLFramebufferObjectFormat &format);
+ void release(QGLFramebufferObject *fbo);
+
+private:
+ QList<QGLFramebufferObject *> m_fbos;
+};
+
+QGLFramebufferObjectPool* qgl_fbo_pool();
class QGLPixmapData : public QPixmapData
{