summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/opengl')
-rw-r--r--src/gui/opengl/opengl.pri6
-rw-r--r--src/gui/opengl/qopenglvertexarrayobject.cpp472
-rw-r--r--src/gui/opengl/qopenglvertexarrayobject.h110
3 files changed, 586 insertions, 2 deletions
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri
index 4f4701f7f5..0c16e1582d 100644
--- a/src/gui/opengl/opengl.pri
+++ b/src/gui/opengl/opengl.pri
@@ -29,7 +29,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) {
opengl/qtriangulator_p.h \
opengl/qrbtree_p.h \
opengl/qopenglversionfunctions.h \
- opengl/qopenglversionfunctionsfactory_p.h
+ opengl/qopenglversionfunctionsfactory_p.h \
+ opengl/qopenglvertexarrayobject.h
SOURCES += opengl/qopengl.cpp \
opengl/qopenglfunctions.cpp \
@@ -47,7 +48,8 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) {
opengl/qopengltextureglyphcache.cpp \
opengl/qtriangulator.cpp \
opengl/qopenglversionfunctions.cpp \
- opengl/qopenglversionfunctionsfactory.cpp
+ opengl/qopenglversionfunctionsfactory.cpp \
+ opengl/qopenglvertexarrayobject.cpp
!contains(QT_CONFIG, opengles2) {
diff --git a/src/gui/opengl/qopenglvertexarrayobject.cpp b/src/gui/opengl/qopenglvertexarrayobject.cpp
new file mode 100644
index 0000000000..7f130505ec
--- /dev/null
+++ b/src/gui/opengl/qopenglvertexarrayobject.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopenglvertexarrayobject.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtGui/qopenglcontext.h>
+
+#if !defined(QT_OPENGL_ES_2)
+#include <QtGui/qopenglfunctions_3_0.h>
+#include <QtGui/qopenglfunctions_3_2_core.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QVertexArrayObjectHelper
+{
+public:
+ QVertexArrayObjectHelper(QOpenGLContext *context)
+ {
+ Q_ASSERT(context);
+#if !defined(QT_OPENGL_ES_2)
+ GenVertexArrays = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , GLuint *)>(context->getProcAddress("glGenVertexArrays"));
+ DeleteVertexArrays = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , const GLuint *)>(context->getProcAddress("glDeleteVertexArrays"));
+ BindVertexArray = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint )>(context->getProcAddress("glBindVertexArray"));
+#else
+ GenVertexArrays = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , GLuint *)>(context->getProcAddress("glGenVertexArraysOES"));
+ DeleteVertexArrays = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , const GLuint *)>(context->getProcAddress("glDeleteVertexArraysOES"));
+ BindVertexArray = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint )>(context->getProcAddress("glBindVertexArrayOES"));
+#endif
+ }
+
+ inline void glGenVertexArrays(GLsizei n, GLuint *arrays)
+ {
+ GenVertexArrays(n, arrays);
+ }
+
+ inline void glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
+ {
+ DeleteVertexArrays(n, arrays);
+ }
+
+ inline void glBindVertexArray(GLuint array)
+ {
+ BindVertexArray(array);
+ }
+
+private:
+ // Function signatures are equivalent between desktop core, ARB and ES 2 extensions
+ void (QOPENGLF_APIENTRYP GenVertexArrays)(GLsizei n, GLuint *arrays);
+ void (QOPENGLF_APIENTRYP DeleteVertexArrays)(GLsizei n, const GLuint *arrays);
+ void (QOPENGLF_APIENTRYP BindVertexArray)(GLuint array);
+};
+
+class QOpenGLVertexArrayObjectPrivate : public QObjectPrivate
+{
+public:
+ QOpenGLVertexArrayObjectPrivate()
+ : vao(0)
+#if defined(QT_OPENGL_ES_2)
+ , vaoFuncs(0)
+#else
+ , vaoFuncsType(NotSupported)
+#endif
+ , context(0)
+ {
+ }
+
+ ~QOpenGLVertexArrayObjectPrivate()
+ {
+#if defined(QT_OPENGL_ES_2)
+ delete vaoFuncs;
+#else
+ if (vaoFuncsType == ARB)
+ delete vaoFuncs.arb;
+#endif
+ }
+
+ bool create();
+ void destroy();
+ void bind();
+ void release();
+
+ GLuint vao;
+
+#if defined(QT_OPENGL_ES_2)
+ QVertexArrayObjectHelper *vaoFuncs;
+#else
+ union {
+ QOpenGLFunctions_3_0 *core_3_0;
+ QOpenGLFunctions_3_2_Core *core_3_2;
+ QVertexArrayObjectHelper *arb;
+ } vaoFuncs;
+ enum {
+ NotSupported,
+ Core_3_0,
+ Core_3_2,
+ ARB
+ } vaoFuncsType;
+#endif
+ QOpenGLContext *context;
+};
+
+bool QOpenGLVertexArrayObjectPrivate::create()
+{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx) {
+ qWarning("QOpenGLVertexArrayObject::create() requires a valid current OpenGL context");
+ return false;
+ }
+
+#if defined(QT_OPENGL_ES_2)
+ if (ctx->hasExtension("GL_OES_vertex_array_object")) {
+ vaoFuncs = new QVertexArrayObjectHelper(ctx);
+ vaoFuncs->glGenVertexArrays(1, &vao);
+ }
+#else
+ vaoFuncs.core_3_0 = 0;
+ vaoFuncsType = NotSupported;
+ QSurfaceFormat format = ctx->format();
+ if (format.version() >= qMakePair<int, int>(3,2)) {
+ vaoFuncs.core_3_2 = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>();
+ vaoFuncsType = Core_3_2;
+ vaoFuncs.core_3_2->initializeOpenGLFunctions();
+ vaoFuncs.core_3_2->glGenVertexArrays(1, &vao);
+ } else if (format.majorVersion() >= 3) {
+ vaoFuncs.core_3_0 = ctx->versionFunctions<QOpenGLFunctions_3_0>();
+ vaoFuncsType = Core_3_0;
+ vaoFuncs.core_3_0->initializeOpenGLFunctions();
+ vaoFuncs.core_3_0->glGenVertexArrays(1, &vao);
+ } else if (ctx->hasExtension("GL_ARB_vertex_array_object")) {
+ vaoFuncs.arb = new QVertexArrayObjectHelper(ctx);
+ vaoFuncsType = ARB;
+ vaoFuncs.arb->glGenVertexArrays(1, &vao);
+ }
+#endif
+ return (vao != 0);
+}
+
+void QOpenGLVertexArrayObjectPrivate::destroy()
+{
+ if (!vao)
+ return;
+#if defined(QT_OPENGL_ES_2)
+ if (vaoFuncs)
+ vaoFuncs->glDeleteVertexArrays(1, &vao);
+#else
+ switch (vaoFuncsType) {
+ case Core_3_2:
+ vaoFuncs.core_3_2->glDeleteVertexArrays(1, &vao);
+ break;
+ case Core_3_0:
+ vaoFuncs.core_3_0->glDeleteVertexArrays(1, &vao);
+ break;
+ case ARB:
+ vaoFuncs.arb->glDeleteVertexArrays(1, &vao);
+ break;
+ case NotSupported:
+ break;
+ }
+ vao = 0;
+#endif
+}
+
+void QOpenGLVertexArrayObjectPrivate::bind()
+{
+#if defined(QT_OPENGL_ES_2)
+ if (vaoFuncs)
+ vaoFuncs->glBindVertexArray(vao);
+#else
+ switch (vaoFuncsType) {
+ case Core_3_2:
+ vaoFuncs.core_3_2->glBindVertexArray(vao);
+ break;
+ case Core_3_0:
+ vaoFuncs.core_3_0->glBindVertexArray(vao);
+ break;
+ case ARB:
+ vaoFuncs.arb->glBindVertexArray(vao);
+ break;
+ case NotSupported:
+ break;
+ }
+#endif
+}
+
+void QOpenGLVertexArrayObjectPrivate::release()
+{
+#if defined(QT_OPENGL_ES_2)
+ if (vaoFuncs)
+ vaoFuncs->glBindVertexArray(0);
+#else
+ switch (vaoFuncsType) {
+ case Core_3_2:
+ vaoFuncs.core_3_2->glBindVertexArray(0);
+ break;
+ case Core_3_0:
+ vaoFuncs.core_3_0->glBindVertexArray(0);
+ break;
+ case ARB:
+ vaoFuncs.arb->glBindVertexArray(0);
+ break;
+ case NotSupported:
+ break;
+ }
+#endif
+}
+
+
+/*!
+ \class QOpenGLVertexArrayObject
+ \brief The QOpenGLVertexArrayObject class wraps an OpenGL Vertex Array Object.
+ \inmodule QtGui
+ \since 5.1
+ \ingroup painting-3D
+
+ A Vertex Array Object (VAO) is an OpenGL container object that encapsulates
+ the state needed to specify per-vertex attribute data to the OpenGL pipeline.
+ To put it another way, a VAO remembers the states of buffer objects (see
+ QOpenGLBuffer) and their associated state (e.g. vertex attribute divisors).
+ This allows a very easy and efficient method of switching between OpenGL buffer
+ states for rendering different "objects" in a scene. The QOpenGLVertexArrayObject
+ class is a thin wrapper around an OpenGL VAO.
+
+ For the desktop, VAOs are supported as a core feature in OpenGL 3.0 or newer and by the
+ GL_ARB_vertex_array_object for older versions. On OpenGL ES 2, VAOs are provided by
+ the optional GL_OES_vertex_array_object extension. You can check the version of
+ OpenGL with QOpenGLContext::surfaceFormat() and check for the presence of extensions
+ with QOpenGLContext::hasExtension().
+
+ As with the other Qt OpenGL classes, QOpenGLVertexArrayObject has a create()
+ function to create the underlying OpenGL object. This is to allow the developer to
+ ensure that there is a valid current OpenGL context at the time.
+
+ Once you have successfully created a VAO the typical usage pattern is:
+
+ \list
+ \li In scene initialization function, for each visual object:
+ \list
+ \li Bind the VAO
+ \li Set vertex data state for this visual object (vertices, normals, texture coordinates etc.)
+ \li Unbind (release()) the VAO
+ \endlist
+ \li In render function, for each visual object:
+ \list
+ \li Bind the VAO (and shader program if needed)
+ \li Call a glDraw*() function
+ \li Unbind (release()) the VAO
+ \endlist
+ \endlist
+
+ The act of binding the VAO in the render function has the effect of restoring
+ all of the vertex data state setup in the initialization phase. In this way we can
+ set a great deal of state when setting up a VAO and efficiently switch between
+ state sets of objects to be rendered. Using VAOs also allows the OpenGL driver
+ to amortise the validation checks of the vertex data.
+
+ \note Vertex Array Objects, like all other OpenGL container objects, are specific
+ to the context for which they were created and cannot be shared amongst a
+ context group.
+
+ \sa QOpenGLVertexArrayObject::Binder, QOpenGLBuffer
+*/
+
+/*!
+ Creates a QOpenGLVertexArrayObject with the given \a parent. You must call create()
+ with a valid OpenGL context before using.
+*/
+QOpenGLVertexArrayObject::QOpenGLVertexArrayObject(QObject* parent)
+ : QObject(*new QOpenGLVertexArrayObjectPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QOpenGLVertexArrayObject::QOpenGLVertexArrayObject(QOpenGLVertexArrayObjectPrivate &dd)
+ : QObject(dd)
+{
+}
+
+/*!
+ Destroys the QOpenGLVertexArrayObject and the underlying OpenGL resource.
+*/
+QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject()
+{
+ QOpenGLContext* ctx = QOpenGLContext::currentContext();
+
+ Q_D(QOpenGLVertexArrayObject);
+ QOpenGLContext *oldContext = 0;
+ if (d->context != ctx) {
+ oldContext = ctx;
+ if (d->context->makeCurrent(oldContext->surface())) {
+ ctx = d->context;
+ } else {
+ qWarning("QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject() failed to make VAO's context current");
+ ctx = 0;
+ }
+ }
+
+ if (ctx)
+ destroy();
+
+ if (oldContext) {
+ if (!oldContext->makeCurrent(oldContext->surface()))
+ qWarning("QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject() failed to restore current context");
+ }
+}
+
+/*!
+ Creates the underlying OpenGL vertex array object. There must be a valid OpenGL context
+ that supports vertex array objects current for this function to succeed.
+
+ Returns true if the OpenGL vertex array object was successfully created.
+*/
+bool QOpenGLVertexArrayObject::create()
+{
+ Q_D(QOpenGLVertexArrayObject);
+ return d->create();
+}
+
+/*!
+ Destroys the underlying OpenGL vertex array object. There must be a valid OpenGL context
+ that supports vertex array objects current for this function to succeed.
+*/
+void QOpenGLVertexArrayObject::destroy()
+{
+ Q_D(QOpenGLVertexArrayObject);
+ d->destroy();
+}
+
+/*!
+ Returns true is the underlying OpenGL vertex array object has been created. If this
+ returns true and the associated OpenGL context is current, then you are able to bind()
+ this object.
+*/
+bool QOpenGLVertexArrayObject::isCreated() const
+{
+ Q_D(const QOpenGLVertexArrayObject);
+ return (d->vao != 0);
+}
+
+/*!
+ Returns the id of the underlying OpenGL vertex array object.
+*/
+GLuint QOpenGLVertexArrayObject::objectId() const
+{
+ Q_D(const QOpenGLVertexArrayObject);
+ return d->vao;
+}
+
+/*!
+ Binds this vertex array object to the OpenGL binding point. From this point on
+ and until release() is called or another vertex array object is bound, any
+ modifications made to vertex data state are stored inside this vertex array object.
+
+ If another vertex array object is then bound you can later restore the set of
+ state associated with this object by calling bind() on this object once again.
+ This allows efficient changes between vertex data states in rendering functions.
+*/
+void QOpenGLVertexArrayObject::bind()
+{
+ Q_D(QOpenGLVertexArrayObject);
+ d->bind();
+}
+
+/*!
+ Unbinds this vertex array object by binding the default vertex array object (id = 0).
+*/
+void QOpenGLVertexArrayObject::release()
+{
+ Q_D(QOpenGLVertexArrayObject);
+ d->release();
+}
+
+
+/*!
+ \class QOpenGLVertexArrayObject::Binder
+ \brief The QOpenGLVertexArrayObject::Binder class is a convenience class to help
+ with the binding and releasing of OpenGL Vertex Array Objects.
+ \inmodule QtGui
+ \reentrant
+ \since 5.1
+ \ingroup painting-3D
+
+ QOpenGLVertexArrayObject::Binder is a simple convenience class that can be used
+ to assist with the binding and releasing of QOpenGLVertexArrayObject instances.
+ This class is to QOpenGLVertexArrayObject as QMutexLocker is to QMutex.
+
+ This class implements the RAII principle which helps to ensure behavior in
+ complex code or in the presence of exceptions.
+
+ The constructor of this class accepts a QOpenGLVertexArrayObject (VAO) as an
+ argument and attempts to bind the VAO, calling QOpenGLVertexArrayObject::create()
+ if necessary. The destructor of this class calls QOpenGLVertexArrayObject::release()
+ which unbinds the VAO.
+
+ If needed the VAO can be temporarily unbound with the release() function and bound
+ once more with rebind().
+
+ \sa QOpenGLVertexArrayObject
+*/
+
+/*!
+ \fn QOpenGLVertexArrayObject::Binder::Binder(QOpenGLVertexArrayObject *v)
+
+ Creates a QOpenGLVertexArrayObject::Binder object and binds \a v by calling
+ QOpenGLVertexArrayObject::bind(). If necessary it first calls
+ QOpenGLVertexArrayObject::create().
+*/
+
+/*!
+ \fn QOpenGLVertexArrayObject::Binder::~Binder()
+
+ Destroys the QOpenGLVertexArrayObject::Binder and releases the associated vertex array object.
+*/
+
+/*!
+ \fn QOpenGLVertexArrayObject::Binder::release()
+
+ Can be used to temporarily release the associated vertex array object.
+
+ \sa rebind()
+*/
+
+/*!
+ \fn QOpenGLVertexArrayObject::Binder::rebind()
+
+ Can be used to rebind the associated vertex array object.
+
+ \sa release()
+*/
+
+QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopenglvertexarrayobject.h b/src/gui/opengl/qopenglvertexarrayobject.h
new file mode 100644
index 0000000000..d5226d3ebd
--- /dev/null
+++ b/src/gui/opengl/qopenglvertexarrayobject.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOPENGLVERTEXARRAYOBJECT_H
+#define QOPENGLVERTEXARRAYOBJECT_H
+
+#ifndef QT_NO_OPENGL
+
+#include <QtCore/QObject>
+#include <QtGui/qopengl.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLVertexArrayObjectPrivate;
+
+class Q_GUI_EXPORT QOpenGLVertexArrayObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QOpenGLVertexArrayObject(QObject* parent = 0);
+ ~QOpenGLVertexArrayObject();
+
+ bool create();
+ void destroy();
+ bool isCreated() const;
+ GLuint objectId() const;
+ void bind();
+ void release();
+
+ class Q_GUI_EXPORT Binder
+ {
+ public:
+ inline Binder(QOpenGLVertexArrayObject *v)
+ : vao(v)
+ {
+ Q_ASSERT(v);
+ if (vao->isCreated() || vao->create())
+ vao->bind();
+ }
+
+ inline ~Binder()
+ {
+ release();
+ }
+
+ inline void release()
+ {
+ vao->release();
+ }
+
+ inline void rebind()
+ {
+ vao->bind();
+ }
+
+ private:
+ Q_DISABLE_COPY(Binder)
+ QOpenGLVertexArrayObject *vao;
+ };
+
+private:
+ Q_DISABLE_COPY(QOpenGLVertexArrayObject)
+ Q_DECLARE_PRIVATE(QOpenGLVertexArrayObject)
+ QOpenGLVertexArrayObject(QOpenGLVertexArrayObjectPrivate &dd);
+};
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QOPENGLVERTEXARRAYOBJECT_H