summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Rødal <sroedal@trolltech.com>2009-04-17 10:04:08 +0200
committerSamuel Rødal <sroedal@trolltech.com>2009-04-17 10:16:35 +0200
commitb3f0d6e31c6897b1701de28d51980a81fb3e778f (patch)
tree29b8095070bb4f1585bee5a3eed45776c033ce5e
parent537c26b2125994b42a5d00540ca4644582111573 (diff)
downloadqt4-tools-b3f0d6e31c6897b1701de28d51980a81fb3e778f.tar.gz
Correctly handle using GL pixmaps that still have an active engine.
In the case where a GL pixmap is used when there it still has an active engine we need to ensure that the pixmap has been flushed from the render FBO first. The newly added QGLPixmapData::copyBackFromRenderFbo() handles this. In addition, because several GL 2 paint engines can be active on the same context at the same time, we can't make any assumptions and need to call the newly added QGL2PaintEngineEx::ensureCreated() in the beginning of any state-dependent paint engine function. QGL2PaintEngineEx::ensureCreated() correctly transfers control to the current engine if a different engine is active. Running lance with -pixmap and -graphicssystem opengl works correctly with the GL pixmap backend now.
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp47
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h3
-rw-r--r--src/opengl/qgl.cpp6
-rw-r--r--src/opengl/qpixmapdata_gl.cpp43
-rw-r--r--src/opengl/qpixmapdata_gl_p.h7
5 files changed, 86 insertions, 20 deletions
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index fe70020f03..8bf31824bb 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -805,6 +805,7 @@ void QGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QGL2PaintEngineEx);
+ ensureActive();
d->setBrush(&brush);
d->fill(path);
d->setBrush(&(state()->brush)); // reset back to the state's brush
@@ -814,6 +815,7 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QGL2PaintEngineEx);
+ ensureActive();
if (pen.style() == Qt::NoPen)
return;
@@ -832,7 +834,6 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
d->setBrush(&(state()->brush));
} else
return QPaintEngineEx::stroke(path, pen);
-
}
void QGL2PaintEngineEx::penChanged()
@@ -887,6 +888,7 @@ void QGL2PaintEngineEx::transformChanged()
void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src)
{
Q_D(QGL2PaintEngineEx);
+ ensureActive();
d->transferMode(ImageDrawingMode);
QGLContext *ctx = d->ctx;
@@ -905,6 +907,7 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
Qt::ImageConversionFlags)
{
Q_D(QGL2PaintEngineEx);
+ ensureActive();
d->transferMode(ImageDrawingMode);
QGLContext *ctx = d->ctx;
@@ -921,6 +924,7 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const
void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
Q_D(QGL2PaintEngineEx);
+ ensureActive();
QOpenGLPaintEngineState *s = state();
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
@@ -974,6 +978,9 @@ void QGL2PaintEngineExPrivate::drawCachedGlyphs(const QPointF &p, const QTextIte
const QImage &image = cache->image();
int margin = cache->glyphMargin();
+ if (image.isNull())
+ return;
+
ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, true);
updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false);
@@ -1085,6 +1092,16 @@ bool QGL2PaintEngineEx::end()
{
Q_D(QGL2PaintEngineEx);
QGLContext *ctx = d->ctx;
+ if (ctx->d_ptr->active_engine != this) {
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(d->last_engine);
+ if (engine) {
+ QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
+ p->transferMode(DefaultMode);
+ p->drawable.doneCurrent();
+ }
+ d->drawable.makeCurrent();
+ }
+
glUseProgram(0);
d->transferMode(DefaultMode);
d->drawable.swapBuffers();
@@ -1106,6 +1123,31 @@ bool QGL2PaintEngineEx::end()
return false;
}
+void QGL2PaintEngineEx::ensureActive()
+{
+ Q_D(QGL2PaintEngineEx);
+ QGLContext *ctx = d->ctx;
+
+ if (isActive() && ctx->d_ptr->active_engine != this) {
+ QGL2PaintEngineEx *engine = static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine);
+ if (engine) {
+ QGL2PaintEngineExPrivate *p = static_cast<QGL2PaintEngineExPrivate *>(engine->d_ptr);
+ p->transferMode(DefaultMode);
+ p->drawable.doneCurrent();
+ }
+ d->drawable.makeCurrent();
+
+ ctx->d_ptr->active_engine = this;
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+
+ glViewport(0, 0, d->width, d->height);
+ setState(state());
+ d->updateDepthClip();
+ }
+}
+
/////////////////////////////////// State/Clipping stolen from QOpenGLPaintEngine //////////////////////////////////////////
@@ -1246,6 +1288,7 @@ void QGL2PaintEngineExPrivate::updateDepthClip()
Q_Q(QGL2PaintEngineEx);
+ q->ensureActive();
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
@@ -1305,7 +1348,7 @@ void QGL2PaintEngineEx::setState(QPainterState *new_state)
QOpenGLPaintEngineState *old_state = state();
const bool needsDepthClipUpdate = !old_state
|| s->clipEnabled != old_state->clipEnabled
- || s->clipEnabled && s->clipRegion != old_state->clipRegion;
+ || (s->clipEnabled && s->clipRegion != old_state->clipRegion);
QPaintEngineEx::setState(s);
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 10e5337439..b31f68538f 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -80,6 +80,8 @@ public:
bool begin(QPaintDevice *device);
bool end();
+ void ensureActive();
+
virtual void fill(const QVectorPath &path, const QBrush &brush);
virtual void stroke(const QVectorPath &path, const QPen &pen);
virtual void clip(const QVectorPath &path, Qt::ClipOperation op);
@@ -102,7 +104,6 @@ public:
Type type() const { return OpenGL; }
-
// State stuff is just for clipping and ripped off from QGLPaintEngine
void setState(QPainterState *s);
QPainterState *createState(QPainterState *orig) const;
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index 64048f29e2..d1cf35d862 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -4289,6 +4289,8 @@ void QGLDrawable::swapBuffers()
if (widget) {
if (widget->autoBufferSwap())
widget->swapBuffers();
+ } else if (pixmapData) {
+ pixmapData->swapBuffers();
} else {
glFlush();
}
@@ -4297,7 +4299,7 @@ void QGLDrawable::swapBuffers()
void QGLDrawable::makeCurrent()
{
if (pixmapData)
- pixmapData->beginPaint();
+ pixmapData->makeCurrent();
else if (widget)
widget->makeCurrent();
else if (buffer)
@@ -4321,7 +4323,7 @@ QGLPixmapData *QGLDrawable::copyOnBegin() const
void QGLDrawable::doneCurrent()
{
if (pixmapData)
- pixmapData->endPaint();
+ pixmapData->doneCurrent();
else if (fbo && !wasBound)
fbo->release();
}
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp
index 0656880c95..1c5056d41f 100644
--- a/src/opengl/qpixmapdata_gl.cpp
+++ b/src/opengl/qpixmapdata_gl.cpp
@@ -246,13 +246,13 @@ QImage QGLPixmapData::toImage() const
return QImage();
if (m_renderFbo)
- return m_renderFbo->toImage().copy(0, m_renderFbo->height() - m_height, m_width, m_height);
+ copyBackFromRenderFbo(true);
else if (!m_source.isNull())
return m_source;
else if (m_dirty)
return QImage(m_width, m_height, QImage::Format_ARGB32_Premultiplied);
-
- ensureCreated();
+ else
+ ensureCreated();
QGLShareContextScope ctx(qt_gl_share_widget()->context());
extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha);
@@ -269,15 +269,7 @@ struct TextureBuffer
static QVector<TextureBuffer> textureBufferStack;
static int currentTextureBuffer = 0;
-void QGLPixmapData::beginPaint()
-{
- if (!isValid())
- return;
-
- m_renderFbo->bind();
-}
-
-void QGLPixmapData::endPaint()
+void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const
{
if (!isValid())
return;
@@ -308,6 +300,16 @@ void QGLPixmapData::endPaint()
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
+ if (keepCurrentFboBound)
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_ctx->d_ptr->current_fbo);
+}
+
+void QGLPixmapData::swapBuffers()
+{
+ if (!isValid())
+ return;
+
+ copyBackFromRenderFbo(false);
m_renderFbo->release();
--currentTextureBuffer;
@@ -316,6 +318,18 @@ void QGLPixmapData::endPaint()
m_engine = 0;
}
+void QGLPixmapData::makeCurrent()
+{
+ if (isValid() && m_renderFbo)
+ m_renderFbo->bind();
+}
+
+void QGLPixmapData::doneCurrent()
+{
+ if (isValid() && m_renderFbo)
+ m_renderFbo->release();
+}
+
static TextureBuffer createTextureBuffer(const QSize &size, QGL2PaintEngineEx *engine = 0)
{
TextureBuffer buffer;
@@ -382,7 +396,10 @@ QPaintEngine* QGLPixmapData::paintEngine() const
GLuint QGLPixmapData::bind() const
{
- ensureCreated();
+ if (m_renderFbo)
+ copyBackFromRenderFbo(true);
+ else
+ ensureCreated();
GLuint id = m_textureId;
glBindTexture(qt_gl_preferredTextureTarget(), id);
diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h
index b1b31f7029..7dda653235 100644
--- a/src/opengl/qpixmapdata_gl_p.h
+++ b/src/opengl/qpixmapdata_gl_p.h
@@ -97,8 +97,9 @@ public:
QGLFramebufferObject *fbo() const;
- void beginPaint();
- void endPaint();
+ void makeCurrent();
+ void doneCurrent();
+ void swapBuffers();
protected:
int metric(QPaintDevice::PaintDeviceMetric metric) const;
@@ -107,6 +108,8 @@ private:
QGLPixmapData(const QGLPixmapData &other);
QGLPixmapData &operator=(const QGLPixmapData &other);
+ void copyBackFromRenderFbo(bool keepCurrentFboBound) const;
+
static bool useFramebufferObjects();
int m_width;