Buffer.hh 13.6 KB
Newer Older
1
2
3
4
5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
6
7
8
9

#ifndef ACGL_OPENGL_OBJECTS_BUFFER_HH
#define ACGL_OPENGL_OBJECTS_BUFFER_HH

Robert Menzel's avatar
Robert Menzel committed
10
/**
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 * 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
35
/**
Robert Menzel's avatar
Robert Menzel committed
36
37
38
39
40
41
42
 * 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
43
    ACGL_NOT_COPYABLE(BufferObject)
44
public:
Robert Menzel's avatar
Robert Menzel committed
45
    BufferObject()
46
47
    {
        glGenBuffers(1, &mObjectName);
Robert Menzel's avatar
Robert Menzel committed
48
49
50
51
52
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate buffer!" << std::endl;
            mObjectName = 0;
            return;
        }
53
54
    }

Robert Menzel's avatar
Robert Menzel committed
55
    ~BufferObject(void)
56
57
58
59
    {
        // buffer 0 will get ignored by OpenGL
        glDeleteBuffers(1, &mObjectName);
    }
Robert Menzel's avatar
Robert Menzel committed
60
    GLuint mObjectName;
61
62
63
64
65
66
67
68
69

    //! has the side effect of binding this buffer.
    //! returned value is in bytes
    GLsizei getSize( GLenum _asTarget ) {
        glBindBuffer( _asTarget, mObjectName );
        GLint value;
        glGetBufferParameteriv( _asTarget, GL_BUFFER_SIZE, &value );
        return value;
    }
Robert Menzel's avatar
Robert Menzel committed
70
};
Robert Menzel's avatar
Robert Menzel committed
71
typedef ptr::shared_ptr<BufferObject> SharedBufferObject;
Robert Menzel's avatar
Robert Menzel committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91


/**
 * 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
92
    Buffer( GLenum _target ) : mSize(0), mTarget(_target)
Robert Menzel's avatar
Robert Menzel committed
93
94
95
96
97
98
99
100
101
102
103
104
105
    {
        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 )
106
        : mBuffer( _pBuffer ),
Robert Menzel's avatar
Robert Menzel committed
107
		  mTarget(_target)
108
    {
109
        mSize = (mBuffer == NULL)?0:mBuffer->getSize( mTarget );
110
    }
111

112
    virtual ~Buffer(){}
Robert Menzel's avatar
Robert Menzel committed
113

114
115
116
117
    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
Robert Menzel's avatar
Robert Menzel committed
118
119
120
121
122
123
124
125
126
    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
127
    void setBufferObject( SharedBufferObject _pBuffer ) { mBuffer = _pBuffer; mSize = (mBuffer == NULL)?0:mBuffer->getSize( mTarget ); }
128

Robert Menzel's avatar
Robert Menzel committed
129
130
131
    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
132
private:
133
134
    inline GLint getParameter( GLenum _parameter ) const
    {
Robert Menzel's avatar
Robert Menzel committed
135
        bind( mTarget );
136
        GLint value;
Robert Menzel's avatar
Robert Menzel committed
137
        glGetBufferParameteriv( mTarget, _parameter, &value );
138
139
140
        return value;
    }

141
142
143
#if ( !defined(ACGL_OPENGL_ES) || (ACGL_OPENGLES_VERSION >= 30))
// desktop or ES 3.0 onwards:

144
#if (ACGL_OPENGL_VERSION >= 32)
145
146
    inline GLint64 getParameter64( GLenum _parameter ) const
    {
Robert Menzel's avatar
Robert Menzel committed
147
        bind( mTarget );
148
        GLint64 value;
Robert Menzel's avatar
Robert Menzel committed
149
        glGetBufferParameteri64v( mTarget, _parameter, &value );
150
151
152
        return value;
    }

Robert Menzel's avatar
Robert Menzel committed
153
public:
154
    //! not side effect free! will bind this buffer to it's last target!
Robert Menzel's avatar
Robert Menzel committed
155
    //! caching of these values on RAM could be a good idea if needed very(!) often (as it's done with the size)!
156
157
158
    //inline GLint64   getSize()        const { return             getParameter64( GL_BUFFER_SIZE         ); }
    inline GLint64   getMapOffset()   const { return             getParameter64( GL_BUFFER_MAP_OFFSET   ); }
    inline GLint64   getMapLength()   const { return             getParameter64( GL_BUFFER_MAP_LENGTH   ); }
159
#else // OpenGL pre 3.2 or OpenGL ES 3.0:
160
161

public:
162
163
164
    //inline GLint     getSize()        const { return             getParameter  ( GL_BUFFER_SIZE         ); }
    inline GLint     getMapOffset()   const { return             getParameter  ( GL_BUFFER_MAP_OFFSET   ); }
    inline GLint     getMapLength()   const { return             getParameter  ( GL_BUFFER_MAP_LENGTH   ); }
165
#endif // OpenGL >= 3.2
166
167
168
    inline GLenum    getAccess()      const { return (GLenum)    getParameter  ( GL_BUFFER_ACCESS       ); }
    inline GLint     getAccessFlags() const { return (GLint)     getParameter  ( GL_BUFFER_ACCESS_FLAGS ); }
    inline GLboolean isMapped()       const { return (GLboolean) getParameter  ( GL_BUFFER_MAPPED       ); }
169

170
171
172
173
#endif // desktop & ES 3
public:
    inline GLenum    getUsage()       const { return (GLenum)    getParameter  ( GL_BUFFER_USAGE        ); }
    
Robert Menzel's avatar
Robert Menzel committed
174
    //! the size is in bytes
175
    inline GLint64   getSize()        const { return mSize; }
176

177
    //! Bind this buffer
178
    inline void bind( GLenum _target ) const
179
    {
Robert Menzel's avatar
Robert Menzel committed
180
        glBindBuffer( _target, mBuffer->mObjectName );
181
182
183
        openGLRareError();
    }

Robert Menzel's avatar
Robert Menzel committed
184
    //! Bind this buffer to its target
185
    inline void bind() const
186
    {
Robert Menzel's avatar
Robert Menzel committed
187
        glBindBuffer( mTarget, mBuffer->mObjectName );
188
189
190
191
192
        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
193
194
    inline void setData( GLenum _target, GLsizeiptr _sizeInBytes, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
        mSize = _sizeInBytes;
195
        bind( _target );
196
        glBufferData( _target, _sizeInBytes, _pData, _usage );
197
198
199
200
        openGLRareError();
    }

    //! Set data for this buffer at the last used target. Use only to init the buffer!
201
202
    inline void setData( GLsizeiptr _sizeInBytes, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
        setData( mTarget, _sizeInBytes, _pData, _usage );
203
204
205
206
    }

    //! Use this to modify the buffer
    inline void setSubData( GLenum _target, GLintptr _offset,
207
                            GLsizeiptr _sizeInBytes, const GLvoid *_pData ) {
208
        bind( _target );
209
        glBufferSubData( _target, _offset, _sizeInBytes, _pData );
210
211
212
213
        openGLRareError();
    }

    //! Use this to modify the buffer
214
215
    inline void setSubData( GLintptr _offset, GLsizeiptr _sizeInBytes, const GLvoid *_pData ) {
        setSubData( mTarget, _offset, _sizeInBytes, _pData );
216
217
218
    }


219
#if ((ACGL_OPENGL_VERSION >= 30) || (ACGL_OPENGLES_VERSION >= 30))
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
    /** 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
236
        return mapRange( mTarget, _offset, _length, _access );
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
    }

    /**
     * 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
255
        flushMappedRange( mTarget, _offset, _length );
256
257
    }

Robert Menzel's avatar
Robert Menzel committed
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
    //! 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 );
    }

281
282
#endif // OpenGL >= 3.0

283
#ifndef ACGL_OPENGLES_VERSION_20
284
285
286
287
288
289
290
291
292
    //! 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
293
        return map( mTarget, _access );
294
295
296
297
298
299
300
301
302
303
    }

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

    inline GLboolean unmap() {
Robert Menzel's avatar
Robert Menzel committed
304
        return unmap( mTarget );
305
    }
306
#endif
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322

    // 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
323
324
325
326
327
328
329
330
331
332
333
334
     * 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();
335
     */
Robert Menzel's avatar
Robert Menzel committed
336
    virtual inline void setTarget( GLenum _target ) { mTarget = _target; }
337
338
339
340
341

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
342
    GLint64            mSize; // as this might get queried often (e.g. ArrayBuffer) we will explicitly mirror it in RAM - bytes
343
344
    SharedBufferObject mBuffer;
    GLenum             mTarget;
345
346
};

Robert Menzel's avatar
Robert Menzel committed
347
ACGL_SMARTPOINTER_TYPEDEFS(Buffer)
348
349
350
351
352

} // OpenGL
} // ACGL

#endif // ACGL_OPENGL_OBJECTS_BUFFER_HH