Buffer.hh 11.6 KB
Newer Older
1
2
3
4
5
6
7
8
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
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

#ifndef ACGL_OPENGL_OBJECTS_BUFFER_HH
#define ACGL_OPENGL_OBJECTS_BUFFER_HH

/*
 * 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
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 {
42
public:
Robert Menzel's avatar
Robert Menzel committed
43
    BufferObject()
44
45
    {
        glGenBuffers(1, &mObjectName);
Robert Menzel's avatar
Robert Menzel committed
46
47
48
49
50
        if (openGLCriticalErrorOccured() ) {
            ACGL::Utils::error() << "could not generate buffer!" << std::endl;
            mObjectName = 0;
            return;
        }
51
52
    }

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


/**
 * 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.
81
    Buffer( GLenum _target ) : mTarget(_target), mSize(0)
Robert Menzel's avatar
Robert Menzel committed
82
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 )
        : mTarget(_target),
96
97
          mBuffer( _pBuffer ),
          mSize(0)
Robert Menzel's avatar
Robert Menzel committed
98
    {}
99
100
101
102
103

    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
Robert Menzel's avatar
Robert Menzel committed
104
105
106
107
108
109
110
111
112
113
    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; }
114
115
116

private:
    inline GLint getParameter( GLenum _parameter ) {
Robert Menzel's avatar
Robert Menzel committed
117
        bind( mTarget );
118
        GLint value;
Robert Menzel's avatar
Robert Menzel committed
119
        glGetBufferParameteriv( mTarget, _parameter, &value );
120
121
122
123
124
        return value;
    }

#if (ACGL_OPENGL_VERSION >= 32)
    inline GLint64 getParameter64( GLenum _parameter ) {
Robert Menzel's avatar
Robert Menzel committed
125
        bind( mTarget );
126
        GLint64 value;
Robert Menzel's avatar
Robert Menzel committed
127
        glGetBufferParameteri64v( mTarget, _parameter, &value );
128
129
130
131
132
        return value;
    }

    //! not side effect free! will bind this buffer to it's last target!
    //! caching of these values on RAM could be a good idea if needed very often!
133
    //inline GLint64   getSize()        { return             getParameter64( GL_BUFFER_SIZE         ); }
134
135
136
    inline GLint64   getMapOffset()   { return             getParameter64( GL_BUFFER_MAP_OFFSET   ); }
    inline GLint64   getMapLength()   { return             getParameter64( GL_BUFFER_MAP_LENGTH   ); }
#else // OpenGL pre 3.2:
137
    //inline GLint     getSize()        { return             getParameter  ( GL_BUFFER_SIZE         ); }
138
139
140
141
142
143
144
145
    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       ); }

146
147
    inline GLint64   getSize()        { return mSize; }

148
149
150
151
152
153
154
    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
public:
    //! Bind this buffer
    inline void bind( GLenum _target )
    {
Robert Menzel's avatar
Robert Menzel committed
155
        glBindBuffer( _target, mBuffer->mObjectName );
156
157
158
        openGLRareError();
    }

Robert Menzel's avatar
Robert Menzel committed
159
    //! Bind this buffer to its target
160
161
    inline void bind()
    {
Robert Menzel's avatar
Robert Menzel committed
162
        glBindBuffer( mTarget, mBuffer->mObjectName );
163
164
165
166
167
168
        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 ) {
169
        mSize = _size;
170
171
172
173
174
175
176
        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
177
        setData( mTarget, _size, _pData, _usage );
178
179
180
181
182
183
184
185
186
187
188
189
    }

    //! 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
190
        setSubData( mTarget, _offset, _size, _pData );
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
    }


#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
211
        return mapRange( mTarget, _offset, _length, _access );
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    }

    /**
     * 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
230
        flushMappedRange( mTarget, _offset, _length );
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
    }

    // TODO: bindBufferRange
    // TODO: bindBufferBase
#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
246
        return map( mTarget, _access );
247
248
249
250
251
252
253
254
255
256
    }

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

    inline GLboolean unmap() {
Robert Menzel's avatar
Robert Menzel committed
257
        return unmap( mTarget );
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
    }

    // 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
275
276
277
278
279
280
281
282
283
284
285
286
     * 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();
287
     */
Robert Menzel's avatar
Robert Menzel committed
288
    virtual inline void setTarget( GLenum _target ) { mTarget = _target; }
289
290
291
292
293

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
Robert Menzel's avatar
Robert Menzel committed
294
295
    GLenum             mTarget;
    SharedBufferObject mBuffer;
Robert Menzel's avatar
Robert Menzel committed
296
    GLint64            mSize; // as this might get queried often (e.g. ArrayBuffer) we will explicitly mirror it in RAM)
297
298
};

Robert Menzel's avatar
Robert Menzel committed
299
ACGL_SHARED_TYPEDEF(Buffer)
300
301
302
303
304

} // OpenGL
} // ACGL

#endif // ACGL_OPENGL_OBJECTS_BUFFER_HH