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:
parent
365b5f7a92
commit
2d39471897
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.");
|
||||
|
@ -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()}.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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()}.
|
||||
*/
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user