Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qopenglbuffer.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
<
QtGui
/
qopengl
.
h
>
6
#
include
<
QtGui
/
private
/
qopenglcontext_p
.
h
>
7
#
include
<
QtCore
/
qatomic
.
h
>
8
#
include
"qopenglbuffer.h"
9
#
include
<
private
/
qopenglextensions_p
.
h
>
10
11
#
ifndef
GL_CONTEXT_LOST
12
#
define
GL_CONTEXT_LOST
0x0507
13
#
endif
14
15
QT_BEGIN_NAMESPACE
16
17
/*!
18
\class QOpenGLBuffer
19
\brief The QOpenGLBuffer class provides functions for creating and managing OpenGL buffer objects.
20
\since 5.0
21
\ingroup painting-3D
22
\inmodule QtOpenGL
23
24
Buffer objects are created in the OpenGL server so that the
25
client application can avoid uploading vertices, indices,
26
texture image data, etc every time they are needed.
27
28
QOpenGLBuffer objects can be copied around as a reference to the
29
underlying OpenGL buffer object:
30
31
\snippet code/src_gui_opengl_qopenglbuffer.cpp 0
32
33
QOpenGLBuffer performs a shallow copy when objects are copied in this
34
manner, but does not implement copy-on-write semantics. The original
35
object will be affected whenever the copy is modified.
36
37
\warning All data consumed by QOpenGLBuffer is expected to be trusted
38
content. Buffer data is passed on to the underlying OpenGL implementation.
39
Application developers are advised to carefully consider the potential
40
implications before passing in user-provided content to functions such as
41
allocate() and write().
42
*/
43
44
/*!
45
\enum QOpenGLBuffer::Type
46
This enum defines the type of OpenGL buffer object to create with QOpenGLBuffer.
47
48
\value VertexBuffer Vertex buffer object for use when specifying
49
vertex arrays.
50
\value IndexBuffer Index buffer object for use with \c{glDrawElements()}.
51
\value PixelPackBuffer Pixel pack buffer object for reading pixel
52
data from the OpenGL server (for example, with \c{glReadPixels()}).
53
Not supported under OpenGL/ES.
54
\value PixelUnpackBuffer Pixel unpack buffer object for writing pixel
55
data to the OpenGL server (for example, with \c{glTexImage2D()}).
56
Not supported under OpenGL/ES.
57
*/
58
59
/*!
60
\enum QOpenGLBuffer::UsagePattern
61
This enum defines the usage pattern of a QOpenGLBuffer object.
62
63
\value StreamDraw The data will be set once and used a few times
64
for drawing operations. Under OpenGL/ES 1.1 this is identical
65
to StaticDraw.
66
\value StreamRead The data will be set once and used a few times
67
for reading data back from the OpenGL server. Not supported
68
under OpenGL/ES.
69
\value StreamCopy The data will be set once and used a few times
70
for reading data back from the OpenGL server for use in further
71
drawing operations. Not supported under OpenGL/ES.
72
\value StaticDraw The data will be set once and used many times
73
for drawing operations.
74
\value StaticRead The data will be set once and used many times
75
for reading data back from the OpenGL server. Not supported
76
under OpenGL/ES.
77
\value StaticCopy The data will be set once and used many times
78
for reading data back from the OpenGL server for use in further
79
drawing operations. Not supported under OpenGL/ES.
80
\value DynamicDraw The data will be modified repeatedly and used
81
many times for drawing operations.
82
\value DynamicRead The data will be modified repeatedly and used
83
many times for reading data back from the OpenGL server.
84
Not supported under OpenGL/ES.
85
\value DynamicCopy The data will be modified repeatedly and used
86
many times for reading data back from the OpenGL server for
87
use in further drawing operations. Not supported under OpenGL/ES.
88
*/
89
90
/*!
91
\enum QOpenGLBuffer::Access
92
This enum defines the access mode for QOpenGLBuffer::map().
93
94
\value ReadOnly The buffer will be mapped for reading only.
95
\value WriteOnly The buffer will be mapped for writing only.
96
\value ReadWrite The buffer will be mapped for reading and writing.
97
*/
98
99
/*!
100
\enum QOpenGLBuffer::RangeAccessFlag
101
This enum defines the access mode bits for QOpenGLBuffer::mapRange().
102
103
\value RangeRead The buffer will be mapped for reading.
104
\value RangeWrite The buffer will be mapped for writing.
105
\value RangeInvalidate Discard the previous contents of the specified range.
106
\value RangeInvalidateBuffer Discard the previous contents of the entire buffer.
107
\value RangeFlushExplicit Indicates that modifications are to be flushed explicitly via \c glFlushMappedBufferRange.
108
\value RangeUnsynchronized Indicates that pending operations should not be synchronized before returning from mapRange().
109
*/
110
111
class
QOpenGLBufferPrivate
112
{
113
public
:
114
QOpenGLBufferPrivate(QOpenGLBuffer::Type t)
115
: ref(1),
116
type(t),
117
guard(
nullptr
),
118
usagePattern(QOpenGLBuffer::StaticDraw),
119
actualUsagePattern(QOpenGLBuffer::StaticDraw),
120
funcs(
nullptr
)
121
{
122
}
123
124
QAtomicInt ref;
125
QOpenGLBuffer::Type type;
126
QOpenGLSharedResourceGuard *guard;
127
QOpenGLBuffer::UsagePattern usagePattern;
128
QOpenGLBuffer::UsagePattern actualUsagePattern;
129
QOpenGLExtensions *funcs;
130
};
131
132
/*!
133
Constructs a new buffer object of type QOpenGLBuffer::VertexBuffer.
134
135
Note: this constructor just creates the QOpenGLBuffer instance. The actual
136
buffer object in the OpenGL server is not created until create() is called.
137
138
\sa create()
139
*/
140
QOpenGLBuffer::QOpenGLBuffer()
141
: d_ptr(
new
QOpenGLBufferPrivate(QOpenGLBuffer::VertexBuffer))
142
{
143
}
144
145
/*!
146
Constructs a new buffer object of \a type.
147
148
Note: this constructor just creates the QOpenGLBuffer instance. The actual
149
buffer object in the OpenGL server is not created until create() is called.
150
151
\sa create()
152
*/
153
QOpenGLBuffer::QOpenGLBuffer(QOpenGLBuffer::Type type)
154
: d_ptr(
new
QOpenGLBufferPrivate(type))
155
{
156
}
157
158
/*!
159
Constructs a shallow copy of \a other.
160
161
Note: QOpenGLBuffer does not implement copy-on-write semantics,
162
so \a other will be affected whenever the copy is modified.
163
*/
164
QOpenGLBuffer::QOpenGLBuffer(
const
QOpenGLBuffer &other)
165
: d_ptr(other.d_ptr)
166
{
167
d_ptr->ref.ref();
168
}
169
170
/*!
171
Destroys this buffer object, including the storage being
172
used in the OpenGL server.
173
*/
174
QOpenGLBuffer::~QOpenGLBuffer()
175
{
176
if
(d_ptr && !d_ptr->ref.deref()) {
177
destroy();
178
delete
d_ptr;
179
}
180
}
181
182
/*!
183
Assigns a shallow copy of \a other to this object.
184
185
Note: QOpenGLBuffer does not implement copy-on-write semantics,
186
so \a other will be affected whenever the copy is modified.
187
*/
188
QOpenGLBuffer &QOpenGLBuffer::operator=(
const
QOpenGLBuffer &other)
189
{
190
if
(d_ptr != other.d_ptr) {
191
other.d_ptr->ref.ref();
192
if
(d_ptr && !d_ptr->ref.deref()) {
193
destroy();
194
delete
d_ptr;
195
}
196
d_ptr = other.d_ptr;
197
}
198
return
*
this
;
199
}
200
201
/*!
202
\fn QOpenGLBuffer::QOpenGLBuffer(QOpenGLBuffer &&other)
203
\since 6.5
204
205
Move-constructs a new QOpenGLBuffer from \a other.
206
207
\note The moved-from object \a other is placed in a partially-formed state,
208
in which the only valid operations are destruction and assignment of a new
209
value.
210
*/
211
212
/*!
213
\fn QOpenGLBuffer &QOpenGLBuffer::operator=(QOpenGLBuffer &&other)
214
\since 6.5
215
216
Move-assigns \a other to this QOpenGLBuffer instance.
217
218
\note The moved-from object \a other is placed in a partially-formed state,
219
in which the only valid operations are destruction and assignment of a new
220
value.
221
*/
222
223
/*!
224
\fn QOpenGLBuffer::swap(QOpenGLBuffer &other)
225
\since 6.5
226
\memberswap{buffer}
227
*/
228
229
/*!
230
Returns the type of buffer represented by this object.
231
*/
232
QOpenGLBuffer::Type QOpenGLBuffer::type()
const
233
{
234
Q_D(
const
QOpenGLBuffer);
235
return
d->type;
236
}
237
238
/*!
239
Returns the usage pattern for this buffer object.
240
The default value is StaticDraw.
241
242
\sa setUsagePattern()
243
*/
244
QOpenGLBuffer::UsagePattern QOpenGLBuffer::usagePattern()
const
245
{
246
Q_D(
const
QOpenGLBuffer);
247
return
d->usagePattern;
248
}
249
250
/*!
251
Sets the usage pattern for this buffer object to \a value.
252
This function must be called before allocate() or write().
253
254
\sa usagePattern(), allocate(), write()
255
*/
256
void
QOpenGLBuffer::setUsagePattern(QOpenGLBuffer::UsagePattern value)
257
{
258
Q_D(QOpenGLBuffer);
259
d->usagePattern = d->actualUsagePattern = value;
260
}
261
262
namespace
{
263
void
freeBufferFunc(QOpenGLFunctions *funcs, GLuint id)
264
{
265
funcs->glDeleteBuffers(1, &id);
266
}
267
}
268
269
/*!
270
Creates the buffer object in the OpenGL server. Returns \c true if
271
the object was created; false otherwise.
272
273
This function must be called with a current QOpenGLContext.
274
The buffer will be bound to and can only be used in
275
that context (or any other context that is shared with it).
276
277
This function will return false if the OpenGL implementation
278
does not support buffers, or there is no current QOpenGLContext.
279
280
\sa isCreated(), allocate(), write(), destroy()
281
*/
282
bool
QOpenGLBuffer::create()
283
{
284
Q_D(QOpenGLBuffer);
285
if
(d->guard && d->guard->id())
286
return
true
;
287
QOpenGLContext *ctx = QOpenGLContext::currentContext();
288
if
(ctx) {
289
delete
d->funcs;
290
d->funcs =
new
QOpenGLExtensions(ctx);
291
GLuint bufferId = 0;
292
d->funcs->glGenBuffers(1, &bufferId);
293
if
(bufferId) {
294
if
(d->guard)
295
d->guard->free();
296
297
d->guard =
new
QOpenGLSharedResourceGuard(ctx, bufferId, freeBufferFunc);
298
return
true
;
299
}
300
}
301
return
false
;
302
}
303
304
/*!
305
Returns \c true if this buffer has been created; false otherwise.
306
307
\sa create(), destroy()
308
*/
309
bool
QOpenGLBuffer::isCreated()
const
310
{
311
Q_D(
const
QOpenGLBuffer);
312
return
d->guard && d->guard->id();
313
}
314
315
/*!
316
Destroys this buffer object, including the storage being
317
used in the OpenGL server. All references to the buffer will
318
become invalid.
319
*/
320
void
QOpenGLBuffer::destroy()
321
{
322
Q_D(QOpenGLBuffer);
323
if
(d->guard) {
324
d->guard->free();
325
d->guard =
nullptr
;
326
}
327
delete
d->funcs;
328
d->funcs =
nullptr
;
329
}
330
331
/*!
332
Reads the \a count bytes in this buffer starting at \a offset
333
into \a data. Returns \c true on success; false if reading from
334
the buffer is not supported. Buffer reading is not supported
335
under OpenGL/ES.
336
337
It is assumed that this buffer has been bound to the current context.
338
339
\sa write(), bind()
340
*/
341
bool
QOpenGLBuffer::read(
int
offset,
void
*data,
int
count)
342
{
343
#
if
!
QT_CONFIG
(
opengles2
)
344
Q_D(QOpenGLBuffer);
345
if
(!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id())
346
return
false
;
347
348
while
(
true
) {
// Clear error state.
349
GLenum error = d->funcs->glGetError();
350
if
(error == GL_NO_ERROR)
351
break
;
352
if
(error == GL_CONTEXT_LOST)
353
return
false
;
354
};
355
d->funcs->glGetBufferSubData(d->type, offset, count, data);
356
return
d->funcs->glGetError() == GL_NO_ERROR;
357
#
else
358
Q_UNUSED(offset);
359
Q_UNUSED(data);
360
Q_UNUSED(count);
361
return
false
;
362
#
endif
363
}
364
365
/*!
366
Replaces the \a count bytes of this buffer starting at \a offset
367
with the contents of \a data. Any other bytes in the buffer
368
will be left unmodified.
369
370
It is assumed that create() has been called on this buffer and that
371
it has been bound to the current context.
372
373
\sa create(), read(), allocate()
374
*/
375
void
QOpenGLBuffer::write(
int
offset,
const
void
*data,
int
count)
376
{
377
#
ifndef
QT_NO_DEBUG
378
if
(!isCreated())
379
qWarning(
"QOpenGLBuffer::write(): buffer not created"
);
380
#
endif
381
Q_D(QOpenGLBuffer);
382
if
(d->guard && d->guard->id())
383
d->funcs->glBufferSubData(d->type, offset, count, data);
384
}
385
386
/*!
387
Allocates \a count bytes of space to the buffer, initialized to
388
the contents of \a data. Any previous contents will be removed.
389
390
It is assumed that create() has been called on this buffer and that
391
it has been bound to the current context.
392
393
\sa create(), read(), write()
394
*/
395
void
QOpenGLBuffer::allocate(
const
void
*data,
int
count)
396
{
397
#
ifndef
QT_NO_DEBUG
398
if
(!isCreated())
399
qWarning(
"QOpenGLBuffer::allocate(): buffer not created"
);
400
#
endif
401
Q_D(QOpenGLBuffer);
402
if
(d->guard && d->guard->id())
403
d->funcs->glBufferData(d->type, count, data, d->actualUsagePattern);
404
}
405
406
/*!
407
\fn void QOpenGLBuffer::allocate(int count)
408
\overload
409
410
Allocates \a count bytes of space to the buffer. Any previous
411
contents will be removed.
412
413
It is assumed that create() has been called on this buffer and that
414
it has been bound to the current context.
415
416
\sa create(), write()
417
*/
418
419
/*!
420
Binds the buffer associated with this object to the current
421
OpenGL context. Returns \c false if binding was not possible, usually because
422
type() is not supported on this OpenGL implementation.
423
424
The buffer must be bound to the same QOpenGLContext current when create()
425
was called, or to another QOpenGLContext that is sharing with it.
426
Otherwise, false will be returned from this function.
427
428
\sa release(), create()
429
*/
430
bool
QOpenGLBuffer::bind()
431
{
432
#
ifndef
QT_NO_DEBUG
433
if
(!isCreated())
434
qWarning(
"QOpenGLBuffer::bind(): buffer not created"
);
435
#
endif
436
Q_D(
const
QOpenGLBuffer);
437
GLuint bufferId = d->guard ? d->guard->id() : 0;
438
if
(bufferId) {
439
if
(d->guard->group() != QOpenGLContextGroup::currentContextGroup()) {
440
#
ifndef
QT_NO_DEBUG
441
qWarning(
"QOpenGLBuffer::bind: buffer is not valid in the current context"
);
442
#
endif
443
return
false
;
444
}
445
d->funcs->glBindBuffer(d->type, bufferId);
446
return
true
;
447
}
else
{
448
return
false
;
449
}
450
}
451
452
/*!
453
Releases the buffer associated with this object from the
454
current OpenGL context.
455
456
This function must be called with the same QOpenGLContext current
457
as when bind() was called on the buffer.
458
459
\sa bind()
460
*/
461
void
QOpenGLBuffer::release()
462
{
463
#
ifndef
QT_NO_DEBUG
464
if
(!isCreated())
465
qWarning(
"QOpenGLBuffer::release(): buffer not created"
);
466
#
endif
467
Q_D(
const
QOpenGLBuffer);
468
if
(d->guard && d->guard->id())
469
d->funcs->glBindBuffer(d->type, 0);
470
}
471
472
/*!
473
Releases the buffer associated with \a type in the current
474
QOpenGLContext.
475
476
This function is a direct call to \c{glBindBuffer(type, 0)}
477
for use when the caller does not know which QOpenGLBuffer has
478
been bound to the context but wants to make sure that it
479
is released.
480
481
\snippet code/src_gui_opengl_qopenglbuffer.cpp 1
482
*/
483
void
QOpenGLBuffer::release(QOpenGLBuffer::Type type)
484
{
485
QOpenGLContext *ctx = QOpenGLContext::currentContext();
486
if
(ctx)
487
ctx->functions()->glBindBuffer(GLenum(type), 0);
488
}
489
490
/*!
491
Returns the OpenGL identifier associated with this buffer; zero if
492
the buffer has not been created.
493
494
\sa isCreated()
495
*/
496
GLuint QOpenGLBuffer::bufferId()
const
497
{
498
Q_D(
const
QOpenGLBuffer);
499
return
d->guard ? d->guard->id() : 0;
500
}
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
*/
511
int
QOpenGLBuffer::size()
const
512
{
513
Q_D(
const
QOpenGLBuffer);
514
if
(!d->guard || !d->guard->id())
515
return
-1;
516
GLint value = -1;
517
d->funcs->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
\note This function is only supported under OpenGL ES 2.0 or
531
earlier if the \c GL_OES_mapbuffer extension is present.
532
533
\note On OpenGL ES 3.0 and newer, or, in case if desktop OpenGL,
534
if \c GL_ARB_map_buffer_range is supported, this function uses
535
\c glMapBufferRange instead of \c glMapBuffer.
536
537
\sa unmap(), create(), bind(), mapRange()
538
*/
539
void
*QOpenGLBuffer::map(QOpenGLBuffer::Access access)
540
{
541
Q_D(QOpenGLBuffer);
542
#
ifndef
QT_NO_DEBUG
543
if
(!isCreated())
544
qWarning(
"QOpenGLBuffer::map(): buffer not created"
);
545
#
endif
546
if
(!d->guard || !d->guard->id())
547
return
nullptr
;
548
if
(d->funcs->hasOpenGLExtension(QOpenGLExtensions::MapBufferRange)) {
549
QOpenGLBuffer::RangeAccessFlags rangeAccess;
550
switch
(access) {
551
case
QOpenGLBuffer::ReadOnly:
552
rangeAccess = QOpenGLBuffer::RangeRead;
553
break
;
554
case
QOpenGLBuffer::WriteOnly:
555
rangeAccess = QOpenGLBuffer::RangeWrite;
556
break
;
557
case
QOpenGLBuffer::ReadWrite:
558
rangeAccess = QOpenGLBuffer::RangeRead | QOpenGLBuffer::RangeWrite;
559
break
;
560
}
561
return
d->funcs->glMapBufferRange(d->type, 0, size(), rangeAccess);
562
}
else
{
563
return
d->funcs->glMapBuffer(d->type, access);
564
}
565
}
566
567
/*!
568
Maps the range specified by \a offset and \a count of the contents
569
of this buffer into the application's memory space and returns a
570
pointer to it. Returns null if memory mapping is not possible.
571
The \a access parameter specifies a combination of access flags.
572
573
It is assumed that create() has been called on this buffer and that
574
it has been bound to the current context.
575
576
\note This function is not available on OpenGL ES 2.0 and earlier.
577
578
\sa unmap(), create(), bind()
579
*/
580
void
*QOpenGLBuffer::mapRange(
int
offset,
int
count, QOpenGLBuffer::RangeAccessFlags access)
581
{
582
Q_D(QOpenGLBuffer);
583
#
ifndef
QT_NO_DEBUG
584
if
(!isCreated())
585
qWarning(
"QOpenGLBuffer::mapRange(): buffer not created"
);
586
#
endif
587
if
(!d->guard || !d->guard->id())
588
return
nullptr
;
589
return
d->funcs->glMapBufferRange(d->type, offset, count, access);
590
}
591
592
/*!
593
Unmaps the buffer after it was mapped into the application's
594
memory space with a previous call to map(). Returns \c true if
595
the unmap succeeded; false otherwise.
596
597
It is assumed that this buffer has been bound to the current context,
598
and that it was previously mapped with map().
599
600
\note This function is only supported under OpenGL ES 2.0 and
601
earlier if the \c{GL_OES_mapbuffer} extension is present.
602
603
\sa map()
604
*/
605
bool
QOpenGLBuffer::unmap()
606
{
607
Q_D(QOpenGLBuffer);
608
#
ifndef
QT_NO_DEBUG
609
if
(!isCreated())
610
qWarning(
"QOpenGLBuffer::unmap(): buffer not created"
);
611
#
endif
612
if
(!d->guard || !d->guard->id())
613
return
false
;
614
return
d->funcs->glUnmapBuffer(d->type) == GL_TRUE;
615
}
616
617
QT_END_NAMESPACE
qtbase
src
opengl
qopenglbuffer.cpp
Generated on
for Qt by
1.18.0