diff options
Diffstat (limited to 'src/opengl/qpixmapdata_gl.cpp')
-rw-r--r-- | src/opengl/qpixmapdata_gl.cpp | 139 |
1 files changed, 96 insertions, 43 deletions
diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 8de1aae..a441a23 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: @@ -112,6 +191,8 @@ QGLPixmapData::~QGLPixmapData() if (!shareWidget) return; + delete m_engine; + if (m_texture.id) { QGLShareContextScope ctx(shareWidget->context()); glDeleteTextures(1, &m_texture.id); @@ -332,8 +413,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,10 +464,9 @@ void QGLPixmapData::swapBuffers() copyBackFromRenderFbo(false); m_renderFbo->release(); - --currentTextureBuffer; + qgl_fbo_pool()->release(m_renderFbo); m_renderFbo = 0; - m_engine = 0; } void QGLPixmapData::makeCurrent() @@ -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() @@ -423,7 +493,7 @@ QPaintEngine* QGLPixmapData::paintEngine() const if (!isValid()) return 0; - if (m_engine) + if (m_renderFbo) return m_engine; if (useFramebufferObjects()) { @@ -433,33 +503,16 @@ 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) { + if (!m_engine) + m_engine = new QGL2PaintEngineEx; return m_engine; } |