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

source code of qtbase/src/opengl/qglbuffer.cpp