From ccf0669da933e519edcff03698643e906b5935d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Thu, 13 Sep 2012 20:50:59 +0200 Subject: Added QGLPixelBuffer implementation using framebuffer objects. Instead of having QGLPixelBuffer be a unusable stub implementation we deprecate it and implement it in terms of QOpenGLFramebufferObject. Framebuffer objects are anyway the recommended replacement for pixelbuffers in modern OpenGL, as the context switching overhead is avoided. Change-Id: Ia220c358ee92813e87981d297c51d84525010322 Reviewed-by: Sean Harmer --- src/opengl/qglpixelbuffer.cpp | 117 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 11 deletions(-) (limited to 'src/opengl/qglpixelbuffer.cpp') diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index d9480c4994..135f2edd01 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -92,7 +92,10 @@ \sa {opengl/pbuffers}{Pbuffers Example} */ +#include + #include +#include #include "gl2paintengineex/qpaintengineex_opengl2_p.h" @@ -129,16 +132,7 @@ void QGLPixelBufferPrivate::common_init(const QSize &size, const QGLFormat &form req_format = format; req_shareWidget = shareWidget; invalid = false; - qctx = new QGLContext(format); - qctx->d_func()->sharing = (shareWidget != 0); - if (shareWidget != 0 && shareWidget->d_func()->glcx) { - QGLContextGroup::addShare(qctx, shareWidget->d_func()->glcx); - shareWidget->d_func()->glcx->d_func()->sharing = true; - } - glDevice.setPBuffer(q); - qctx->d_func()->paintDevice = q; - qctx->d_func()->valid = true; } } @@ -198,7 +192,6 @@ QGLPixelBuffer::~QGLPixelBuffer() if (current != d->qctx) makeCurrent(); d->cleanup(); - delete d->qctx; if (current && current != d->qctx) current->makeCurrent(); } @@ -217,6 +210,17 @@ bool QGLPixelBuffer::makeCurrent() if (d->invalid) return false; d->qctx->makeCurrent(); + if (!d->fbo) { + QOpenGLFramebufferObjectFormat format; + if (d->req_format.stencil()) + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + else if (d->req_format.depth()) + format.setAttachment(QOpenGLFramebufferObject::Depth); + if (d->req_format.sampleBuffers()) + format.setSamples(d->req_format.samples()); + d->fbo = new QOpenGLFramebufferObject(d->req_size, format); + d->fbo->bind(); + } return true; } @@ -306,14 +310,39 @@ bool QGLPixelBuffer::doneCurrent() void QGLPixelBuffer::updateDynamicTexture(GLuint texture_id) const { Q_D(const QGLPixelBuffer); - if (d->invalid) + if (d->invalid || !d->fbo) + return; + + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) return; + +#undef glBindFramebuffer + +#ifndef GL_READ_FRAMEBUFFER +#define GL_READ_FRAMEBUFFER 0x8CA8 +#endif + +#ifndef GL_DRAW_FRAMEBUFFER +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif + + QOpenGLExtensions extensions(ctx); + + if (d->blit_fbo) { + QOpenGLFramebufferObject::blitFramebuffer(d->blit_fbo, d->fbo); + extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, d->blit_fbo->handle()); + } + glBindTexture(GL_TEXTURE_2D, texture_id); #ifndef QT_OPENGL_ES glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, d->req_size.width(), d->req_size.height(), 0); #else glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, d->req_size.width(), d->req_size.height(), 0); #endif + + if (d->blit_fbo) + extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, ctx->d_func()->current_fbo); } /*! @@ -521,4 +550,70 @@ QGLFormat QGLPixelBuffer::format() const \internal */ +bool QGLPixelBufferPrivate::init(const QSize &, const QGLFormat &f, QGLWidget *shareWidget) +{ + widget = new QGLWidget(f, 0, shareWidget); + widget->resize(1, 1); + qctx = const_cast(widget->context()); + return widget->isValid(); +} + +bool QGLPixelBufferPrivate::cleanup() +{ + delete fbo; + fbo = 0; + delete blit_fbo; + blit_fbo = 0; + delete widget; + widget = 0; + return true; +} + +bool QGLPixelBuffer::bindToDynamicTexture(GLuint texture_id) +{ + Q_UNUSED(texture_id); + return false; +} + +void QGLPixelBuffer::releaseFromDynamicTexture() +{ +} + +GLuint QGLPixelBuffer::generateDynamicTexture() const +{ + Q_D(const QGLPixelBuffer); + if (!d->fbo) + return 0; + + if (d->fbo->format().samples() > 0 + && QOpenGLExtensions(QOpenGLContext::currentContext()) + .hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) + { + if (!d->blit_fbo) + const_cast(d->blit_fbo) = new QOpenGLFramebufferObject(d->req_size); + } else { + return d->fbo->texture(); + } + + GLuint texture; + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d->req_size.width(), d->req_size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, 0); + + return texture; +} + +bool QGLPixelBuffer::hasOpenGLPbuffers() +{ + return QOpenGLFramebufferObject::hasOpenGLFramebufferObjects(); +} + QT_END_NAMESPACE -- cgit v1.2.3