diff options
author | Samuel Rødal <samuel.rodal@nokia.com> | 2012-01-26 11:44:05 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-01-27 10:58:32 +0100 |
commit | 2d39471897f0a3a769406ec9c2b39558ebd45af3 (patch) | |
tree | 8c417f4ba814e9dbe70e56bdbf8a13cc46b3827f | |
parent | 365b5f7a9271e5fc503b10e6c17371d76643fc94 (diff) |
Introduced QOpenGLContext::defaultFramebufferObject().
Also add some debugging helpers to make sure applications are correctly
written even on less restrictive platforms.
Change-Id: Ie92e497c32e07b2b83662f7ab5540d8f37777fd0
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
-rw-r--r-- | src/gui/kernel/qopenglcontext.cpp | 71 | ||||
-rw-r--r-- | src/gui/kernel/qopenglcontext.h | 10 | ||||
-rw-r--r-- | src/gui/kernel/qopenglcontext_p.h | 23 | ||||
-rw-r--r-- | src/gui/kernel/qplatformopenglcontext_qpa.cpp | 12 | ||||
-rw-r--r-- | src/gui/kernel/qplatformopenglcontext_qpa.h | 3 | ||||
-rw-r--r-- | src/gui/opengl/qopenglframebufferobject.cpp | 8 | ||||
-rw-r--r-- | src/gui/opengl/qopenglfunctions.cpp | 3 | ||||
-rw-r--r-- | src/gui/opengl/qopenglfunctions.h | 2 | ||||
-rw-r--r-- | src/opengl/qglfunctions.cpp | 3 | ||||
-rw-r--r-- | src/opengl/qglfunctions.h | 3 |
10 files changed, 129 insertions, 9 deletions
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 29107d4261..cd4e8ebc01 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -68,6 +68,11 @@ public: static QThreadStorage<QGuiGLThreadContext *> qwindow_context_storage; +#ifndef QT_NO_DEBUG +QHash<QOpenGLContext *, bool> QOpenGLContextPrivate::makeCurrentTracker; +QMutex QOpenGLContextPrivate::makeCurrentTrackerMutex; +#endif + void QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context) { QGuiGLThreadContext *threadContext = qwindow_context_storage.localData(); @@ -204,6 +209,10 @@ void QOpenGLContext::destroy() QOpenGLContext::~QOpenGLContext() { destroy(); + +#ifndef QT_NO_DEBUG + QOpenGLContextPrivate::cleanMakeCurrentTracker(this); +#endif } /*! @@ -230,6 +239,29 @@ QOpenGLFunctions *QOpenGLContext::functions() const } /*! + Call this to get the default framebuffer object for the current surface. + + On some platforms the default framebuffer object depends on the surface being rendered to, + and might be different from 0. Thus, instead of calling glBindFramebuffer(0), you should + call glBindFramebuffer(ctx->defaultFramebufferObject()) if you want your application to + work across different Qt platforms. + + If you use the glBindFramebuffer() in QOpenGLFunctions you do not have to worry about this, + as it automatically binds the current context's defaultFramebufferObject() when 0 is passed. +*/ +GLuint QOpenGLContext::defaultFramebufferObject() const +{ + if (!isValid()) + return 0; + + Q_D(const QOpenGLContext); + if (!d->surface || !d->surface->surfaceHandle()) + return 0; + + return d->platformGLContext->defaultFramebufferObject(d->surface->surfaceHandle()); +} + +/*! If surface is 0 this is equivalent to calling doneCurrent(). Do not call this function from a different thread than the one the QOpenGLContext instance lives in. If @@ -260,6 +292,10 @@ bool QOpenGLContext::makeCurrent(QSurface *surface) d->shareGroup->d_func()->deletePendingResources(this); +#ifndef QT_NO_DEBUG + QOpenGLContextPrivate::toggleMakeCurrentTracker(this, true); +#endif + return true; } @@ -294,6 +330,17 @@ QSurface *QOpenGLContext::surface() const } +/*! + Swap the back and front buffers of the given surface. + + Call this to finish a frame of OpenGL rendering, and make sure to + call makeCurrent() again before you begin a new frame. + + If you have bound a non-default framebuffer object, you need to + use bindDefaultFramebufferObject() to make sure that the default + framebuffer object is bound before calling swapBuffers(), as + some Qt platforms assume that the default framebuffer object is bound. +*/ void QOpenGLContext::swapBuffers(QSurface *surface) { Q_D(QOpenGLContext); @@ -306,8 +353,28 @@ void QOpenGLContext::swapBuffers(QSurface *surface) } QPlatformSurface *surfaceHandle = surface->surfaceHandle(); - if (surfaceHandle) - d->platformGLContext->swapBuffers(surfaceHandle); + if (!surfaceHandle) + return; + +#if !defined(QT_NO_DEBUG) + if (currentContext() != this) + qWarning() << "QOpenGLContext::swapBuffers() called with non-current surface"; + else if (!QOpenGLContextPrivate::toggleMakeCurrentTracker(this, false)) + qWarning() << "QOpenGLContext::swapBuffers() called without corresponding makeCurrent()"; + +#ifndef GL_FRAMEBUFFER_BINDING +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#endif + + GLint framebufferBinding = 0; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &framebufferBinding); + + GLint platformFramebuffer = GLint(d->platformGLContext->defaultFramebufferObject(surfaceHandle)); + if (framebufferBinding != platformFramebuffer) + qWarning() << "QOpenGLContext::swapBuffers() called with non-default framebuffer object bound"; +#endif + + d->platformGLContext->swapBuffers(surfaceHandle); } QFunctionPointer QOpenGLContext::getProcAddress(const QByteArray &procName) diff --git a/src/gui/kernel/qopenglcontext.h b/src/gui/kernel/qopenglcontext.h index 2d86a6db31..449c75f22a 100644 --- a/src/gui/kernel/qopenglcontext.h +++ b/src/gui/kernel/qopenglcontext.h @@ -50,11 +50,17 @@ #include <QtGui/QSurfaceFormat> +#ifdef __GLEW_H__ +#warning qopenglfunctions.h is not compatible with GLEW, GLEW defines will be undefined +#warning To use GLEW with Qt, do not include <qopengl.h> or <QOpenGLFunctions> after glew.h +#endif + +#include <QtGui/qopengl.h> + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE - class QOpenGLContextPrivate; class QOpenGLContextGroupPrivate; class QOpenGLFunctions; @@ -103,6 +109,8 @@ public: QOpenGLContextGroup *shareGroup() const; QScreen *screen() const; + GLuint defaultFramebufferObject() const; + bool makeCurrent(QSurface *surface); void doneCurrent(); diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h index bd5fae989b..819f86fb24 100644 --- a/src/gui/kernel/qopenglcontext_p.h +++ b/src/gui/kernel/qopenglcontext_p.h @@ -47,6 +47,10 @@ #include <private/qobject_p.h> #include <qmutex.h> +#ifndef QT_NO_DEBUG +#include <QtCore/QHash> +#endif + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -185,7 +189,6 @@ public: , surface(0) , functions(0) , current_fbo(0) - , default_fbo(0) , workaround_brokenFBOReadBack(false) , workaround_brokenTexSubImage(false) , active_engine(0) @@ -210,7 +213,6 @@ public: QOpenGLFunctions *functions; GLuint current_fbo; - GLuint default_fbo; bool workaround_brokenFBOReadBack; bool workaround_brokenTexSubImage; @@ -220,6 +222,23 @@ public: static void setCurrentContext(QOpenGLContext *context); int maxTextureSize() const { return 1024; } + +#if !defined(QT_NO_DEBUG) + static bool toggleMakeCurrentTracker(QOpenGLContext *context, bool value) + { + QMutexLocker locker(&makeCurrentTrackerMutex); + bool old = makeCurrentTracker.value(context, false); + makeCurrentTracker.insert(context, value); + return old; + } + static void cleanMakeCurrentTracker(QOpenGLContext *context) + { + QMutexLocker locker(&makeCurrentTrackerMutex); + makeCurrentTracker.remove(context); + } + static QHash<QOpenGLContext *, bool> makeCurrentTracker; + static QMutex makeCurrentTrackerMutex; +#endif }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qplatformopenglcontext_qpa.cpp b/src/gui/kernel/qplatformopenglcontext_qpa.cpp index ba7a75a6b8..244556b13b 100644 --- a/src/gui/kernel/qplatformopenglcontext_qpa.cpp +++ b/src/gui/kernel/qplatformopenglcontext_qpa.cpp @@ -41,6 +41,8 @@ #include "qplatformopenglcontext_qpa.h" +#include <QOpenGLFunctions> + QT_BEGIN_NAMESPACE /*! @@ -94,6 +96,16 @@ QPlatformOpenGLContext::~QPlatformOpenGLContext() { } +/*! + Reimplement in subclass if your platform uses framebuffer objects for surfaces. + + The default implementation returns 0. +*/ +GLuint QPlatformOpenGLContext::defaultFramebufferObject(QPlatformSurface *) const +{ + return 0; +} + QOpenGLContext *QPlatformOpenGLContext::context() const { Q_D(const QPlatformOpenGLContext); diff --git a/src/gui/kernel/qplatformopenglcontext_qpa.h b/src/gui/kernel/qplatformopenglcontext_qpa.h index 772fbdf06f..5a838a0909 100644 --- a/src/gui/kernel/qplatformopenglcontext_qpa.h +++ b/src/gui/kernel/qplatformopenglcontext_qpa.h @@ -45,6 +45,7 @@ #include <QtCore/qnamespace.h> #include <QtGui/qsurfaceformat.h> #include <QtGui/qwindow.h> +#include <QtGui/qopengl.h> QT_BEGIN_HEADER @@ -64,6 +65,8 @@ public: virtual void swapBuffers(QPlatformSurface *surface) = 0; + virtual GLuint defaultFramebufferObject(QPlatformSurface *surface) const; + virtual bool makeCurrent(QPlatformSurface *surface) = 0; virtual void doneCurrent() = 0; diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index bb723b7ce6..6cfb3c1b01 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -892,8 +892,8 @@ bool QOpenGLFramebufferObject::release() #endif if (current) { - current->d_func()->current_fbo = current->d_func()->default_fbo; - d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->default_fbo); + current->d_func()->current_fbo = current->defaultFramebufferObject(); + d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->current_fbo); } return true; @@ -1057,8 +1057,8 @@ bool QOpenGLFramebufferObject::bindDefault() QOpenGLFunctions functions(ctx); if (ctx) { - ctx->d_func()->current_fbo = ctx->d_func()->default_fbo; - functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->default_fbo); + ctx->d_func()->current_fbo = ctx->defaultFramebufferObject(); + functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo); #ifdef QT_DEBUG } else { qWarning("QOpenGLFramebufferObject::bindDefault() called without current context."); diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp index b2a329067b..50f70d7408 100644 --- a/src/gui/opengl/qopenglfunctions.cpp +++ b/src/gui/opengl/qopenglfunctions.cpp @@ -478,6 +478,9 @@ void QOpenGLFunctions::initializeGLFunctions() Convenience function that calls glBindFramebuffer(\a target, \a framebuffer). + Note that Qt will translate a \a framebuffer argument of 0 to the currently + bound QOpenGLContext's defaultFramebufferObject(). + For more information, see the OpenGL/ES 2.0 documentation for \l{http://www.khronos.org/opengles/sdk/docs/man/glBindFramebuffer.xml}{glBindFramebuffer()}. */ diff --git a/src/gui/opengl/qopenglfunctions.h b/src/gui/opengl/qopenglfunctions.h index 99b35a3a93..d197ccac91 100644 --- a/src/gui/opengl/qopenglfunctions.h +++ b/src/gui/opengl/qopenglfunctions.h @@ -478,6 +478,8 @@ inline void QOpenGLFunctions::glBindBuffer(GLenum target, GLuint buffer) inline void QOpenGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffer) { + if (framebuffer == 0) + framebuffer = QOpenGLContext::currentContext()->defaultFramebufferObject(); #if defined(QT_OPENGL_ES_2) ::glBindFramebuffer(target, framebuffer); #else diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp index 2a11ee6a28..6e640b0fe7 100644 --- a/src/opengl/qglfunctions.cpp +++ b/src/opengl/qglfunctions.cpp @@ -395,6 +395,9 @@ void QGLFunctions::initializeGLFunctions(const QGLContext *context) Convenience function that calls glBindFramebuffer(\a target, \a framebuffer). + Note that Qt will translate a \a framebuffer argument of 0 to the currently + bound QOpenGLContext's defaultFramebufferObject(). + For more information, see the OpenGL/ES 2.0 documentation for \l{http://www.khronos.org/opengles/sdk/docs/man/glBindFramebuffer.xml}{glBindFramebuffer()}. */ diff --git a/src/opengl/qglfunctions.h b/src/opengl/qglfunctions.h index af6c583a10..40c00f1af8 100644 --- a/src/opengl/qglfunctions.h +++ b/src/opengl/qglfunctions.h @@ -48,6 +48,7 @@ #endif #include <QtOpenGL/qgl.h> +#include <QtGui/qopenglcontext.h> QT_BEGIN_HEADER @@ -450,6 +451,8 @@ inline void QGLFunctions::glBindBuffer(GLenum target, GLuint buffer) inline void QGLFunctions::glBindFramebuffer(GLenum target, GLuint framebuffer) { + if (framebuffer == 0) + framebuffer = QOpenGLContext::currentContext()->defaultFramebufferObject(); #if defined(QT_OPENGL_ES_2) ::glBindFramebuffer(target, framebuffer); #else |