Buffer.hh 12.8 KB
Newer Older
1 2 3 4 5 6 7 8
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

#ifndef ACGL_OPENGL_OBJECTS_BUFFER_HH
#define ACGL_OPENGL_OBJECTS_BUFFER_HH

Robert Menzel's avatar
Robert Menzel committed
9
/**
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 * A generic OpenGL Buffer Object
 *
 * Mostly an OpenGL Buffer Wrapper: names of OpenGL calls are stripped of the
 * 'gl' and 'Buffer' tokens and setters got a 'set' prefix.
 *
 * Calls that give the target the buffer should get bound to have an alternative
 * call that uses the last used or set target.
 *
 * Note: Most methods will bind this buffer!
 */

#include <ACGL/ACGL.hh>

#include <ACGL/Base/Macros.hh>
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>

#include <string>
#include <vector>

namespace ACGL{
namespace OpenGL{


Robert Menzel's avatar
Robert Menzel committed
34
/**
Robert Menzel's avatar
Robert Menzel committed
35 36 37 38 39 40 41
 * A minimal(!) wrapper to allow multiple Buffer objects pointing to the same
 * OpenGL resource (like an ArrayBuffer and a TransformFeedbackBuffer).
 *
 * This has to be an extra object so all Buffer types can inherit from Buffer
 * below to allow a unified API.
 */
class BufferObject {
Robert Menzel's avatar
Robert Menzel committed
42
    ACGL_NOT_COPYABLE(BufferObject)
43
public:
Robert Menzel's avatar
Robert Menzel committed
44
    BufferObject()
45 46
    {
        glGenBuffers(1, &mObjectName);
Robert Menzel's avatar
Robert Menzel committed
47 48 49 50 51
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate buffer!" << std::endl;
            mObjectName = 0;
            return;
        }
52 53
    }

Robert Menzel's avatar
Robert Menzel committed
54
    ~BufferObject(void)
55 56 57 58
    {
        // buffer 0 will get ignored by OpenGL
        glDeleteBuffers(1, &mObjectName);
    }
Robert Menzel's avatar
Robert Menzel committed
59 60
    GLuint mObjectName;
};
Robert Menzel's avatar
Robert Menzel committed
61
typedef ptr::shared_ptr<BufferObject> SharedBufferObject;
Robert Menzel's avatar
Robert Menzel committed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81


/**
 * Buffers are general OpenGL Buffer Wrapper.
 * The OpenGL resource itself is attached via a shared pointer (GLBufferObject).
 * This was multiple Buffers can use internaly the same OpenGL resource, this is
 * useful if one resource should get interpreted as _different_ buffer types
 * so in that case the same GLBufferObject will get attached to different
 * Subclass Objects.
 *
 * Note: Subclasses should set the mTarget in there constructors!
 */
class Buffer
{
    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
public:
    //! Most common default: a new Buffer corresponds to a new GL resource. You might decide on a binding point
    //! now or later.
Robert Menzel's avatar
Robert Menzel committed
82
    Buffer( GLenum _target ) : mSize(0), mTarget(_target)
Robert Menzel's avatar
Robert Menzel committed
83 84 85 86 87 88 89 90 91 92 93 94 95
    {
        mBuffer = SharedBufferObject( new BufferObject() );
    }

    /**
     * Init with a given, external GL resource.
     *
     * Calling this with:
     * Buffer b( SharedGLBufferObject(NULL) );
     * Is the way to _explicitly_ state that a real OpenGL resource will get added later.
     * In this case no GL wrapper calls should ever get called until one gets set!
     */
    Buffer( SharedBufferObject _pBuffer, GLenum _target )
Robert Menzel's avatar
Robert Menzel committed
96 97 98
        : mSize(0),
		  mBuffer( _pBuffer ),
		  mTarget(_target)
Robert Menzel's avatar
Robert Menzel committed
99
    {}
100

Robert Menzel's avatar
Robert Menzel committed
101 102
	virtual ~Buffer(){}

103 104 105 106
    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
Robert Menzel's avatar
Robert Menzel committed
107 108 109 110 111 112 113 114 115 116
    inline GLuint getObjectName (void) const { return mBuffer->mObjectName; }
    inline bool   isValid       (void) const { return (mBuffer && glIsBuffer( mBuffer->mObjectName ) ); }
    inline SharedBufferObject getBufferObject () const { return mBuffer; }

    // ==================================================================================================== \/
    // ============================================================================================ SETTERS \/
    // ==================================================================================================== \/

    //! the GL buffer can get changed at any time
    void setBufferObject( SharedBufferObject _pBuffer ) { mBuffer = _pBuffer; }
117

Robert Menzel's avatar
Robert Menzel committed
118 119 120
    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
121 122
private:
    inline GLint getParameter( GLenum _parameter ) {
Robert Menzel's avatar
Robert Menzel committed
123
        bind( mTarget );
124
        GLint value;
Robert Menzel's avatar
Robert Menzel committed
125
        glGetBufferParameteriv( mTarget, _parameter, &value );
126 127 128 129 130
        return value;
    }

#if (ACGL_OPENGL_VERSION >= 32)
    inline GLint64 getParameter64( GLenum _parameter ) {
Robert Menzel's avatar
Robert Menzel committed
131
        bind( mTarget );
132
        GLint64 value;
Robert Menzel's avatar
Robert Menzel committed
133
        glGetBufferParameteri64v( mTarget, _parameter, &value );
134 135 136
        return value;
    }

Robert Menzel's avatar
Robert Menzel committed
137
public:
138
    //! not side effect free! will bind this buffer to it's last target!
Robert Menzel's avatar
Robert Menzel committed
139
    //! caching of these values on RAM could be a good idea if needed very(!) often (as it's done with the size)!
140
    //inline GLint64   getSize()        { return             getParameter64( GL_BUFFER_SIZE         ); }
141 142 143
    inline GLint64   getMapOffset()   { return             getParameter64( GL_BUFFER_MAP_OFFSET   ); }
    inline GLint64   getMapLength()   { return             getParameter64( GL_BUFFER_MAP_LENGTH   ); }
#else // OpenGL pre 3.2:
144
    //inline GLint     getSize()        { return             getParameter  ( GL_BUFFER_SIZE         ); }
145 146 147 148 149 150 151 152
    inline GLint     getMapOffset()   { return             getParameter  ( GL_BUFFER_MAP_OFFSET   ); }
    inline GLint     getMapLength()   { return             getParameter  ( GL_BUFFER_MAP_LENGTH   ); }
#endif // OpenGL >= 3.2
    inline GLenum    getUsage()       { return (GLenum)    getParameter  ( GL_BUFFER_USAGE        ); }
    inline GLenum    getAccess()      { return (GLenum)    getParameter  ( GL_BUFFER_ACCESS       ); }
    inline GLint     getAccessFlags() { return (GLint)     getParameter  ( GL_BUFFER_ACCESS_FLAGS ); }
    inline GLboolean isMapped()       { return (GLboolean) getParameter  ( GL_BUFFER_MAPPED       ); }

Robert Menzel's avatar
Robert Menzel committed
153
    //! the size is in bytes
154 155
    inline GLint64   getSize()        { return mSize; }

156 157 158
    //! Bind this buffer
    inline void bind( GLenum _target )
    {
Robert Menzel's avatar
Robert Menzel committed
159
        glBindBuffer( _target, mBuffer->mObjectName );
160 161 162
        openGLRareError();
    }

Robert Menzel's avatar
Robert Menzel committed
163
    //! Bind this buffer to its target
164 165
    inline void bind()
    {
Robert Menzel's avatar
Robert Menzel committed
166
        glBindBuffer( mTarget, mBuffer->mObjectName );
167 168 169 170 171 172
        openGLRareError();
    }

    //! Set data for this buffer. Use only to init the buffer!
    //! Note: The function is not const, because it changes the corresponding GPU data
    inline void setData( GLenum _target, GLsizeiptr _size, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
173
        mSize = _size;
174 175 176 177 178 179 180
        bind( _target );
        glBufferData( _target, _size, _pData, _usage );
        openGLRareError();
    }

    //! Set data for this buffer at the last used target. Use only to init the buffer!
    inline void setData( GLsizeiptr _size, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
Robert Menzel's avatar
Robert Menzel committed
181
        setData( mTarget, _size, _pData, _usage );
182 183 184 185 186 187 188 189 190 191 192 193
    }

    //! Use this to modify the buffer
    inline void setSubData( GLenum _target, GLintptr _offset,
                            GLsizeiptr _size, const GLvoid *_pData ) {
        bind( _target );
        glBufferSubData( _target, _offset, _size, _pData );
        openGLRareError();
    }

    //! Use this to modify the buffer
    inline void setSubData( GLintptr _offset, GLsizeiptr _size, const GLvoid *_pData ) {
Robert Menzel's avatar
Robert Menzel committed
194
        setSubData( mTarget, _offset, _size, _pData );
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
    }


#if (ACGL_OPENGL_VERSION >= 30)
    /** Map a part of the buffer to client memory
     * _offset & _length are values in bytes relative to the buffer
     * _access must contain one (or both) of:
     *      GL_MAP_READ_BIT and GL_MAP_WRITE_BIT
     *  and optionally:
     *      GL_MAP_INVALIDATE_RANGE_BIT GL_MAP_INVALIDATE_BUFFER_BIT
     *      GL_MAP_FLUSH_EXPLICIT_BIT GL_MAP_UNSYNCHRONIZED_BIT
     */
    GLvoid *mapRange( GLenum _target, GLintptr _offset, GLsizeiptr _length, GLbitfield _access ) {
        bind( _target );
        GLvoid *ret = glMapBufferRange( _target, _offset, _length, _access );
        openGLRareError();
        return ret;
    }

    inline GLvoid *mapRange( GLintptr _offset, GLsizeiptr _length, GLbitfield _access ) {
Robert Menzel's avatar
Robert Menzel committed
215
        return mapRange( mTarget, _offset, _length, _access );
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    }

    /**
     * Spec:
     * If a buffer is mapped with the GL_MAP_FLUSH_EXPLICIT_BIT flag, modifications
     * to the mapped range may be indicated by calling this.
     * _offset and _length indicate a modified subrange of the mapping, in byte. The specified
     * subrange to flush is relative to the start of the currently mapped range of buffer.
     * This can be called multiple times to indicate distinct subranges
     * of the mapping which require flushing.
     */
    void flushMappedRange( GLenum _target, GLsizeiptr _offset, GLsizeiptr _length ) {
        bind( _target );
        glFlushMappedBufferRange( _target, _offset, _length );
        openGLRareError();
    }

    inline void flushMappedRange( GLintptr _offset, GLsizeiptr _length ) {
Robert Menzel's avatar
Robert Menzel committed
234
        flushMappedRange( mTarget, _offset, _length );
235 236
    }

Robert Menzel's avatar
Robert Menzel committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
    //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER
    inline void bindBufferRange( GLenum _target, GLuint _index, GLintptr _offset, GLsizeiptr _size ) {
        glBindBufferRange( _target, _index, mBuffer->mObjectName, _offset, _size );
    }

    //! maps a subset of the buffer defined by _offset and _size
    //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER
    inline void bindBufferRange( GLuint _index, GLintptr _offset, GLsizeiptr _size ) {
        glBindBufferRange( mTarget, _index, mBuffer->mObjectName, _offset, _size );
    }

    //! maps the full buffer to the given index (binding point)
    //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER
    inline void bindBufferBase( GLenum _target, GLuint _index ) {
        glBindBufferBase( _target, _index, mBuffer->mObjectName );
    }

    //! maps the full buffer to the given index (binding point)
    //! valid targets are only GL_TRANSFORM_FEEDBACK_BUFFER and GL_UNIFORM_BUFFER
    inline void bindBufferBase( GLuint _index ) {
        glBindBufferBase( mTarget, _index, mBuffer->mObjectName );
    }

260 261 262 263 264 265 266 267 268 269 270
#endif // OpenGL >= 3.0

    //! Maps the whole buffer, if using GL 3+, better use mapRange!
    //! _access is GL_READ_ONLY GL_WRITE_ONLY or GL_READ_WRITE
    GLvoid *map( GLenum _target, GLenum _access ) {
        bind( _target );
        GLvoid *ret = glMapBuffer( _target, _access );
        openGLRareError();
        return ret;
    }
    inline GLvoid *map( GLenum _access ) {
Robert Menzel's avatar
Robert Menzel committed
271
        return map( mTarget, _access );
272 273 274 275 276 277 278 279 280 281
    }

    GLboolean unmap( GLenum _target ) {
        bind( _target );
        GLboolean ret = glUnmapBuffer( _target );
        openGLRareError();
        return ret;
    }

    inline GLboolean unmap() {
Robert Menzel's avatar
Robert Menzel committed
282
        return unmap( mTarget );
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
    }

    // TODO: CopyBufferSubData

    /**
     * _target must be one of:
        GL_ARRAY_BUFFER
        GL_ATOMIC_COUNTER_BUFFER
        GL_COPY_READ_BUFFER
        GL_COPY_WRITE_BUFFER
        GL_DRAW_INDIRECT_BUFFER
        GL_ELEMENT_ARRAY_BUFFER
        GL_PIXEL_PACK_BUFFER
        GL_PIXEL_UNPACK_BUFFER
        GL_TEXTURE_BUFFER
        GL_TRANSFORM_FEEDBACK_BUFFER
        GL_UNIFORM_BUFFER
Robert Menzel's avatar
Robert Menzel committed
300 301 302 303 304 305 306 307 308 309 310 311
     * Can be changed at any time.
     *
     * Subclasses should overload this with a non-working function (+ a warning)
     * because an X-Buffer should not be attached _per default_ to Y!
     * Subclass buffers can however always use the method calls / binds with an
     * _explicit_ target (that doesn't match there one ones):
     *
     * XBuffer x;
     * x.bind( Y ); // ok, hope the programmer knowns what s/he does
     *
     * x.setTarget( Y ); // this is just calling for unintended side-effects!
     * x.bind();
312
     */
Robert Menzel's avatar
Robert Menzel committed
313
    virtual inline void setTarget( GLenum _target ) { mTarget = _target; }
314 315 316 317 318

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
Robert Menzel's avatar
Robert Menzel committed
319
    GLint64            mSize; // as this might get queried often (e.g. ArrayBuffer) we will explicitly mirror it in RAM)
Robert Menzel's avatar
Robert Menzel committed
320 321
	SharedBufferObject mBuffer;
	GLenum             mTarget;
322 323
};

Robert Menzel's avatar
Robert Menzel committed
324
ACGL_SMARTPOINTER_TYPEDEFS(Buffer)
325 326 327 328 329

} // OpenGL
} // ACGL

#endif // ACGL_OPENGL_OBJECTS_BUFFER_HH