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 | |
48 | QT_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 | |
130 | class QGLBufferPrivate |
131 | { |
132 | public: |
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 | */ |
157 | QGLBuffer::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 | */ |
170 | QGLBuffer::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 | */ |
181 | QGLBuffer::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 | */ |
193 | QGLBuffer::~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 | */ |
207 | QGLBuffer &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 | */ |
223 | QGLBuffer::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 | */ |
235 | QGLBuffer::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 | */ |
247 | void 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 | */ |
278 | bool 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 | */ |
305 | bool 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 | */ |
316 | void 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 | */ |
339 | bool 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 | */ |
366 | void 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 | */ |
386 | void 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 | */ |
421 | bool 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 | */ |
453 | void 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 | */ |
479 | void 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 | */ |
494 | GLuint 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 | */ |
513 | int 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 | */ |
537 | void *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 | */ |
568 | bool 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 | |
582 | QT_END_NAMESPACE |
583 | |