diff options
author | Samuel Rødal <samuel.rodal@nokia.com> | 2011-08-22 10:49:28 +0200 |
---|---|---|
committer | Samuel Rødal <samuel.rodal@nokia.com> | 2011-08-29 10:25:24 +0200 |
commit | 6e28e8441b698c3397c2c78125c877f2e9867cb1 (patch) | |
tree | 1e3ad0e43cb775854835817cd04bdc8b5e047e15 /src/gui/opengl/qopenglbuffer.cpp | |
parent | aaa4a26f82f99fa8724841eba91bad029306e0ce (diff) |
Copy core GL functionality to QtGui with QGL -> QOpenGL naming.
Change-Id: Ibc989afa4a30dd184d41d1a1cd89f97196e48855
Reviewed-on: http://codereview.qt.nokia.com/3710
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
Diffstat (limited to 'src/gui/opengl/qopenglbuffer.cpp')
-rw-r--r-- | src/gui/opengl/qopenglbuffer.cpp | 582 |
1 files changed, 582 insertions, 0 deletions
diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp new file mode 100644 index 0000000000..612938df16 --- /dev/null +++ b/src/gui/opengl/qopenglbuffer.cpp @@ -0,0 +1,582 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/qopengl.h> +#include <QtGui/private/qopenglcontext_p.h> +#include <QtCore/qatomic.h> +#include "qopenglbuffer.h" +#include <private/qopenglextensions_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLBuffer + \brief The QOpenGLBuffer class provides functions for creating and managing GL buffer objects. + \since 4.7 + \ingroup painting-3D + + Buffer objects are created in the GL server so that the + client application can avoid uploading vertices, indices, + texture image data, etc every time they are needed. + + QOpenGLBuffer objects can be copied around as a reference to the + underlying GL buffer object: + + \code + QOpenGLBuffer buffer1(QOpenGLBuffer::IndexBuffer); + buffer1.create(); + + QOpenGLBuffer buffer2 = buffer1; + \endcode + + QOpenGLBuffer performs a shallow copy when objects are copied in this + manner, but does not implement copy-on-write semantics. The original + object will be affected whenever the copy is modified. +*/ + +/*! + \enum QOpenGLBuffer::Type + This enum defines the type of GL buffer object to create with QOpenGLBuffer. + + \value VertexBuffer Vertex buffer object for use when specifying + vertex arrays. + \value IndexBuffer Index buffer object for use with \c{glDrawElements()}. + \value PixelPackBuffer Pixel pack buffer object for reading pixel + data from the GL server (for example, with \c{glReadPixels()}). + Not supported under OpenGL/ES. + \value PixelUnpackBuffer Pixel unpack buffer object for writing pixel + data to the GL server (for example, with \c{glTexImage2D()}). + Not supported under OpenGL/ES. +*/ + +/*! + \enum QOpenGLBuffer::UsagePattern + This enum defines the usage pattern of a QOpenGLBuffer object. + + \value StreamDraw The data will be set once and used a few times + for drawing operations. Under OpenGL/ES 1.1 this is identical + to StaticDraw. + \value StreamRead The data will be set once and used a few times + for reading data back from the GL server. Not supported + under OpenGL/ES. + \value StreamCopy The data will be set once and used a few times + for reading data back from the GL server for use in further + drawing operations. Not supported under OpenGL/ES. + \value StaticDraw The data will be set once and used many times + for drawing operations. + \value StaticRead The data will be set once and used many times + for reading data back from the GL server. Not supported + under OpenGL/ES. + \value StaticCopy The data will be set once and used many times + for reading data back from the GL server for use in further + drawing operations. Not supported under OpenGL/ES. + \value DynamicDraw The data will be modified repeatedly and used + many times for drawing operations. + \value DynamicRead The data will be modified repeatedly and used + many times for reading data back from the GL server. + Not supported under OpenGL/ES. + \value DynamicCopy The data will be modified repeatedly and used + many times for reading data back from the GL server for + use in further drawing operations. Not supported under OpenGL/ES. +*/ + +/*! + \enum QOpenGLBuffer::Access + This enum defines the access mode for QOpenGLBuffer::map(). + + \value ReadOnly The buffer will be mapped for reading only. + \value WriteOnly The buffer will be mapped for writing only. + \value ReadWrite The buffer will be mapped for reading and writing. +*/ + +class QOpenGLBufferPrivate +{ +public: + QOpenGLBufferPrivate(QOpenGLBuffer::Type t) + : ref(1), + type(t), + guard(0), + usagePattern(QOpenGLBuffer::StaticDraw), + actualUsagePattern(QOpenGLBuffer::StaticDraw), + funcs(0) + { + } + + QAtomicInt ref; + QOpenGLBuffer::Type type; + QOpenGLSharedResourceGuard *guard; + QOpenGLBuffer::UsagePattern usagePattern; + QOpenGLBuffer::UsagePattern actualUsagePattern; + QOpenGLExtensions *funcs; +}; + +/*! + Constructs a new buffer object of type QOpenGLBuffer::VertexBuffer. + + Note: this constructor just creates the QOpenGLBuffer instance. The actual + buffer object in the GL server is not created until create() is called. + + \sa create() +*/ +QOpenGLBuffer::QOpenGLBuffer() + : d_ptr(new QOpenGLBufferPrivate(QOpenGLBuffer::VertexBuffer)) +{ +} + +/*! + Constructs a new buffer object of \a type. + + Note: this constructor just creates the QOpenGLBuffer instance. The actual + buffer object in the GL server is not created until create() is called. + + \sa create() +*/ +QOpenGLBuffer::QOpenGLBuffer(QOpenGLBuffer::Type type) + : d_ptr(new QOpenGLBufferPrivate(type)) +{ +} + +/*! + Constructs a shallow copy of \a other. + + Note: QOpenGLBuffer does not implement copy-on-write semantics, + so \a other will be affected whenever the copy is modified. +*/ +QOpenGLBuffer::QOpenGLBuffer(const QOpenGLBuffer &other) + : d_ptr(other.d_ptr) +{ + d_ptr->ref.ref(); +} + +#define ctx QOpenGLContext::currentContext(); + +/*! + Destroys this buffer object, including the storage being + used in the GL server. +*/ +QOpenGLBuffer::~QOpenGLBuffer() +{ + if (!d_ptr->ref.deref()) { + destroy(); + delete d_ptr; + } +} + +/*! + Assigns a shallow copy of \a other to this object. + + Note: QOpenGLBuffer does not implement copy-on-write semantics, + so \a other will be affected whenever the copy is modified. +*/ +QOpenGLBuffer &QOpenGLBuffer::operator=(const QOpenGLBuffer &other) +{ + if (d_ptr != other.d_ptr) { + other.d_ptr->ref.ref(); + if (!d_ptr->ref.deref()) + destroy(); + d_ptr = other.d_ptr; + } + return *this; +} + +/*! + Returns the type of buffer represented by this object. +*/ +QOpenGLBuffer::Type QOpenGLBuffer::type() const +{ + Q_D(const QOpenGLBuffer); + return d->type; +} + +/*! + Returns the usage pattern for this buffer object. + The default value is StaticDraw. + + \sa setUsagePattern() +*/ +QOpenGLBuffer::UsagePattern QOpenGLBuffer::usagePattern() const +{ + Q_D(const QOpenGLBuffer); + return d->usagePattern; +} + +/*! + Sets the usage pattern for this buffer object to \a value. + This function must be called before allocate() or write(). + + \sa usagePattern(), allocate(), write() +*/ +void QOpenGLBuffer::setUsagePattern(QOpenGLBuffer::UsagePattern value) +{ + Q_D(QOpenGLBuffer); + d->usagePattern = d->actualUsagePattern = value; +} + +#undef ctx + +namespace { + void freeBufferFunc(QOpenGLFunctions *funcs, GLuint id) + { + funcs->glDeleteBuffers(1, &id); + } +} + +/*! + Creates the buffer object in the GL server. Returns true if + the object was created; false otherwise. + + This function must be called with a current QOpenGLContext. + The buffer will be bound to and can only be used in + that context (or any other context that is shared with it). + + This function will return false if the GL implementation + does not support buffers, or there is no current QOpenGLContext. + + \sa isCreated(), allocate(), write(), destroy() +*/ +bool QOpenGLBuffer::create() +{ + Q_D(QOpenGLBuffer); + if (d->guard && d->guard->id()) + return true; + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + delete d->funcs; + d->funcs = new QOpenGLExtensions(ctx); + GLuint bufferId = 0; + d->funcs->glGenBuffers(1, &bufferId); + if (bufferId) { + if (d->guard) + d->guard->free(); + + d->guard = new QOpenGLSharedResourceGuard(ctx, bufferId, freeBufferFunc); + return true; + } + } + return false; +} + +#define ctx QOpenGLContext::currentContext() + +/*! + Returns true if this buffer has been created; false otherwise. + + \sa create(), destroy() +*/ +bool QOpenGLBuffer::isCreated() const +{ + Q_D(const QOpenGLBuffer); + return d->guard && d->guard->id(); +} + +/*! + Destroys this buffer object, including the storage being + used in the GL server. All references to the buffer will + become invalid. +*/ +void QOpenGLBuffer::destroy() +{ + Q_D(QOpenGLBuffer); + if (d->guard) { + d->guard->free(); + d->guard = 0; + } +} + +/*! + Reads the \a count bytes in this buffer starting at \a offset + into \a data. Returns true on success; false if reading from + the buffer is not supported. Buffer reading is not supported + under OpenGL/ES. + + It is assumed that this buffer has been bound to the current context. + + \sa write(), bind() +*/ +bool QOpenGLBuffer::read(int offset, void *data, int count) +{ +#if !defined(QT_OPENGL_ES) + Q_D(QOpenGLBuffer); + if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id()) + return false; + while (glGetError() != GL_NO_ERROR) ; // Clear error state. + d->funcs->glGetBufferSubData(d->type, offset, count, data); + return glGetError() == GL_NO_ERROR; +#else + Q_UNUSED(offset); + Q_UNUSED(data); + Q_UNUSED(count); + return false; +#endif +} + +/*! + Replaces the \a count bytes of this buffer starting at \a offset + with the contents of \a data. Any other bytes in the buffer + will be left unmodified. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + \sa create(), read(), allocate() +*/ +void QOpenGLBuffer::write(int offset, const void *data, int count) +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::allocate(): buffer not created"); +#endif + Q_D(QOpenGLBuffer); + if (d->guard && d->guard->id()) + d->funcs->glBufferSubData(d->type, offset, count, data); +} + +/*! + Allocates \a count bytes of space to the buffer, initialized to + the contents of \a data. Any previous contents will be removed. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + \sa create(), read(), write() +*/ +void QOpenGLBuffer::allocate(const void *data, int count) +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::allocate(): buffer not created"); +#endif + Q_D(QOpenGLBuffer); + if (d->guard && d->guard->id()) + d->funcs->glBufferData(d->type, count, data, d->actualUsagePattern); +} + +/*! + \fn void QOpenGLBuffer::allocate(int count) + \overload + + Allocates \a count bytes of space to the buffer. Any previous + contents will be removed. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + \sa create(), write() +*/ + +/*! + Binds the buffer associated with this object to the current + GL context. Returns false if binding was not possible, usually because + type() is not supported on this GL implementation. + + The buffer must be bound to the same QOpenGLContext current when create() + was called, or to another QOpenGLContext that is sharing with it. + Otherwise, false will be returned from this function. + + \sa release(), create() +*/ +bool QOpenGLBuffer::bind() +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::bind(): buffer not created"); +#endif + Q_D(const QOpenGLBuffer); + GLuint bufferId = d->guard ? d->guard->id() : 0; + if (bufferId) { + if (d->guard->group() != QOpenGLContextGroup::currentContextGroup()) { +#ifndef QT_NO_DEBUG + qWarning("QOpenGLBuffer::bind: buffer is not valid in the current context"); +#endif + return false; + } + d->funcs->glBindBuffer(d->type, bufferId); + return true; + } else { + return false; + } +} + +/*! + Releases the buffer associated with this object from the + current GL context. + + This function must be called with the same QOpenGLContext current + as when bind() was called on the buffer. + + \sa bind() +*/ +void QOpenGLBuffer::release() +{ +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::release(): buffer not created"); +#endif + Q_D(const QOpenGLBuffer); + if (d->guard && d->guard->id()) + d->funcs->glBindBuffer(d->type, 0); +} + +#undef ctx + +/*! + Releases the buffer associated with \a type in the current + QOpenGLContext. + + This function is a direct call to \c{glBindBuffer(type, 0)} + for use when the caller does not know which QOpenGLBuffer has + been bound to the context but wants to make sure that it + is released. + + \code + QOpenGLBuffer::release(QOpenGLBuffer::VertexBuffer); + \endcode +*/ +void QOpenGLBuffer::release(QOpenGLBuffer::Type type) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (ctx) { + QOpenGLFunctions(ctx).glBindBuffer(GLenum(type), 0); + } +} + +#define ctx QOpenGLContext::currentContext() + +/*! + Returns the GL identifier associated with this buffer; zero if + the buffer has not been created. + + \sa isCreated() +*/ +GLuint QOpenGLBuffer::bufferId() const +{ + Q_D(const QOpenGLBuffer); + return d->guard ? d->guard->id() : 0; +} + +#ifndef GL_BUFFER_SIZE +#define GL_BUFFER_SIZE 0x8764 +#endif + +/*! + Returns the size of the data in this buffer, for reading operations. + Returns -1 if fetching the buffer size is not supported, or the + buffer has not been created. + + It is assumed that this buffer has been bound to the current context. + + \sa isCreated(), bind() +*/ +int QOpenGLBuffer::size() const +{ + Q_D(const QOpenGLBuffer); + if (!d->guard || !d->guard->id()) + return -1; + GLint value = -1; + d->funcs->glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value); + return value; +} + +/*! + Maps the contents of this buffer into the application's memory + space and returns a pointer to it. Returns null if memory + mapping is not possible. The \a access parameter indicates the + type of access to be performed. + + It is assumed that create() has been called on this buffer and that + it has been bound to the current context. + + This function is only supported under OpenGL/ES if the + \c{GL_OES_mapbuffer} extension is present. + + \sa unmap(), create(), bind() +*/ +void *QOpenGLBuffer::map(QOpenGLBuffer::Access access) +{ + Q_D(QOpenGLBuffer); +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::map(): buffer not created"); +#endif + if (!d->guard || !d->guard->id()) + return 0; +#if 0 + if (!glMapBufferARB) + return 0; + return glMapBufferARB(d->type, access); +#endif + Q_UNUSED(access); + qWarning("QOpenGLBuffer::map(): pending implementation"); + return 0; +} + +/*! + Unmaps the buffer after it was mapped into the application's + memory space with a previous call to map(). Returns true if + the unmap succeeded; false otherwise. + + It is assumed that this buffer has been bound to the current context, + and that it was previously mapped with map(). + + This function is only supported under OpenGL/ES if the + \c{GL_OES_mapbuffer} extension is present. + + \sa map() +*/ +bool QOpenGLBuffer::unmap() +{ + Q_D(QOpenGLBuffer); +#ifndef QT_NO_DEBUG + if (!isCreated()) + qWarning("QOpenGLBuffer::unmap(): buffer not created"); +#endif + if (!d->guard || !d->guard->id()) + return false; +#if 0 + if (!glUnmapBufferARB) + return false; + return glUnmapBufferARB(d->type) == GL_TRUE; +#endif + qWarning("QOpenGLBuffer::map(): pending implementation"); + return 0; +} + +QT_END_NAMESPACE |