source: trunk/src/opengl/qglbuffer.cpp@ 1099

Last change on this file since 1099 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 16.5 KB
RevLine 
[844]1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtOpenGL module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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 d_ptr = other.d_ptr;
214 }
215 return *this;
216}
217
218/*!
219 Returns the type of buffer represented by this object.
220*/
221QGLBuffer::Type QGLBuffer::type() const
222{
223 Q_D(const QGLBuffer);
224 return d->type;
225}
226
227/*!
228 Returns the usage pattern for this buffer object.
229 The default value is StaticDraw.
230
231 \sa setUsagePattern()
232*/
233QGLBuffer::UsagePattern QGLBuffer::usagePattern() const
234{
235 Q_D(const QGLBuffer);
236 return d->usagePattern;
237}
238
239/*!
240 Sets the usage pattern for this buffer object to \a value.
241 This function must be called before allocate() or write().
242
243 \sa usagePattern(), allocate(), write()
244*/
245void QGLBuffer::setUsagePattern(QGLBuffer::UsagePattern value)
246{
247 Q_D(QGLBuffer);
248#if defined(QT_OPENGL_ES_1)
249 // OpenGL/ES 1.1 does not support GL_STREAM_DRAW, so use GL_STATIC_DRAW.
250 // OpenGL/ES 2.0 does support GL_STREAM_DRAW.
251 d->usagePattern = value;
252 if (value == StreamDraw)
253 d->actualUsagePattern = StaticDraw;
254 else
255 d->actualUsagePattern = value;
256#else
257 d->usagePattern = d->actualUsagePattern = value;
258#endif
259}
260
261#undef ctx
262
263/*!
264 Creates the buffer object in the GL server. Returns true if
265 the object was created; false otherwise.
266
267 This function must be called with a current QGLContext.
268 The buffer will be bound to and can only be used in
269 that context (or any other context that is shared with it).
270
271 This function will return false if the GL implementation
272 does not support buffers, or there is no current QGLContext.
273
274 \sa isCreated(), allocate(), write(), destroy()
275*/
276bool QGLBuffer::create()
277{
278 Q_D(QGLBuffer);
279 if (d->guard.id())
280 return true;
281 const QGLContext *ctx = QGLContext::currentContext();
282 if (ctx) {
283 if (!qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
284 return false;
285 GLuint bufferId = 0;
286 glGenBuffers(1, &bufferId);
287 if (bufferId) {
288 d->guard.setContext(ctx);
289 d->guard.setId(bufferId);
290 return true;
291 }
292 }
293 return false;
294}
295
296#define ctx d->guard.context()
297
298/*!
299 Returns true if this buffer has been created; false otherwise.
300
301 \sa create(), destroy()
302*/
303bool QGLBuffer::isCreated() const
304{
305 Q_D(const QGLBuffer);
306 return d->guard.id() != 0;
307}
308
309/*!
310 Destroys this buffer object, including the storage being
311 used in the GL server. All references to the buffer will
312 become invalid.
313*/
314void QGLBuffer::destroy()
315{
316 Q_D(QGLBuffer);
317 GLuint bufferId = d->guard.id();
318 if (bufferId) {
319 // Switch to the original creating context to destroy it.
320 QGLShareContextScope scope(d->guard.context());
321 glDeleteBuffers(1, &bufferId);
322 }
323 d->guard.setId(0);
324 d->guard.setContext(0);
325}
326
327/*!
328 Reads the \a count bytes in this buffer starting at \a offset
329 into \a data. Returns 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 (!glGetBufferSubData || !d->guard.id())
342 return false;
343 while (glGetError() != GL_NO_ERROR) ; // Clear error state.
344 glGetBufferSubData(d->type, offset, count, data);
345 return 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("QGLBuffer::allocate(): buffer not created");
369#endif
370 Q_D(QGLBuffer);
371 if (d->guard.id())
372 glBufferSubData(d->type, offset, 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("QGLBuffer::allocate(): buffer not created");
389#endif
390 Q_D(QGLBuffer);
391 if (d->guard.id())
392 glBufferData(d->type, count, data, 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 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("QGLBuffer::bind(): buffer not created");
424#endif
425 Q_D(const QGLBuffer);
426 GLuint bufferId = d->guard.id();
427 if (bufferId) {
428 if (!QGLContext::areSharing(QGLContext::currentContext(),
429 d->guard.context())) {
430#ifndef QT_NO_DEBUG
431 qWarning("QGLBuffer::bind: buffer is not valid in the current context");
432#endif
433 return false;
434 }
435 glBindBuffer(d->type, bufferId);
436 return true;
437 } else {
438 return false;
439 }
440}
441
442/*!
443 Releases the buffer associated with this object from the
444 current GL context.
445
446 This function must be called with the same QGLContext current
447 as when bind() was called on the buffer.
448
449 \sa bind()
450*/
451void QGLBuffer::release()
452{
453#ifndef QT_NO_DEBUG
454 if (!isCreated())
455 qWarning("QGLBuffer::release(): buffer not created");
456#endif
457 Q_D(const QGLBuffer);
458 if (d->guard.id())
459 glBindBuffer(d->type, 0);
460}
461
462#undef ctx
463
464/*!
465 Releases the buffer associated with \a type in the current
466 QGLContext.
467
468 This function is a direct call to \c{glBindBuffer(type, 0)}
469 for use when the caller does not know which QGLBuffer has
470 been bound to the context but wants to make sure that it
471 is released.
472
473 \code
474 QGLBuffer::release(QGLBuffer::VertexBuffer);
475 \endcode
476*/
477void QGLBuffer::release(QGLBuffer::Type type)
478{
479 const QGLContext *ctx = QGLContext::currentContext();
480 if (ctx && qt_resolve_buffer_extensions(const_cast<QGLContext *>(ctx)))
481 glBindBuffer(GLenum(type), 0);
482}
483
484#define ctx d->guard.context()
485
486/*!
487 Returns the GL identifier associated with this buffer; zero if
488 the buffer has not been created.
489
490 \sa isCreated()
491*/
492GLuint QGLBuffer::bufferId() const
493{
494 Q_D(const QGLBuffer);
495 return d->guard.id();
496}
497
498#ifndef GL_BUFFER_SIZE
499#define GL_BUFFER_SIZE 0x8764
500#endif
501
502/*!
503 Returns the size of the data in this buffer, for reading operations.
504 Returns -1 if fetching the buffer size is not supported, or the
505 buffer has not been created.
506
507 It is assumed that this buffer has been bound to the current context.
508
509 \sa isCreated(), bind()
510*/
511int QGLBuffer::size() const
512{
513 Q_D(const QGLBuffer);
514 if (!d->guard.id())
515 return -1;
516 GLint value = -1;
517 glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value);
518 return value;
519}
520
521/*!
522 Maps the contents of this buffer into the application's memory
523 space and returns a pointer to it. Returns null if memory
524 mapping is not possible. The \a access parameter indicates the
525 type of access to be performed.
526
527 It is assumed that create() has been called on this buffer and that
528 it has been bound to the current context.
529
530 This function is only supported under OpenGL/ES if the
531 \c{GL_OES_mapbuffer} extension is present.
532
533 \sa unmap(), create(), bind()
534*/
535void *QGLBuffer::map(QGLBuffer::Access access)
536{
537 Q_D(QGLBuffer);
538#ifndef QT_NO_DEBUG
539 if (!isCreated())
540 qWarning("QGLBuffer::map(): buffer not created");
541#endif
542 if (!d->guard.id())
543 return 0;
544 if (!glMapBufferARB)
545 return 0;
546 return glMapBufferARB(d->type, access);
547}
548
549/*!
550 Unmaps the buffer after it was mapped into the application's
551 memory space with a previous call to map(). Returns true if
552 the unmap succeeded; false otherwise.
553
554 It is assumed that this buffer has been bound to the current context,
555 and that it was previously mapped with map().
556
557 This function is only supported under OpenGL/ES if the
558 \c{GL_OES_mapbuffer} extension is present.
559
560 \sa map()
561*/
562bool QGLBuffer::unmap()
563{
564 Q_D(QGLBuffer);
565#ifndef QT_NO_DEBUG
566 if (!isCreated())
567 qWarning("QGLBuffer::unmap(): buffer not created");
568#endif
569 if (!d->guard.id())
570 return false;
571 if (!glUnmapBufferARB)
572 return false;
573 return glUnmapBufferARB(d->type) == GL_TRUE;
574}
575
576QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.