Buffer.hh 13.2 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
    {
Robert Menzel's avatar
Robert Menzel committed
47
        mObjectName = 0;
48
49
50
        glGenBuffers(1, &mObjectName);
    }

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

    //! 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
66
};
Robert Menzel's avatar
Robert Menzel committed
67
typedef ptr::shared_ptr<BufferObject> SharedBufferObject;
Robert Menzel's avatar
Robert Menzel committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87


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

108
    virtual ~Buffer(){}
Robert Menzel's avatar
Robert Menzel committed
109

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

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

137
138
139
#if ( !defined(ACGL_OPENGL_ES) || (ACGL_OPENGLES_VERSION >= 30))
// desktop or ES 3.0 onwards:

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

Robert Menzel's avatar
Robert Menzel committed
149
public:
150
    //! not side effect free! will bind this buffer to it's last target!
Robert Menzel's avatar
Robert Menzel committed
151
    //! caching of these values on RAM could be a good idea if needed very(!) often (as it's done with the size)!
152
153
154
    //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   ); }
155
#else // OpenGL pre 3.2 or OpenGL ES 3.0:
156
157

public:
158
159
160
    //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   ); }
161
#endif // OpenGL >= 3.2
162
163
164
    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       ); }
165

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

173
    //! Bind this buffer
174
    inline void bind( GLenum _target ) const
175
    {
Robert Menzel's avatar
Robert Menzel committed
176
        glBindBuffer( _target, mBuffer->mObjectName );
177
178
    }

Robert Menzel's avatar
Robert Menzel committed
179
    //! Bind this buffer to its target
180
    inline void bind() const
181
    {
Robert Menzel's avatar
Robert Menzel committed
182
        glBindBuffer( mTarget, mBuffer->mObjectName );
183
184
185
186
    }

    //! Set data for this buffer. Use only to init the buffer!
    //! Note: The function is not const, because it changes the corresponding GPU data
187
188
    inline void setData( GLenum _target, GLsizeiptr _sizeInBytes, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
        mSize = _sizeInBytes;
189
        bind( _target );
190
        glBufferData( _target, _sizeInBytes, _pData, _usage );
191
192
193
    }

    //! Set data for this buffer at the last used target. Use only to init the buffer!
194
195
    inline void setData( GLsizeiptr _sizeInBytes, const GLvoid *_pData = NULL, GLenum _usage = GL_STATIC_DRAW ) {
        setData( mTarget, _sizeInBytes, _pData, _usage );
196
197
198
199
    }

    //! Use this to modify the buffer
    inline void setSubData( GLenum _target, GLintptr _offset,
200
                            GLsizeiptr _sizeInBytes, const GLvoid *_pData ) {
201
        bind( _target );
202
        glBufferSubData( _target, _offset, _sizeInBytes, _pData );
203
204
205
    }

    //! Use this to modify the buffer
206
207
    inline void setSubData( GLintptr _offset, GLsizeiptr _sizeInBytes, const GLvoid *_pData ) {
        setSubData( mTarget, _offset, _sizeInBytes, _pData );
208
209
210
    }


211
#if ((ACGL_OPENGL_VERSION >= 30) || (ACGL_OPENGLES_VERSION >= 30))
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    /** 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 );
        return ret;
    }

    inline GLvoid *mapRange( GLintptr _offset, GLsizeiptr _length, GLbitfield _access ) {
Robert Menzel's avatar
Robert Menzel committed
227
        return mapRange( mTarget, _offset, _length, _access );
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
    }

    /**
     * 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 );
    }

    inline void flushMappedRange( GLintptr _offset, GLsizeiptr _length ) {
Robert Menzel's avatar
Robert Menzel committed
245
        flushMappedRange( mTarget, _offset, _length );
246
247
    }

Robert Menzel's avatar
Robert Menzel committed
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
    //! 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 );
    }

271
272
#endif // OpenGL >= 3.0

273
#ifndef ACGL_OPENGLES_VERSION_20
274
275
276
277
278
279
280
281
    //! 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 );
        return ret;
    }
    inline GLvoid *map( GLenum _access ) {
Robert Menzel's avatar
Robert Menzel committed
282
        return map( mTarget, _access );
283
284
285
286
287
288
289
290
291
    }

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

    inline GLboolean unmap() {
Robert Menzel's avatar
Robert Menzel committed
292
        return unmap( mTarget );
293
    }
294
#endif
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310

    // 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
311
312
313
314
315
316
317
318
319
320
321
322
     * 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();
323
     */
Robert Menzel's avatar
Robert Menzel committed
324
    virtual inline void setTarget( GLenum _target ) { mTarget = _target; }
325
326
327
328
329

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
330
    GLint64            mSize; // as this might get queried often (e.g. ArrayBuffer) we will explicitly mirror it in RAM - bytes
331
332
    SharedBufferObject mBuffer;
    GLenum             mTarget;
333
334
};

Robert Menzel's avatar
Robert Menzel committed
335
ACGL_SMARTPOINTER_TYPEDEFS(Buffer)
336
337
338
339
340

} // OpenGL
} // ACGL

#endif // ACGL_OPENGL_OBJECTS_BUFFER_HH