From 31d8058a32a1d2d2d6bc1ba3d48f5a382d7b87a7 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Tue, 8 Sep 2009 15:09:00 +0200 Subject: Make QGLPixmapData work with the new QGLPaintDevice API This patch changes the ordering of QGL2PaintEngine::begin a bit because QGLPixmapData needs to use the paint engine's drawTexture method within beginPaint(). Also, this initialises needsSync to true and removes the setState call. So now all the state initialisation is done in ensureActive rather than begin. --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 24 +---- src/opengl/qglframebufferobject.cpp | 9 ++ src/opengl/qglframebufferobject_p.h | 3 +- src/opengl/qglpaintdevice.cpp | 29 ++++-- src/opengl/qglpaintdevice_p.h | 4 +- src/opengl/qpixmapdata_gl.cpp | 116 ++++++++++++++------- src/opengl/qpixmapdata_gl_p.h | 52 +++++---- 7 files changed, 152 insertions(+), 85 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index c280803..e028e63 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -1321,7 +1321,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->ctx->d_ptr->active_engine = this; d->last_created_state = 0; - d->device->beginPaint(); QSize sz = d->device->size(); d->width = sz.width(); d->height = sz.height(); @@ -1333,8 +1332,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->shaderManager = new QGLEngineShaderManager(d->ctx); - glViewport(0, 0, d->width, d->height); - d->brushTextureDirty = true; d->brushUniformsDirty = true; d->matrixDirty = true; @@ -1343,10 +1340,12 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) d->simpleShaderDepthUniformDirty = true; d->depthUniformDirty = true; d->opacityUniformDirty = true; - d->needsSync = false; - + d->needsSync = true; d->use_system_clip = !systemClip().isEmpty(); + + d->device->beginPaint(); + if (!d->inRenderText) { glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); @@ -1358,21 +1357,6 @@ bool QGL2PaintEngineEx::begin(QPaintDevice *pdev) glDisable(GL_MULTISAMPLE); #endif -// QGLPixmapData *source = d->drawable.copyOnBegin(); -// if (source) { -// QGLContext *ctx = d->ctx; -// -// d->transferMode(ImageDrawingMode); -// -// glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); -// source->bind(false); -// -// QRect rect(0, 0, source->width(), source->height()); -// d->updateTextureFilter(GL_TEXTURE_2D, GL_REPEAT, false); -// d->drawTexture(QRectF(rect), QRectF(rect), rect.size(), true); -// } - - d->systemStateChanged(); return true; } diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index f60eb62..9dbf5c8 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -299,6 +299,12 @@ bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& ot return !(*this == other); } +void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f) +{ + fbo = f; + m_thisFBO = fbo->d_func()->fbo; // This shouldn't be needed +} + void QGLFBOGLPaintDevice::ensureActiveTarget() { QGLContext* ctx = const_cast(QGLContext::currentContext()); @@ -377,6 +383,7 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, QGLContext *currentContext = const_cast(QGLContext::currentContext()); ctx = QGLContextPrivate::contextGroup(currentContext); glDevice.setFBO(q); + bool ext_detected = (QGLExtensions::glExtensions & QGLExtensions::FramebufferObject); if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(currentContext))) return; @@ -389,6 +396,8 @@ void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo); + glDevice.setFBO(q); + QT_CHECK_GLERROR(); // init texture if (samples == 0) { diff --git a/src/opengl/qglframebufferobject_p.h b/src/opengl/qglframebufferobject_p.h index 65fcf54..58e6505 100644 --- a/src/opengl/qglframebufferobject_p.h +++ b/src/opengl/qglframebufferobject_p.h @@ -110,11 +110,12 @@ public: virtual QPaintEngine* paintEngine() const {return fbo->paintEngine();} virtual QSize size() const {return fbo->size();} virtual QGLContext* context() const {return const_cast(QGLContext::currentContext());} - void setFBO(QGLFramebufferObject* f) {fbo = f; } virtual void ensureActiveTarget(); virtual void beginPaint(); virtual void endPaint(); + void setFBO(QGLFramebufferObject* f); + private: bool wasBound; QGLFramebufferObject* fbo; diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index 4cdeb76..15ea217 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -44,8 +44,10 @@ #include #include #include +#include QGLPaintDevice::QGLPaintDevice() + : m_thisFBO(0) { } @@ -56,14 +58,17 @@ QGLPaintDevice::~QGLPaintDevice() void QGLPaintDevice::beginPaint() { - // Record the currently bound FBO so we can restore it again - // in endPaint() + // Make sure our context is the current one: QGLContext *ctx = context(); - ctx->makeCurrent(); + if (ctx != QGLContext::currentContext()) + ctx->makeCurrent(); + + // Record the currently bound FBO so we can restore it again + // in endPaint() and bind this device's FBO m_previousFBO = ctx->d_func()->current_fbo; - if (m_previousFBO != 0) { - ctx->d_ptr->current_fbo = 0; - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + if (m_previousFBO != m_thisFBO) { + ctx->d_ptr->current_fbo = m_thisFBO; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO); } } @@ -73,8 +78,10 @@ void QGLPaintDevice::ensureActiveTarget() if (ctx != QGLContext::currentContext()) ctx->makeCurrent(); - if (ctx->d_ptr->current_fbo != 0) - glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); + if (ctx->d_ptr->current_fbo != m_thisFBO) { + ctx->d_ptr->current_fbo = m_thisFBO; + glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO); + } } void QGLPaintDevice::endPaint() @@ -193,6 +200,12 @@ QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd) case QInternal::FramebufferObject: glpd = &(static_cast(pd)->d_func()->glDevice); break; + case QInternal::Pixmap: { + QPixmapData* pmd = static_cast(pd)->pixmapData(); + Q_ASSERT(pmd->classId() == QPixmapData::OpenGLClass); + glpd = static_cast(pmd)->glDevice(); + break; + } default: qWarning("QGLPaintDevice::getDevice() - Unknown device type %d", pd->devType()); break; diff --git a/src/opengl/qglpaintdevice_p.h b/src/opengl/qglpaintdevice_p.h index b0e8826..a175b8c 100644 --- a/src/opengl/qglpaintdevice_p.h +++ b/src/opengl/qglpaintdevice_p.h @@ -84,10 +84,10 @@ public: protected: // Inline? // void setContext(QGLContext* c); - + GLuint m_previousFBO; + GLuint m_thisFBO; private: // QGLContext* m_context; - GLuint m_previousFBO; }; diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index a394716..ae616a8 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -127,6 +127,76 @@ void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) m_fbos << fbo; } + +QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const +{ + return data->paintEngine(); +} + +void QGLPixmapGLPaintDevice::beginPaint() +{ + if (!data->isValid()) + return; + + // QGLPaintDevice::beginPaint will store the current binding and replace + // it with m_thisFBO: + m_thisFBO = data->m_renderFbo->handle(); + QGLPaintDevice::beginPaint(); + + Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2); + + // QPixmap::fill() is deferred until now, where we actually need to do the fill: + if (data->needsFill()) { + const QColor &c = data->fillColor(); + float alpha = c.alphaF(); + glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + glClear(GL_COLOR_BUFFER_BIT); + } + else if (!data->isUninitialized()) { + // If the pixmap (GL Texture) has valid content (it has been + // uploaded from an image or rendered into before), we need to + // copy it from the texture to the render FBO. + + // Pass false to tell bind to _not_ copy the FBO into the texture! + GLuint texId = data->bind(false); + + QGL2PaintEngineEx* pe = static_cast(data->paintEngine()); + QRect rect(0, 0, data->width(), data->height()); + pe->drawTexture(QRectF(rect), texId, rect.size(), QRectF(rect)); + } +} + +void QGLPixmapGLPaintDevice::endPaint() +{ + if (!data->isValid()) + return; + + data->copyBackFromRenderFbo(false); + + data->m_renderFbo->release(); + qgl_fbo_pool()->release(data->m_renderFbo); + data->m_renderFbo = 0; + + // Base's endPaint will restore the previous FBO binding + QGLPaintDevice::endPaint(); +} + +QGLContext* QGLPixmapGLPaintDevice::context() const +{ + data->ensureCreated(); + return data->m_ctx; +} + +QSize QGLPixmapGLPaintDevice::size() const +{ + return data->size(); +} + +void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) +{ + data = d; +} + static int qt_gl_pixmap_serial = 0; QGLPixmapData::QGLPixmapData(PixelType type) @@ -139,6 +209,7 @@ QGLPixmapData::QGLPixmapData(PixelType type) , m_hasAlpha(false) { setSerialNumber(++qt_gl_pixmap_serial); + m_glDevice.setPixmapData(this); } QGLPixmapData::~QGLPixmapData() @@ -232,11 +303,6 @@ void QGLPixmapData::ensureCreated() const m_texture.options &= ~QGLContext::MemoryManagedBindOption; } -QGLFramebufferObject *QGLPixmapData::fbo() const -{ - return m_renderFbo; -} - void QGLPixmapData::fromImage(const QImage &image, Qt::ImageConversionFlags) { @@ -412,31 +478,6 @@ void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); } -void QGLPixmapData::swapBuffers() -{ - if (!isValid()) - return; - - copyBackFromRenderFbo(false); - m_renderFbo->release(); - - qgl_fbo_pool()->release(m_renderFbo); - - m_renderFbo = 0; -} - -void QGLPixmapData::makeCurrent() -{ - if (isValid() && m_renderFbo) - m_renderFbo->bind(); -} - -void QGLPixmapData::doneCurrent() -{ - if (isValid() && m_renderFbo) - m_renderFbo->release(); -} - bool QGLPixmapData::useFramebufferObjects() { return QGLFramebufferObject::hasOpenGLFramebufferObjects() @@ -485,6 +526,10 @@ QPaintEngine* QGLPixmapData::paintEngine() const return m_source.paintEngine(); } + +// If copyBack is true, bind will copy the contents of the render +// FBO to the texture (which is not bound to the texture, as it's +// a multisample FBO). GLuint QGLPixmapData::bind(bool copyBack) const { if (m_renderFbo && copyBack) { @@ -504,12 +549,6 @@ GLuint QGLPixmapData::bind(bool copyBack) const return id; } -GLuint QGLPixmapData::textureId() const -{ - ensureCreated(); - return m_texture.id; -} - QGLTexture* QGLPixmapData::texture() const { return &m_texture; @@ -548,4 +587,9 @@ int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const } } +QGLPaintDevice *QGLPixmapData::glDevice() const +{ + return &m_glDevice; +} + QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index ab1ff47..31ae7c7 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -57,12 +57,14 @@ #include "qgl.h" #include "private/qpixmapdata_p.h" +#include "private/qglpaintdevice_p.h" QT_BEGIN_NAMESPACE class QPaintEngine; class QGLFramebufferObject; class QGLFramebufferObjectFormat; +class QGLPixmapData; class QGLFramebufferObjectPool { @@ -76,31 +78,50 @@ private: QGLFramebufferObjectPool* qgl_fbo_pool(); + +class QGLPixmapGLPaintDevice : public QGLPaintDevice +{ +public: + QPaintEngine* paintEngine() const; + + void beginPaint(); + void endPaint(); + QGLContext* context() const; + QSize size() const; + + void setPixmapData(QGLPixmapData*); +private: + QGLPixmapData *data; +}; + + class QGLPixmapData : public QPixmapData { public: QGLPixmapData(PixelType type); ~QGLPixmapData(); - bool isValid() const; - + // Re-implemented from QPixmapData: void resize(int width, int height); - void fromImage(const QImage &image, - Qt::ImageConversionFlags flags); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); void copy(const QPixmapData *data, const QRect &rect); - bool scroll(int dx, int dy, const QRect &rect); - void fill(const QColor &color); bool hasAlphaChannel() const; QImage toImage() const; QPaintEngine *paintEngine() const; + int metric(QPaintDevice::PaintDeviceMetric metric) const; + // For accessing as a target: + QGLPaintDevice *glDevice() const; + + // For accessing as a source: + bool isValidContext(const QGLContext *ctx) const; GLuint bind(bool copyBack = true) const; - GLuint textureId() const; QGLTexture *texture() const; - bool isValidContext(const QGLContext *ctx) const; +private: + bool isValid() const; void ensureCreated() const; @@ -109,22 +130,13 @@ public: bool needsFill() const { return m_hasFillColor; } QColor fillColor() const { return m_fillColor; } - QSize size() const { return QSize(w, h); } - - QGLFramebufferObject *fbo() const; - void makeCurrent(); - void doneCurrent(); - void swapBuffers(); -protected: - int metric(QPaintDevice::PaintDeviceMetric metric) const; - -private: QGLPixmapData(const QGLPixmapData &other); QGLPixmapData &operator=(const QGLPixmapData &other); void copyBackFromRenderFbo(bool keepCurrentFboBound) const; + QSize size() const { return QSize(w, h); } static bool useFramebufferObjects(); @@ -145,6 +157,10 @@ private: mutable bool m_hasFillColor; mutable bool m_hasAlpha; + + mutable QGLPixmapGLPaintDevice m_glDevice; + + friend class QGLPixmapGLPaintDevice; }; QT_END_NAMESPACE -- cgit v0.12