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
34
////////////////////////////////////////////////////////////////////////////////
// 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>
#include <tr1/memory>

namespace ACGL{
namespace OpenGL{


Robert Menzel's avatar
Robert Menzel committed
35
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 {
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    GLuint mObjectName;
};
typedef std::tr1::shared_ptr<BufferObject> SharedBufferObject;


/**
 * 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.
82
    Buffer( GLenum _target ) : mTarget(_target), mSize(0)
Robert Menzel's avatar
Robert Menzel committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
    {
        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),
97
98
          mBuffer( _pBuffer ),
          mSize(0)
Robert Menzel's avatar
Robert Menzel committed
99
    {}
100
101
102
103
104

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

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

#if (ACGL_OPENGL_VERSION >= 32)
    inline GLint64 getParameter64( GLenum _parameter ) {
Robert Menzel's avatar
Robert Menzel committed
126
        bind( mTarget );
127
        GLint64 value;
Robert Menzel's avatar
Robert Menzel committed
128
        glGetBufferParameteri64v( mTarget, _parameter, &value );
129
130
131
132
133
        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!
134
    //inline GLint64   getSize()        { return             getParameter64( GL_BUFFER_SIZE         ); }
135
136
137
    inline GLint64   getMapOffset()   { return             getParameter64( GL_BUFFER_MAP_OFFSET   ); }
    inline GLint64   getMapLength()   { return             getParameter64( GL_BUFFER_MAP_LENGTH   ); }
#else // OpenGL pre 3.2:
138
    //inline GLint     getSize()        { return             getParameter  ( GL_BUFFER_SIZE         ); }
139
140
141
142
143
144
145
146
    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       ); }

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

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

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

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


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

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

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

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

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

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

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

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

} // OpenGL
} // ACGL

#endif // ACGL_OPENGL_OBJECTS_BUFFER_HH