Buffer.hh 13 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

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

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
private:
122
123
    inline GLint getParameter( GLenum _parameter ) const
    {
Robert Menzel's avatar
Robert Menzel committed
124
        bind( mTarget );
125
        GLint value;
Robert Menzel's avatar
Robert Menzel committed
126
        glGetBufferParameteriv( mTarget, _parameter, &value );
127
128
129
130
        return value;
    }

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

Robert Menzel's avatar
Robert Menzel committed
139
public:
140
    //! not side effect free! will bind this buffer to it's last target!
Robert Menzel's avatar
Robert Menzel committed
141
    //! caching of these values on RAM could be a good idea if needed very(!) often (as it's done with the size)!
142
143
144
    //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   ); }
145
#else // OpenGL pre 3.2:
146
147

public:
148
149
150
    //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   ); }
151
#endif // OpenGL >= 3.2
152
153
154
155
    inline GLenum    getUsage()       const { return (GLenum)    getParameter  ( GL_BUFFER_USAGE        ); }
    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       ); }
156

Robert Menzel's avatar
Robert Menzel committed
157
    //! the size is in bytes
158
    inline GLint64   getSize()        const { return mSize; }
159

160
    //! Bind this buffer
161
    inline void bind( GLenum _target ) const
162
    {
Robert Menzel's avatar
Robert Menzel committed
163
        glBindBuffer( _target, mBuffer->mObjectName );
164
165
166
        openGLRareError();
    }

Robert Menzel's avatar
Robert Menzel committed
167
    //! Bind this buffer to its target
168
    inline void bind() const
169
    {
Robert Menzel's avatar
Robert Menzel committed
170
        glBindBuffer( mTarget, mBuffer->mObjectName );
171
172
173
174
175
        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
176
177
    inline void setData( GLenum _target, GLsizeiptr _sizeInBytes, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
        mSize = _sizeInBytes;
178
        bind( _target );
179
        glBufferData( _target, _sizeInBytes, _pData, _usage );
180
181
182
183
        openGLRareError();
    }

    //! Set data for this buffer at the last used target. Use only to init the buffer!
184
185
    inline void setData( GLsizeiptr _sizeInBytes, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
        setData( mTarget, _sizeInBytes, _pData, _usage );
186
187
188
189
    }

    //! Use this to modify the buffer
    inline void setSubData( GLenum _target, GLintptr _offset,
190
                            GLsizeiptr _sizeInBytes, const GLvoid *_pData ) {
191
        bind( _target );
192
        glBufferSubData( _target, _offset, _sizeInBytes, _pData );
193
194
195
196
        openGLRareError();
    }

    //! Use this to modify the buffer
197
198
    inline void setSubData( GLintptr _offset, GLsizeiptr _sizeInBytes, const GLvoid *_pData ) {
        setSubData( mTarget, _offset, _sizeInBytes, _pData );
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    }


#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
219
        return mapRange( mTarget, _offset, _length, _access );
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
    }

    /**
     * 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
238
        flushMappedRange( mTarget, _offset, _length );
239
240
    }

Robert Menzel's avatar
Robert Menzel committed
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
    //! 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 );
    }

264
265
266
267
268
269
270
271
272
273
274
#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
275
        return map( mTarget, _access );
276
277
278
279
280
281
282
283
284
285
    }

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

    inline GLboolean unmap() {
Robert Menzel's avatar
Robert Menzel committed
286
        return unmap( mTarget );
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    }

    // 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
304
305
306
307
308
309
310
311
312
313
314
315
     * 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();
316
     */
Robert Menzel's avatar
Robert Menzel committed
317
    virtual inline void setTarget( GLenum _target ) { mTarget = _target; }
318
319
320
321
322

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
323
    GLint64            mSize; // as this might get queried often (e.g. ArrayBuffer) we will explicitly mirror it in RAM - bytes
324
325
    SharedBufferObject mBuffer;
    GLenum             mTarget;
326
327
};

Robert Menzel's avatar
Robert Menzel committed
328
ACGL_SMARTPOINTER_TYPEDEFS(Buffer)
329
330
331
332
333

} // OpenGL
} // ACGL

#endif // ACGL_OPENGL_OBJECTS_BUFFER_HH