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>
This commit is contained in:
Samuel Rødal 2012-01-26 11:44:05 +01:00 committed by Qt by Nokia
parent 365b5f7a92
commit 2d39471897
10 changed files with 129 additions and 9 deletions

View File

@ -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
}
/*!
@ -229,6 +238,29 @@ QOpenGLFunctions *QOpenGLContext::functions() const
return d->functions;
}
/*!
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().
@ -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)

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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.");

View File

@ -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()}.
*/

View File

@ -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

View File

@ -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()}.
*/

View File

@ -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