1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtOpenGL module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QtOpenGL/qgl.h>
43#include <QtOpenGL/private/qgl_p.h>
44#include <QtOpenGL/private/qglextensions_p.h>
45#include <QtCore/qatomic.h>
46#include "qglbuffer.h"
47
48QT_BEGIN_NAMESPACE
49
50/*!
51 \class QGLBuffer
52 \brief The QGLBuffer class provides functions for creating and managing GL buffer objects.
53 \since 4.7
54 \ingroup painting-3D
55
56 Buffer objects are created in the GL server so that the
57 client application can avoid uploading vertices, indices,
58 texture image data, etc every time they are needed.
59
60 QGLBuffer objects can be copied around as a reference to the
61 underlying GL buffer object:
62
63 \code
64 QGLBuffer buffer1(QGLBuffer::IndexBuffer);
65 buffer1.create();
66
67 QGLBuffer buffer2 = buffer1;
68 \endcode
69
70 QGLBuffer performs a shallow copy when objects are copied in this
71 manner, but does not implement copy-on-write semantics. The original
72 object will be affected whenever the copy is modified.
73*/
74
75/*!
76 \enum QGLBuffer::Type
77 This enum defines the type of GL buffer object to create with QGLBuffer.
78
79 \value VertexBuffer Vertex buffer object for use when specifying
80 vertex arrays.
81 \value IndexBuffer Index buffer object for use with \c{glDrawElements()}.
82 \value PixelPackBuffer Pixel pack buffer object for reading pixel
83 data from the GL server (for example, with \c{glReadPixels()}).
84 Not supported under OpenGL/ES.
85 \value PixelUnpackBuffer Pixel unpack buffer object for writing pixel
86 data to the GL server (for example, with \c{glTexImage2D()}).
87 Not supported under OpenGL/ES.
88*/
89
90/*!
91 \enum QGLBuffer::UsagePattern
92 This enum defines the usage pattern of a QGLBuffer object.
93
94 \value StreamDraw The data will be set once and used a few times
95 for drawing operations. Under OpenGL/ES 1.1 this is identical
96 to StaticDraw.
97 \value StreamRead The data will be set once and used a few times
98 for reading data back from the GL server. Not supported
99 under OpenGL/ES.
100 \value StreamCopy The data will be set once and used a few times
101 for reading data back from the GL server for use in further
102 drawing operations. Not supported under OpenGL/ES.
103 \value StaticDraw The data will be set once and used many times
104 for drawing operations.
105 \value StaticRead The data will be set once and used many times
106 for reading data back from the GL server. Not supported
107 under OpenGL/ES.
108 \value StaticCopy The data will be set once and used many times
109 for reading data back from the GL server for use in further
110 drawing operations. Not supported under OpenGL/ES.
111 \value DynamicDraw The data will be modified repeatedly and used
112 many times for drawing operations.
113 \value DynamicRead The data will be modified repeatedly and used
114 many times for reading data back from the GL server.
115 Not supported under OpenGL/ES.
116 \value DynamicCopy The data will be modified repeatedly and used
117 many times for reading data back from the GL server for
118 use in further drawing operations. Not supported under OpenGL/ES.
119*/
120
121/*!
122 \enum QGLBuffer::Access
123 This enum defines the access mode for QGLBuffer::map().
124
125 \value ReadOnly The buffer will be mapped for reading only.
126 \value WriteOnly The buffer will be mapped for writing only.
127 \value ReadWrite The buffer will be mapped for reading and writing.
128*/
129
130class QGLBufferPrivate
131{
132public:
133 QGLBufferPrivate(QGLBuffer::Type t)
134 : ref(1),
135 type(t),
136 guard(0),
137 usagePattern(QGLBuffer::StaticDraw),
138 actualUsagePattern(QGLBuffer::StaticDraw)
139 {
140 }
141
142 QAtomicInt ref;
143 QGLBuffer::Type type;
144 QGLSharedResourceGuard guard;
145 QGLBuffer::UsagePattern usagePattern;
146 QGLBuffer::UsagePattern actualUsagePattern;
147};
148
149/*!
150 Constructs a new buffer object of type QGLBuffer::VertexBuffer.
151
152 Note: this constructor just creates the QGLBuffer instance. The actual
153 buffer object in the GL server is not created until create() is called.
154
155 \sa create()
156*/
157QGLBuffer::QGLBuffer()
158 : d_ptr(new QGLBufferPrivate(QGLBuffer::VertexBuffer))
159{
160}
161
162/*!
163 Constructs a new buffer object of \a type.
164
165 Note: this constructor just creates the QGLBuffer instance. The actual
166 buffer object in the GL server is not created until create() is called.
167
168 \sa create()
169*/
170QGLBuffer::QGLBuffer(QGLBuffer::Type type)
171 : d_ptr(new QGLBufferPrivate(type))
172{
173}
174
175/*!
176 Constructs a shallow copy of \a other.
177
178 Note: QGLBuffer does not implement copy-on-write semantics,
179 so \a other will be affected whenever the copy is modified.
180*/
181QGLBuffer::QGLBuffer(const QGLBuffer &other)
182 : d_ptr(other.d_ptr)
183{
184 d_ptr->ref.ref();
185}
186
187#define ctx d->guard.context()
188
189/*!
190 Destroys this buffer object, including the storage being
191 used in the GL server.
192*/
193QGLBuffer::~QGLBuffer()
194{
195 if (!d_ptr->ref.deref()) {
196 destroy();
197 delete d_ptr;
198 }
199}
200
201/*!
202 Assigns a shallow copy of \a other to this object.
203
204 Note: QGLBuffer does not implement copy-on-write semantics,
205 so \a other will be affected whenever the copy is modified.
206*/
207QGLBuffer &QGLBuffer::operator=(const QGLBuffer &other)
208{
209 if (d_ptr != other.d_ptr) {
210 other.d_ptr->ref.ref();
211 if (!d_ptr->ref.deref()) {
212 destroy();
213 delete d_ptr;
214 }
215 d_ptr = other.d_ptr;
216 }
217 return *this;
218}
219
220/*!
221 Returns the type of buffer represented by this object.
222*/
223QGLBuffer::Type QGLBuffer::type() const
224{
225 Q_D(const QGLBuffer);
226 return d->type;
227}
228
229/*!
230 Returns the usage pattern for this buffer object.
231 The default value is StaticDraw.
232
233 \sa setUsagePattern()
234*/
235QGLBuffer::UsagePattern QGLBuffer::usagePattern() const
236{
237 Q_D(const QGLBuffer);
238 return d->usagePattern;
239}
240
241/*!
242 Sets the usage pattern for this buffer object to \a value.
243 This function must be called before allocate() or write().
244
245 \sa usagePattern(), allocate(), write()
246*/
247void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
248{
249 Q_D(QGLBuffer);
250#if defined(QT_OPENGL_ES_1)
251 // OpenGL/ES 1.1 does not support GL_STREAM_DRAW, so use GL_STATIC_DRAW.
252 // OpenGL/ES 2.0 does support GL_STREAM_DRAW.
253 d->usagePattern = value;
254 if (value == StreamDraw)
255 d->actualUsagePattern = StaticDraw;
256 else
257 d->actualUsagePattern = value;
258#else
259 d->usagePattern = d->actualUsagePattern = value;
260#endif
261}
262
263#undef ctx
264
265/*!
266 Creates the buffer object in the GL server. Returns true if
267 the object was created; false otherwise.
268
269 This function must be called with a current QGLContext.
270 The buffer will be bound to and can only be used in
271 that context (or any other context that is shared with it).
272
273 This function will return false if the GL implementation
274 does not support buffers, or there is no current QGLContext.
275
276 \sa isCreated(), allocate(), write(), destroy()
277*/
278bool QGLBuffer::create()
279{
280 Q_D(QGLBuffer);
281 if (d->guard.id())
282 return true;
283 const QGLContext *ctx = QGLContext::currentContext();
284 if (ctx) {
285 if (!qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
286 return false;
287 GLuint bufferId = 0;
288 glGenBuffers(1, &bufferId);
289 if (bufferId) {
290 d->guard.setContext(ctx);
291 d->guard.setId(bufferId);
292 return true;
293 }
294 }
295 return false;
296}
297
298#define ctx d->guard.context()
299
300/*!
301 Returns true if this buffer has been created; false otherwise.
302
303 \sa create(), destroy()
304*/
305bool QGLBuffer::isCreated() const
306{
307 Q_D(const QGLBuffer);
308 return d->guard.id() != 0;
309}
310
311/*!
312 Destroys this buffer object, including the storage being
313 used in the GL server. All references to the buffer will
314 become invalid.
315*/
316void QGLBuffer::destroy()
317{
318 Q_D(QGLBuffer);
319 GLuint bufferId = d->guard.id();
320 if (bufferId) {
321 // Switch to the original creating context to destroy it.
322 QGLShareContextScope scope(d->guard.context());
323 glDeleteBuffers(1, &bufferId);
324 }
325 d->guard.setId(0);
326 d->guard.setContext(0);
327}
328
329/*!
330 Reads the \a count bytes in this buffer starting at \a offset
331 into \a data. Returns true on success; false if reading from
332 the buffer is not supported. Buffer reading is not supported
333 under OpenGL/ES.
334
335 It is assumed that this buffer has been bound to the current context.
336
337 \sa write(), bind()
338*/
339bool QGLBuffer::read(int offset, void *data, int count)
340{
341#if !defined(QT_OPENGL_ES)
342 Q_D(QGLBuffer);
343 if (!glGetBufferSubData || !d->guard.id())
344 return false;
345 while (glGetError() != GL_NO_ERROR) ; // Clear error state.
346 glGetBufferSubData(d->type, offset, count, data);
347 return glGetError() == GL_NO_ERROR;
348#else
349 Q_UNUSED(offset);
350 Q_UNUSED(data);
351 Q_UNUSED(count);
352 return false;
353#endif
354}
355
356/*!
357 Replaces the \a count bytes of this buffer starting at \a offset
358 with the contents of \a data. Any other bytes in the buffer
359 will be left unmodified.
360
361 It is assumed that create() has been called on this buffer and that
362 it has been bound to the current context.
363
364 \sa create(), read(), allocate()
365*/
366void QGLBuffer::write(int offset, const void *data, int count)
367{
368#ifndef QT_NO_DEBUG
369 if (!isCreated())
370 qWarning("QGLBuffer::allocate(): buffer not created");
371#endif
372 Q_D(QGLBuffer);
373 if (d->guard.id())
374 glBufferSubData(d->type, offset, count, data);
375}
376
377/*!
378 Allocates \a count bytes of space to the buffer, initialized to
379 the contents of \a data. Any previous contents will be removed.
380
381 It is assumed that create() has been called on this buffer and that
382 it has been bound to the current context.
383
384 \sa create(), read(), write()
385*/
386void QGLBuffer::allocate(const void *data, int count)
387{
388#ifndef QT_NO_DEBUG
389 if (!isCreated())
390 qWarning("QGLBuffer::allocate(): buffer not created");
391#endif
392 Q_D(QGLBuffer);
393 if (d->guard.id())
394 glBufferData(d->type, count, data, d->actualUsagePattern);
395}
396
397/*!
398 \fn void QGLBuffer::allocate(int count)
399 \overload
400
401 Allocates \a count bytes of space to the buffer. Any previous
402 contents will be removed.
403
404 It is assumed that create() has been called on this buffer and that
405 it has been bound to the current context.
406
407 \sa create(), write()
408*/
409
410/*!
411 Binds the buffer associated with this object to the current
412 GL context. Returns false if binding was not possible, usually because
413 type() is not supported on this GL implementation.
414
415 The buffer must be bound to the same QGLContext current when create()
416 was called, or to another QGLContext that is sharing with it.
417 Otherwise, false will be returned from this function.
418
419 \sa release(), create()
420*/
421bool QGLBuffer::bind()
422{
423#ifndef QT_NO_DEBUG
424 if (!isCreated())
425 qWarning("QGLBuffer::bind(): buffer not created");
426#endif
427 Q_D(const QGLBuffer);
428 GLuint bufferId = d->guard.id();
429 if (bufferId) {
430 if (!QGLContext::areSharing(QGLContext::currentContext(),
431 d->guard.context())) {
432#ifndef QT_NO_DEBUG
433 qWarning("QGLBuffer::bind: buffer is not valid in the current context");
434#endif
435 return false;
436 }
437 glBindBuffer(d->type, bufferId);
438 return true;
439 } else {
440 return false;
441 }
442}
443
444/*!
445 Releases the buffer associated with this object from the
446 current GL context.
447
448 This function must be called with the same QGLContext current
449 as when bind() was called on the buffer.
450
451 \sa bind()
452*/
453void QGLBuffer::release()
454{
455#ifndef QT_NO_DEBUG
456 if (!isCreated())
457 qWarning("QGLBuffer::release(): buffer not created");
458#endif
459 Q_D(const QGLBuffer);
460 if (d->guard.id())
461 glBindBuffer(d->type, 0);
462}
463
464#undef ctx
465
466/*!
467 Releases the buffer associated with \a type in the current
468 QGLContext.
469
470 This function is a direct call to \c{glBindBuffer(type, 0)}
471 for use when the caller does not know which QGLBuffer has
472 been bound to the context but wants to make sure that it
473 is released.
474
475 \code
476 QGLBuffer::release(QGLBuffer::VertexBuffer);
477 \endcode
478*/
479void QGLBuffer::release(QGLBuffer::Type type)
480{
481 const QGLContext *ctx = QGLContext::currentContext();
482 if (ctx && qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
483 glBindBuffer(GLenum(type), 0);
484}
485
486#define ctx d->guard.context()
487
488/*!
489 Returns the GL identifier associated with this buffer; zero if
490 the buffer has not been created.
491
492 \sa isCreated()
493*/
494GLuint QGLBuffer::bufferId() const
495{
496 Q_D(const QGLBuffer);
497 return d->guard.id();
498}
499
500#ifndef GL_BUFFER_SIZE
501#define GL_BUFFER_SIZE 0x8764
502#endif
503
504/*!
505 Returns the size of the data in this buffer, for reading operations.
506 Returns -1 if fetching the buffer size is not supported, or the
507 buffer has not been created.
508
509 It is assumed that this buffer has been bound to the current context.
510
511 \sa isCreated(), bind()
512*/
513int QGLBuffer::size() const
514{
515 Q_D(const QGLBuffer);
516 if (!d->guard.id())
517 return -1;
518 GLint value = -1;
519 glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
520 return value;
521}
522
523/*!
524 Maps the contents of this buffer into the application's memory
525 space and returns a pointer to it. Returns null if memory
526 mapping is not possible. The \a access parameter indicates the
527 type of access to be performed.
528
529 It is assumed that create() has been called on this buffer and that
530 it has been bound to the current context.
531
532 This function is only supported under OpenGL/ES if the
533 \c{GL_OES_mapbuffer} extension is present.
534
535 \sa unmap(), create(), bind()
536*/
537void *QGLBuffer::map(QGLBuffer::Access access)
538{
539 Q_D(QGLBuffer);
540#ifndef QT_NO_DEBUG
541 if (!isCreated())
542 qWarning("QGLBuffer::map(): buffer not created");
543#endif
544 if (!d->guard.id())
545 return 0;
546 if (!glMapBufferARB)
547 return 0;
548#ifdef QT_OPENGL_ES_2
549 if (access != QGLBuffer::WriteOnly)
550 return 0;
551#endif
552 return glMapBufferARB(d->type, access);
553}
554
555/*!
556 Unmaps the buffer after it was mapped into the application's
557 memory space with a previous call to map(). Returns true if
558 the unmap succeeded; false otherwise.
559
560 It is assumed that this buffer has been bound to the current context,
561 and that it was previously mapped with map().
562
563 This function is only supported under OpenGL/ES if the
564 \c{GL_OES_mapbuffer} extension is present.
565
566 \sa map()
567*/
568bool QGLBuffer::unmap()
569{
570 Q_D(QGLBuffer);
571#ifndef QT_NO_DEBUG
572 if (!isCreated())
573 qWarning("QGLBuffer::unmap(): buffer not created");
574#endif
575 if (!d->guard.id())
576 return false;
577 if (!glUnmapBufferARB)
578 return false;
579 return glUnmapBufferARB(d->type) == GL_TRUE;
580}
581
582QT_END_NAMESPACE
583