Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qopenglframebufferobject.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
6
7#include <qdebug.h>
8#include <private/qopengl_p.h>
9#include <private/qopenglcontext_p.h>
10#include <private/qopenglextensions_p.h>
11#include <private/qfont_p.h>
12
13#include <qwindow.h>
14#include <qimage.h>
15#include <QtCore/qbytearray.h>
16
17#include <qtopengl_tracepoints_p.h>
18
20
22 "#include <private/qopengl2pexvertexarray_p.h>" \
23 "#include <private/qopengltextureuploader_p.h>" \
24 "#include <qopenglframebufferobject.h>"
25);
28Q_TRACE_METADATA(qtopengl, "ENUM { } QOpenGLFramebufferObject::Attachment; ");
29
30#ifndef QT_NO_DEBUG
31#define QT_RESET_GLERROR() \
32{ \
33 while (true) {\
34 GLenum error = QOpenGLContext::currentContext()->functions()->glGetError(); \
35 if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST) \
36 break; \
37 } \
38}
39#define QT_CHECK_GLERROR() \
40{ \
41 GLenum err = QOpenGLContext::currentContext()->functions()->glGetError(); \
42 if (err != GL_NO_ERROR && err != GL_CONTEXT_LOST) { \
43 qDebug("[%s line %d] OpenGL Error: %d", \
44 __FILE__, __LINE__, (int)err); \
45 } \
46}
47#else
48#define QT_RESET_GLERROR() {}
49#define QT_CHECK_GLERROR() {}
50#endif
51
52#ifndef GL_MAX_SAMPLES
53#define GL_MAX_SAMPLES 0x8D57
54#endif
55
56#ifndef GL_RENDERBUFFER_SAMPLES
57#define GL_RENDERBUFFER_SAMPLES 0x8CAB
58#endif
59
60#ifndef GL_DEPTH24_STENCIL8
61#define GL_DEPTH24_STENCIL8 0x88F0
62#endif
63
64#ifndef GL_DEPTH_COMPONENT24
65#define GL_DEPTH_COMPONENT24 0x81A6
66#endif
67
68#ifndef GL_DEPTH_COMPONENT24_OES
69#define GL_DEPTH_COMPONENT24_OES 0x81A6
70#endif
71
72#ifndef GL_READ_FRAMEBUFFER
73#define GL_READ_FRAMEBUFFER 0x8CA8
74#endif
75
76#ifndef GL_DRAW_FRAMEBUFFER
77#define GL_DRAW_FRAMEBUFFER 0x8CA9
78#endif
79
80#ifndef GL_RGB8
81#define GL_RGB8 0x8051
82#endif
83
84#ifndef GL_RGB10
85#define GL_RGB10 0x8052
86#endif
87
88#ifndef GL_RGB16
89#define GL_RGB16 0x8054
90#endif
91
92#ifndef GL_RGBA8
93#define GL_RGBA8 0x8058
94#endif
95
96#ifndef GL_RGB10_A2
97#define GL_RGB10_A2 0x8059
98#endif
99
100#ifndef GL_RGBA16
101#define GL_RGBA16 0x805B
102#endif
103
104#ifndef GL_BGRA
105#define GL_BGRA 0x80E1
106#endif
107
108#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
109#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
110#endif
111
112#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
113#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
114#endif
115
116#ifndef GL_CONTEXT_LOST
117#define GL_CONTEXT_LOST 0x0507
118#endif
119
120#ifndef GL_DEPTH_STENCIL_ATTACHMENT
121#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
122#endif
123
124#ifndef GL_DEPTH_STENCIL
125#define GL_DEPTH_STENCIL 0x84F9
126#endif
127
128#ifndef GL_HALF_FLOAT
129#define GL_HALF_FLOAT 0x140B
130#endif
131
132#ifndef GL_RGBA32F
133#define GL_RGBA32F 0x8814
134#endif
135
136#ifndef GL_RGB32F
137#define GL_RGB32F 0x8815
138#endif
139
140#ifndef GL_RGBA16F
141#define GL_RGBA16F 0x881A
142#endif
143
144#ifndef GL_RGB16F
145#define GL_RGB16F 0x881B
146#endif
147
148
178void QOpenGLFramebufferObjectFormat::detach()
179{
180 if (d->ref.loadRelaxed() != 1) {
183 if (!d->ref.deref())
184 delete d;
185 d = newd;
186 }
187}
188
201{
203}
204
210{
211 d = other.d;
212 d->ref.ref();
213}
214
220{
221 if (d != other.d) {
222 other.d->ref.ref();
223 if (!d->ref.deref())
224 delete d;
225 d = other.d;
226 }
227 return *this;
228}
229
234{
235 if (!d->ref.deref())
236 delete d;
237}
238
253{
254 detach();
255 d->samples = samples;
256}
257
266{
267 return d->samples;
268}
269
283{
284 detach();
285 d->mipmap = enabled;
286}
287
294{
295 return d->mipmap;
296}
297
304{
305 detach();
307}
308
316{
317 return d->attachment;
318}
319
327{
328 detach();
329 d->target = target;
330}
331
340{
341 return d->target;
342}
343
352{
353 detach();
355}
356
366{
367 return d->internal_format;
368}
369
375{
376 if (d == other.d)
377 return true;
378 else
379 return d->equals(other.d);
380}
381
387{
388 return !(*this == other);
389}
390
392{
393 if (!ctx)
394 return false; // Context no longer exists.
395 GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);
396 switch(status) {
397 case GL_NO_ERROR:
399 return true;
401 qDebug("QOpenGLFramebufferObject: Unsupported framebuffer format.");
402 break;
404 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete attachment.");
405 break;
407 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment.");
408 break;
409#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT
410 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT:
411 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
412 break;
413#endif
414#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
415 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
416 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
417 break;
418#endif
419#ifdef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
420 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
421 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
422 break;
423#endif
424#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
426 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
427 break;
428#endif
429#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
431 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
432 break;
433#endif
434#ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
436 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
437 break;
438#endif
439 default:
440 qDebug() <<"QOpenGLFramebufferObject: An undefined error has occurred: "<< status;
441 break;
442 }
443 return false;
444}
445
446namespace
447{
448 void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)
449 {
450 funcs->glDeleteFramebuffers(1, &id);
451 }
452
453 void freeRenderbufferFunc(QOpenGLFunctions *funcs, GLuint id)
454 {
455 funcs->glDeleteRenderbuffers(1, &id);
456 }
457
458 void freeTextureFunc(QOpenGLFunctions *funcs, GLuint id)
459 {
460 funcs->glDeleteTextures(1, &id);
461 }
462}
463
465 QOpenGLFramebufferObject *qfbo, const QSize &size,
467 GLenum texture_target, GLenum internal_format,
468 GLint samples, bool mipmap)
469{
470 Q_TRACE_SCOPE(QOpenGLFramebufferObjectPrivate_init, qfbo, size, attachment, texture_target, internal_format, samples, mipmap);
471 Q_UNUSED(qfbo);
472
474
476
478 return;
479
480 // Fall back to using a normal non-msaa FBO if we don't have support for MSAA
483 samples = 0;
484 } else if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
485 GLint maxSamples;
486 funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
487 samples = qBound(0, int(samples), int(maxSamples));
488 }
489
490 colorAttachments.append(ColorAttachment(size, internal_format));
491
492 dsSize = size;
493
494 samples = qMax(0, samples);
496
497 target = texture_target;
498
499 QT_RESET_GLERROR(); // reset error state
500 GLuint fbo = 0;
501
504
506
508
509 format.setTextureTarget(target);
510 format.setInternalTextureFormat(internal_format);
511 format.setMipmap(mipmap);
512
513 if (samples == 0)
514 initTexture(0);
515 else
517
518 format.setSamples(int(samples));
519
521
522 if (valid)
523 fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
524 else
526
528}
529
531{
533 GLuint texture = 0;
534
537
538 funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
539 funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
540 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
541 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
542
544
545 GLuint pixelType = GL_UNSIGNED_BYTE;
546 if (color.internalFormat == GL_RGB10_A2 || color.internalFormat == GL_RGB10)
548 else if (color.internalFormat == GL_RGB16 || color.internalFormat == GL_RGBA16)
549 pixelType = GL_UNSIGNED_SHORT;
550 else if (color.internalFormat == GL_RGB16F || color.internalFormat == GL_RGBA16F)
551 pixelType = GL_HALF_FLOAT;
552
553 funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
554 GL_RGBA, pixelType, nullptr);
555 if (format.mipmap()) {
556 int width = color.size.width();
557 int height = color.size.height();
558 int level = 0;
559 while (width > 1 || height > 1) {
560 width = qMax(1, width >> 1);
561 height = qMax(1, height >> 1);
562 ++level;
563 funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0,
564 GL_RGBA, pixelType, nullptr);
565 }
566 }
568 target, texture, 0);
569
573 if (valid) {
574 color.guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
575 } else {
577 }
578}
579
581{
583 GLuint color_buffer = 0;
584
586
587 GLenum storageFormat = color.internalFormat;
588 // ES requires a sized format. The older desktop extension does not. Correct the format on ES.
589 if (ctx->isOpenGLES()) {
590 if (color.internalFormat == GL_RGBA) {
592 storageFormat = GL_RGBA8;
593 else
594 storageFormat = GL_RGBA4;
595 } else if (color.internalFormat == GL_RGB10) {
596 // GL_RGB10 is not allowed in ES for glRenderbufferStorage.
597 storageFormat = GL_RGB10_A2;
598 }
599 }
600
601 funcs.glGenRenderbuffers(1, &color_buffer);
603 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, *samples, storageFormat, color.size.width(), color.size.height());
605 GL_RENDERBUFFER, color_buffer);
606
609 if (valid) {
610 // Query the actual number of samples. This can be greater than the requested
611 // value since the typically supported values are 0, 4, 8, ..., and the
612 // requests are mapped to the next supported value.
614 color.guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
615 } else {
616 funcs.glDeleteRenderbuffers(1, &color_buffer);
617 }
618}
619
622{
623 // Use the same sample count for all attachments. format.samples() already contains
624 // the actual number of samples for the color attachment and is not suitable. Use
625 // requestedSamples instead.
626 const int samples = requestedSamples;
627
628 // free existing attachments
629 if (depth_buffer_guard) {
630#ifdef Q_OS_WASM
632#else
634#endif
636 }
641 }
642
643 depth_buffer_guard = nullptr;
644 stencil_buffer_guard = nullptr;
645
646 GLuint depth_buffer = 0;
647 GLuint stencil_buffer = 0;
648
649 // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
650 // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
651 // might not be supported while separate buffers are, according to QTBUG-12861.
652#ifdef Q_OS_WASM
653 // WebGL doesn't allow separately attach buffers to
654 // STENCIL_ATTACHMENT and DEPTH_ATTACHMENT
655 // QTBUG-69913
657 funcs.glGenRenderbuffers(1, &depth_buffer);
659 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
660
661 if (samples != 0 ) {
664 } else {
667 }
668
670 GL_RENDERBUFFER, depth_buffer);
671
673 if (!valid) {
674 funcs.glDeleteRenderbuffers(1, &depth_buffer);
675 depth_buffer = 0;
676 }
677 }
678#else
681 {
682 // depth and stencil buffer needs another extension
683 funcs.glGenRenderbuffers(1, &depth_buffer);
685 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
689 else
692
693 stencil_buffer = depth_buffer;
695 GL_RENDERBUFFER, depth_buffer);
697 GL_RENDERBUFFER, stencil_buffer);
698
700 if (!valid) {
701 funcs.glDeleteRenderbuffers(1, &depth_buffer);
702 stencil_buffer = depth_buffer = 0;
703 }
704 }
705
708 {
709 funcs.glGenRenderbuffers(1, &depth_buffer);
711 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
713 if (ctx->isOpenGLES()) {
717 else
720 } else {
722 GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());
723 }
724 } else {
725 if (ctx->isOpenGLES()) {
729 } else {
732 }
733 } else {
735 }
736 }
738 GL_RENDERBUFFER, depth_buffer);
740 if (!valid) {
741 funcs.glDeleteRenderbuffers(1, &depth_buffer);
742 depth_buffer = 0;
743 }
744 }
745
746 if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) {
747 funcs.glGenRenderbuffers(1, &stencil_buffer);
749 Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer));
750
751#if QT_CONFIG(opengles2)
753#else
755#endif
756
759 else
761
763 GL_RENDERBUFFER, stencil_buffer);
765 if (!valid) {
766 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
767 stencil_buffer = 0;
768 }
769 }
770#endif //Q_OS_WASM
771
772 // The FBO might have become valid after removing the depth or stencil buffer.
774
775#ifdef Q_OS_WASM
776 if (depth_buffer) {
777#else
778 if (depth_buffer && stencil_buffer) {
779#endif
781 } else if (depth_buffer) {
783 } else {
785 }
786
787 if (valid) {
788 if (depth_buffer)
789 depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
790 if (stencil_buffer) {
791 if (stencil_buffer == depth_buffer)
793 else
794 stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
795 }
796 } else {
797 if (depth_buffer)
798 funcs.glDeleteRenderbuffers(1, &depth_buffer);
799 if (stencil_buffer && depth_buffer != stencil_buffer)
800 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
801 }
803
804 format.setAttachment(fbo_attachment);
805}
806
876{
877 if (!internalFormat)
878#if QT_CONFIG(opengles2)
880#else
882#endif
883 return internalFormat;
884}
885
912{
915}
916
926{
927}
928
937{
939 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
940 format.samples(), format.mipmap());
941}
942
951{
952}
953
970{
973}
974
991{
994}
995
1001{
1003 if (isBound())
1004 release();
1005
1006 for (const auto &color : std::as_const(d->colorAttachments)) {
1007 if (color.guard)
1008 color.guard->free();
1009 }
1010 d->colorAttachments.clear();
1011
1012 if (d->depth_buffer_guard)
1013 d->depth_buffer_guard->free();
1014 if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
1015 d->stencil_buffer_guard->free();
1016 if (d->fbo_guard)
1017 d->fbo_guard->free();
1018
1020 if (contextPrv && contextPrv->qgl_current_fbo == this) {
1021 contextPrv->qgl_current_fbo_invalid = true;
1022 contextPrv->qgl_current_fbo = nullptr;
1023 }
1024}
1025
1056{
1058
1059 if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
1060 qWarning("Multiple render targets not supported, ignoring extra color attachment request");
1061 return;
1062 }
1063
1065 d->colorAttachments.append(color);
1066 const int idx = d->colorAttachments.size() - 1;
1067
1068 if (d->requestedSamples == 0) {
1069 d->initTexture(idx);
1070 } else {
1071 GLint samples = d->requestedSamples;
1072 d->initColorBuffer(idx, &samples);
1073 }
1074}
1075
1086{
1088}
1089
1109{
1110 Q_D(const QOpenGLFramebufferObject);
1111 return d->valid && d->fbo_guard && d->fbo_guard->id();
1112}
1113
1128{
1129 if (!isValid())
1130 return false;
1133 if (!current)
1134 return false;
1135#ifdef QT_DEBUG
1136 if (current->shareGroup() != d->fbo_guard->group())
1137 qWarning("QOpenGLFramebufferObject::bind() called from incompatible context");
1138#endif
1139
1140 d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
1141
1144
1145 if (d->format.samples() == 0) {
1146 // Create new textures to replace the ones stolen via takeTexture().
1147 for (int i = 0; i < d->colorAttachments.size(); ++i) {
1148 if (!d->colorAttachments.at(i).guard)
1149 d->initTexture(i);
1150 }
1151 }
1152
1153 return d->valid;
1154}
1155
1166{
1167 if (!isValid())
1168 return false;
1169
1171 if (!current)
1172 return false;
1173
1175#ifdef QT_DEBUG
1176 if (current->shareGroup() != d->fbo_guard->group())
1177 qWarning("QOpenGLFramebufferObject::release() called from incompatible context");
1178#endif
1179
1180 if (current) {
1181 d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->defaultFramebufferObject());
1182
1184 contextPrv->qgl_current_fbo_invalid = true;
1185 contextPrv->qgl_current_fbo = nullptr;
1186 }
1187
1188 return true;
1189}
1190
1207{
1208 Q_D(const QOpenGLFramebufferObject);
1209 return d->colorAttachments[0].guard ? d->colorAttachments[0].guard->id() : 0;
1210}
1211
1222{
1223 Q_D(const QOpenGLFramebufferObject);
1225 if (d->format.samples() != 0)
1226 return ids;
1227 ids.reserve(d->colorAttachments.size());
1228 for (const auto &color : d->colorAttachments)
1229 ids.append(color.guard ? color.guard->id() : 0);
1230 return ids;
1231}
1232
1252{
1253 return takeTexture(0);
1254}
1255
1276{
1278 GLuint id = 0;
1279 if (isValid() && d->format.samples() == 0 && d->colorAttachments.size() > colorAttachmentIndex) {
1281 if (current && current->shareGroup() == d->fbo_guard->group() && isBound())
1282 release();
1283 auto &guard = d->colorAttachments[colorAttachmentIndex].guard;
1284 id = guard ? guard->id() : 0;
1285 // Do not call free() on texture_guard, just null it out.
1286 // This way the texture will not be deleted when the guard is destroyed.
1287 guard = nullptr;
1288 }
1289 return id;
1290}
1291
1297{
1298 Q_D(const QOpenGLFramebufferObject);
1299 return d->dsSize;
1300}
1301
1309{
1310 Q_D(const QOpenGLFramebufferObject);
1311 QList<QSize> sz;
1312 sz.reserve(d->colorAttachments.size());
1313 for (const auto &color : d->colorAttachments)
1314 sz.append(color.size);
1315 return sz;
1316}
1317
1334{
1335 Q_D(const QOpenGLFramebufferObject);
1336 return d->format;
1337}
1338
1339static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool include_alpha, QOpenGLContext *context)
1340{
1341 QOpenGLFunctions *funcs = context->functions();
1342 const int w = size.width();
1343 const int h = size.height();
1344 bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
1345 if (isOpenGL12orBetter) {
1347 if (!img.isNull())
1348 funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, img.bits());
1349 return img;
1350 }
1351
1352 // For OpenGL ES stick with the byte ordered format / RGBA readback format
1353 // since that is the only spec mandated way. (also, skip the
1354 // GL_IMPLEMENTATION_COLOR_READ_FORMAT mess since there is nothing saying a
1355 // BGRA capable impl would return BGRA from there)
1356
1358 if (!rgbaImage.isNull())
1359 funcs->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits());
1360 return rgbaImage;
1361}
1362
1363static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool include_alpha, QOpenGLContext *context)
1364{
1365 // We assume OpenGL 1.2+ or ES 3.0+ here.
1367 if (!img.isNull())
1368 context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, img.bits());
1369 return img;
1370}
1371
1372static inline QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool include_alpha, QOpenGLContext *context)
1373{
1374 // We assume OpenGL 1.2+ or ES 3.0+ here.
1376 if (!img.isNull())
1377 context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_SHORT, img.bits());
1378 return img;
1379}
1380
1381static inline QImage qt_gl_read_framebuffer_rgba16f(const QSize &size, bool include_alpha, QOpenGLContext *context)
1382{
1383 // We assume OpenGL (ES) 3.0+ here.
1385 if (!img.isNull())
1386 context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_HALF_FLOAT, img.bits());
1387 return img;
1388}
1389
1390static inline QImage qt_gl_read_framebuffer_rgba32f(const QSize &size, bool include_alpha, QOpenGLContext *context)
1391{
1393 if (!img.isNull())
1394 context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_FLOAT, img.bits());
1395 return img;
1396}
1397
1398static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
1399{
1401 QOpenGLFunctions *funcs = ctx->functions();
1402 while (true) {
1403 GLenum error = funcs->glGetError();
1404 if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST)
1405 break;
1406 }
1407 switch (internal_format) {
1408 case GL_RGB:
1409 case GL_RGB8:
1410 return qt_gl_read_framebuffer_rgba8(size, false, ctx).mirrored(false, flip);
1411 case GL_RGB10:
1412 return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);
1413 case GL_RGB10_A2:
1414 return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);
1415 case GL_RGB16:
1416 return qt_gl_read_framebuffer_rgba16(size, false, ctx).mirrored(false, flip);
1417 case GL_RGBA16:
1418 return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).mirrored(false, flip);
1419 case GL_RGB16F:
1420 return qt_gl_read_framebuffer_rgba16f(size, false, ctx).mirrored(false, flip);
1421 case GL_RGBA16F:
1422 return qt_gl_read_framebuffer_rgba16f(size, include_alpha, ctx).mirrored(false, flip);
1423 case GL_RGB32F:
1424 return qt_gl_read_framebuffer_rgba32f(size, false, ctx).mirrored(false, flip);
1425 case GL_RGBA32F:
1426 return qt_gl_read_framebuffer_rgba32f(size, include_alpha, ctx).mirrored(false, flip);
1427 case GL_RGBA:
1428 case GL_RGBA8:
1429 default:
1430 return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).mirrored(false, flip);
1431 }
1432
1433 Q_UNREACHABLE_RETURN(QImage());
1434}
1435
1436Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
1437{
1438 return qt_gl_read_framebuffer(size, alpha_format ? GL_RGBA : GL_RGB, include_alpha, true);
1439}
1440
1480{
1481 return toImage(flipped, 0);
1482}
1483
1497QImage QOpenGLFramebufferObject::toImage(bool flipped, int colorAttachmentIndex) const
1498{
1499 Q_D(const QOpenGLFramebufferObject);
1500 if (!d->valid)
1501 return QImage();
1502
1504 if (!ctx) {
1505 qWarning("QOpenGLFramebufferObject::toImage() called without a current context");
1506 return QImage();
1507 }
1508
1509 if (d->colorAttachments.size() <= colorAttachmentIndex) {
1510 qWarning("QOpenGLFramebufferObject::toImage() called for missing color attachment");
1511 return QImage();
1512 }
1513
1514 GLuint prevFbo = 0;
1515 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
1516
1517 if (prevFbo != d->fbo())
1518 const_cast<QOpenGLFramebufferObject *>(this)->bind();
1519
1520 QImage image;
1521 QOpenGLExtraFunctions *extraFuncs = ctx->extraFunctions();
1522 // qt_gl_read_framebuffer doesn't work on a multisample FBO
1523 if (format().samples() != 0) {
1524 QRect rect(QPoint(0, 0), size());
1527 fmt.setInternalTextureFormat(d->colorAttachments[colorAttachmentIndex].internalFormat);
1528 QOpenGLFramebufferObject temp(d->colorAttachments[colorAttachmentIndex].size, fmt);
1529 blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect,
1530 GL_COLOR_BUFFER_BIT, GL_NEAREST,
1531 colorAttachmentIndex, 0);
1532 image = temp.toImage(flipped);
1533 } else {
1534 fmt.setInternalTextureFormat(d->colorAttachments[0].internalFormat);
1536 blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect);
1537 image = temp.toImage(flipped);
1538 }
1539 } else {
1541 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachmentIndex);
1542 image = qt_gl_read_framebuffer(d->colorAttachments[colorAttachmentIndex].size,
1543 d->colorAttachments[colorAttachmentIndex].internalFormat,
1544 true, flipped);
1546 } else {
1547 image = qt_gl_read_framebuffer(d->colorAttachments[0].size,
1548 d->colorAttachments[0].internalFormat,
1549 true, flipped);
1550 }
1551 }
1552
1553 if (prevFbo != d->fbo())
1554 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
1555
1556 return image;
1557}
1558
1569{
1571
1572 if (ctx) {
1573 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
1576 }
1577#ifdef QT_DEBUG
1578 else
1579 qWarning("QOpenGLFramebufferObject::bindDefault() called without current context.");
1580#endif
1581
1582 return ctx != nullptr;
1583}
1584
1592{
1594}
1595
1606{
1607 Q_D(const QOpenGLFramebufferObject);
1608 return d->fbo();
1609}
1610
1617{
1618 Q_D(const QOpenGLFramebufferObject);
1619 if (d->valid)
1620 return d->fbo_attachment;
1621 return NoAttachment;
1622}
1623
1633{
1635 if (attachment == d->fbo_attachment || !isValid())
1636 return;
1638 if (!current)
1639 return;
1640#ifdef QT_DEBUG
1641 if (current->shareGroup() != d->fbo_guard->group())
1642 qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");
1643#endif
1644 d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
1646 d->initDepthStencilAttachments(current, attachment);
1647}
1648
1654{
1655 Q_D(const QOpenGLFramebufferObject);
1657 if (!ctx)
1658 return false;
1659 GLint fbo = 0;
1660 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
1661 return GLuint(fbo) == d->fbo();
1662}
1663
1673{
1675}
1676
1677
1686{
1687 if (!target && !source)
1688 return;
1689
1690 QSize targetSize;
1691 QSize sourceSize;
1692
1693 if (target)
1694 targetSize = target->size();
1695 if (source)
1696 sourceSize = source->size();
1697
1698 if (targetSize.isEmpty())
1699 targetSize = sourceSize;
1700 else if (sourceSize.isEmpty())
1701 sourceSize = targetSize;
1702
1703 blitFramebuffer(target, QRect(QPoint(0, 0), targetSize),
1704 source, QRect(QPoint(0, 0), sourceSize),
1705 buffers, filter);
1706}
1707
1713 QOpenGLFramebufferObject *source, const QRect &sourceRect,
1715 GLenum filter)
1716{
1717 blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter, 0, 0);
1718}
1719
1785 QOpenGLFramebufferObject *source, const QRect &sourceRect,
1787 GLenum filter,
1788 int readColorAttachmentIndex,
1789 int drawColorAttachmentIndex,
1791{
1793 if (!ctx)
1794 return;
1795
1796 QOpenGLExtensions extensions(ctx);
1798 return;
1799
1800 GLuint prevFbo = 0;
1801 if (restorePolicy == RestoreFrameBufferBinding)
1802 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
1803
1804 const int sx0 = sourceRect.left();
1805 const int sx1 = sourceRect.left() + sourceRect.width();
1806 const int sy0 = sourceRect.top();
1807 const int sy1 = sourceRect.top() + sourceRect.height();
1808
1809 const int tx0 = targetRect.left();
1810 const int tx1 = targetRect.left() + targetRect.width();
1811 const int ty0 = targetRect.top();
1812 const int ty1 = targetRect.top() + targetRect.height();
1813
1814 const GLuint defaultFboId = ctx->defaultFramebufferObject();
1815
1816 extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);
1817 extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);
1818
1819 const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets);
1820 if (supportsMRT) {
1821 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0 + readColorAttachmentIndex);
1822 if (target) {
1823 GLenum drawBuf = GL_COLOR_ATTACHMENT0 + drawColorAttachmentIndex;
1824 extensions.glDrawBuffers(1, &drawBuf);
1825 }
1826 }
1827
1828 extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
1829 tx0, ty0, tx1, ty1,
1830 buffers, filter);
1831
1832 if (supportsMRT)
1834
1835 switch (restorePolicy) {
1837 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW
1838 break;
1839
1841 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); // sets both READ and DRAW
1842 break;
1843
1845 break;
1846 }
1847}
1848
1859 QOpenGLFramebufferObject *source, const QRect &sourceRect,
1861 GLenum filter,
1862 int readColorAttachmentIndex,
1863 int drawColorAttachmentIndex)
1864{
1865 blitFramebuffer(target, targetRect, source, sourceRect,
1866 buffers, filter,
1867 readColorAttachmentIndex,
1868 drawColorAttachmentIndex,
1870}
1871
bool ref() noexcept
bool deref() noexcept
T loadRelaxed() const noexcept
\inmodule QtGui
Definition qimage.h:37
uchar * bits()
Returns a pointer to the first pixel data.
Definition qimage.cpp:1677
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1197
@ Format_RGBA32FPx4_Premultiplied
Definition qimage.h:77
@ Format_RGB32
Definition qimage.h:46
@ Format_RGBX32FPx4
Definition qimage.h:75
@ Format_RGBA64_Premultiplied
Definition qimage.h:69
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
@ Format_RGBA16FPx4_Premultiplied
Definition qimage.h:74
@ Format_RGBX64
Definition qimage.h:67
@ Format_A2BGR30_Premultiplied
Definition qimage.h:62
@ Format_RGBX16FPx4
Definition qimage.h:72
@ Format_BGR30
Definition qimage.h:61
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_RGBX8888
Definition qimage.h:58
QImage mirrored(bool horizontally=false, bool vertically=true) const &
Definition qimage.h:218
Definition qlist.h:74
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
QOpenGLFramebufferObject * qgl_current_fbo
static QOpenGLContextPrivate * get(QOpenGLContext *context)
\inmodule QtGui
QOpenGLContextGroup * shareGroup() const
Returns the share group this context belongs to.
GLuint defaultFramebufferObject() const
Call this to get the default framebuffer object for the current surface.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
QOpenGLFunctions * functions() const
Get the QOpenGLFunctions instance for this context.
bool isOpenGLES() const
Returns true if the context is an OpenGL ES context.
bool hasOpenGLExtension(QOpenGLExtensions::OpenGLExtension extension) const
Returns true if extension is present on this system's OpenGL implementation; false otherwise.
The QOpenGLExtraFunctions class provides cross-platform access to the OpenGL ES 3....
void glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
Convenience function that calls glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0,...
void glRenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
Convenience function that calls glRenderbufferStorageMultisample(target, samples, internalformat,...
void glDrawBuffers(GLsizei n, const GLenum *bufs)
Convenience function that calls glDrawBuffers(n, bufs).
void glReadBuffer(GLenum mode)
Convenience function that calls glReadBuffer(src).
QOpenGLFramebufferObject::Attachment attachment
bool equals(const QOpenGLFramebufferObjectFormatPrivate *other)
The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL framebuffer object.
void setInternalTextureFormat(GLenum internalTextureFormat)
Sets the internal format of a framebuffer object's texture or multisample framebuffer object's color ...
QOpenGLFramebufferObjectFormat & operator=(const QOpenGLFramebufferObjectFormat &other)
Assigns other to this object.
bool operator!=(const QOpenGLFramebufferObjectFormat &other) const
Returns false if all the options of this framebuffer object format are the same as other; otherwise r...
QOpenGLFramebufferObjectFormat()
Creates a QOpenGLFramebufferObjectFormat object for specifying the format of an OpenGL framebuffer ob...
bool mipmap() const
Returns true if mipmapping is enabled.
GLenum textureTarget() const
Returns the texture target of the texture attached to a framebuffer object.
void setSamples(int samples)
Sets the number of samples per pixel for a multisample framebuffer object to samples.
QOpenGLFramebufferObject::Attachment attachment() const
Returns the configuration of the depth and stencil buffers attached to a framebuffer object.
int samples() const
Returns the number of samples per pixel if a framebuffer object is a multisample framebuffer object.
void setAttachment(QOpenGLFramebufferObject::Attachment attachment)
Sets the attachment configuration of a framebuffer object to attachment.
bool operator==(const QOpenGLFramebufferObjectFormat &other) const
Returns true if all the options of this framebuffer object format are the same as other; otherwise re...
void setMipmap(bool enabled)
Enables mipmapping if enabled is true; otherwise disables it.
~QOpenGLFramebufferObjectFormat()
Destroys the QOpenGLFramebufferObjectFormat.
GLenum internalTextureFormat() const
Returns the internal format of a framebuffer object's texture or multisample framebuffer object's col...
void setTextureTarget(GLenum target)
Sets the texture target of the texture attached to a framebuffer object to target.
bool checkFramebufferStatus(QOpenGLContext *ctx) const
void initDepthStencilAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment)
QOpenGLSharedResourceGuard * fbo_guard
QOpenGLFramebufferObject::Attachment fbo_attachment
void init(QOpenGLFramebufferObject *q, const QSize &size, QOpenGLFramebufferObject::Attachment attachment, GLenum texture_target, GLenum internal_format, GLint samples=0, bool mipmap=false)
void initColorBuffer(int idx, GLint *samples)
QOpenGLSharedResourceGuard * depth_buffer_guard
QVarLengthArray< ColorAttachment, 8 > colorAttachments
QOpenGLSharedResourceGuard * stencil_buffer_guard
The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer object.
Attachment attachment() const
Returns the status of the depth and stencil buffers attached to this framebuffer object.
static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, QOpenGLFramebufferObject *source, const QRect &sourceRect, GLbitfield buffers, GLenum filter, int readColorAttachmentIndex, int drawColorAttachmentIndex, FramebufferRestorePolicy restorePolicy)
virtual ~QOpenGLFramebufferObject()
Destroys the framebuffer object and frees any allocated resources.
Attachment
This enum type is used to configure the depth and stencil buffers attached to the framebuffer object ...
static bool bindDefault()
Switches rendering back to the default, windowing system provided framebuffer.
void setAttachment(Attachment attachment)
Sets the attachments of the framebuffer object to attachment.
GLuint takeTexture()
Returns the texture id for the texture attached to this framebuffer object.
static bool hasOpenGLFramebufferBlit()
Returns true if the OpenGL {GL_EXT_framebuffer_blit} extension is present on this system; otherwise r...
void addColorAttachment(const QSize &size, GLenum internalFormat=0)
Creates and attaches an additional texture or renderbuffer of size width and height.
QOpenGLFramebufferObjectFormat format() const
Returns the format of this framebuffer object.
bool release()
Switches rendering back to the default, windowing system provided framebuffer.
QOpenGLFramebufferObject(const QSize &size, GLenum target=GL_TEXTURE_2D)
Constructs an OpenGL framebuffer object and binds a 2D OpenGL texture to the buffer of the size size.
bool isBound() const
Returns true if the framebuffer object is currently bound to the current context, otherwise false is ...
GLuint handle() const
Returns the OpenGL framebuffer object handle for this framebuffer object (returned by the {glGenFrame...
QImage toImage(bool flipped=true) const
Returns the contents of this framebuffer object as a QImage.
static bool hasOpenGLFramebufferObjects()
Returns true if the OpenGL {GL_EXT_framebuffer_object} extension is present on this system; otherwise...
GLuint texture() const
Returns the texture id for the texture attached as the default rendering target in this framebuffer o...
QList< GLuint > textures() const
Returns the texture id for all attached textures.
bool bind()
Switches rendering from the default, windowing system provided framebuffer to this framebuffer object...
bool isValid() const
Returns true if the framebuffer object is valid.
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
GLboolean glIsRenderbuffer(GLuint renderbuffer)
Convenience function that calls glIsRenderbuffer(renderbuffer).
void glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
Convenience function that calls glDeleteFramebuffers(n, framebuffers).
void glGenTextures(GLsizei n, GLuint *textures)
Convenience function that calls glGenTextures(n, textures).
void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
Convenience function that calls glDeleteRenderbuffers(n, renderbuffers).
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Convenience function that calls glTexImage2D(target, level, internalformat, width,...
void glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params)
Convenience function that calls glGetRenderbufferParameteriv(target, pname, params).
void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers)
Convenience function that calls glGenRenderbuffers(n, renderbuffers).
void glBindRenderbuffer(GLenum target, GLuint renderbuffer)
Convenience function that calls glBindRenderbuffer(target, renderbuffer).
void glTexParameteri(GLenum target, GLenum pname, GLint param)
Convenience function that calls glTexParameteri(target, pname, param).
void glBindTexture(GLenum target, GLuint texture)
Convenience function that calls glBindTexture(target, texture).
void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
Convenience function that calls glFramebufferTexture2D(target, attachment, textarget,...
void glDeleteTextures(GLsizei n, const GLuint *textures)
Convenience function that calls glDeleteTextures(n, textures).
void glBindFramebuffer(GLenum target, GLuint framebuffer)
Convenience function that calls glBindFramebuffer(target, framebuffer).
void initializeOpenGLFunctions()
Initializes OpenGL function resolution for the current context.
void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
Convenience function that calls glFramebufferRenderbuffer(target, attachment, renderbuffertarget,...
void glGenFramebuffers(GLsizei n, GLuint *framebuffers)
Convenience function that calls glGenFramebuffers(n, framebuffers).
bool hasOpenGLFeature(QOpenGLFunctions::OpenGLFeature feature) const
Returns true if feature is present on this system's OpenGL implementation; false otherwise.
void glGetIntegerv(GLenum pname, GLint *params)
Convenience function that calls glGetIntegerv(pname, params).
void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
Convenience function that calls glRenderbufferStorage(target, internalformat, width,...
The QOpenGLSharedResourceGuard class is a convenience sub-class of QOpenGLSharedResource to be used t...
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:175
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:172
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
EGLContext ctx
static VulkanServerBufferGlFunctions * funcs
rect
[4]
Combined button and popup list for selecting options.
Definition image.cpp:4
static void * context
DBusConnection const char DBusError * error
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
typedef GLint(GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC)(GLuint program
GLuint const GLuint * buffers
GLsizei samples
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei const GLuint * ids
GLenum GLuint id
[7]
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLint GLsizei width
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLenum target
GLenum GLuint texture
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLenum attachment
GLint GLsizei GLsizei GLenum format
GLsizei GLenum internalFormat
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
#define GL_RENDERBUFFER_SAMPLES
#define GL_DEPTH24_STENCIL8
#define GL_DEPTH_COMPONENT16
Definition qopenglext.h:328
GLint void * img
Definition qopenglext.h:233
#define GL_RGBA16F
Definition qopenglext.h:913
#define GL_RGB16F
Definition qopenglext.h:914
#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
#define GL_COLOR_ATTACHMENT0
#define GL_DEPTH_STENCIL_ATTACHMENT
#define GL_STENCIL_INDEX8
#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
typedef GLbitfield(APIENTRYP PFNGLQUERYMATRIXXOESPROC)(GLfixed *mantissa
#define GL_FRAMEBUFFER_COMPLETE
#define GL_DRAW_FRAMEBUFFER
#define GL_MAX_SAMPLES
#define GL_RENDERBUFFER
#define GL_FRAMEBUFFER_UNSUPPORTED
#define GL_FRAMEBUFFER
#define GL_HALF_FLOAT
#define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
#define GL_DEPTH_STENCIL
#define GL_FRAMEBUFFER_BINDING
#define GL_READ_FRAMEBUFFER
#define GL_DEPTH_ATTACHMENT
#define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
#define GL_DEPTH_COMPONENT24
Definition qopenglext.h:329
#define GL_CLAMP_TO_EDGE
Definition qopenglext.h:100
#define GL_STENCIL_ATTACHMENT
static QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool include_alpha, QOpenGLContext *context)
static QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool include_alpha, QOpenGLContext *context)
#define GL_RGB10
static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)
#define GL_RGBA8
#define GL_RGBA16F
static QImage qt_gl_read_framebuffer_rgba16f(const QSize &size, bool include_alpha, QOpenGLContext *context)
#define GL_RGB16
#define GL_RGB16F
#define QT_RESET_GLERROR()
static GLenum effectiveInternalFormat(GLenum internalFormat)
#define GL_BGRA
#define GL_RGB8
#define QT_CHECK_GLERROR()
#define GL_RGB10_A2
#define GL_HALF_FLOAT
static QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool include_alpha, QOpenGLContext *context)
#define GL_RGBA32F
#define GL_RGBA16
#define GL_RGB32F
static QImage qt_gl_read_framebuffer_rgba32f(const QSize &size, bool include_alpha, QOpenGLContext *context)
#define GL_UNSIGNED_INT_8_8_8_8_REV
#define GL_UNSIGNED_INT_2_10_10_10_REV
#define GL_CONTEXT_LOST
#define GL_UNSIGNED_INT_2_10_10_10_REV
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GL_RGBA8
#define GL_STENCIL_INDEX
#define GLuint
#define GL_FLOAT
#define GL_UNSIGNED_BYTE
#define GL_RGBA
#define Q_UNUSED(x)
#define Q_TRACE_PARAM_REPLACE(in, out)
Definition qtrace_p.h:231
#define Q_TRACE_METADATA(provider, metadata)
Definition qtrace_p.h:234
#define Q_TRACE_PREFIX(provider, prefix)
Definition qtrace_p.h:233
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE_INSTRUMENT(provider)
Definition qtrace_p.h:230
QVideoFrameFormat::PixelFormat fmt
#define enabled
QStorageInfo storage
[1]
QSharedPointer< T > other(t)
[5]